11 de julio de 2016

Normas de codificación en Visual FoxPro

Texto original: Visual FoxPro Coding Standards
http://www.craigberntson.com/Articles/kb015.htm
Autor: Craig Berntson
Traducido por: Ana María Bisbé York
Última actualización: Septiembre 26, 2003


Resumen

Aplicar buenas normas de codificación es importante para el desarrollo de cualquier proyecto; pero es particularmente importante cuando muchos desarrolladores están trabajando en el mismo proyecto. Tener establecido pautas de codificación contribuye a garantizar que el código es de alta calidad, con pocos errores y de fácil mantenimiento.

Estas normas o pautas se basan en años de desarrollo de aplicaciones con Visual FoxPro y de aprendizaje de cuáles técnicas de codificación trabajan mejor. Además, muchos conceptos han sido adaptados a partir de Code Complete (Microsoft Press, ISBN 1-55615-484-4) escrito por Steve McConnell. Este libro, es considerado una de las guías más importantes en prácticas de codificación. Puede que usted no esté de acuerdo con éstas normas, no hay problemas. Para mí, estas normas han funcionado bien.

Normas de codificación

Convenciones de variables.

No utilice guiones bajos en nombres de variables. Mezclar mayúsculas y minúsculas mejora la legibilidad. La primera letra de la variable debe indicar su alcance y debe ser siempre minúscula. Trate de evitar el uso de variables públicas (PUBLIC) y privadas. En su lugar utilice propiedades de los objetos de su aplicación, propiedades de formularios y variables locales.

  • l - Local
  • g - Global
  • p - Private
  • t - Parameter

La segunda letra indica el tipo de dato.

  • c - Character
  • n - Numeric
  • d - Date
  • t - DateTime
  • l - Logical
  • m - Memo
  • a - Array
  • o - Object
  • x - Indeterminate

Ejemplos de nombres de variables válidos:

lcFirstName
tdBeginDate

Tenga en mente el alcance de la variable. Preferiblemente deben utilizarse variables locales (LOCAL). Las variables públicas (PUBLIC) deben evitarse tanto como sea posible. Las declaraciones de variables, tales como: LOCAL lcMyVar se deben colocar todas al inicio de la rutina a ejecutar, en lugar de dispersarlas por el código. Declare todas las variables al inicio de la rutina, en lugar de entremezclarlas por todo el código y asigne su valor predeterminado.

Forma incorrecta:

LOCAL lnMyNum
lnMyNum = 12

LOCAL lcMyString
lcMyString = "ABCD"

LOCAL lnCounter
lnCounter = 0

Forma correcta:

LOCAL lnMyNum, lcMyString, lnCounter

lnMyNum = 12
lcMyString = "ABCD"
lnCounter = 0

Convenciones para nombrar objetos.

Las primeras tres letras del nombre de un objeto deben ser utilizadas para indicar el tipo del objeto.

  • chk - Check box
  • cbo - Combo box
  • cmd - Command button
  • cmg - Command Group
  • cnt - Container
  • ctl - Control
  • cus - Custom
  • edt - Edit box
  • frm - Form
  • frs - Form set
  • grd - Grid
  • grc - Grid Column
  • grh - Grid Column Header
  • img - Image
  • lbl - Label
  • lin - Line
  • lst - List box
  • olb - OLE Bound Control
  • ole - OLE Object como un ActiveX Control
  • opg - Option Group
  • pag - Page
  • pgf - Pageframe
  • sep - Separator
  • shp - Shape
  • spn - Spinner
  • txt - Text box
  • tmr - Timer
  • tbr - Toolbar

Normas para el código fuente:

  1. Utilice abundantes espacios en blanco. Hará más legible su código.
  2. Utilice tabuladores, en lugar de espacios para indentar.
  3. Los comandos y funciones de Visual FoxPro deben escribirse en mayúsculas y con la totalidad de sus letras, el resto del código debe estar escrito con combinación de mayúsculas y minúsculas. Mantenga líneas cortas, tanto como sea posible, para evitar desorden (line wrap) durante la impresión. Si una línea de código, ocupa físicamente más de una línea, utilice las expresiones de unión como primer carácter de la línea siguiente. Las expresiones de unión son del tipo +, AND, OR, NOT, etc. Recuerde además, que la línea debe ser tan válida como si fuera una sola línea. Coloque un espacio antes del punto y coma.

