viernes, 22 de mayo de 2009

Tiempos de compilación en Java y la versión del NMake


En una KB estaba teniendo demoras en la compilación de varios minutos, lo cual no era para nada razonable.

Es una KB con GeneXus 9.0 U4, generando Java, y compilando con jikes de IBM y el nmake de Microsoft.

Analizando un poco, lo que encontré fue que cada vez que compilaba estaba copiando todas las clases al directorio del Tomcat. El .mak en cuestión hace referencia a más de 1.000 clases, con un tamaño de más de 500MB.

En otro PC, compilar el mismo objeto en la misma KB, no demoraba nada... Así que comparando las versiones de los ejecutables en cuestión, encontré que el que estaba distinto era el nmake.exe

La versión que yo tenía, era la 8.0.50727.762. La versión con la que funciona bien es la 7.10.3077.0...

Así que ahora por suerte volví a tiempos razonables de unos pocos segundos en la compilación.

Un tip: si alguien necesita ver que es lo que está haciendo la compilación, lo que hay que hacer es:
  1. en el archivo callmake.bat (en el directorio data002 o en el web según sea el caso), hay que comentar la primer línea que dice "@echo off"
  2. en el archivo .mak, cuando copia los archivos al directorio del Tomcat, lo hace con "@copy" que no imprime nada a pantalla; para ver lo que se está copiando hay que cambiarlos todos por "copy"
El callmake.bat no cambia a menos que se cambie de versión del generador, por lo que después hay que volver a dejarlo como estaba. El .mak cambia cuando cambia el árbol de llamadas, así que vuelve solo a su estado normal.

jueves, 21 de mayo de 2009

Comando "do case" en GeneXus

El comando do case de GeneXus tiene una sintaxis que no me termina de convencer...

El problema es que las condiciones de cada case pueden ir sobre variables distintas. Más que un do case, la sintaxis permite usarlo como un if-elseif.

En Java y C#, el comando equivalente es el switch, que discrimina según los valores que toma una variable dada. Por ejemplo:
switch (variable) {
    case 1:
        // hago algo para el valor 1
        break;
    case 2:
        // hago algo para el valor 2
        break;
    default:
        // hago algo para los demás valores
        break;
}
En GeneXus, el do case me permite hacer cosas como
do case {
    case &variable = 1:
        // hago algo para el valor 1 de &variable
    case &otra_variable = 2:
        // hago algo para el valor 2
de &otra_variable
    otherwise:
        // hago algo para los demás valores
endcase
Me gustaría más tener un comando if-elseif que me permitiera hacer:
if &variable = 1:
    // hago algo para el valor 1 de &variable
elseif &otra_variable = 2:
    // hago algo para el valor 2
de &otra_variable
else
    // hago algo para los demás valores
endif
y un comando do case que fuera sobre los valores de una sola variable, algo así:
do case &variable
    case 1:
        // hago algo para el valor 1 de &variable
    case 2:
        // hago algo para el valor 2
de &variable
    otherwise:
        // hago algo para los demás valores
endcase
Creo que nos forzaría a que el código quede más prolijo.

miércoles, 13 de mayo de 2009

Testeos de regresión de aplicaciones que usan bases de datos

El tema de testeo es un tema complicado en general, y más complicado todavía cuando involucra aplicaciones que usan base de datos, como lo son las aplicaciones generadas con GeneXus.

Por suerte están surgiendo herramientas como GXTest o GXUnit que pretenden resolver el problema, aunque (por lo que se) todavía no han madurado demasiado. Creo que el testeo es un tema que está en el debe de la comunidad GeneXus en general.

Ya de paso le respondo a Enrique, una charla que estaría buena para el encuentro GeneXus, es alguien que tenga medianamente resuelto el problema del testeo, que cuente su experiencia.

En esta oportunidad quería comentar sobre un caso particular con el que me tocó enfrentarme.

Tenemos una base de conocimiento que tiene un proceso bastante complicado (tiene varios, uno en particular...), por la cantidad de casos particulares que hay que manejar. Cada vez que hay que hacer algo en ese proceso, terminamos rompiendo alguno de los casos particulares que ya estaban funcionando.

Tipico caso en el que se necesitan tests de regresión...

Hacer el testeo a mano de este proceso es bastante engorroso, porque involucra varios pasos previos (hay que crear varias entidades: cotización, carpeta, uno o más documentos, una o más órdenes de trabajo, etc.). Cada caso de prueba, dependiendo de la complejidad, puede llevar entre 5 y 10 minutos aproximádamente.

Entonces lo que estamos haciendo para automatizarlo es:
  1. tenemos una base de datos que se usa solo para el testeo automático, que tiene todos los datos básicos cargados.
  2. hay un script que borra (truncate table) todas las tablas operativas del sistema, para poder ejecutar cada caso en una base en blanco
  3. se diseña y ejecuta a mano el caso de prueba que se quiere registrar, hasta llegar al paso previo a presionar el botón que larga el proceso que queremos testear
  4. llegado a este punto, se genera (mediante un script SQL) un script SQL que genera todos los insert necesarios para dejar la base de datos en ese estado y se salva como script de inicialización para el caso de prueba
  5. se ejecuta el proceso y se verifica a mano que esté bien, y si es así se graba el resultado (el proceso genera información en una sola tabla...)
  6. se hace un procedimiento en GeneXus que carga un SDT con los valores esperados (los obtenidos en el paso anterior) y otro SDT con los valores reales haciendo un for each a la tabla, y se llama a otro que compara los SDTs campo a campo
  7. se agrega el caso de prueba al programa main de testeo.
Una vez hechos todos esos pasos, se puede ejecutar el caso de prueba todas las veces que se quiera, lo que es prácticamente instantaneo.

Por ahora es algo con lo que estamos experimentando. Desarrollar todo este procedimiento de testeo llevó algún tiempo, así como hacer los programas la primera vez, pero ahora el costo de agregar un nuevo caso de prueba es relativamente bajo, en relación al tiempo de testeo que va a ahorrar y la tranquilidad que nos da.

Creo que como experiencia sirvió, lo que no logro ver todavía es como extender esto a N situaciones distintas, porque por ahora es solo un proceso el que estamos testeando...

¿Alguien tiene experiencia de testeo con bases de datos? ¿Alguien más hace testeo automático?

viernes, 8 de mayo de 2009

Bloques de reglas en transacciones GeneXus

Una cosa que me gustaría tener en GeneXus, son bloques de reglas.

Muchas veces pasa que tenemos varias reglas en una transacción que se ejecutan con las mismas condiciones.

Un ejemplo sencillo:
msg('Atención: el atributo Att queda con valor "valor"') If [condiciones] on AfterValidate;
Att = "valor" If [condiciones] on AfterValidate;
Me gustaría poder escribir estas líneas como:

{
msg('Atención: el atributo Att queda con valor "valor"');
Att = "valor";
}
If [condiciones] on AfterValidate;
El inicio y fin de bloque no tienen por que ser con { y }, es solo un ejemplo.

Me parece que el código quedaría mucho más fácil de leer, sobre todo teniendo en cuenta que ahora las reglas pueden estar separadas por otras reglas en el código.

Otra cosa que estaría bueno es poder decirle a GeneXus que las reglas de un determinado bloque se ejecuten en el orden que están escritas, pero eso ya me parece más difícil de conseguir.