17 de enero de 2015

Patrones de diseño en Visual FoxPro (Parte 2/2)

Texto original: Design Patterns in Visual FoxPro
http://www.tightlinecomputers.com/Documents/Des_Patterns.ZIP

Autor: Andy Kramek
Traducido por: Ana María Bisbé York

...continuación de (Patrones de diseño en Visual FoxPro (Parte 1/2))

¿Qué es un mediador y cómo lo utilizo?

El mediador describe una solución como una llave, que todos hemos encontrado siempre que tratamos de diseñar una clase nueva. Cómo tratar con situaciones donde un objeto tiene que responder a cambios, o controlar el comportamiento de otro.

¿Cómo reconozco donde necesito un mediador?

La definición formal del mediador, y dada por "GoF" es:

"Define un objeto que encapsula cómo interactúan un conjunto de objetos. El mediador estimula la pérdida de acoplamiento manteniendo objetos explícitamente, a partir de la referencias de otro, y le permite variar su interacción independientemente."

Este dirige uno de los problemas fundamentales que tenemos que afrontar en cualquier tarea de desarrollo de aplicaciones, que asegura que los objetos pueden comunicar con otros sin tener realmente que incluir referencias de código duro en sus clases.

En ningún lugar es esto más crítico, que al crear la interfaz de usuarios compleja que la generación actual usuarios finales de PC, no esperan; pero exigen. Típicamente, tenemos que hacer que toda la interfaz de usuario, responda como una única entidad, habilitando e inhabilitando funciones y controles como respuesta a las acciones del usuario u opciones, o, de acuerdo con sus derechos y permisos. Al mismo tiempo, queremos diseñar y generar clases genéricas, reutilizables. Los dos requerimientos están, aparentemente en conflicto directo uno con el otro.

Dele un vistazo al formulario de ejemplo el que hemos utilizado para ilustrar la cadena de responsabilidades en la sección precedente (Figura 6). Si ejecuta este ejemplo, verá que el botón de comandos "Add Tax" está activo cuando el formulario es instanciado, incluso si no existe la propiedad Price (precio). Por supuesto, al hacer clic en el botón con el precio de $0.00 simplemente retorna cero $0.00 y aparentemente no ocurre nada más. Pero, ¿qué pasa si se introduce un valor negativo? La respuesta corta es, que esto siempre puede ocurrir y funcionará, de tal forma, si introduce $ -29.95 como el precio y hace clic en el botón "Add Tax" el formulario le dirá que la tasa es $ -1.722 y el precio total es $ -31.67.

Podría ser mejor, si el botón "Add Tax" estuviese sólo habilitado cuando el precio fuera mayor que cero. Por supuesto, la solución más simple es justamente agregar una pareja de líneas de código al Valid() del cuadro de texto (textbox) de este formulario que implemente esta funcionalidad, como, por ejemplo:

IF This.Value > 0
  ThisForm.cmdCalc.Enabled = .T.
ELSE
  ThisForm.cmdCalc.Enabled = .F.
ENDIF 

Este tipo de "acoplamiento ligero" (Tight coupling) puede ser aceptable cuando estamos tratando con un cuadro de texto (textbox) y un botón de comandos en un único formulario. Sin embargo, rápidamente tendremos problemas si tratamos de adoptar esta solución al tratar con controles múltiples que tienen que interactuar en combinaciones diferentes y complejas. Incluso, encontrando dónde se especifica el código que controla una interacción particular, puede haber problemas, y simplemente cambiar el nombre de un objeto provoca daños mayores. Es aquí donde juega su papel el patrón de mediador.

La idea básica es, que cada objeto se comunica con un "mediador" central, el que conoce de todos los objetos que están al alcance actual, y cómo manipular su estado cuando un evento dado es reportado. De esta forma, evitamos todas las cosas asociadas con colocar código específico dentro de un método asociado con el evento Valid(). En su lugar, podemos escribir completamente código genérico con su clase padre. Entonces, si utilizamos un objeto mediador, podemos reemplazar el código específico en la instancia del cuadro de texto precio con el código algo así como lo siguiente:

This.oMediator.StateChange( This ) 

Como ha visto, el cuadro de texto no tiene idea de qué hará el mediador con la información, o incluso qué información desea. Todo lo que tiene que hacer es llamar al método "StateChange" y pasa una referencia por si misma. Cualquier acción subsiguiente es para especificar la implementación del mediador.


10 de enero de 2015

Patrones de diseño en Visual FoxPro (Parte 1/2)