Ejemplos de malas separaciones de líneas:

lcCommand = "Hoy es Miércoles, 16 de Octubre de 2003" + ;
"Son las 2:00 PM"
 
IF ldBeginDate >= DATE() OR ;
   ldEndDate >= DATE()

Ejemplos de buenas separaciones de líneas:

lcCommand = " Hoy es Miércoles, 16 de Octubre de 2003" ;
   + "Son las 2:00 PM"
 
IF ldBeginDate >= DATE() ;
   OR ldEndDate >= DATE() 
  1. Por lo visto, cada uno combina las mayúsculas y minúsculas de forma diferente. Aunque no existe vía correcta o incorrecta en este aspecto, si hay algunas normas que ayudan a la legibilidad. Además, utilice expresiones CASE en lugar de IF, cuando parezca que se pueden agregar posteriormente más opciones, incluso si existen sólo dos opciones en el momento en que es escrito el código o, para liberarse de las instrucciones IF, ELSE, IF. Separe cada CASE por una línea en blanco. El comentario para el CASE debe ir por debajo del mismo.

Forma incorrecta:

DO CASE
  * Este es el comentario para el caso 1
  CASE lnCount = 1
    lcRetVal = "Uno"
  * Este es el comentario para el caso 2
  CASE lnCount = 2
    lcRetVal = "Dos"
  * Este es el comentario para otherwise 
  OTHERWISE
    lcRetVal = "Otro"
ENDCASE

Forma correcta:

DO CASE
  CASE lnCount = 1
    * Este es el comentario para el caso 1
    lcRetVal = "Uno" 
  CASE lnCount = 2
    * Este es el comentario para el caso 2
    lcRetVal = "Dos" 
  OTHERWISE
    * Este es el comentario para otherwise 
    lcRetVal = "Otro"
ENDCASE 
  1. Trate de evitar macro sustitución. A veces la macrosutitución es la única vía para lograr algo. Asegúrese de documentar, por qué utiliza macrosustitución y cuál es el propósito del código. En la mayoría de los casos, la macrosustitución hace que el código sea menos legible. Utilice la función EVALUATE(). Si es posible, pero nuevamente los comentarios son importantes para ayudar a leer el código.
  2. Evite utilizar STORE.
  3. Utilice "[]" en lugar de paréntesis en los arreglos. Así, el código es más legible.
  4. Coloque espacios entre los operadores matemáticos. Esto mejora la legibilidad.
  5. Utilice paréntesis cuando llame métodos o funciones, incluso, si no pasa ningún parámetro.
  6. Evite el uso de m. a la izquierda del signo igual. Esto mejorará el rendimiento.
  7. Al concatenar cadenas, coloque la variable a la izquierda del signo +. Esto mejorará el rendimiento.

Normas para comentar código

Los comentarios son parte importante de cualquier aplicación. Utilícelos abundantemente. Los comentarios deben explicar por qué se han hecho algunas cosas e indicar cuáles son las líneas de código que están afectadas. Debe explicar solamente cómo se hizo algo, en caso de estar utilizando complejos algoritmos o cálculos.

No emplee comentarios al final de las líneas con &&. Cada comentario debe ocupar una línea propia.

Encabezados de programa, método y procedimiento.

Los encabezados de programa, método y procedimiento deben indicar el nombre de la rutina, la fecha en que fue creada originalmente, el autor y una descripción del objetivo del procedimiento o método. En caso de existir parámetros y valores devueltos, incluya una descripción de los mismos. Para los métodos, incluya la jerarquía de objetos.

Ejemplo 1:

*********************************************************
* Método........: frmQueue.cmdNext.Click
* Descripción...: Displays the next item in the selected queue
* Fecha.........: 01-Oct-2001
* Autor.... ....: Fred Flintstone
*********************************************************
* Modification Summary
*
*********************************************************

Ejemplo 2:

*********************************************************
* Función......: CalcIntrest
* Descripción...: Calculate the interest in dollars on the loan
* Parámetros....: tnBalance: Required: The balance amount
* : tnRate: Required: The interest rate to apply
* Devuelve......: Numeric: The dollar amount of the interest
* Fecha.........: 01-Oct-2001
* Autor.........: Bullwinkle J. Moose
*********************************************************
* Modification Summary (Resumen de modificaciones)
*
********************************************************* 

