viernes, agosto 29, 2014

Nueva versión v2.4.28 de las herramientas Visual FoxPro 9 para PlasticSCM (Incluye FoxBin2Prg.exe v1.19.33)

Qué son las Herramientas VFP 9 para Plastic:


Estas herramientas son un grupo de scripts vbs y programas Visual FoxPro 9 que se configuran dentro de PlasticSCM para poder invocar a FoxBin2Prg (incluye solo el EXE) desde dentro de la interfaz de Plastic.


Está liberada la versión v2.4.28 de las herramientas Visual FoxPro 9 para PlasticSCM, con los siguientes cambios:




El README.txt explica como se configura en Inglés y Español, y también está explicado en esta nota: Cómo configurar las Herramientas de VFP 9 para Plastic


Nota: Los fuentes del proyecto FoxBin2Prg y el historial de ambios, están en CodePlex, en este link.


Como actualizar las existentes:
Con descargarlas y reemplazar los archivos en el sitio que los hayan puesto antes es suficiente.


Link de descarga:
https://github.com/fdbozzo/foxpro_plastic_diff_merge


Saludos!

Nueva versión v1.19.33 de FoxBin2Prg (arreglo de bugs mnx)

Qué es FoxBin2Prg:


Es un programa pensado para ser utilizado con herramientas SCM (Administradores de Control de Código Fuente, como VSS, CVS, SVN) y herramientas DVCS (como Git, Mercurial, Plastic, and others), o como programa independiente, para hacer operaciones de Diff (ver diferencias) y Merge (mezclar cambios), que pretende sustituir a SccText(X) y TwoFox y mejorar sus funcionalidades, generando versiones de texto estilo-PRG que permiten recrear el binario original.


Está liberada la versión v1.19.33 de FoxBin2Prg con los siguientes cambios:

  • Bug mnx: El menú no se genera bien cuando hay Bars del tipo #BAR y nombre vacío (Peter Hipp).
  • Bug mnx: Si una opción tiene asociado un Procedure de 1 línea, no se mantiene como Procedure y se convierte a Command (Peter Hipp).


Como actualizar el FoxBin2Prg existente:Con descargar el zip y reemplazar los archivos en el sitio que los hayan puesto antes es suficiente.


Link  de descarga:
https://vfpx.codeplex.com/releases/view/116407


 Saludos!

martes, agosto 26, 2014

Nueva versión v1.19.32 de FoxBin2Prg (arreglo bug)

Está liberada la versión v1.19.32 de FoxBin2Prg con los siguientes cambios:

  • Una propiedad llamada "text" es confundida con la estructura text/endtext (ph42).




Como actualizar el FoxBin2Prg existente:
Con descargar el zip y reemplazar los archivos en el sitio que los hayan puesto antes es suficiente.


Link  de descarga:
https://vfpx.codeplex.com/releases/view/116407


 Saludos!

sábado, agosto 23, 2014

PlasticSCM: Opciones de búsqueda y visualización de ramas y changesets

Por: Fernando D. Bozzo

Cuando se comienza a trabajar con ramas, al poco tiempo se puede convertir en un frondoso árbol donde a veces es difícil poder ver una rama particular y sus relaciones, porque es cruzada por varias otras que en principio no nos interesa ver.

Una de las cosas más importantes que se debe conocer, cuando se trabaja con una herramienta SCM o DVCS, es poder visualizar lo que se quiere de distintas formas, para tener un mejor control sobre lo que se está haciendo o viendo.

En este artículo veremos varias de ellas, y les recomiendo elegir estas opciones al menos una vez para conocerlas y ver su utilidad.

Nota: Todas las vistas permiten trabajar desde ellas. No solo son para visualizar.


Todas las vistas se seleccionan desde el panel izquierdo, el cuál está siempre visible:




Vista del Explorador de ramas


Esta es una vista típica de las ramas de un equipo de desarrollo donde, como se puede observar, cuesta un poco poder ver solo las ramas marcadas en amarillo:





Panel derecho del Explorador de ramas


Con el botón Navegador se puede habilitar o inhabilitar el panel derecho, que tiene varias opciones interesantes:




Apartado: Propiedades


Dentro de este apartado podemos ver información sobre el changeset o rama seleccionada, además de que desde aquí podemos modificar los comentarios:




Apartado: Opciones de visualización


Dentro de este apartado podemos controlar varios aspectos de lo que se muestra en el Explorador de ramas, incluso opciones de filtrao por fechas o niveles de hijos desde el changeset 0.

La mayoría de las opciones son simples y se pueden entender a primera vista, pero hay un par de opciones que no son tan obvian y que requieren algo de explicación, y que son las de debajo de todo: Activar modo de edición de visibilidad y Activar edición de disposición.


Activar modo de edición de visibilidad

Permite ocultar/mostrar ramas: Se elige esta opción, se marcan las ramas a ocultar y se desmarca esta opción para finalizar. Todavía no me tocó una situación donde requiera esto.

Nota: Cuando se elige esta opción, se muestra una explicación de uso debajo.


Activar edición de disposición

Esta opción permite reorganizar las ramas, para poder agruparlas de una forma más útil que la forma por defecto, por ejemplo, acercando entre sí las ramas que tienen relación directa.

Nota: Cuando se elige esta opción, se muestra una explicación de uso debajo.


La forma se uso es simple: Se marca esta opción, se elige la rama que se quiere mover (solo hacia arriba/abajo, ya que izquierda/derecha es controlado por la fecha/hora de la rama según su columna), se mueve la rama con las flechas de cursor y se vuelve a desmarcar esta opción para que queden los cambios guardados.



Nota: Si no se llegara a ver todo el panel completo y apareciera recortado en altura, seguramente el problema sea la resolución de pantalla, que debería ser como mínimo de 1280x1024 para poder ver las opciones completas.


Búsqueda rápida


El cuadro superior-derecho permite escribir para hacer un filtrado en cuando se pulsa <Enter>.

Por ejemplo, si escribiéramos tarea-025, la vista anterior resaltaría en amarillo todas las ramas que contengan ese texto en su nombre, marcando la rama seleccionada en naranja, permitiendo la navegación por las mismas con las flechas de navegación.




Nota: Una búsqueda que a veces puede ser útil, es la búsqueda por changeset, que da un único resultado. En ese caso la forma de buscar es usand la nomenclatura cs:nn , por ejemplo para buscar el changeset 51, escribiríamos cs:51 <Enter>


Opciones del Explorador de ramas


Si hacemos click-derecho sobre una rama y elegimos la opción Explorador de ramas, podemos ver las siguientes opciones:




Opción: Ir a la base de la rama


Nos permite ir al changeset de la rama padre de donde se creó esta rama, y que es a donde apunta la flecha gris fina de cada rama.



Opción: Mostrar ramas seleccionadas en un nuevo diagrama


Si quisiéramos ver una rama (o varias) por separado, sin el ruido de las que no nos interesan, las podemos marcar con CTRL+Click, al igual que se hace para elegir varios archivos en el explorador de archivos, luego hacemos click-derecho sobre una de las ramas seleccionadas y elegimos la opción en cuestión.

Si eligiéramos las 2 ramas en amarillo del principio, se abriría una nueva vista filtrada así:




Opción: Mostrar ramas seleccionadas y relacionadas en un nuevo diagrama


Si quisiéramos ver una rama (o varias) y las  ramas directamente relaciondas por separado, las podemos marcar con CTRL+Click, al igual que se hace para elegir varios archivos en el explorador de archivos, luego hacemos click-derecho sobre una de las ramas seleccionadas y elegimos la opción en cuestión.

Por ejemplo, si quisiéramos ver las ramas relacionadas a la tarea-025 del primer ejemplo, con sólo seleccionar esa rama y eligiendo esta opción se abriría una nueva vista filtrada así:





Opción: Mostrar merges pendientes para las ramas seleccionadas en un nuevo diagrama


Si alguno entiende lo que muestra este diagrama y cuándo y porqué lo hace, por favor, que me lo explique :)




Opción: Mostrar diagrama personalizado de las ramas seleccionadas...


Esta opción muestra un cuadro de diálogo que permite indicar algunas de las opciones anteriores y algunas condiciones de filtrado adicionales:





Vista de Ramas


Esta es una vista de texto con información adicional como los comentarios de las ramas, muy útil en algunos casos, que también permite seleccionar ramas y operar con ellas para hacer Diff, Merge y otras operaciones.

Nota: La rama con el changeset actual siempre se muestra en negritas.


Esta es la vista plana, donde de paso se puede ver que no comentar las ramas quita información útil a la derecha:



Y esta es la vista jerárquica (solo para ramas Plastic nativas, las de GitHub y otros repositorios pueden no verse bien anidadas):



Misma vista, pero abriendo el panel derecho de detalles con el icono marcado en rojo:




Búsqueda rápida


El cuadro superior-derecho permite escribir para hacer un filtrado en tiempo real.

Por ejemplo, si escribiéramos tarea-025, la vista plana anterior filtraría todo lo que contenga ese texto en cualquiera de las columnas mostradas, comentarios incluidos:


Nota: Las columnas permiten ordenar la información mostrada, si se cliquea en ellas.



Vista de Changesets


Al igual que la vista de Ramas, esta es una vista de texto que permite ver rápidamente los changesets con sus comentarios, fecha de creación y otros datos, y que también permite seleccionar changesets y operar con ellos para hacer Diff, Merge y otras operaciones.



Búsqueda rápida


El cuadro superior-derecho permite escribir para hacer un filtrado en tiempo real.

Por ejemplo, si escribiéramos fidel, la vista plana anterior filtraría todo lo que contenga ese texto en cualquiera de las columnas mostradas, comentarios incluidos, y ese es otro motivo para escribir cosas útiles en los comentarios:


Nota: Las columnas permiten ordenar la información mostrada, si se cliquea en ellas.




Vista de Etiquetas


Esta es otra vista de texto que permite ver rápidamente las etiquetas con sus comentarios, fecha de creación y otros datos, y que también permite operar con ellas para hacer Diff, Merge y otras operaciones.



Búsqueda rápida


El cuadro superior-derecho permite escribir para hacer un filtrado en tiempo real.

Por ejemplo, si escribiéramos 1.1, la vista plana anterior filtraría todo lo que contenga ese texto en cualquiera de las columnas mostradas, comentarios incluidos:


Nota: Las columnas permiten ordenar la información mostrada, si se cliquea en ellas.



Vista de Shelves


Esta es otra vista de texto que permite ver rápidamente las etiquetas con sus comentarios, fecha de creación y otros datos, y que también permite operar con ellas para hacer Diff, Merge y otras operaciones.



Búsqueda rápida


Tiene el mismo funcionamiento que las demás vistas de texto.


Comentarios finales


Conocer todas estas vistas y opciones de filtrado, es fundamental para poder navegar por la información que brinda una herramienta SCM o DVCS y para poder realizar operaciones con la misma.

Poder hacer todo esto es una de las mayores ventajas que aporta trabajar con estas herramientas, donde la mayoría de opciones son prácticamente imposibles si se trabaja a la antigua usanza.

Esto es lo que permite poder manipular el código de una aplicación completa con un control total y a distintos niveles de detalle.


Hasta la próxima!

viernes, agosto 22, 2014