Texto original: Design Patterns in Visual FoxPro
http://www.tightlinecomputers.com/Documents/Des_Patterns.ZIP

Autor: Andy Kramek
Traducido por: Ana María Bisbé York

Resumen

Los patrones de diseño ofrecen un lenguaje estándar para reconocer, definir, y describir soluciones a problemas de la creación de aplicaciones. El conocimiento de los patrones de diseño, hace más fácil entender los sistemas existentes y describir los requerimientos para nuevos sistemas complejos. Sin embargo, es importante indicar que los patrones de diseño, no son, de por sí, la solución a problemas específicos. Son vías sencillas de identificación de los problemas y una descripción genérica de soluciones, que han sido probadas por la experiencia. La implementación actual del diseño de patrones sigue siendo el trabajo de un desarrollador de aplicaciones.

¿Qué son patrones de diseño?

Antes de comenzar a bucear en ejemplos específicos de cómo implementar patrones de diseños específicos en Visual FoxPro, debemos comenzar por definir qué entendemos por "Patrones de Diseño". Se han propuesto varias definiciones y quizás la más reconocida es la que aparece en el trabajo "Design Patterns, Elements of Reusable Object-Oriented Software" (Patrones de Diseño, elementos de reutilización de aplicaciones orientadas a objetos) escrito por Erich Gamma, Richard Helm, Ralph Johnson y John Vlissides (comúnmente conocidos por la pandilla de los cuatro o simplemente como "GoF"). Ellos ofrecen en el primer capítulo de su libro "What is a Design Pattern" (¿Qué es el diseño de patrones?) la siguiente definición:

"Un diseño de patrones nombra, abstrae e identifica los aspectos claves de una estructura de diseño común que lo hace útil para la creación de un diseño orientado a objetos reutilizable. El diseño de patrones identifica la participación de clases e instancias, sus roles y colaboraciones, y la distribución de responsabilidades."

Esta es una buena definición, porque encapsula los cuatro elementos de cualquier diseño de patrones.

Primero, que tiene un nombre. Es vital, porque permite a los desarrolladores superar uno de los problemas fundamentales del diseño de aplicaciones – ¿Cómo comunicar lo que haces a otros? Recordamos bien, cómo hemos empleado cerca de tres cuartos de hora sentados en un hotel de Alemania, debatiendo sobre un problema de una aplicación con un colega. Fue tortuosamente difícil la explicación, que incluyó varios bocetos (si, por supuesto, ¡en servilletas de papel!) y batallamos para comprender de qué se trataba, cuando… algo ocurrió de repente. ¡El estaba implementando una estrategia de patrones! Si nuestro amigo hubiera empezado por ahí, hubiéramos ahorrado mucho tiempo, porque todos hubiéramos sabido inmediatamente (al menos en términos generales) cuál era el problema, y la estrategia que debíamos utilizar para tratar de solucionarlo.

Segundo, abstrae el problema. Esto es referido por "GoF" como el "objetivo". Nos dice la naturaleza del problema y la solución descrita por el patrón. Considere el problema frecuente de advertir a los usuarios de no crear múltiples instancias de una aplicación. Los usuarios, por lo general, tratan de comenzar nuevas instancias de la aplicación porque, al tener minimizada la pantalla principal, se olvida que está activa y hace clic en el icono del escritorio, en lugar de de maximizar la instancia existente. Podemos ver inmediatamente que el patrón Singleton es relevante porque su objetivo se da como "Asegura una clase que tiene una sola instancia y provee un punto global de acceso a ella".

Tercero, define un diseño de estructura. Es importante darse cuenta que el diseño de patrones no proporciona soluciones. Describe estructuras que permiten solucionar un problema de manera que resulte más fácil de reutilizar que si se escribe simplemente el código para solucionar el problema en el contexto en el que surge. Todos hemos pasado por estas experiencias de darnos cuenta que hemos solucionado ya un problema particular en algún lugar en nuestro código, pero no podemos re-utilizarlo, porque no hicimos una solución aislada de la situación. El objetivo del diseño de patrones es ayudarnos a reconocer las situaciones como estas y evitarlas.