Comentar modificaciones

Es importante poner comentarios al hacer modificaciones para saber cuáles fueron las modificaciones realizadas, y por qué las realizó. La sección Modification Summary (Resumen de modificaciones) en el encabezado explicará por qué, cuándo y por quién fueron realizadas las modificaciones. En cada lugar del código, donde fue realizada una modificación, debe comentar el código viejo e indicar cuál es el código nuevo que fue añadido. Cada modificación debe ser numerada. Los cambios pueden ser borrados después de un año; pero el Resumen de modificaciones debe permanecer.

Ejemplo:

*********************************************************
* Modification Summary
*
* /01 05-Oct-2001 George Jetson
* Changed interest calculation to include a date range factor.
* /02 10-Oct-2001 Tennessee Tuxedo
* 1. Added code to handle interest on widgets. The calculation is different.
* 2. Changed the return value from numeric to character.
********************************************************* 
*/01 lcNote =  "This is the old line commented out "
*/01
lcNote =  "This is the new line of code. " 
*/02-1 lnInterest = a * b
*/02-1 lnInterest = lnInterest / 43 
*/02-1 - Begin - Multiple lines are being added, so indicate they start here
IF UPPER(tcIntType) =  "WIDGETS "
  lnInterest = a * c
ELSE
  lnInterest = a * b
  lnInterest = lnInterest / 43
ENDIF
*/02-1 - End

Las líneas de comentario deben indentarse al mismo nivel del código.

Este ejemplo es incorrecto:

IF lnTotalInterest = 0
*/01 – Begin
  FOR lnCount = 1 TO lnTotal
    lnTotalInterest = lnTotalInterest + laLoans[lnCount, 2]
  ENDFOR
*/02 – End
ENDIF

Este ejemplo es correcto:

IF lnTotalInterest = 0
  */01 – Begin
  FOR lnCount = 1 TO lnTotal
    lnTotalInterest = lnTotalInterest + laLoans[lnCount, 2]
  ENDFOR
  */02 – End
ENDIF

Al comentar líneas que continúan, hay que comentar cada línea física.

Incorrecto:

*/01 lcString =  "Esta cadena contiene mucho texto porque es un  " ;
  +  "ejemplo de una línea verdaderamente larga "

Correcto:

*/01 lcString =  "Esta cadena contiene mucho texto porque es un  " ;
*/01 +  "ejemplo de una línea verdaderamente larga " 

Normas para interfaz de usuario

Normas generales para interfaz de usuario (UI)

Cuando sea posible, la interfaz de usuario debe cumplir con las directivas de Windows Standards descritas en el libro  "Microsoft Windows User Experience ", Microsoft Press, ISBN 0-7356-0566-1. Este libro se encuentra disponible en: http://msdn.microsoft.com/library/en-us/dnwue/html/welcome.asp. Tenga en mente todo el tiempo al usuario. Mientras más sencilla sea la funcionalidad para el usuario, mejor será la aplicación. Esto puede significar que el código que está detrás de esta funcionalidad es más complejo.

Formularios de entrada de datos

  1. Todos los campos aptos para entrada deben utilizar Select On Entry.
  2. Los campos numéricos deben ser formateados con comas y signos negativos cuando sea necesario.
  3. Si un campo es de sólo lectura, establezca la propiedad TabStop en .F., Establezca la propiedad ReadOnly a .T. o la propiedad Enabled a .F., según sea el caso. La propiedad ReadOnly se utiliza cuando el campo nunca es modificable. La propiedad Enabled se utiliza cuando el campo es modificable cuando se cumple una determinada condición (es evaluada a .F.)
  4. Utilice la barra de estado para mostrar un mensaje al usuario que indique el propósito del campo.
  5. Muestre siempre los valores predeterminados, en los casos en que se aplique.
  6. Inhabilite (Enabled = .F.) los objetos cuando sea necesario. Esto proporciona indicación visual al usuario de que el objeto no puede ser modificado en ese momento.