Nueva versión v2.4.26 de las herramientas Visual FoxPro 9 para PlasticSCM (Incluye FoxBin2Prg.exe v1.19.31)

Está liberada la versión v2.4.26 de las herramientas Visual FoxPro 9 para PlasticSCM, con los siguientes cambios:

  • Se ha mejorado el control de algunos errores y los mensajes mostrados
  • Se ha agregado el conteo de archivos procesados en la vista de Cambios Pendientes con los script específicos para esta vista



Estas herramientas son un grupo de scripts vbs y programas Visual FoxPro 9 que se configuran dentro de PlasticSCM para poder invocar a FoxBin2Prg (incluye solo el EXE) desde dentro de la interfaz de Plastic.

El README.txt explica como se configura en Inglés y Español.

Nota: Los fuentes del proyecto FoxBin2Prg y el historial de ambios, están en CodePlex, en este link.


Como actualizar las existentes:
Con descargarlas y reemplazar los archivos en el sitio que los hayan puesto antes es suficiente.


Link de descarga:
https://github.com/fdbozzo/foxpro_plastic_diff_merge


Saludos!

Nueva versión v1.19.31 de FoxBin2Prg (mejoras)

Está liberada la versión v1.19.31 de FoxBin2Prg con los siguientes cambios:

  • Limpieza de código basura en campo methods, normalmente puesto por programas como ReFox y otros. En un caso reciente de conversión de código antiguo originado en VFP6, se ha dado el caso de encontrar métodos inhabilitados ocultos en clases y forms, puestos por programas como ReFox o similares en sitios que el IDE de VFP no puede acceder ni usar. En estos casos, FoxBin2Prg limpiará esos restos de código inhabilitado para poder generar las versiones texto estilo-prg sin errores.
  • Agregada versión del EXE cuando se genera LOG de depuración. Este agregado es útil para cuando es necesario analizar un LOG generado por FoxBin2Prg, poder saber con qué versión de compilación se hizo.
  • Mejorado el reconocimiento de instrucciones #IF..#ENDIF cuando hay espacios entre # y el nombre de comando. En recientes conversiones de código antiguo originado en VFP 5 y posterior, se han encontrado comandos mal escritos que no dan errores de sintaxis, por lo que se deben aceptar. Por ejemplo: # IF o # ENDIF con espacios entre el símbolo # y el IF/ENDIF. Ahora se soporta este caso.
  • Ajuste de capitalización de los archivos origen. Hasta ahora sólo se ajustaba la capitalización de los archivos generados, y era necesario un ajuste manual extra con script para los archivos origen. Ahora se ajustan automáticamente los archivos origen de la conversión, evitando un paso manual extra.
  • Agregada nueva propiedad c_Language para conocer el lenguaje activo (EN,ES,DE,etc). Esta nueva propiedad pública es útil para poder consultarla externamente desde scripts u otros programas y poder saber qué lenguage compilado está activo por defecto. Lo usan algunos de los scripts de las Herramientas VFP 9 para Plastic, para poder mostrar algunos mensajes en Español o Inglés.



Como actualizar el FoxBin2Prg existente:
Con descargar el zip y reemplazar los archivos en el sitio que los hayan puesto antes es suficiente.


Link  de descarga:
https://vfpx.codeplex.com/releases/view/116407


 Saludos!

domingo, agosto 17, 2014

Cómo configurar las Herramientas de VFP 9 en Plastic


Por: Fernando D. Bozzo

Aunque esto está en el README.txt, lo transcribo aquí por comodidad.

Nota 1: No confundir estas herramientas (scripts) específicos para Plastic, con los scripts que vienen con el proyecto FoxBin2Prg y que son para el explorador de archivos de Windows, no para Plastic!


Nota 2: Donde diga <Path-a-FoxBin2Prg> o <Path-a-las-herramientas> poner el path donde copiaron las Herramientas VFP 9 para Plastic y FoxBin2Prg (es el mismo directorio para ambas)

Nota 3: Ojo que la configuración para Diff no es la misma que para Merge!


Antes de comenzar: Descarga de las Herramientas VFP 9 para Plastic


Configuración de DIFF en PlasticSCM


  • Clickear en el icono de Preferencias de PlasticSCM
  • Seleccionar "Herramientas Diff" y "agregar" esto:
    • Herramienta Diff externa:
      "<path-a-las-herramientas>\foxpro_plasticscm_dm.exe" "'DIFF' '@sourcefile' '@destinationfile' '@sourcesymbolic' '@destinationsymbolic'"
    • Patrón:
      .pjx;.vcx;.scx;.frx;.lbx;.mnx;.dbf;.dbc     (¡usar misúsculas!)
  • Clickear OK
  • Mover la extension agregada al inicio de la lista, para priorizarla



Configuración de MERGE en PlasticSCM


  • Clickear en el icono de Preferencias de PlasticSCM
  • Seleccionar "Herramientas Merge" y "agregar" esto:
    • Herramienta Merge externa:
      "<path-a-las-herramientas>\foxpro_plasticscm_dm.exe" "'PRESERVE_WS' '@sourcefile'"
    • Patrón:
      .pjx;.pjt;.vcx;.vct;.scx;.sct;.frx;.frt;.lbx;.lbt;.mnx;.mnt;.dbf;.fpt;.cdx;.dbc;.dcx;.dct     (¡usar misúsculas!)
  • Clickear OK
  • Mover la extension agregada al inicio de la lista, para priorizarla




Configuración de Custom "Open with..." en PlasticSCM



  • Click en el icono de Preferencias de PlasticSCM
  • Seleccionar "Abrir con... personalizado"

  • Click en "Añadir..." y completar los campos:
    • Nombre a mostrar:
      (VFP) Cambios Pendientes: Regenerar Binarios
    • Ruta completa del ejecutable:
      <Path-a-FoxBin2Prg>\PlasticSCM_VFP9_Pending_Changes_Regenerate_Binary.vbs
  • Click en Aceptar


  • Click en "Añadir..." y completar los campos:
    • Nombre a mostrar:
      (VFP) Cambios Pendientes: Regenerar versiones Texto
    • Ruta completa del ejecutable:
      <Path-a-FoxBin2Prg>\PlasticSCM_VFP9_Pending_Changes_Regenerate_Text.vbs
  • Click en Aceptar


  • Click en "Añadir..." y completar los campos:
    • Nombre a mostrar:
      (VFP) FoxBin2Prg
    • Ruta completa del ejecutable:
      <Path-a-FoxBin2Prg>\PlasticSCM_VFP9_FoxBin2Prg.vbs
  • Click en Aceptar


  • Click en "Añadir..." y completar los campos:
    • Display Name:
      Normalizar Capitalización de un archivo
    • Full path to the executable:
      <Path-a-FoxBin2Prg>\Normalize_FileNames.vbs
  • Click OK


  • Click en "Añadir..." y completar los campos:
    • Nombre a mostrar:
      (VFP) Todos los Archivos: Regenerar Binarios
    • Ruta completa del ejecutable:
      <Path-a-FoxBin2Prg>\PlasticSCM_VFP9_All_Files_Regenerate_Binary.vbs
  • Click en Aceptar


  • Click en "Añadir..." y completar los campos:
    • Nombre a mostrar:
      (VFP) Todos los Archivos: Regenerar versiones Texto
    • Ruta completa del ejecutable:
      <Path-a-FoxBin2Prg>\PlasticSCM_VFP9_All_Files_Regenerate_Text.vbs
  • Click en Aceptar




sábado, agosto 16, 2014

PlasticSCM: ¿Qué es nivelar un rama?

Por: Fernando D. Bozzo

En un SCM o en un DVCS trabajar con ramas es algo de todos los días.

Se suelen hacer ramas por tarea para poder trabajar en cada tarea de forma independiente, también se hacen ramas por release, de las que cuelgan las ramas de las sub-tareas que la conforman, también podemos tener a uno o más desarrolladores en cada tarea, donde cada uno tiene su propia rama de trabajo, y finalmente está la rama principal (main o trunk) de donde cuelga todo lo anterior.



Nivelación de ramas


La nivelación de ramas es el mecanismo que se usa para actualizar una rama que tiene un ritmo de actualización menor o distinto a otras ramas, y que se hace mediante la operación de merge o de cherry pick.


Un ejemplo:
Si dos o más personas trabajan en una misma petición o tarea, cada uno haciendo una parte específica de la misma (por ej, uno hace la parte visual y otro el acceso a datos y la lógica de negocio), uno no ve lo que hacen los otros y ninguno tiene todo lo de todos, entonces lo que se hace es que todos combinan sus cambios en la rama de la tarea mediante el merge y luego cada uno nivela su rama con el trabajo de los demás desde la propia tarea.


En la siguiente imagen, se puede observar una tarea TESTS en la que trabajan 2 desarrolladores, DEV_1 y DEV_2, trabajando cada uno en su rama, como se detalló antes, y ocurre la siguiente secuencia de eventos, irando de izquierda a derecha:

1. DEV_1 hace un merge desde su rama de trabajo /main/DEV_1 hacia la rama de la tarea TESTS (flecha verde ascendente), que será automático por ser el primero

2. DEV_2 hace un merge desde su rama de trabajo /main/DEV_2 hacia la rama de la tarea TESTS (flecha verde descendente)

3. En este punto, la rama de la tarea TESTS tiene la suma de los cambios de DEV_1 y DEV_2, por lo que DEV_2 ahora hace una nivelación en su propia rama (flecha verde ascendente) teniendo así los cambios de DEV_1

4. DEV_1 hace lo mismo, y nivela su rama con los cambios de TESTS (flecha verde descendente) mediante un merge, por lo que al terminar tendrá todo lo que hizo el compañero DEV_2

5. DEV_1 termina sus cambios y hace merge en TESTS (flecha verde ascendente)

6. DEV_2 termina sus cambios y hace merge también en TESTS (flecha verde descendente)

7. Finalmente, la tarea TESTS se integra en /main (flecha verde ascendente)





Técnicas de nivelación de ramas


Cuando se hacen merges o nivelaciones, siempre se debe buscar actualizar lo más nuevo sobre lo antiguo y nunca al revés, ya que es más fácil pensar integrar "lo que se agregó nuevo" que hacer el razonamiento y la operación opuesta.

El siguiente es un ejemplo típico de una Release, donde la v1.0 está en Producción (o en el cliente), se está trabajando en la próxima Release v2.0 y en medio hay que sacar un parche v1.1 urgentemente.

La secuencia de eventos es la siguiente:

1. Partiendo de la v1.0 de la primera etiqueta circular verde, salen tanto la rama de la próxima release_2 como la rama del parche v1.1

2. El parche se desarrolla y se integra con un merge sobre la v1.0, lo que crea un nuevo changeset que se etiqueta como v1.1 en segunda etiqueta verde

3. Luego, en vez de integrar este mismo parche sobre la rama de la release_2, se crea una subrama de nivelación desde la v1.1 de arriba (1), se le hace un merge desde la rama de la release_2 (2) para agregar todo lo nuevo, y finalmente se hace la nivelación de la rama release_2 desde la rama_de_nivelación que ya contiene el parche aplicado (3)


De esta forma se maximiza la posibilidad de que los merges que se hacen sean automáticos, ya que de la otra forma (aplicando el parche sobre la release_2) es más probable que haya que hacer merge manual.



Aunque a primera vista pueda parecer un poco complejo, realmente no lo es una vez que se comienza a practicar.