Cuarto, que identifica la distribución de responsabilidades. Esto es, por supuesto, la clave a todos los tópicos de diseño y no está limitado al diseño de patrones. Después de todo, una vez conocido lo que tiene que hacer una clase (u objeto), escribir el código para hacerlo es relativamente fácil. La ventaja del diseño de patrones es que una vez que haya reconocido el problema y lo haga corresponder con un patrón, el patrón nos dirá cómo debemos asignar las responsabilidades y por consiguiente nos ayudará a crear rápidamente una solución.
Nuestra intención, en esta sesión, no es ofrecer una revisión exhaustiva de todos los patrones de diseño conocidos (existen libros enteros dedicados a eso). A continuación discutiremos algunos de los patrones más comúnmente encontrados y mostraremos cómo puede utilizar el Visual FoxPro para implementar una solución. Comencemos por ver lo que se conoce como la madre de los patrones, el puente (the Bridge).


27 de diciembre de 2014

Abrir tablas o no

Abrir tablas o no abrir tablas. Esa es la pregunta.

por Jim Booth (Publicado originalmente en FoxTALK Diciembre 1998)
Traducido por Roberto Alfredo Moré
¿Se ha preguntado alguna vez si hay algún beneficio abriendo las tablas para un comando SQL SELECT antes de ejecutar el SELECT?. ¿Usa el SELECT las tablas que ya están abiertas?. Interesante pregunta.

¿Qué tan rápido es rápido?

Una simple prueba para averiguar cuál es el efecto de abrir primero las tablas sobre la performance de SQL en Visual FoxPro se muestra en el siguiente ejemplo de código.


LPARAMETERS plCloseThem
DIMENSION laTimes(100)
FOR lnCnt = 1 TO 100
lnStart = SECONDS()
SELECT * FROM BigFile WHERE cState = "NY" INTO CURSOR Result
lnEnd = SECONDS()
laTimes(lnCnt) = lnEnd - lnStart
IF plCloseThem
CLOSE ALL
ENDIF
ENDFOR
* Calcular el tiempo promedio
lnTime = 0
FOR lnCnt = 1 TO 100
lnTime = lnTime + laTimes(lnCnt)
ENDFOR
lnTime = lnTime/100
?lnTime

En el programa de prueba de arriba, la tabla BigFile es una tabla de 200,000 registros con índices sobre el campo cState y sobre DELETED(). El programa puede ser llamado con un parámetro que le indica si cierra o no las tablas entre las corridas del comando SELECT. Ejecuta el SELECT 100 veces y luego promedia el tiempo que toma el SELECT.
En mi máquina (Pentium II 300MHz con 128 MB RAM y un disco rígido SCSI) obtuve un promedio de tiempo de 1.23 segundos cuando las tablas se cierran entre los SELECTS. Si las tablas se dejan abiertas, el tiempo promedio fue de 0.67 segundos, ¡dos veces más rápido!.
Conclusión: Abra sus tablas primero y déjelas abiertas, especialmente si estará ejecutando múltiples SELECTS que acceden a estas tablas.

¿Usa realmente el SELECT las tablas que están abiertas?

No, no las usa. Utiliza un USE AGAIN para abrir la tabla en otra área de trabajo. Para ver esto, usted puede realizar la siguiente prueba:

1. Abra la ventana Data Session desde el menú Window.
2. En la ventana de comandos ejecute un comando SELECT simple como SELECT * FROM AlgunaTabla INTO CURSOR Resultado.
3. En la ventana Data Session haga click sobre el nombre de la tabla origen y observe el eco del comando en la ventana de comandos (será SELECT 1 o algo así). El número es el área de trabajo en que el cursor está abierto.
4. Haga click sobre el cursor Resultado y observe el área de trabajo (podría ser 2).
5. Tipee USE en la ventana de comandos para cerrar el cursor Resultado.
6. Corra nuevamente el comando SELECT.
7. Repita los pasos 3. y 4. nuevamente.
Encontrará que la segunda vez hay un hueco en las áreas de trabajo que usó el comando SELECT. Si usted hace esto cuando no hay ninguna tabla abierta, la primera vez las áreas de trabajo deberían ser 1 para la tabla origen y 2 para el resultado. La segunda vez, serían 1 para la tabla origen y 3 para el resultado.
La razón por la que el resultado está en un área de trabajo diferente la segunda vez es que el SELECT abrió la tabla origen en el área 2 durante el proceso de consulta. Esto fue hecho con una operación USE AGAIN. El beneficio de este comportamiento son dos cosas:

1) el segundo SELECT se ejecutará más rápido y
2) el puntero de registro en el área de trabajo de la tabla origen no se afecta.
¿Por qué es más rápido abrir las tablas?