Mensajes

  1. No utilice WAIT WINDOW para mostrar mensajes importantes al usuario. Es muy fácil que el usuario no note el mensaje. En su lugar utilice MESSAGEBOX. Incluya siempre el icono apropiado en el cuadro de mensaje (message box). Evite la utilización del parámetro TIMEOUT, ya que el usuario puede perder información importante.
  2. Utilice la barra de estado para mostrar ayuda en línea para el objeto actual, ya sea en un formulario o un menú.

Objetos de formulario

  1. Text box. (cuadros de texto) El cuadro de texto es el control más comúnmente utilizado. Puede contener valores de caracteres, numéricos o fecha.
  2. Check box. (casilla de verificación) La casilla de verificación es un control sencillo que está establecido en ON u OFF. Son utilizadas típicamente para indicar un estado de Sí o No.
  3. Command button. (Botón de comando) El botón de comandos es utilizado para iniciar una acción. Los botones más comúnmente utilizados son OK (Aceptar) y Cancel (Cancelar). Algunas veces los botones de comandos son agrupados en los command group (grupos de comandos). Intente evitar los grupos de comandos, los botones individuales son más fáciles de mantener.
  4. Option button. (Botón de opción) En ocasiones se les llama radio button. Se utiliza para indicar que el usuario puede seleccionar una opción de un grupo de opciones. Los botones de opciones son frecuentemente agrupados en Option group (grupo de opciones). Esto simplifica el código para el proceso de selección. Se recomienda que los grupos de opciones se utilicen en lugar de los botones de opciones. Los grupos de opciones deben ser preferiblemente ordenados verticalmente antes que horizontalmente.
  5. Drop-down list. (Lista desplegable) Una lista desplegable permite al usuario hacer una selección de una lista de varios objetos, como con un botón de opción. Sin embargo, la lista desplegable requiere de menos espacio en pantalla.
  6. Combo box. (Cuadro combinado) Los cuadros combinados se identifican como un textbox en una flecha hacia abajo. Se llama cuadro combinado, porque es una combinación de un cuadro de texto y una lista desplegable. El usuario puede escribir un nuevo valor o seleccionarlo de la lista.
  7. List box. (Cuadro de lista) Un cuadro de lista puede ser utilizado uno o varios objetos de una lista.
  8. Spinner. Un control spinner es una especie de textbox con flechas hacia arriba y hacia abajo. Es utilizado normalmente para datos numéricos. El número aumenta o disminuye al hacer clic en las flechas o el usuario puede introducir un valor específico.
  9. Edit box. (Cuadro de edición) Un cuadro de edición se comporta de forma parecida al textbox; pero normalmente es utilizado para campos memo. Un editbox puede tener barras de desplazamiento y deslizamiento de filas (word wrap)

Copyright © 2001-2004, Craig Berntson. All Rights Reserved.

9 de julio de 2016

Dígito verificador CURP (México)

Rutina para calcular el dígito verificador de la CURP (México) a partir de los 17 caracteres iniciales de la misma.

* Dígito Verificador CURP

Function _Curp(cCurp)

  cCaracteres='0123456789ABCDEFGHIJKLMNÑOPQRSTUVWXYZ'
  nFactor=19
  nSuma=0

  FOR nIndice=1 TO LEN(cCaracteres)

    cCaracter=SUBSTR(cCurp,nIndice,1)
    nPos=AT(cCaracter,cCaracteres)
    nFactor=nFactor-1
    nSuma=nSuma+nPos*nFactor
 
  ENDFOR 

  nDigito=10-MOD(nSuma,10)
  nDigito=IIF(nDigito=10,0,nDigito)
  cCurp=cCurp+TRANSFORM(nDigito)

  RETURN cCurp
ENDFUNC

Jesus Caro V

6 de julio de 2016

El huevo o la gallina, ¿Propiedades o métodos?

Artículo original: Egg or Chicken, Properties or Methods?
http://www.foxpert.com/knowlbits_200701_6.htm
Autor: Christof Wollenhaupt
Traducido por: Ana María Bisbé York


En Visual FoxPro se pueden utilizar expresiones para iniciar propiedades. Estas expresiones son evaluadas una vez que carga la primera vez la clase en la memoria. El resultado se guarda en el objeto de clase. Para crear una expresión para una propiedad, puede, o entrar el signo igual en la ventana Propiedades seguido por la expresión, o presionar el botón "fx" que está junto al botón Zoom, en la ventana Propiedades.