Hasta la próxima!

viernes, agosto 15, 2014

PlasticSCM: Sincronización con GitHub

Por: Fernando D. Bozzo

En esta nota vamos a ver cómo se vincula y sincroniza un repositorio Plastic con GitHub.

Nota: Plastic tiene sus propios repositorios, y no necesita conectarse a repositorios externos como GitHub o BitBucket para funcionar. Esto solo se hace cuando específicamente se quiere trabajar con esos repositorios.


Un aviso importante:


   Una vez hecha la sincronización con GitHub ya no hay marcha atrás, y lo que se suba quedará subido y no se podrá borrar localmente. Aunque se intente borrar localmente (por ejemplo un changeset) en la siguiente sincronización se volverá a descargar todo y volverá a aparecer, y si no se controla bien los archivos que suben, sus conversiones a texto, su capitalización y el tipo de archivo (que no sea basura), puede perjudicar la sincronización con GitHub, lo que en la práctica puede significar tener que volver a hacer todo desde cero (crear otro repositorio Plastic, otro repositorio GitHub, etc), por eso insisto tanto en tomar las precauciones necesarias para no tener que perder tanto tiempo luego en reconfiguraciones.

Una vez aclarado el tema, ahora sí, el proceso de sincronización.


Pasos a seguir para sincronizar con un repositorio GitHub


1) Seleccionar el alias del workspace que se quiere sincronizar desde la solapa superior, justo bajo el título de la ventana (ejemplo: dvcs_vfp9). Como el workspace está vinculado a un directorio y al Repositorio (de hecho es un alias para una vista del repositorio), Plastic sabe de donde tomar la información y donde actualizar. También puede observarse que justo bajo la solapa del workspace está la información del mismo, en el formato:

Rama @ Repositorio @ servidor : puerto  y Workspace path (directorio del workspace)




2) Ahora vamos vincular nuestro repositorio con GitHub. Hacemos click-derecho en la rama /main sobre la parte gris que está fuera del punto azul (es poco margen al principio, pero se puede seleccionar y se quedará coloreada de azul claro, bajo los puntos circulares), se abrirá el menú contextual y en el título del panel derecho deben ver que dice "Nombre de la rama" (si dice "numero de changeset" eligieron mal), en este menú eligen "Replicación / Sincronizar con Git":



3) Aquí ponen la URL del repositorio de GitHub ( ejemplo: https://github.com/fdbozzo/dvcs_vfp9.git ) y el usuario y contraseña que usaron para darse de alta en GitHub, y pulsan "Sincronizar" (no se preocupen del nombre que figura en la captura, que es solo ilustrativo):



4) Si todo salió bien, deberían ver esto:



Si lo anterior sale en rojo, es que algo salió mal (por ejemplo, siguiente imagen) y se debe analizar el mensaje de error dado. En este caso, el error se debió a un bug de Plastic que reporté en febrero y que solucionaron:




5) Una vez que cierren esta pantalla, ya está hecha la sincronización y guardadas las credenciales para las próximas sincronizaciones.En el Explorador de ramas, si actualizan con F5 o con el icono de la flecha circular (a la derecha de ACCIONES PRINCIPALES), deberían poder ver dos o más puntos azules, al menos más puntos de los que veían antes de sincronizar. Esta vista es un gráfico de changesets (cambios) en el tiempo, donde pueden ver la fecha (arriba), y hacia la derecha siempre está lo más nuevo.



Nota importante:
Las ramas nuevas no hacerlas nunca del primer nodo de /main (el de más a la izquierda), debe hacerse de los posteriores y normalmente se hace desde el último changeset de la derecha, ya que si no les quedarán ramas fantasma que no podrá ver nadie mas.



Solución a algunos problemas sincronizando con GitHub u otro repositorio externo no-Plastic


Cuando se trabaja con repositorios externos como GitHub, BitBucket u otros, a veces las cosas pueden no salir como esperamos.

Si el problema es de conexión, o sea que da un error nada más intentar sincronizar, lo primero que se debe verificar son los datos de conexión al repositorio externo, como la URL, el usuario y la contraseña, que a veces poner mal un carácter impide la conexión.

Si se detecta que lo que uno de los usuarios ve no se corresponde con lo que debería ver, una solución podría ser que el usuario se cree un nuevo repositorio local, en un nuevo workspace y un nuevo directorio, vuelva a configurar la conexión al repositorio externo y sincronice. De esta forma se le bajará todo nuevamente, y si el repositorio local anterior tenía algún problema, entonces ese problema desaparece.

Normalmente esto lleva unos minutos, dependiendo del tamaño del repositorio externo.




Hasta la próxima!



Reglas mínimas y buenas prácticas de programación

Por: Fernando D. Bozzo

Las reglas que se indican a continuación, son buenas prácticas de programación que sirven, no sólo para trabajar con control de código fuente, sino para toda la programación en general.

Aunque para algunos sea obvio, para otros no lo es tanto, así que es mejor explicar los motivos de esto.



¿Qué son y para qué sirven las buenas prácticas?


Las buenas prácticas no existen desde siempre, sino que se fueron desarrollando como resultado de la experiencia común de muchos desarrolladores y empresas dedicadas al desarrollo de software, como Microsoft y otras.

En esas experiencias se han pasado muchas veces por situaciones conflictivas, que luego de haber identificado fallos o problemas comunes, y luego de haber analizado los motivos que llevaron a ellos, se han ido perfeccionando ciertas prácticas que minimizan la posibilidad de los mismos.

Otra ventaja de las buenas prácticas, es que tienen a facilitar el mantenimiento del código, no solo por la persona que lo hace, sino por otros, lo que permite "normalizar" la forma de hacer las cosas, bajar los tiempos de desarrollo y maximizar la eficiencia.

Finalmente, el uso de estas normas minimiza los problemas y las diferencias a la hora de tener que mezclar el código de dos desarrollos sobre los mismos componentes (llamado merge), aumentando la posibilidad de que sea automático y no requiera intervención manual.


Buenas prácticas de programación


La siguiente lista de recomendaciones es lo mínimo que conviene tener en cuenta en todos los desarrollos, tanto trabajando en solitario como en equipo.



1. Convención de nomenclatura de variables (VFP)

Está detallada en la ayuda de FoxPro y en el MSDN de Microsoft

Ejemplos:
Parámetros => tcCadena, tnNumero, tdFecha, tlBoolean, taArray, toObjeto
Variables Locales => lcCadena, lnNumero, ldFecha, llBoolean, laArray, loObjeto
Variables Privadas => pcCadena, pnNumero, pdFecha, plBoolean, paArray, poObjeto
Variables Publicas => gcCadena, gnNumero, gdFecha, glBoolean, gaArray, goObjeto



2. Convensión de nomenclatura de objetos (VFP)

Está detallada en la ayuda de FoxPro y en el MSDN de Microsoft

Ejemplos:
custom => cus_nombre
label => lbl_nombre
form => frm_nombre
checkbox => chk_nombre
editbox => edt_nombre
listbox => lst_nombre
spinner => spn_nombre
pageFrame => pgf_Nombre
page => pag_Nombre
commandButton => cmd_nombre



3. Checkin y checkout de componentes (SCM/VFP)

Antes de hacer un checkin o un checkout de componentes, es conveniente limpiar el entorno para evitar problemas:

CLEAR ALL
CLOSE ALL
(y ahora se puede hacer el checkin o checkout)



4. Cambio de changeset (Plastic/VFP)

Al igual que en el caso anterior, es conveniente hacer el CLEAR ALL / CLOSE ALL, pero además es conveniente revisar y refrescar la vista de Cambios Pendientes, ya que si hubiera archivos modificados, generaría un aviso.



5. Trabajo en ramas (SCM)

Regla de oro: Nunca se debe trabajar o modificar en la rama personal de otro usuario, ya que se le puede ocasionar una inconsistencia en el desarrollo. La rama de trabajo personal es como el maletín de cada uno, no se comparte y es actualizada por el propietario exclusivamente.

Si se quieren compartir ramas, se deberá hacer con ramas que no sean personales (como una rama de una tarea) y solamente se debe actualizar mediante merge o cherry pick, nunca manualmente.



6. Sesiones de FoxPro

Evitar cambiar el directorio de una sesión de FoxPro que sea usada para modificar componentes (o sea, no usar CD <directorio> o SET DEFAULT TO <directorio> si se modifican programas con MODIFY), ya que los programas se suelen cachear en la memoria, y al modificar en otra ubicación se podrían provocar problemas de ruta inválida sobre todo en las clases y forms.



7. Parámetros

Usar LPARAMETERS en vez de PARAMETERS y si hay que agregar parámetros a un método, agregarlos siempre al final, nunca en medio, que eso rompe la compatibilidad de los programas.

Ejemplo agregando nuevo parámetro "tnCosto":
LPARAMETERS tcNombre, tnEdad, tnCosto




Como todo, esta lista no es definitiva, pero al menos es una buena base para poder trabajar de forma "compatible" con otros desarrolladores.


Hasta la próxima!


PlasticSCM: Cómo configurar el usuario Administrador del Servidor

Por: Fernando D. Bozzo

Cuando instalamos Plastic, por defecto no hay un usuario Administrador preconfigurado (no tiene nada que ver con ser Administrador de Windows!).

Normalmente esto no es un problema y se puede trabajar sin más, sobre todo si lo usamos para trabajar en solitario, pero hay que recordar que la Licencia Comunitaria de Plastic es hasta 15 usuarios, y si usamos uno o más repositorios sincronizados con un repositorio externo, como GitHub o BitBucket, nos pueden aparecer otros usuarios sin que nos demos cuenta, y encima se dan de alta de forma automática como usuarios habilitados, que por ende consumen una licencia cada uno.



Ejemplo del problema


Nos creamos uno o varios repositorios locales, (que por defecto usan el backend local de SQLCE en Windows y SQLite en Linux y Mac, salvo que configuremos una BDD externa), y uno o más de esos repositorios los configuramos para que se sincronicen con un repositorio externo, por ejemplo, con GitHub.

Cuando hagamos la sincronización y se actualicen los datos del repositorio local, todos los usuarios que hayan intervenido en el desarrollo de los programas del repositorio (o sea, del proyecto), se darán de alta localmente de forma automática, lo que consumirá parte de las licencias que tenemos disponibles, o, en el peor caso, todas!, y si esto llegara a ocurrir, Plastic se bloquea automáticamente por haber alcanzado el máximo de licencias permitidas. Pero tiene solución...



Cómo evitarlo


La solución es fácil, lo que pasa es que cuesta encontrarla  ...y para eso es este artículo :D

Se trata de establecer el usuario Administrador del Servidor Plastic, que es el único que puede habilitar e inhabilitar licencias, y ahí está lo bueno, porque se pueden desactivar las licencias que no se usen!

Esto es útil incluso si se trabaja en un equipo, donde uno de los integrantes se va de vacaciones y otro integrante ocupa su lugar: Se desactiva la licencia del que se va (ojo, no se borra!, solo se desactiva!) y se habilita al nuevo.

Cabe aclarar que las licencias de uso se activan automáticamente cuando se hace el primer checkin, no cuando se agrega un usuario a Plastic.



1 - Comprobar licencias en uso y disponibles