Porque cuando una tabla está abierta, con SET OPTIMIZE ON, VFP trata de capturar tanto como pueda del índice para proveer a Rushmore con lo que necesita. Así, cada vez que se abre una tabla, se lee en memoria una cierta cantidad de información. Cuando se usa USE AGAIN para una tabla que ya está abierta, esa información ya está en memoria y no necesita ser leída del disco. Usted habrá notado, en el programa de prueba, que no hay un comando USE Bigfile. Esto ilustra otra sutil cualidad del comando SQL SELECT. Si se ejecuta el SELECT y la(s) tabla(s) de origen no está(n) abierta(s), la(s) abrirá y la(s) mantendrá abierta(s). Si la(s) tabla(s) de origen está(n) abierta(s), las usará nuevamente en otra área de trabajo y cerrará dicha área de trabajo cuando se completa el SELECT.

Una nota final.

Hay una preocupación reciente sobre el uso de SYS(2015) para generar nombres únicos de cursor. Existe un informe sobre que SUBSTR(SYS(2015),3) comenzará con un dígito en un futuro cercano. Bueno, esto es cierto, pero es irrelevante. Los cursores creados con el comando SQL SELECT o CREATE CURSOR usan el nombre para definir el alias del área de trabajo donde se ubica el cursor, NO el nombre del archivo en disco usado por el cursor para sus datos. Los nombres de archivo para los cursores serán siempre únicos y se crearán en el directorio temporal del usuario. Los nombres alias son siempre locales al equipo actual y no necesitan ser únicos. Pruebe lo siguiente en una ventana de comandos:

CREATE CURSOR MyCsr (Test C(10))
? ALIAS()
?DBF()

Lo que se obtiene como resultado de Alias() es MyCsr y DBF() es C:Temp2E4H000C.TMP. De aquí se puede deducir que
1) el archivo para el cursor fue creado en el directorio temporal, no en el disco de red, y
2) el nombre utilizado en el comando CREATE CURSOR no es el mismo que el que se usó en el archivo dbf.
No es necesario usar ningún algoritmo para crear un nombre único de un cursor; usted puede usar nombres significativos en su código y no encontrará problemas en un entorno multiusuario.

13 de diciembre de 2014

Introducción a los Patrones de diseño

Artículo original: Introduction to Design Patterns
http://weblogs.foxite.com/andykramek/2006/12/02/introduction-to-design-patterns/
Autor: Andy Kramek
Traducido por: Ana María Bisbé York


¡ Cuánto tiempo !

Hace ya tiempo que no he podido actualizar mi blog y existen varias razones para ello, no solamente se debe a que he estado extremadamente ocupado profesionalmente, trabajando en varios proyectos interesantes. Más recientemente, Marcia y yo viajamos a Frankfurt a hablar en la 13ra European DevCon donde nos unimos a Craig Bernston, Doug Henning, Lisa Slater-Nicholls y Rick Schummer.

Esta fue, como siempre, una G R A N conferencia y mantuvo el misterio de siempre, para todos nosotros los que hemos presenciado este evento, la poca cantidad de personas de EEUU que han estado. Los vuelos son (relativamente) baratos y agradables, y la oportunidad de presenciar una conferencia genuinamente buena combinado con un descanso europeo y recreación, es sencillamente una buena idea. Puede encontrar detalles de lo que se perdió en varios lugares de la red, incluyendo la cobertura en Universal Thread y los blogs de algunos presentes como Craig, Doug y Rick.

Tengo en plan comenzar otra pequeña serie de artículos en mi blog, justo ahora, con el tema de patrones de diseño. Esto es algo que me interesa desde hace ya tiempo (vea "The Revolutionary Guide to Visual FoxPro OOP", Wrox Press, 1996 escrito por Will Phelps, Bob Groomes y yo, con algunos ejemplos iniciales basados en patrones de diseño con VFP), y a juzgar por los comentarios y discuciones que he presenciado en conferencias, no soy el único interesado. La pregunta más común que he escuchado es "¿Cómo utilizo los Patrones de diseño en VFP?" y esto es lo que trataré de enfocar con esta pequeña serie de artículos - al menos para algunos de los patrones más comunes.

¿Porqué me debo preocupar por los Patrones de diseño?

Los patrones de diseño ofrecen un lenguaje estándar para reconocer, definir, y describir soluciones a problemas de la creación de aplicaciones. El conocimiento de los patrones de diseño, hace más fácil entender los sistemas existentes y describir los requerimientos para nuevos sistemas complejos.