He mostrado en varias ocasiones que estas expresiones pueden incluir THIS. La referencia apunta al objeto clase, no al objeto que está creando. De hecho, THIS ni siquiera apunta a un objeto de la misma clase. Si solamente accede a las propiedades del objeto clase, no notará la diferencia.

No obstante, si intenta llamar a un método debe tener en cuenta que las propiedades son evaluadas antes que los métodos. ¿Esto qué significa? Cree una clase "Level1" basada en Form y guárdela en Level1.VCX. Agregue el método "CallMethod" con el siguiente código:

Activate Screen
? "Llamada ", This.Class

Ahora, añada la propiedad nTest y asigne la siguiente expresión:

=This.CallMethod()*2

En la ventana de comandos escriba:

Clear All
Release All
Clear
ox = NewObject("Level1","Level1")
? ox.nTest

Notará dos cosas. La pantalla está vacía y nTest es .F., no 2. La razón para esto es que, en el momento en que es evaluada la expresión, aún no ha sido adjuntado el código al método. CallMethod existe; pero está vacío. Ahora, permítame avanzar a un punto superior. Crear un programa ShowInfo.prg con el siguiente contenido

Lparameters toRef
? toRef.Class
toRef.CallMethod()
Return 1

Cree una nueva clase Level2 que hereda de Level1. Almacene la nueva clase en Level2.vcx. Sobreescriba CallMethod con este código:

Activate Screen
? "Subclase llamada ", This.Class

Ahora active la ventana Comandos y escriba:

Clear All
Release All
Clear
ox = NewObject("Level2","Level2")

Esta vez puede ver la siguiente salida:

Level2
Called Level2

Cuando se carga la clase, ya está claramente llamado el método ShowInfo. La llamada del método también trabaja, al menos en alguna medida. En lugar de ejecutar el código en la clase Level2, ahora ejecuta el código desde la clase Level,1 que no ha sido ejecutada cuando se instancia el Level1.

Lo que ocurre es que cuando instancie Level2, Visual FoxPro, crea primeramente un objeto para Level1. Esto ocurre en dos pasos. Primero, son evaluadas todas las propiedades. Luego, se añaden todos los métodos. Como se ha pedido Level2, Visual FoxPro, crea luego el objeto para Level2. VFP crea una copia para la clase Level1 incluyendo el código del método. Como antes, las propiedades se evalúan primero. En este momento, CallMethod combina aun el código que ha sido copiado desde la clase de Level1.

Únicamente después de que todas las propiedades hayan sido evaluadas, Visual FoxPro agrega los códigos de los métodos a la clase Level2. Si crea una variable pública en ShowInfo.prg y guarda toRef en esa variable, obtiene una referencia a la clase. Cuando ejecuta CallMethod() en este objeto global  después de crear una instancia, obtiene además el código de la subclase.

Por tanto, recuerde: Las propiedades existen antes de que existan los métodos. Si no desea crear estas clases por si mismo, las puede descargar desde aquí:

http://www.foxpert.com/files/EggOrChicken.zip

2 de julio de 2016

Información con WSH

Podemos utilizar Microsoft ® Windows Script Host para mostrar información de nuestra PC, como por ejemplo: Dominio, Usuario, Nombre de PC, Unidades de red e Impresoras como lo muestra el siguiente ejemplo:

? "Información con WSH"
o = CREATEOBJECT('Wscript.Network')
? "Dominio: " + o.UserDomain
? "Usuario: " + o.UserName
? "Computadora: " + o.ComputerName
?
? "Unidades de red:"
oD = o.EnumNetworkDrives
FOR i = 0 TO oD.COUNT-1 STEP 2
  ? "Unidad: " + oD.ITEM(i) + " - Recurso: " + oD.ITEM(i+1)
ENDFOR
?
? "Impresoras:"
oP = o.EnumPrinterConnections
FOR i = 0 TO oP.COUNT-1 STEP 2
  ? "Puerto: " + oP.ITEM(i) +  " - Impresora: " + oP.ITEM(i+1)
ENDFOR
RELEASE oD
RELEASE oP
RELEASE o

Luis María Guayán