Para comprobar qué licencias se están usando de nuestro servidor Plastic, usamos el comando "cm" desde la línea de comandos de DOS, así:

C:\DESA\dvcs_vfp9>cm li
Información de licencia de Plastic SCM:

* Información de usuarios con licencia:

fdbozzo                   ACTIVO
chewbacca                 ACTIVO

---------------------------------------
Registrado a: Community edition particular - Fernando Bozzo

Fecha de expiración: 02/03/2015 00:22:18

Total de licencias: 15
Total usuarios activos: 2
Total licencias disponibles: 13
---------------------------------------



En el ejemplo anterior podemos ver que el usuario "chewbacca" está usando una licencia, por estar ACTIVO, y podría haber más. En este caso el total de usuarios activos es 2.



2 - Comprobar el usuario actual


Aunque cada uno sabe con qué usuario se dió de alta en Plastic, lo puede comprobar igual que se hace en Linux, con el comando whoami (en Plastic es cm whoami):

C:\DESA\dvcs_vfp9>cm whoami
fdbozzo




3 - Consultar el usuario administrador del Servidor Plastic


A continuación consultamos el usuario administrador del Servidor Plastic, que inicialmente será "all":

C:\DESA\dvcs_vfp9>cm showowner repserver:win7u:8087
repserver:win7u:8087 all Usuario




Si el usuario es "all", conviene configurar el usuario Administrador como se indica en el siguiente paso.



4 - Configurar un nuevo usuario Administrador del Servidor Plastic


Ahora configuramos (o reconfiguramos) el usuario Administrador (el nuestro, que consultamos antes), como se indica a continuación, reemplazando el usuario por el vuestro y el servidor (PC) por el nombre de la máquina donde hayan instalado Plastic (el mismo que en FoxPro se obtiene con SYS(0) ):

C:\DESA\dvcs_vfp9>cm setowner -user=fdbozzo repserver:win7u:8087


Una vez configurado el usuario Administrador, lo verificamos (reemplazar win7u por vuestro nombre del Servidor Plastic):

C:\DESA\dvcs_vfp9>cm showowner repserver:win7u:8087
repserver:win7u:8087 fdbozzo Usuario




5 - Desactivar licencias de usuario


Siendo Administradores del Servidor Plastic podemos usar el comando "cm du" (o también "cm deactivateuser") para desactivar licencias. En este caso desactivaremos la licencia del usuario "chewbacca":

C:\DESA\dvcs_vfp9>cm du chewbacca --nosolveuser
El usuario chewbacca_cp ha sido desactivado correctamente



Volvemos a listar las licencias en uso para comprobar los cambios:

C:\DESA\dvcs_vfp9>cm li
Información de licencia de Plastic SCM:

* Información de usuarios con licencia:

fdbozzo                   ACTIVO
chewbacca                 INACTIVO (No tiene licencia)
---------------------------------------
Registrado a: Community edition particular - Fernando Bozzo

Fecha de expiración: 02/03/2015 00:22:18

Total de licencias: 15
Total usuarios activos: 1
Total licencias disponibles: 14
---------------------------------------



Listo! Eso es todo. Ya tenemos esa licencia DESACTIVADA (que no borrada), que podremos volver a activar cuando querramos, y en este caso quedó un único usuario activo.



6 - Activar licencias de usuario


Siendo Administradores del Servidor Plastic podemos usar el comando "cm au" (o también "cm activateuser") para activar o reactivar licencias.  En este caso activaremos la licencia del usuario "chewbacca":

C:\DESA\dvcs_vfp9>cm au chewbacca --nosolveuser
El usuario chewbacca_cp ha sido activado correctamente



Volvemos a listar las licencias en uso para comprobar los cambios:

C:\DESA\dvcs_vfp9>cm li
Información de licencia de Plastic SCM:

* Información de usuarios con licencia:

fdbozzo                   ACTIVO
chewbacca                 ACTIVO
---------------------------------------
Registrado a: Community edition particular - Fernando Bozzo

Fecha de expiración: 02/03/2015 00:22:18

Total de licencias: 15
Total usuarios activos: 2
Total licencias disponibles: 13
---------------------------------------




Tengan muy presente esto, porque si el Servidor Plastic se bloquea por aclanzar las licencias permitidas, desactivando licencias es la manera de desbloquearlo.


Hasta la Próxima!

Prácticas de VFP 9 con control de código fuente desde CERO - ¡Ayuda! ¡Me perdí! (agosto 2014)

Por: Fernando D. Bozzo

Para estas prácticas de agosto 2014 hice un nuevo Blog para los que se perdieron y para quienes quieran rapasar lo que vamos haciendo, donde iré actualizando todas las tareas que hagamos en el foro, con links a las mismas y a los articulos que publico, en el orden que los vamos viendo, así pueden volver a ponerse en tema rápidamente.

Con solo seguir el orden de los artículos publicados en el Blog, será suficiente para poder avanzar paso a paso en el uso del control de código fuente con Plastic, y en el foro hacen las preguntas.

Gente, de verdad no se preocupen si en algún momento alguno se retrasa. Simplemente hagan las preguntas en el hilo correspondiente a la práctica, marcada como [Foro], y los que ya la hayan hecho podrán responderles sin problemas, yo incluido.

Por ejemplo, si estamos en la PARTE 3 de las prácticas y alguno sigue en PARTE 2, no pasa nada, solo haga sus preguntas en el hilo de la PARTE 2 en la que se encuentra, que todos recibirán el correo de notificación, y por el asunto se sabrá dónde está cada uno.

Con este tipo de participación online, el término "rezagado" no existe, porque es atemporal, de la misma forma que todavía hay preguntas de FoxPro 2.6 y se siguen contestando.

Importante: Es conveniente que primero lo lean el artículo completo antes de hacer nada, para tener una idea del conjunto de pasos, y luego vayan haciendo los pasos. No se apuren.


¿Tienes algún problema? Chequea este artículo, que voy actualizando contínuamente:
PlasticSCM: ¡Houston, tenemos problemas!


¿No puedes bajarte el programa por algún problema en la página de Plastic?
Aquí hay un enlace a una versión de Plastic actualizada que temporalmente va a servir (versión evaluación 30 días y 5 desarrolladores), así que luego hay que bajarse el archivo de licencia gratuita anual para 15 desarrolladores antes de que caduque:
PlasticSCM-5.0.44.596-windows-installer.exe.7z


Recursos de software necesarios (links):


- Visual FoxPro 9.0
- Herramientas FoxPro para Plastic => (Incluyen el EXE de FoxBin2Prg, pero no sus fuentes, que están aquí si los quieren)



Todo lo que estamos viendo está aquí:



Cualquier duda, me escriben o preguntan en el foro.

Fernando D. Bozzo

miércoles, agosto 13, 2014

Control de versiones: ¿Para qué sirve? ¿Por qué es necesario?

Por: Fernando D. Bozzo

Muchos han oido hablar, o incluso han leido, sobre la existencia del Control de Versiones (VCS: Versioning Control System) también conocido como Control de Código Fuente (SCM: Source Code Managment) o su variante Distribuida (DVCS: Distributed Versioning Code Management), pero todavía son pocos los que se han dado cuenta de qué les aporta un SCM a su trabajo programando.

Para complicar más la experiencia, la gente que sí ha usado control de versiones, pero que ha sido mediante SourceSafe, tienden a pensar en una herramienta SCM como un "repositorio de código", debido a las limitaciones de SourceSafe que todo el que haya trabajado con él ya conoce.

Un SCM es mucho más que un repositorio de código, y tienen muchas ventajas trabajar con uno. La mayoría de los lenguajes de programación, que son basados en texto, como Java, PHP, PLSQL, Python, Javascript, C/C++ y muchos otros, vienen beneficiándose de ellos desde los 90, siendo el primero cvs, y siguiendo luego por Subversion (svn), Perforce , y evolucionando luego a DVCS (Distributed Version Control System o Sistemas Distribuidos de Control de Versiones) como Git, Mercurial, Plastic y otros.

En el caso de Visual FoxPro, un SCM tradicionalmente se podía solo usar parcialmente, más que nada para comparar versiones de un archivo, que es muy útil, pero donde los cambios de otros desarrolladores había que seguir haciéndolos a mano para integrar.

Desde fines de 2013, y con la ayuda de un proyecto Open Source hecho en Visual FoxPro, FoxBin2Prg, es posible aprovechar absolutamente todas las ventajas de un SCM o un DVCS que ya disfrutaban los demás lenguajes basados en texto:

  • Se pueden comparar los binarios usando archivos de texto estilo PRG
  • Se puede saber qué se cambió en cualquier momento del tiempo, incluso entre versiones no consecutivas (por ejemplo, hace 3 versiones atrás)
  • Se puede saber quién hizo un determinado cambio, incluso a nivel de cada línea de código
  • Se pueden obtener varias estadísticas, como, por ejemplo, cuántos cambios se hicieron desde la última versión, o qué componentes cambiaron
  • Se puede tener un equipo de desarrolladores que puede trabajar en los mismos componentes (forms, librerías de clases, menús, etc) y que pueden hacer merge (mezcla) de código concurrentemente y obtener binarios FoxPro funcionales de esas mezclas sin bloquearse entre ellos
  • Cada desarrollador tiene su copia local del sistema, donde puede hacer todas las pruebas que necesite sin tener interferencias o bloqueos por los cambios de los demás
  • Si un desarrollador comete un error, los demás no pagarán las consecuencias ni quedarán bloqueados por ello
  • Un desarrollador puede trabajar en la versión actual del sistema, mientras otro puede estar trabajando en el parche de la versión anterior con código más antiguo, y ambos no se verán afectados
  • Se puede trabajar en más de una versión a la vez (esta versión, la próxima, un parche, etc) usando ramas
  • Se tiene la opción de trabajar en un proyecto con gente que está en sitios geográficamente separados. Esto permite que tu trabajes en tu casa, yo en la mía y ambos podamos compartir el mismo repositorio, por ejemplo, GitHub o BitBucket, como repositorio intermedio
  • Se pueden sincronizar varios repositorios de código fuente para backup, para replicación o para otros usos
  • Se tiene la opción de "deshacer" un cambio, o muchos cambios, que afectan a uno o varios componentes de forma segura y volver a una versión anterior
  • Se puede ser libre de los formatos privativos y usar formatos libres que pueden ser usados por más de una herramienta SCM, lo que permite pasarse de una a otra herramienta
  • En definitiva, se tiene el completo control de todos los aspectos del desarrollo de un sistema, de sus versiones, sus cambios y evitando los bloqueos entre miembros del equipo


Si luego de leer esto, siguen con dudas sobre la utilidad que le puedan encontrar, incluso trabajando en solitario, intenten responder estas preguntas a situaciones de la vida real y comparen sus propias respuestas con las que dicen "Con SCM":



¿Llevas el control de las versiones de tu programa?

Con SCM: Siempre es así, además se etiquetan, para mantener un histórico de cambios consultable




¿Cómo lo haces ese control? ¿usando un zip o un subdirectorio por versión? ¿en serio?

Con SCM: Guardando instantáneas de los cambios en una BDD



¿Cómo comparas dos versiones de un archivo?

Con SCM: Se eligen 2 momentos del historial de un archivo y se compara, o se elige una versión y automáticamente se compara con la anterior