Recuerdo que hace unos años, sentado con Paul Maskens en el lobby de Lindner Conference Hotel en Frankfurt, mientras el me explicaba una idea para la columna Kitbox. El estaba describiendo una solución a un problema que había desarrollado y luego de aproximadamente 20 minutos, de pronto, me di cuenta de que estaba hablando de el "patrón de estrategia". El comenzó diciendo que había implementado el patrón de estrategia quise saber inmediatamente qué uso general tenía aquí, y el método que había empleado para solucionarlo. Esto nos ahorró mucho tiempo y esfuerzo y nos permitió concentrarnos en los detalles de la implementación.

Sin embargo, es importante indicar que los patrones de diseño, no son, de por sí, la solución a problemas específicos. Son vías sencillas de identificación de los problemas y una descripción genérica de soluciones, que han sido probadas por la experiencia. La implementación real de los patrones de diseño sigue siendo el trabajo de un desarrollador de aplicaciones.

¿Qué son patrones de diseño?

Antes de comenzar a bucear en ejemplos específicos de cómo implementar patrones de diseño específicos en Visual FoxPro, debo comenzar por definir qué entendemos por "Patrones de Diseño". Se han propuesto varias definiciones y quizás la más reconocida es la que aparece en el trabajo "Design Patterns, Elements of Reusable Object-Oriented Software" (Diseño de patrones, elementos de reutilización de aplicaciones orientadas a objetos) escrito por Erich Gamma, Richard Helm, Ralph Johnson y John Vlissides (comúnmente conocidos por la pandilla de los cuatro o simplemente como "GoF"). Ellos ofrecen, en el primer capítulo de su libro "What is a Design Pattern" (¿Qué es el diseño de patrones?), la siguiente definición:

Un diseño de patrones nombra, abstrae e identifica los aspectos claves de una estructura de diseño común que lo hace útil para la creación de un diseño orientado a objetos reutilizables. El diseño de patrones identifica la participación de clases e instancias, sus roles y colaboraciones, y la distribución de responsabilidades.

Esta es una buena definición, porque encapsula los cuatro elementos de cualquier diseño de patrones.

  • Tiene un nombre. Esto es vital, porque permite a los desarrolladores superar uno de los problemas fundamentales del diseño de aplicaciones – cómo comunicar lo que haces a otros? El ejemplo de Paul y yo discutiendo una idea para un artículo, que he mostrado antes, ilustra este punto perfectamente.
  • Abstrae el problema. Esto es referido por "GoF" como el "objetivo". Nos dice la naturaleza del problema y la solución descrita por el patrón. Considere el problema frecuente de advertir a los usuarios de no crear múltiples instancias de una aplicación. Los usuarios, por lo general, tratan de comenzar nuevas instancias de la aplicación porque, al tener minimizada la pantalla principal, se olvidan que está activa y hace clic en el icono del escritorio, en lugar de de maximizar la instancia existente. Podemos ver inmediatamente que el patrón Singleton es relevante porque su objetivo es "Asegurar una clase que tiene una sola instancia y provee un punto global de acceso a ella".
  • Define una estructura de diseño. Es importante darse cuenta que los patrones de diseño no ofrecen soluciones a los problemas. Ellos describen estructuras que permiten solucionar un problema de manera que resulte más fácil de reutilizar que si se escribe simplemente el código para solucionar el problema en el contexto en el que surge. Todos hemos pasado por estas experiencias de darnos cuenta que hemos solucionado ya un problema particular en algún lugar en nuestro código, pero no podemos re-utilizarlo, porque no hicimos una solución aislada de la situación. El objetivo de los patrones de diseño es ayudarnos a reconocer situaciones como estas y evitarlas.
  • Identifica la distribución de responsabilidades. Esto es, por supuesto, la clave a todos los tópicos de diseño y no está limitado a los patrones de diseño. Después de todo, una vez conocido lo que tiene que hacer una clase (u objeto), escribir el código para hacerlo es relativamente fácil. La ventaja de los patrones de diseño es que una vez que haya reconocido el problema y lo haga corresponder con un patrón, el patrón nos dirá cómo debemos asignar las responsabilidades y por consiguiente nos ayudará a crear rápidamente le "mejor" solución.

No es mi intención ofrecer una revisión exhaustiva de todos los patrones de diseño conocidos (existen libros enteros dedicados a eso). Pero en esta pequeña serie mi plan es cubrir los patrones encontrados más frecuentemente y mostrar cómo puede utilizar el Visual FoxPro para implementar una solución. Cada artículo es independiente y cubrirá un patrón, aunque intentaré en lo posible mantener un hilo único en ellos.

Espero que encuentre útil esta información, y si tiene cualquier comentario, por favor, sea libre de publicarlo.