Cuando descubres o te reportan un bug, ¿cómo lo buscas? ¿depurando siempre?

Con SCM: Algunos errores se descubren solo mirando los cambios, porque se resaltan nada más que los cambios hechos y no hay que revisar todo el código




Si luego de una o dos horas de refactorización descubres que lo has hecho mal y que sería mejor comenzar de nuevo, ¿cómo haces? ¿restauras un backup?

Con SCM: Se elige el punto de guardado (changeset) anterior con un click




¿Tienes backup de todos los momentos en los que agregas funcionalidades?

Con SCM: Guardar una instantánea de todos los archivos cambiados son unos pocos clicks




Estás trabajando en varios requisitos del cliente a la vez, y al finalizar, o en medio de los desarrollos, te llama y te dice que uno de ellos realmente no lo necesita, o que prefiere otra cosa, ¿qué haces ahora mismo? ¿acaso llevas backup para cada requisito? No vale suicidarse :)

Con SCM: Cada requisito se puede trabajar en su propia rama, y quitar un requisito puede llegar a ser tan fácil como desintegrar una rama (unos clicks)



Estás en medio de una release (versión), y te reportan un bug importante que no puede esperar a la siguiente versión, ¿qué haces? ¿mueves todo el desarrollo a otro sitio y restauras un backup? ¿y una vez hecho el arreglo? ¿vuelves a reponer todo a su sitio y vuelves a realizar los cambios en la versión que tenías a medio hacer?

Con SCM: Se crea una rama para el parche (un click), se desarrolla el parche y se aplica a la versión anterior y a la actual, por medio de merge (mezcla de código)




Sigamos complicando: Tienes un mal día, sacas el parche y resulta que no funciona. Hay que deshacer los cambios, que además también los habías hecho en la versión actual, pero además la versión actual tiene otros cambios posteriores que no quieres deshacer. ¿Cómo deshaces el parche? ¿Tienes tantos backups como para volver atrás? Pero en ese caso perderías los cambios que te servían...

Con SCM hay varios caminos posibles: 1) Puedes hacer un merge sustractivo del parche, tanto en la versión anterior como en la actual (algunos clicks), 2) Puedes elegir comenzar a trabajar en una nueva rama de un momento de la historia anterior al parche, 3) otras alternativas.




¡Ok! ¡Suficiente! Parece que esto sirve, pero suena todo muy complicado o no entiendo todos los conceptos, además que seguramente sea muy difícil de usar y no es que me sobre el tiempo para aprender algo nuevo...

¿De verdad crees eso? ¿Y si te digo que con unas buenas prácticas en dos o tres tardes tienes los conocimientos necesarios para seguir adelante? ¿No crees que estás perdiendo más tiempo haciendo manualmente algunas de las cosas antes comentadas, cuando ya existen herramientas que te lo ponen fácil?

¿Ves todas las facilidades que estás perdiendo, y que te luego te ahorrarán mucho más tiempo que el que vayas a invertir en aprender?


Actualmente en VFP 9 hay varias opciones disponibles para trabajar con control de versiones, desde herramientas SCM/DVCS gratuitas hasta herramientas de pago. Sólo es cuestión de elegir algunas, probarlas y quedarte con la que más te guste para tu forma de trabajo.


Si te interesa seguir adelante, te invito a continuar por aquí:

FoxBin2Prg: Control de código fuente con PlasticSCM

Instalación de PlasticSCM paso a paso

Programas para control de versiones


Hasta la próxima!

domingo, agosto 10, 2014

Nueva versión v2.4.24 de las herramientas Visual FoxPro 9 para PlasticSCM (Incluye FoxBin2Prg.exe v1.19.30)

Está liberada la versión v2.4.24 de las herramientas Visual FoxPro 9 para PlasticSCM, con los siguientes cambios:




Estas herramientas son un grupo de scripts vbs y programas Visual FoxPro 9 que se configuran dentro de PlasticSCM para poder invocar a FoxBin2Prg (incluye solo el EXE) desde dentro de la interfaz de Plastic.

El README.txt explica como se configura en Inglés y Español.

Nota: Los fuentes del proyecto FoxBin2Prg y el historial de ambios, están en CodePlex, en este link.


Como actualizar las existentes:
Con descargarlas y reemplazar los archivos en el sitio que los hayan puesto antes es suficiente.


Link de descarga:
https://github.com/fdbozzo/foxpro_plastic_diff_merge


Saludos!

Nueva versión v1.19.30 de FoxBin2Prg (Arreglo, limpieza, refactorización)

Está liberada la versión v1.19.30 de FoxBin2Prg con los siguientes cambios:

  • Arreglo bug scx/vcx: Cuando la línea anterior a un ENDTEXT termina en ";" o "," no se reconoce como ENDTEXT sino como continuación (Jim Nelson). El "EndText" resaltado era reconocido como una estructura TEXT/ENDTEXT, por lo que se tomaba todo el resto del código del form como si fuera parte del mismo método:
           TEXT TO cSQL NOSHOW
              algo_aqui ,
           ENDTEXT


           TEXT TO cSQL NOSHOW
              algo_aqui ;
           ENDTEXT


  • Arreglo bug scx/vcx: En ciertos casos de herencia no se mantiene el orden alfabetico de algunos metodos (Ryan Harris). FoxBin2Prg ordena los métodos alfabéticamente para facilitar la comparación entre versiones, y dentro de este ordenamiento hay dos grupos: primero los métodos de clase (Init, mi_metodo, etc) y luego los de los objetos (optiongroup1.option1, etc). En este caso, bajo ciertos niveles de herencia, algunos métodos no quedaban bien ordenados.
  • Agregados casos de prueba de FoxUnit para comprobar la solución de ambos bugs
  • Limpieza de código y refactorización



Como actualizar el FoxBin2Prg existente:
Con descargar el zip y reemplazar los archivos en el sitio que los hayan puesto antes es suficiente.


Link  de descarga:
https://vfpx.codeplex.com/releases/view/116407


 Saludos!

domingo, agosto 03, 2014

Cómo trabaja FoxPro internamente (Traducción)

[Reposición de un artículo enviado a PortalFox hace algunos años, que me interesa mantener a mano]
por Christof Wollenhaupt, Foxpert

Traducido por: Fernando D. Bozzo (fdbozzo@gmail.com)



FoxPro desde adentro


Érase una vez, que el xBase no era un lenguaje de programación, era una herramienta para recuperar y para manipular automáticamente datos. Los usuarios de las herramientas xBase no eran principalmente desarrolladores; eran expertos en una variedad enorme de diversas áreas que utilizaban FoxBase, dBase, y herramientas similares para manejar sus datos. El xBase fue mejorado constantemente y finalmente desarrollado como un verdadero lenguaje de programación. FoxPro se convirtió en un entorno profesional de desarrollo que alcanzó sus alturas con FoxPro 2.5/2.6. En 1995 el paradigma de la herramienta cambió otra vez. Un lenguaje de programación procedural se convirtió en una herramienta orientada a objetos que continúa desarrollándose como un diseño basado en componentes.


Visual FoxPro no es sólo un entorno orientado a objetos como Delphi o Visual Basic.NET. Visual FoxPro todavía contiene sus raíces. Sólo intente hacer funcionar un programa de Turbo PASCAL 3.0 en Delphi 7.0. ¿Qué tal sus programas de GW-BASIC en Visual Basic.NET? ¿Pero Foxbase? Hasta hoy puede hacer funcionar código sin cambios en Visual FoxPro que ha escrito en los años ochenta. La salida por pantalla no luce tan agradable, pero todavía puede ejecutar código en VFP 8 casi 20 años después de que lo ha escrito.


Visual FoxPro es casi totalmente compatible hacia atrás. Pensando sobre esto, significa que mucho del código en FoxPro y FoxBase es todavía parte de Visual FoxPro. Esto significa que la orientación a objetos se sienta encima de FoxPro, y no viceversa. Muchos comportamientos extraños de Visual FoxPro llegan a ser solamente explicables si piensas cómo habrías hecho algo en FoxBase, sólo para darte cuenta de que Visual FoxPro no lo hace distinto.


Una advertencia por adelantado: Los siguientes artículos intentan describir cómo trabaja internamente Visual FoxPro. Los interiores reales de FoxPro son propiedad intelectual de Microsoft y no se divulgan públicamente. Cada uno de los que realmente saben como trabaja FoxPro internamente esta impedido para hablar de esto firmando un Acuerdo de No-Divulgación (NDA). He recogido la siguiente información de una variedad de fuentes públicas. Cierta información está en la biblioteca MSDN que Microsoft publica trimestralmente (algunos items existen solamente en versiones más viejas de la biblioteca MSDN). Otra información viene del código de ejemplo que Microsoft envía. La mayoría de las piezas, sin embargo, vienen de pruebas y de observaciones, no sólo de mí, sino de muchos, muchos desarrolladores en varios foros. Especialmente las diferencias en el comportamiento de varias versiones permiten hacer conclusiones de la estructura interna de VFP. Algunas de las estructuras siguientes se han extendido en la versión más reciente de FoxPro.



El índice de la tabla de nombres (NTI)


En Visual FoxPro podemos nombrar varios items. A esos items, Visual FoxPro les asigna algo llamado un nombre. Estos items son variables (no propiedades), nombres de matrices, procedimientos, funciones, alias de tablas, nombres de campo y objetos (no clases). Cada uno de estos elementos tiene una etiqueta y un alcance. La visibilidad (alcance) de una variable, por ejemplo, depende de su tipo, mientras que el alcance de un alias es la sesión de datos. Un nombre de campo debe ser único en una tabla y los procedimientos son limitados en alcance a un archivo de programa.


Siempre que se crea una variable, se abre una tabla, y así sucesivamente, Visual FoxPro crea una nueva entrada en una lista interna, la Tabla de Nombres. La posición dentro de esta lista es el Índice de la Tabla de Nombres - o NTI para abreviar. En esta lista, a cada nombre se el asigna un número único entre 1 y 65.000, porque se mantiene como valor de 16-bits. Hay sólo una lista global. Esta es la razón por la cuál se pueden crear hasta 65.000 variables solamente. Puesto que los alias y los nombres de objetos (hasta Visual FoxPro 6.0) también se incluyen en esta lista, el número real de variables es reducido por el número de objetos instanciados y áreas de trabajo asignadas.


El manejo de esta lista se ha optimizado en las distintas versiones de FoxPro. Cuando se libera un nombre cerrando una tabla o porque no se necesita más una variable, Visual FoxPro no quita la entrada inmediatamente. Solamente marca la entrada como inválida, como se hace con los registros eliminados.


Los items finalmente son quitados por un proceso llamado Garbage Collection (recolección de basura). Este término se refiere al proceso de quitar entradas inválidas de las listas, liberar entradas desactualizadas de la caché, compactar la memoria moviendo bloques de memoria alrededor, comprobando el acceso a los ficheros temporales, y así sucesivamente. Visual FoxPro ejecuta la recolección de basura en su bucle ocioso (idle loop). Se entra en este bucle siempre que Visual FoxPro está en una condición de espera causada por READ, READ EVENTS, INKEY() o WAIT WINDOW. Esto sigue siendo cierto si se utiliza el comando con las opciones de no esperar (NOWAIT). Se puede utilizar este truco para forzar a Visual FoxPro a limpiar la memoria usando un WAIT WINDOW "" NOWAIT.


No fue hasta Visual FoxPro 7.0 que SYS(1104) se hizo en la documentación aún cuando la función está disponible desde FoxPro 2.6, por lo menos. SYS(1104) dispara manualmente una recolección de basura. No es lo mismo que el bucle ocioso, aunque, como en el bucle ocioso Visual FoxPro hace más que ejecutar la recolección de basura, como adicionalmente procesar los mensajes de Windows. Durante la ejecución del programa, Visual FoxPro no está en un bucle ocioso y por lo tanto no realiza una recolección de basura. Hasta Visual FoxPro 5.0 esto tenía el efecto de que más y más entradas en la tabla de nombres se marcaban como inválidas, pero no se liberaban.


Esto tenía consecuencias de gran envergadura en la performance, pero también en la estabilidad. Cada vez que una nueva entrada se agrega a la tabla de nombres, Visual FoxPro tiene que buscar todas las entradas existentes para encontrar nombres conflictivos. Para las variables esto implica comprobar si existe una nueva variable con un alcance más bajo, porque no se puede, por ejemplo, crear una variable PÚBLICA cuando existe una variable LOCAL con el mismo nombre. Para los alias esto implica verificar que el nombre del alias no esté usado en la sesión actual de datos. Este proceso de búsqueda ha causado la degradación exponencial de la performance. Mientras que se podría medir la creación del primer objeto en milisegundos o incluso nanosegundos, a Visual FoxPro le tomó varios minutos para crear el objeto 60,000.


Las aplicaciones que nunca alcanzaban un estado ocioso, como las rutinas de importación o los proveedores de servicio, se hacían más lentos cuanto más tiempo funcionaban. Algunas funciones, también, exigían una nueva entrada en la tabla de nombres, como la función REQUERY al recargar una vista. La desaceleración no era el único problema. Cuanto más se acercaba una aplicación al límite, más inestable se volvía. Si se era afortunado, Visual FoxPro indicaba un error de “demasiados nombres”, pero generalmente simplemente se colgaba.


Visual FoxPro 6.0 mejoró perceptiblemente este comportamiento. Cuando el número de items en la tabla de nombres se acerca al 95% del límite, Visual FoxPro inicia automáticamente una recolección de basura. En un programa que crea 65.000 objetos se nota como un descanso más largo al crear ese objeto.


Una mejora importante vino en Visual FoxPro 7.0. Todas las versiones anteriores contaban objetos. Cuando se crean dos etiquetas


LOCAL loLabel1, loLabel2
loLabel1 = CreateObject("Label")
loLabel2 = CreateObject("Label")



Visual FoxPro ajusta la propiedad NAME. La primera etiqueta se nombra “Label1”, para la segunda etiqueta Label2.Name resulta en “Label2”. Para hacer que esto suceda, Visual FoxPro coloca cada objeto en la tabla de nombres. La consecuencia es que cada creación de objeto dura más que la anterior. Se puede saltear esto hasta cierto grado asignando un nombre único como SYS(2015) en el evento Init. No obstante, este comportamiento limita el número de los objetos que pueden ser instanciados a 65.000. En Visual FoxPro 3.0 a 6.0 no se pueden crear más de 65.000 objetos incluyendo todos los objetos que estén en formularios. Cuando se ha alcanzado ese límite, no se puede incluso abrir al diseñador de formularios ya que también intenta crear objetos.


Visual FoxPro 7.0 y 8.0 no hacen ninguna búsqueda de nombre único cuando se crean objetos con CREATEOBJECT () o NEWOBJECT (), ni colocan objetos en la tabla de nombres. Por lo tanto se pueden crear lejos más de 65.000 objetos… e incluso más rápidamente que en Visual FoxPro 6.0 también. La desventaja es que los nombres de objetos no son mas únicos. Un pequeño precio a pagar.



Variables, Matrices y Objetos


Una de las consultas más frecuentes que hacen los desarrolladores que acaban de aprender que Visual FoxPro puede manejar solamente hasta 65.000 variables es si eso se aplica a los elementos de matrices también. La respuesta es un NO definitivo. Una matriz cuenta como una sola variable, no importa cuántos elementos contenga. Porque el número de elementos se limita a 65.000 también, se pueden crear 65.000 matrices con 65.000 elementos cada una, como máximo. Incluso en Visual FoxPro se pueden almacenar masas de datos en memoria. Debido a razones de performance, ninguna aplicación se acerca a estos límites siquiera. La razón de todas estas limitaciones es la tabla de nombres, de nuevo. Realmente, Visual FoxPro sólo sabe tratar con variables - simples variables, eso es todo. El soporte de matrices, y posteriormente objetos, ha sido acomodado en este diseño.


¿Pero qué es una variable en Visual FoxPro? Las variables en FoxPro pueden almacenar valores de cualquier tipo de datos. Sin embargo, como Visual FoxPro está escrito en C en sí mismo, las variables de FoxPro también tienen que ser almacenadas en formato C hasta cierto punto. Visual FoxPro almacena variables en estructuras de C. Aún cuando la estructura siguiente proviene del kit de construcción de bibliotecas (SDK), está probablemente cerca de qué utiliza internamente Visual FoxPro, si no es incluso idéntico:


typedef struct {
    char ev_type;
    char ev_padding;
    short ev_width;
    unsigned ev_length;
    long ev_long;
    double ev_real;
    CCY ev_currency;
    MHandle ev_handle;
    unsigned long ev_object;
   } Value;



Además del tipo, hay una entrada para cada tipo de dato soportado. Visual FoxPro utiliza diversos campos dependiendo de qué tipo de datos deba ser almacenado. La estructura explica porqué las cadenas pueden contener cualquier carácter (porque su longitud se almacena por separado) y cómo Visual FoxPro se ocupa del número de posiciones decimales en valores de coma flotante para permitir diferencias entre 1.0 y 1.00. Las cadenas y los objetos reales no se almacenan directamente en esta estructura porque su tamaño puede variar ampliamente. Para acceder a cadenas, Visual FoxPro utiliza algo llamado manejador de memoria que será explicado en un momento. Los objetos se identifican usando un número de 32-bits no muy documentado. Puede ser que sorprenda que las matrices no están siquiera mencionadas.


Cada vez que un programa crea una nueva variable de memoria, Visual FoxPro asigna un bloque de la memoria con la estructura antedicha. Su dirección tiene que ser almacenada en alguna parte, justo como el nombre, que no es parte de la estructura anterior. Almacenar esta información es el trabajo de la tabla de nombres. Cada entrada en la tabla de nombres contiene además de nombre y alcance, los detalles del tipo de la entrada (variable, campo, alias, etc.) y su localización en memoria. La lista se limita a 65.000 entradas, por lo tanto, el límite máximo de variables.


Una matriz no se puede almacenar en una sola estructura, sin embargo. Cada elemento de matriz se almacena en una estructura como una sola variable. Ésta es la única manera de poder almacenar los items de varios tipos de datos en una sola matriz. En la tabla de nombres Visual FoxPro crea una sola entrada para la matriz entera. El siguiente ejemplo setea todos los elementos en la matriz a NULL:


LOCAL laArray[3]
laArray = .NULL.



Esta sola entrada es la que es usada para pasar una matriz por referencia. La matriz real, por otra parte, es una simple tabla de lista que contiene punteros a todos los elementos individuales. La entrada de matrices en la tabla de nombres real contiene un puntero a esta lista. No hay obviamente manera de tener acceso directamente a un elemento de la matriz como se puede tener acceso a una variable. Al pasar el índice de la tabla de nombres (NTI) que Visual FoxPro utiliza para identificar unívocamente una entrada en la tabla de nombres a una función que devuelva un elemento de la tabla de nombres, esta función podría solamente devolver la entrada para la matriz entera. Otra función recibe esta entrada y devuelve un elemento particular.


Los objetos se almacenan de manera similar. El valor en la estructura es la dirección de otra tabla de nombres. Para cada objeto Visual FoxPro parece crear una nueva tabla de nombres. Probablemente ha sido elegido ese camino porque la tabla de nombres ya maneja nombre y alcance. Las propiedades en Visual FoxPro son realmente variables que se mantienen en un lugar oculto. Más asombrosamente, esto es así para los métodos, que son también variables. Por esta razón no se puede crear una clase que tenga más de 65.000 métodos, propiedades, y eventos.


Este diseño tiene muchas ventajas ya que de otra manera las matrices y las propiedades comerían rápidamente el espacio disponible de la tabla de nombres. La desventaja más obvia, sin embargo, es pasar parámetros por referencia usando el carácter @. En este caso, Visual FoxPro no pasa una copia del valor como lo hace normalmente, sino simplemente el NTI, el índice de la tabla de nombres. A la función que llama se le pide amablemente que ponga el resultado en la variable número x. Una matriz, sin embargo, tiene solamente un simple índice de la tabla de nombres. No hay posibilidad tampoco de especificar en qué elemento debe ser escrito el resultado. Por lo tanto, se puede pasar solamente una matriz entera por referencia. En Visual FoxPro es imposible pasar un solo elemento de matriz por referencia. Se tiene que copiar el elemento en una variable, pasar una referencia a esa variable y actualizar el valor en la matriz.


Igual se aplica a las propiedades de objetos. En teoría, no se puede pasar una propiedad por referencia porque es una parte integral del objeto. Pasar una propiedad por referencia, por lo tanto, rompería la encapsulación. La respuesta verdadera, sin embargo, es que una propiedad no tiene una entrada dedicada en la tabla de nombres y pasarla por referencia es por lo tanto imposible. Son afectadas especialmente por este diseño las propiedades matrices. Ni las matrices ni las propiedades se pueden pasar por referencia. Por lo tanto no se tiene ninguna otra posibilidad que copiar la matriz en una variable local, pasarla en lugar de la otra, y copiar la matriz entera nuevamente usando ACOPY() para ambas maneras. Combinado con los métodos access y assign este método tiene aún más desventajas que sólo reducir la velocidad de ejecución. Afortunadamente, Visual FoxPro 8 agregó las colecciones que lucen como una matriz, pero pueden ser fácilmente pasados alrededor.


El acceso a las variables ha sido optimizado por Visual FoxPro. Ya al compilar un programa Visual FoxPro traduce nombres en valores enteros fáciles de manejar. Las líneas:


LOCAL lcName, lcZIP
? lcName



Se convierten en el pseudo código siguiente durante la compilación:


LOCAL #1, #2
? #1



En el archivo FXP resultante todas las variables se enumeran al final del archivo. Dentro del código compilado, se utilizan valores de 16 bits que indican la posición en la lista.


0x00000000 : FE F2 FF 20 02 01 00 00 00 B0 00 00 00 8F 00 00 þòÿ .....°...�..
0x00000010 : 00 21 00 00 00 00 00 00 00 00 00 00 00 00 00 00 .!..............
0x00000020 : 00 00 00 00 00 00 00 94 11 00 00 00 00 25 00 00 .......”.....%..
0x00000030 : 00 00 00 00 00 00 00 00 00 56 00 00 00 03 00 00 .........V......
0x00000040 : 00 50 00 00 00 C2 8B 56 2B 11 00 00 00 FC 18 00 .P...‹V+....ü..
0x00000050 : 0B 00 AE F7 00 00 07 F7 01 00 FE 0A 00 02 F8 03 ..®÷...÷..þ...ø.
0x00000060 : 01 F7 00 00 FE 03 00 55 02 00 06 00 4C 43 4E 41 .÷..þ..U....LCNA
0x00000070 : 4D 45 05 00 4C 43 5A 49 50 B1 00 A1 00 31 00 00 ME..LCZIP±.¡.1..
0x00000080 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 65 ...............e
0x00000090 : 3A 5C 74 65 6D 70 5C 00 76 61 72 2E 66 78 70 00 :\temp\.var.fxp.
0x000000A0 : 65 3A 5C 74 65 6D 70 5C 76 61 72 2E 70 72 67 00 e:\temp\var.prg.
0x000000B0 : 00 29 00 00 00 8F 00 00 00 00 00 00 00 09 00 00 .)...�..........
0x000000C0 : 00 00 00 00 00 00 00 00 00 .........


Es reconocible inmediatamente que el código real empieza en la posición 0x50 y finaliza en 0x64. Lo siguiente lista el significado de la parte en negritas del archivo:


0B 00 length of first line (11 bytes)
AE code for the LOCAL statement
F7 expression: a variable follows
00 00 variable #1 (lcName)
07 comma in list of parameters
F7 another variable follows
01 00 variable #2 (lcZIP)
FE end of expression

0A 00 length of second line (10 bytes)
02 F8 03 code for the ? statement
01 number of parameters: 1
F7 expression: a variable follows
00 00 Variable #1 (lcName)
FE end of expression




Al ejecutar tal programa, Visual FoxPro crea una lista que asigna cada variable en el código al índice de la tabla de nombres. Internamente, FoxPro llama una función que recibe el índice como parámetro y devuelve una estructura completada conteniendo el valor. Como se puede ver la longitud del nombre de la variable no es relevante. No se utiliza en el código real del programa, sólo está enumerada una vez al final. Los nombres de variables más largos (y a menudo más legibles) por lo tanto no tienen ningún efecto significativo en la velocidad de ejecución.



Una vez más la situación es diferente al observar las matrices. Las funciones internas para determinar el NTI pueden todavía ser utilizadas, pero Visual FoxPro no sabe hasta entonces que esta variable es una matriz. En el paso siguiente los parámetros índice se evalúan y se pasan a otra función que copie la estructura del valor para cargar un elemento de la matriz. Acceder a un elemento de una matriz, por lo tanto, es siempre más lento que acceder a una variable. Para complicar más las cosas, Visual FoxPro soporta corchetes y paréntesis para las matrices así como para funciones. No hay distinción clara entre los dos de antemano. Como las matrices tienen precedencia, Visual FoxPro tiene que comprobar para saber si hay una matriz del mismo nombre en cada llamada de función.


Es más difícil para los accesos a los objetos. Una vez más los nombres de propiedad se convierten a números usando el mismo algoritmo. Sin embargo, object1.name es casi igual que object2.name. Si Visual FoxPro encuentra código como este:


LOCAL loLabel
loLabel = CREATEOBJECT("Label")
? loLabel.Caption



No es difícil resolver la referencia a loLabel en la tercera línea. La función para obtener un valor para la NTI devuelve una estructura que representa el objeto entero. El paso siguiente es considerablemente más complejo. Los objetos mantienen su propia tabla de nombres. La lista disponible para convertir nombres en el NTI es inútil. Por lo tanto, Visual FoxPro tiene que localizar el nombre en el código (CAPTION, en este ejemplo) en la tabla de nombres privada y cargar la estructura allí. Esto requiere la resolución del nombre real en vez de usar el valor de índice y los resultados no se pueden poner en la caché como para los valores simples. Por lo tanto, acceder a una propiedad de objeto es incluso más lento que acceder a una variable o un elemento de matriz.


Eso explica porqué WITH…ENDWITH puede aumentar la performance tan notablemente. Simplemente mantiene la estructura de valores en memoria y hace innecesario resolver la primera parte. Esto también explica porqué tiene mucho más sentido guardar referencias profundas en una variable local. Esa variable se puede resolver mucho más rápidamente que una propiedad.



Administración de la memoria


Ni un bit menos complejo es el manejo de la memoria en Visual FoxPro. Ha habido dos versiones de FoxPro 2.x, una versión de 16 bits y otra de 32 bits que utilizaban un extensor del DOS. El extensor del DOS incluso cambió entre 2.0 y 2.6. Para las aplicaciones DOS hay varios tipos de memoria, que son todos manejados por diversos administradores de memoria. Están XMS y EMS como modelos concurrentes de memoria. Está HIMEM el cuál extendía la memoria convencional y DPMI, el interfaz de modo protegido do DOS, que todavía es soportado por Windows. Todos estos tipos de memoria han sido soportados por varias versiones de FoxPro; todavía hay código que permanece en Visual FoxPro, no obstante, no activo. Por ejemplo, la mayor parte de las funciones indocumentadas de la memoria entre SYS(1001) y SYS(1016) todavía trabajan.


Windows agregó modelos de memoria más modernos dependiendo de la versión de Windows. Incluso en la versión actual de 32-bits de Windows hay varias clases de tipos de memoria disponibles. Los tipos más conocidos son la memoria física y la de intercambio (swap). La memoria puede ser dividida aún más granularmente, como en montones locales y globales, memoria virtual, memoria mapeada y muchos tipos más.


Encima de la memoria física y de varios modelos de memoria implementados por el sistema operativo, Visual FoxPro tiene su propia manejo de la memoria. Visual FoxPro distingue cinco tipos de memoria: pila, memoria intermediaria fuera de la pantalla, grupo de manejadores y ficheros temporales. El apilado se utiliza para los procesos temporales y no es relevante para los desarrolladores de Visual FoxPro. Generalmente, se nota el apilado en condiciones de error tales como “insufficient stack space” o “Mismatched PUSHJMP/POPJMP call”. Solamente los desarrolladores de C/C++ que escriben un FLL tienen que tratar con las pilas.


El grupo de manejadores (handle pool) es la administración real de la memoria de Visual FoxPro. Para hacer frente a todos los distintos módulos de memoria, FoxPro implementa un modelo inteligente que prohíbe el acceso directo a la memoria. Debido a este modelo, FoxPro puede ser portado hacia hacia otras plataformas que utilizan modelos de memoria enteramente distintos, tales como Windows, Unix o el Mac.


Hay muchos datos para mantener en memoria. Esto incluye variables, menúes, ventanas, cadenas, pero también objetos, definiciones de clases, formularios, y mucho más. Cada vez que Visual FoxPro exige memoria, el administrador de memoria es llamado con el tamaño del bloque de memoria deseado. En vez de devolver una dirección, sin embargo, está devolviendo una manejador de memoria. Se puede imaginar esto como una clase de clave primaria. Siempre que un programa desee tener acceso a esta memoria debe bloquearla antes, como se bloquea un registro. Después de eso se puede determinar la dirección usando una función interna. Una vez accedida la memoria el código tiene que desbloquear el manejador, como desbloquear un registro.


El propósito de estos bloqueos es diferente al de los registros, sin embargo. El acceso paralelo a la memoria es lo que debe ser prevenido, moviendo el bloque alrededor. Cuando los bloques de la memoria son constantemente asignados, la memoria libre se fragmenta con el tiempo. Lo mismo se aplica a los discos duros cuando se crean y eliminan archivos. Después de funcionar un largo tiempo esto podría conducir a la situación de que hay bastante memoria disponible, pero no hay ningún bloque que sea lo bastante grande como para almacenar los datos solicitados. Esto sería fatal para un sistema de base de datos que debe funcionar desatendido por días o semanas, ya que esa situación colgaría el sistema.


Para evitar que esto suceda, la recolección de basura debe mover bloques de memoria alrededor. Internamente, Visual FoxPro realiza cierta clase de defragmentación mientras que está ocioso. Pero la defragmentación no es la única razón para implementar este modelo. Además, la memoria no está siempre fácilmente disponible. Por ejemplo, en DOS la memoria axtendida debe ser mapeada a la memoria convencional antes que la versión extendida de FoxPro pueda accederla. Cuando un manejador de FoxPro es bloqueado, las funciones de administración de FoxPro pueden tener el cuidado de asegurarse de que este bloque de memoria está fácilmente disponible para el programa que llama. Cuando está desbloqueado, FoxPro puede mover el bloque de nuevo a su posición original.


Parte del grupo de manejadores es visible a nosotros los desarrolladores con el comando LIST MEMORY, pero no todos los manejadores. Internamente Visual FoxPro hace uso intensivo de manejadores también. Todas las ventanas de edición, por ejemplo, son manejadores también. Por lo tanto podemos utilizar ACTIVATE WINDOW no sólo para activar nuestras propias ventanas, sino todas las ventanas proporcionadas por FoxPro incluyendo las barras de herramientas. En Visual FoxPro el grupo de manejadores es limitado solamente por la memoria física y virtual disponible.


La función SYS(1001) devuelve el tamaño máximo del grupo de manejadores. La función indocumentada SYS(1011) devuelve el número de manejadores asignados. Esta función debe devolver el mismo valor antes y después de una llamada de función. Cualquier otro valor indica un escape de memoria. SYS(1016) devuelve el tamaño de la parte asignada del grupo de manejadores. SYS(1104) inicia manualmente una recolección de basura. Esta función está documentada oficialmente desde Visual FoxPro 7.0. Todas estas funciones devuelven varios valores cuando son ejecutadas en la ventana de comandos, porque la ventana de comandos entra permanentemente en el bucle ocioso y por lo tanto ejecuta una recolección de basura. Algunas funciones se filtran en los manejadores usados internamente, otras no hacen eso. No obstante, estas funciones son buenos indicadores para el uso de la memoria.


Básicamente, todo lo que no es temporal se almacena en el grupo de manejadores en alguna parte. Esto incluye transacciones y los cambios sin comprometer en un buffer intermedio que deben ser escritos nuevamente con TABLEUPDATE().


El grupo de páginas (page pool) es el área de la memoria que es controlada por SYS(3050). Visual FoxPro guarda en ella mapas de bits creados por Rushmore y la utiliza para guardar en caché las tablas y los índices. Esta parte de la memoria es principalmente responsable de la impresionante velocidad de Visual FoxPro. Todo lo que se lee en disco es cacheado aquí para una reutilización posterior. Se puede controlar el tamaño máximo de esta área de memoria por separado para el primer plano (foreground) y para el proceso de fondo (background). Eso significa que dependiendo de si el usuario está trabajando con su aplicación, o no, usted puede decirle a Visual FoxPro que utilice menos o más memoria. Esa memoria no es asignada inmediatamente, sino que se asigna según lo necesitado. Se puede especificar un valor enorme sin tener que temer que esta cantidad de memoria se vaya inmediatamente.


SYS(3050) intenta asignar memoria en Windows que no se intercambie al disco. Sin embargo, no hay garantía. Los qué podría sucederle es que Visual FoxPro haya asignado la memoria para propósitos de caché que existe solamente en el disco duro local como memoria virtual. Obviamente, esto tiene un impacto absoluto en la performance. Reduciendo el valor de SYS(3050) inmediatamente libera toda la memoria superflua. Como el valor mínimo es 256 KB (no MB), se puede utilizar el código siguiente para liberar memoria más allá de 256 KB:


lcMemory = Sys(3050,1)
Sys(3050,1,1)
Sys(3050,1,Val(lcMemory))



Aún cuando es verdad que se tiene control completo sobre el grupo de páginas, ésta es solamente la mitad de la verdad en cuanto al consumo de memoria concierne. Si Visual FoxPro es de la opinión que necesita más memoria, por ejemplo, para almacenar un mapa de bits de la optimización, entonces no vacila en crear ficheros temporales si el grupo de páginas no es suficientemente grande. FoxPro continúa funcionando, aunque el valor de SYS(3050) sea demasiado bajo, eventualmente con la misma velocidad, quizá más lento, o aún más rápidamente. Esto depende de qué clase de memoria se asigne a Visual FoxPro y qué dispositivo sea más rápido. ¿Es el que está usado por Windows para la memoria virtual o el que es utilizado por Visual FoxPro para almacenar ficheros temporales? Como Windows, también puede almacenar en caché el acceso a los archivos TMP, puede ser que note repentinamente que su aplicación funciona más rápidamente.


Qué directorio se utiliza para los ficheros temporales depende de los ajustes del registro, el TMPFILES=… que elija (no TEMPFILES!) y varios ajustes en Windows. Bajo circunstancias normales puedes utilizar SYS(2023) para descubrir el directorio temporal. A veces, sin embargo, Visual FoxPro puede silenciosamente cambiar a un directorio distinto. Esto puede ser causado por un número de factores. En todo caso, se debería observar la salida del seteo SYS(2023) actual ya que puede ser que difiera del directorio temporal normal usado por Windows. El peor caso es que Visual FoxPro utilice el directorio raíz del usuario o el directorio del programa, ambos a menudo que están en el servidor. Realmente para estar seguro donde van los ficheros temporales, se podría crear un cursor y determinar su posición con la función de DBF(). Aún cuando un cursor se crea generalmente en el mismo directorio donde apunta SYS(2023), este no siempre es el caso.



Rushmore


Rushmore es más que una tecnología, es un mito. Esto no debe pararnos, sin embargo, de figurarnos que hay detrás de ese mito. Especialmente con este asunto es importante distinguir los hechos de la ficción. En la última década la regla era crear un índice por DELETED(), justo lo contrario es verdad en esta década. Ninguna de ambas, sin embargo, son realmente la verdad.


La razón del funcionamiento de Visual FoxPro tiene dos fundamentos. Un fundamento es Rushmore, el otro fundamento es el uso verdaderamente agresivo de la caché. La diferencia del funcionamiento de otras bases de datos con algoritmos de búsqueda centrados en mapas de bits (pues Rushmore es uno) no es causada sobre todo por Rushmore, sino debido a su estrategia de caché y a un acceso de red optimizado.


Rushmore es un algoritmo orientado a mapas de bits. Visual FoxPro crea una lista para cada condición que se pueda optimizar con Rushmore. Esta lista determina si un registro satisface los criterios de búsqueda o no. Visual FoxPro utiliza un solo bit para cada registro, pues hay solamente dos estados posibles para cada registro. Ocho registros caben en un byte. Si se tiene una tabla de 8-millones-de-registros, cada condición de la búsqueda toma 1 MB de la memoria.


Cada bit comienza siendo 0 - no seteado - y el registro correspondiente está por lo tanto en el conjunto de resultados. Una vez que los mapas de bits hayan sido determinados para todas las condiciones, esos mapas de bits se combinan bit-a-bit. Si se utiliza la condición siguiente en una consulta:


NAME = "Smith" AND InvoiceDate < DATE()-60


Esta consulta resulta en la creación de dos mapas de bits independientes que contienen todos los registros para “Smith” y todos los registros con una fecha de factura menor a 60 días. En cada mapa no importa si la otra condición no se satisface. Después de eso ambos mapas de bits son combinadas bit-a-bit con AND. El resultado es un mapa de bits que tiene solamente un bit seteado para aquellos registros que satisfagan ambas condiciones. No es difícil imaginarse que el uso de la memoria para acumular estos mapas de bits puede rápidamente crecer y retrasar una consulta. Si tienes solamente una sola condición, puedes utilizar el viejo estilo del dBase:


SET ORDER TO RequiredIndex
SEEK Value
SCAN WHILE Field=Values
   * do something
ENDSCAN



En muchos casos esto es incluso más rápido que una consulta optimizada con Rushmore porque Visual FoxPro no tiene que crear un mapa de bits. Por otra parte, esta técnica no utiliza la caché de la misma forma que Rushmore, haciendo consultas repetidas a los mismos datos más rápidas en Rushmore. Rushmore trabaja como el bucle SCAN anterior seteando el bit dentro del bucle.


¿Cómo se crea realmente este mapa de bits? El factor más importante es que el índice en Visual FoxPro está almacenado como b-tree, un árbol equilibrado. Cada nodo es un bloque de 512 bytes que puede contener hasta 100 punteros para subordinar nodos. Los nodos cerca de la raíz referencian a los valores clave, sólo los nodos de la hoja referencian a registros. Como cada nodo no referencia solamente a otros dos bloques, como se podría haber supuesto, la jerarquía en el archivo del índice puede seguir siendo generalmente muy plana. Además, todos los nodos se ligan horizontalmente.


Cuando Visual FoxPro busca un valor, navega a través del árbol verticalmente de arriba hacia abajo hasta que encuentra el registro. Entonces continúa leyendo horizontalmente mientras el valor de la búsqueda coincida con el que está en el índice. Esta estrategia de lectura abajo y de lado reduce el número de los nodos del índice que tiene que leer, pero incrementa el número de nodos al actualizar el índice. Mientras que lee horizontalmente, Visual FoxPro setea el bit correspondiente para cada registro encontrado. Esto es posible porque la entrada de índice contiene el número de registro así como el valor clave. Los datos se almacenan comprimidos sin embargo. Así es cómo el operador igual trabaja.


Otras operaciones trabajan de manera similar. Por ejemplo, si se desean encontrar los registros que no son iguales, Visual FoxPro comienza con un mapa de bits en el cuál se setean todos los registros. Entonces realiza la misma búsqueda que cuando busca los registros iguales, salvo que limpia bits cuando encuentra un registro. Al buscar por menor o mayor que, simplemente se mantiene leyendo la lista hacia la derecha o hacia la izquierda hasta que FoxPro alcanza el final del archivo.


Con Rushmore Visual FoxPro puede determinar qué registros no están en el conjunto de resultados, no los registros que están en el conjunto de resultados. Ése es el porqué la fase de Rushmore es seguida por la fase post-exploración. Cada registro que ha sido determinado por Rushmore se lee totalmente desde disco. Sin una expresión optimizada éstos son todos los registros en todas las tablas. Cada uno de estos registros entonces se comprueba para las expresiones inoptimizables restantes. Además, todas las expresiones optimizables se evalúan de nuevo, ya que algún otro pudo haber cambiado el registro mientras que Visual FoxPro creaba el mapa. Por lo tanto el conjunto de resultados podría no contener todos los registros que coinciden actualmente con los criterios de búsqueda, pero nunca se obtienen registros que no coinciden con los criterios de búsqueda.


Hay una excepción a esta regla, sin embargo. Al contar registros, Visual FoxPro intenta evitar la fase post-exploración. Cuando se ha construido el mapa de bits y no se deja ninguna expresión inoptimizable, Visual FoxPro comienza a contar los bits seteados. Por lo tanto COUNT FOR y SELECT CNT(*) FROM son extremadamente rápidos si una consulta se optimiza completamente. Una optimización parcial no es suficiente. Tampoco ayuda utilizar ningún otro método de cuenta como SELECT SUM(1) FROM…


Cuando se crea el mapa de bits Visual FoxPro tiene que leer todos los bloques de índice que coinciden con los criterios de búsqueda. Las accesos repetidos hacen que Visual FoxPro recupere estos bloques de la caché. Sin embargo, se desecha la caché si una estación de trabajo cambia un campo puesto en un índice o agrega un nuevo registro. Visual FoxPro puede determinar sólamente que otra estación de trabajo ha cambiado el índice, pero no qué ha cambiado exactamente. Por lo tanto la caché entera se desecha. Se puede explotar esto para medir la performance. Usando una segunda instancia de FoxPro que reemplace un campo del índice en el primer registro en un bucle.


Hace algún tiempo la gente comenzó a darse cuenta de que un índice por DELETED() no es siempre la solución óptima. Parece que hay una clase de contra-movimiento que condena totalmente el índice, que tampoco es una buena idea. Cuándo Rushmore es una buena idea es realmente muy fácil de determinar. Si se leen más bytes en el archivo del índice que los registros que se quitan durante la post-exploración, Rushmore disminuye la performance. Se tienen que comparar los bytes que se transfieren realmente.


Por lo tanto se necesita tener presente que la caché tiene un impacto con Rushmore y que los índices CDX están almacenados comprimidos. Los comienzos iguales de una palabra se almacenan solamente una vez. La cantidad real de datos se puede determinar con el monitor del sistema en Windows. Aún los resultados más exactos son posibles con un monitor de red como NETMON.EXE que viene con Windows 2000 server, o Ethereal que está disponible gratuitamente en http://www.ethereal.com . Tal monitor de red revela qué parte de un archivo se lee realmente. Combinado con la estructura de los archivos del archivo de ayuda se pueden determinar muchos detalles.


Si una aplicación cambia montones de datos estos invalidan con más frecuencia la caché. Por lo tanto, tal aplicación se beneficia menos de Rushmore que, por ejemplo, una aplicación de catálogo de CD's que ha puesto todos los datos en la caché después de un corto tiempo de usarla.


Si su aplicación tiene muchos registros eliminados también se beneficia de Rushmore. Si su aplicación visita un registro múltiples veces porque, por ejemplo, el algoritmo requiere la navegación por los registros siguientes y anteriores, Rushmore es superior pues puede reutilizar los mapas de bits mientras que el código del viejo estilo del xBase tiene que releer todos los registros repetidamente.


Si se desea determinar el número de hits antes de que realmente se ejecute la consulta dando a sus usuarios la chance de evitar consultas duraderas, su consulta debe ser completamente optimizable. Esto le da una ventaja verdadera de velocidad ya que crear un mapa de bits toma significativamente menos tiempo que leer la tabla entera, y el mapa de bits puede incluso ser reutilizado si el usuario decide ejecutar la consulta.


Otro factor importante es la distribución de valores en el campo indexado. Hay una diferencia enorme si se busca un valor único como una clave primaria o un campo de estado que pueda tomar solamente diez valores distintos. Un ejemplo extremo es el índice por DELETED() para el cual todos los campos tienen generalmente el mismo valor. En general se deben evitar tales índices a menos que los necesite para propósitos de contar.



Palabras Finales


Este documento puede dar solamente una breve introducción sobre el funcionamiento de Visual FoxPro. Muchas cosas sólo las he mencionado brevemente. Algunas cosas incluso no pudieron tener sentido cuando usted las leyó la primera vez. Se mantiene la pregunta: ¿Se necesitan conocer todas estas cosas? Ciertamente, no. Pero saber algunas de estas cosas le puede ayudar a evaluar riesgos de forma más precisa. Podría explicar porqué ocurren ciertos errores que parecen ser al azar. Y es sólo y simplemente interesante saber qué está ocurriendo por dentro.