martes, 29 de diciembre de 2009

Buscar un elemento dentro de un SDT en GeneXus

En GeneXus, no hay una forma de buscar un elemento dentro de una colección (SDT), que no sea recorriendo toda la lista. Hay una función IndexOf, pero compara referencias y no el contenido de los elementos.

Ejemplo:
&esta = Boolean.False
for &depUbiItem in &depUbis
    if &depUbiItem.DepId = &DepId and &depUbiItem.CicUbiId = &CicUbiId
        &esta = Boolean.True
        exit
    endif
endfor

Esto no parece ser lo más elegante... No debería necesitar 7 líneas de código para saber si un elemento está en la colección, lo debería poder hacer en una sola línea.

El problema es que dado un SDT, GeneXus no tiene forma de saber cuales son los elementos que quiero comparar. En el ejemplo, estoy comparando DepId y CicUbiId, pero el SDT tiene varios campos más.

Una posibilidad sería poder definirle comportamiento a los SDTs, de forma de poder decirle cual es la función de comparación que tengo que usar. Esta función de comparación se definiría una vez para el SDT, y siempre que se quiera buscar un elemento se haría usando este comparador.

Otra opción que me gustaría más, es poder definir on-line la función de comparación. En C# por ejemplo, usando lambda expressions, quedaría algo así:
bool esta = depUbis.Exists(d => ((d.DepId = depId) && (d.CicUbiId = cicUbiId)));

O escribiendolo como me gustaría verlo en GeneXus:
&esta = &depUbis.Exists(d => d.DepId = &DepId and d.CicUbiId = &CicUbiId)
 Esto se lee "existe un elemento d en la colección &depUbis que cumple que d.DepId = &DepId y d.CicUbiId = &CicUbiId".

Las colecciones en C# definen otras funciones que también sería intereante tener, como ser:
  • First: devuelve el primer elemento que cumple con la condición
  • Where: devuelve otra colección con los elementos que cumplen con la condición
  • Select: permite hacer una proyección, devuelve otra colección pero de otro tipo

lunes, 28 de diciembre de 2009

Atributos y controles como parámetro en GeneXus

Capaz que el título no dice mucho, es dificil explicar lo que quiero en una línea...

Todos sabemos que es una buena práctica de programación, reutilizar código siempre que sea posible. En GeneXus X con los data selectors se dio un gran paso, pero hay cosas que me siguen faltando.

Por ejemplo, tengo el siguiente código que borra los datos de tablas referenciadas, cuando borro una determinada entidad (sí, seguro que es más prolijo hacer un Business Component y borrar con eso, pero no es el punto).



¿Se ve el patrón de código repetido? El problema es que no tengo forma de unificar el código en un procedimiento o subrutina, de forma de pasarle solamente el atributo que va en el defined by.

Seguramente no es fácil de implementar, pero sería interesante.

Otro caso donde pasa algo similar, es con los controles en pantalla.

Por ejemplo, recibo unas variables por parámetro, si vienen cargadas las muestro en el form deshabilitadas, y si no las muestro habilitadas.

El código es el siguiente:



Otra vez, creo que es fácil ver el patrón en el código, y otra vez no tengo forma de hacer algo genérico, que reciba dos variables (el parámetro y la variable que tengo en el form), y le aplique la lógica...

Capaz que este caso es más sencillo de implementar que el otro, porque no cambia la forma en que navega el programa.

jueves, 24 de diciembre de 2009

Lo que le falta al Chrome OS

Primero que nada, quiero aclarar que no he usado Chrome OS... lo que sigue es más bien una reflexión.

Y no lo he probado, porque creo que no aporta nada nuevo. Es decir muchas de las cosas que hago con un PC, las podría hacer con aplicaciones Web corriendo en Chrome OS, pero hay una actividad que hoy (creo) no se puede hacer: desarrollar software.

El problema es que mientras que los desarrolladores no se sientan atraidos a la nueva plataforma, no van a surgir desarrollos optimizados para Chromes OS, lo que se transforma en un círculo vicioso porque los usuarios no van a ver el valor de cambiar a un sistema operativo que no les aporta nada nuevo.

Claro que tiene sus ventajas (levanta mucho más rápido que cualquier otro PC, está enfocado a la Web que hoy por hoy es lo que más usan los usuarios, los equipos pueden ser más baratos, etc.), pero todavía está por verse que adopción va a tener.

Creo que en algún momento Google va a tener que liberar un conjunto de herramientas Web para desarrollar software, para que los desarrolladores puedan usar la plataforma a la que estarían apuntando. Tal vez algo como Bespin de Mozilla Labs, aunque seguramente debería ser algo un poco más avanzado, no solo un editor de texto.

Va a ser interesante de ver...

jueves, 10 de diciembre de 2009

Great programming quotes

Leo en el blog de Sebastián Gomez sobre great programming quotes, de una pregunta en Stack Overflow.

A mi también me pareció interesante para compartir :), así que acá van algunas de las que me gustaron:
Hofstadter's Law: It always takes longer than you expect, even when you take into account Hofstadter's Law.
Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live. (Rick Osborne)
Some people, when confronted with a problem, think "I know, I’ll use regular expressions." Now they have two problems.
In order to understand recursion, one must first understand recursion (un clásico)
It works on my machine.
If debugging is the process of removing software bugs, then programming must be the process of putting them in. (Edsger Dijkstra, otro clásico...)
Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away. (Antoine de Saint Exupéry, no creo que fuera programador, pero igual cuenta...)
Debuggers don't remove bugs. They only show them in slow motion.
Never trust a programmer in a suit.
Measuring programming progress by lines of code is like measuring aircraft building progress by weight. (Bill Gates)

martes, 8 de diciembre de 2009

Compilación GeneXus 9.0/Java: problemas de performance

En una KB GeneXus 9.0 grande (en nuestro caso unos 8.100 objetos), ubicada en la red y de uso compartido, la compilación puede tener algunos serios problemas de performance.

Existen dos formas de compilar, y las dos presentan dificultades:
  • usando NMake, la compilación es rápida, pero demora mucho cuando tiene que generar algún .mak porque cambió el árbol de llamadas
  • usando GXJMake, la generación es rápida, pero la compilación nos demoraba en algunos casos más de 2 minutos.
En particular el GXJMake, tiene un algoritmo que dista mucho de ser óptimo. Enrique estuvo analizando por que demoraba tanto, y llegó a que lo que hace es recorrer todo el árbol de llamadas (lo lee de los archivos .ari) y por cada objeto, compara la fecha del .java con la del .class. El tema es que lo hace una vez por cada aparición del objeto en el árbol.

En el caso que analizamos, había un objeto que estaba comparando las fechas más de 1.400 veces... ¡Y ni siquiera era el objeto que había modificado!

Una demora de 2 minutos como teníamos, para compilar un solo objeto modificado baja muchísimo la productividad, no solo por la demora en sí de la compilación, sino también porque la persona que tiene que esperar esos dos minutos casi seguro que se distrae y se pone a hacer alguna otra cosa.

Este problema es conocido, y está reportado en al menos dos SACs:
La solución, fue desarrollar nuestro propio programa de Make: COJMake.

Este programa ejecuta en el servidor donde está ubicada la KB, y queda monitoreando si hay algún .java modificado. Cuando detecta un .java modificado, lo manda a compilar(1). El programa graba un log que permite monitorear lo que está haciendo y detectar si se produjo algún error en la compilación.

Con esto, el programa ni siquiera necesita que se termine de generar para poder empezar a compilar. Si se están generando varios objetos, a medida que se va terminando de generar uno ya queda listo para compilar.

El efecto es que ahora la compilación es prácticamente instantanea. En condiciones normales (cuando se manda a generar unos pocos objetos), cuando se termina de generar demora menos de dos segundos en terminar de compilar.

(1) En realidad lo que hace es ir guardando los archivos modificados en una cola, y hay otro hilo que va compilando lo que aparece en la cola. Esto permite limitar el número de procesos que se largan a compilar, sin perder ningún archivo en el medio.

martes, 1 de diciembre de 2009

Primer Pattern generado por el Automatic Pattern Generator

Es un gusto anunciar que el Automatic Pattern Generator ya está generando su primer Pattern.

Claro, por el momento no es demasiado útil, porque genera un solo Pattern, que es fijo, pero al menos nos permite saber que vamos por el buen camino.

Todavía queda mucho por hacer, a quien le interese participar del proyecto, será bienvenido.

El pattern que genera consiste de un solo procedimiento que devuelve el valor de un objeto.

En este momento no estamos liberando binarios, porque no tiene demasiado sentido. Si alguien quiere ver el código del proyecto, o bajarlo, o hacer algún aporte, lo puede hacer en el sitio de Assembla.

Dejo algunas fotos de pantalla de la aplicación.


Figura 1: Acceso a la aplicación

Figura 2: Proyecto Visual Studio Generado


Figura 3: Proyecto Visual Studio



Figura 4: Aplicando el Pattern a un atributo y las propiedades


Figura 5: Procedure generado

lunes, 23 de noviembre de 2009

XCode vs. Visual Studio


Hace unos días empecé mis primeras pruebas para desarrollar aplicaciones para el iPhone, con lo cual tuve que estudiar un poco de Objective-C (el lenguaje de programación) y XCode (el ambiente de desarrollo).

No puedo evitar la comparación con C#/Visual Studio, que es el otro lenguaje de propósito general que manejo... Si bien tal vez la comparación no sea del todo justa, ya que en Visual Studio nunca desarrollé aplicaciones móviles, creo que como ambientes de desarrollo deberían ser bastante comparables.

Intellitips

Se extrañan... En Visual Studio cuando escribo "variable." muestra una lista de todas las propiedades, métodos y eventos que están disponibles para esa variable. Esto es muy útil cuando uno no se acuerda exáctamente el nombre de una función.

En XCode no encontré que tuviera intellitips, lo más parecido que tiene es una especie de "autocomplete", que muestra el primér método que coincide con lo que voy escribiendo.

Por lo tanto, si quiero buscar un método que no me acuerdo exáctamente del nombre, no tengo más remedio que salir del editor y buscarlo en la API en el navegador.

Propiedades "automáticas"

En los dos lenguajes se tienen propiedades automáticas (desde C# 3.0), pero la forma que se definen son distintas.

En C#, es una sola línea de código:
public int Prop { get; set; }
 En Objective-C, hay que definirla en tres lugares distintos...
  1. en el .h, en la definición de la clase
  2. en el .h con una directiva @property
  3. en el .m con una directiva @synthetize
Interfaz de usuario

En Visual Studio al agregar un elemento a la interfaz de usuario de la aplicación, el IDE se encarga de generar todo el código necesario para que ese elemento funcione. Después hay que definir el comportamiento, pero por lo menos el elemento está ahí.

En XCode, la definición de la interfaz se hace en otra aplicación, Interface Builder, y para poder utilizar los componentes que se agregaron con drag&drop, hay que definir outlets, delegates y alguna cosa más, que lo hace bastante complicado para novatos.

Conclusión

Si bien XCode tiene unas cuantas cosas interesantes, creo que como IDE se queda un poco corto. La productividad, al menos para los que recién estamos empezando, es mucho menor que la que se puede lograr con otras herramientas, como ser Visual Studio.

Habrá que seguir experimentando para agarrarle la mano.

martes, 17 de noviembre de 2009

Supercomputadoras


TOP500 es un sitio que se encarga de llevar estadísticas de las 500 supercomputadoras más rápidas que existen. Publican dos listas al año, una junio y otra en noviembre.

En el sitio ya está publicada la lista de noviembre de 2009.

La supercomputadora que está en el puesto número 1, tiene una capacidad de procesamiento de 1.76 tera-flops (= 1.76x1012 operaciones de punto flotante por segundo = 1760000000000 operaciones de punto flotante por segundo).

Cuenta con 224.162 CPU cores. Los procesadores que usa son AMD x86_64 Opteron Six Core de 2600 MHz.

Pero más allá de cual sea la lista ahora, lo que más me llamó la atención fue la siguiente gráfica, con la proyección para los próximos años.



Tres cosas que me parece vale la pena destacar:
  1. Es increible como se mantienen en una recta(1) la suma de performance de las 500 de la lista, y también como se mantiene en una recta(1) la performance de la número 500.
  2. La que hoy es número 500, hubiera sido la número 1 en el 2001, hace 8 años.
  3. Según la proyección, para junio de 2016 (6 años y medio), la que ahora es número 1 va a estar en el número 500.
(1)  Si bien en la gráfica se ve como una recta, tener en cuenta que es una escala logarítmica, por lo que la curva es en realidad exponencial...

viernes, 13 de noviembre de 2009

Impresiones sobre Google Wave


Desde hace unos días tengo una cuenta en Google Wave, con lo que pude hacer unas pruebas.

Primero que nada, ¿qué es Wave? Según la Wikipedia:
Google Wave es una herramienta en línea que permite a sus usuarios comunicarse y colaborar en tiempo real. El proyecto fue anunciado por Google en la última conferencia Google I/O, el 28 de mayo de 2009. Es una aplicación web y una plataforma de computación diseñada para unir los servicios de e-mail, mensajería instantánea, wiki, y redes sociales.
Básicamente, es como un mail en el que tengo mensajes (waves), pero sobre los que se puede colaborar en tiempo real, como si fuera un chat, comentando y editando lo que otros escriben.

Está interesante el artículo de Enrique Dans al respecto, con el cual comparto algunas cosas:
  • a simple vista, es un lindo chiche para hacre algunas pruebas
  • puede ser una herramienta muy potente si realmente se le da el uso apropiado.
Hay que tener en cuenta que la versión actual es un Preview, por lo que tampoco se debería poner nada crítico ahí sin respaldarlo.

En mi caso, quise empezar con la documentación del proyecto colaborativo, para poder trabajar sobre ella con el resto del equipo, y parece ser bastante útil. Lo dejamos de usar porque dio un problema y estuvimos a punto de perder todo lo que habíamos escrito (pensamos que lo habíamos perdido pero después se pudo recuperar...)

La pricipal contra que le veo, al menos por el momento, es que representa tener otra bandeja de entrada a la cual tengo que ir para ver si hay algo nuevo. Ya son demasiadas: mail personal y de trabajo, Facebook, Twitter, Google Reader, y ahora Wave... En algún momento debería surgir algo que permite tener una sola bandeja de entrada para todas estas cosas (¿Mozilla Raindrop?)

Como resumen, podría decir que es una tecnología que hay que tener en el radar. No creo que vaya a reemplazar a todas las demás formas de comunicación, pero van a haber casos en las que resulte la más adecuada.

martes, 27 de octubre de 2009

Automatic Pattern Generator, lanzamiento del proyecto colaborativo

En una nota anterior, comentaba una idea para presentar en los Collaborative Projects 2.0, de hacer un generador de patterns basado en código que ya existe en una base de conocimiento.

Por suerte en la nota había dicho que no lo iba a hacer... lo que demuestra una vez más que lo único constante es el cambio. Con Enrique queríamos presentar algo, y decidimos presentar este proyecto.

Desde ya damos la bienvenida a todos los que quieran sumarse al proyecto. Se necesitan desarrolladores, documentadores, testers, beta testers, etc. También se aceptan ideas y sugerencias.

El primer paso ahora va a ser definir el alcance y hacer una primera iteración, con una versión que genere un pattern a partir de una instancia compuesta por un único procedimiento, lo más sencillo posible. Cuando eso esté pronto, vamos a tener más claro el panorama y podremos repartir tareas entre los interesados.

En breve estaremos publicando el proyecto en el Wiki de la comunidad.

martes, 20 de octubre de 2009

Neptuno.net Open Source

Concepto acaba de hacer público el proyecto Neptuno.net, que consiste en una aplicación que permite ver en un árbol de llamadas los objetos que hacen commit, de forma de poder buscar problemas de integridad transaccional.

Hay una descripción un poco más amplia en esta otra nota del blog.

El proyecto está en Assembla, se puede obtener mediante SVN de http://code.assembla.com/neptuno_net.

Si alguien lo quiere probar, tiene que bajar el proyecto y hacer un Build. Yo lo tengo funcionando con Visual C# 2008 Express, con el .Net Framework 3.5.

La idea es colaborar con otro proyecto en el marco de los Collaborative Proyects 2.0, planteado por Edgar Jimenez Demestri y titulado "Analizador de UTLs". Espero que Neptuno.net sirva como punto de partida.

Quienes bajen el proyecto, tengan en cuenta que era un desarrollo interno, por lo que no se caracteriza por la prolijidad...

Si alguien le quiere hacer alguna mejora, será bienvenida. Por el momento el único que puede hacer commits en este proyecto soy yo, así que si alguien quiere colaborar me debería mandar el código modificado para que yo lo suba.

Actualización:  Me olvidé de decir que solo funciona con GeneXus9.0...

jueves, 8 de octubre de 2009

Automatic Pattern Generator, idea para los proyectos colaborativos

Motivación
Una de las cosas que veo que pasa bastante seguido, es que hacemos cosas que resultan repetitivas, pero no lo suficiente como para desarrollar un pattern que las haga más automáticas.

Por ejemplo, ahora estoy trabajando en una aplicación para transferir datos del sistema a la base de datos local de un PDA. Son varias cosas las que hay que transferir, y todos los programas son iguales:
  • una pantalla de selcción con filtros, paginado y un link en la grilla para agregar el elemento a una tabla intermedia que luego va al PDA
  • un web panel para ver los datos agregados
  • un web panel y un procedimiento para agregar los datos
  • un web panel y un procedimiento para borrar algún dato que se agregó.
Ahora lo estoy haciendo a mano, entro a cada uno de los 6 objetos de una de las "instancias", le doy Save as..., le pongo el nombre adecuado y le cambio las partes que son variables.

Es claramente un pattern. Pero entonces, ¿por que no desarrollo uno que se que me va a hacer la vida más fácil? Porque desarrollar un pattern nuevo es muy complicado. Porque el tiempo que me llevaría no justifica la inversión, porque haciéndolo a mano lo hago mucho más rápido para las 4 o 5 instancias que necesito ahora.

La idea
La idea sería entonces hacer una herramienta que tome varias instancias de un pattern (que todavía no existe, en realidad sería de un proyecto de pattern), saque factor común, y genere los XMLs, DKTs y demás cosas que se precisan para crear el pattern.

En el ejemplo anterior, tomaría las 2 o3 "instancias" que ya tengo hechas, cada una compuesta por 6 objetos, le diría a la herramienta como son las correspondencias (que objeto de cada instancia corresponde a que objeto de la otra, se podría hacer con expresiones regulares), y el programa dejaría fijas las cosas que son comunes y pondría como variables las cosas que están distintas.

No es trivial, pero pienso que se puede lograr algo bastante interesante.

El proyecto colaborativo
Como comentaba en otra nota, no tengo tiempo para liderar un proyecto, así que no lo voy a hacer. Si a alguien le interesa presentarlo, me anoto para definir el alcance, la arquitectura y colaborar en el desarrollo.

Entonces, lo que se necesitaría es:
  • Alguien que lidere el proyecto, debería definir el alcance (junto conmigo), las tareas a realizar y coordinar el equipo de desarrollo.
  • Uno o más desarrolladores, porque si bien yo podría participar, no voy a poder hacer todo el desarrollo.
  • Uno o más beta testers.
Si a alguien le interesa, le ve potencial, le parece que es factible, y quiere participar, que me avise. Así vemos si el proyecto es viable o no.

lunes, 5 de octubre de 2009

Tema por defecto en un modelo GeneXus 9.0


En un modelo de una KB GeneXus 9.0 (upgrade 4) quería cambiar el tema por defecto... Esto que parece trivial fue más complicado de lo que pensaba.

Lo primero que hice fue ir a las propiedades del modelo, pero ahí no hay nada.

En el modelo de diseño hay una propiedad con el tema, pero lo cambié y no me cambió el tema por defecto en el modelo de prototipo.

Después de darle varias vueltas sin encontrar nada, busqué con el KBQuery en las propiedades del modelo, y encontré que ahí sí aparecía...

Al final, encontré que la propiedad está en el archivo model.ini.

Debería ser más fácil de cambiar, tendría que estar en las propiedades del modelo.

martes, 29 de septiembre de 2009

Collaborative Projects 2.0


En el último encuentro GeneXus, se hizo el lanzamiento de los Collaborative Proyects 2.0.

La página en el Wiki de la comunidad es www.gxtechnical.com/cp, además en las últimas noticias GeneXus hay una entrevista a Armin que explica en que consiste, y por último también está la charla que se dio durante el encuentro.

Estaría bueno participar, pero lamentablemente no tengo mucho tiempo, así que descarto liderar un proyecto. Veré en cual de las propuestas me anoto. Por ahora hay unos pocos proyectos, esperemos que en breve hayan varios más para poder elegir.

Me gustaría participar en alguno que se dedique a extender de alguna forma GeneXus Server, para probar esta nueva tecnología...

sábado, 19 de septiembre de 2009

Comprar un iPhone en Uruguay, ¿puede ser tan complicado?


En Uruguay, en general, estamos bastante atrasados respecto al mundo civilizado en lo que tiene que ver con la tecnología. Las cosas siempre llegan tarde y son mucho más caras.

Con el iPhone, pasa exáctamente lo mismo...

Acá el iPhone lo traen dos compañías: Claro y Movistar.

Lo de Claro es una vergüenza... El plan de $1.000 por mes (unos 45 dólares americanos), tiene 200MB de navegación por mes. ¿Quién compra un iPhone para usarlo solo como teléfono? ¿A quién le alcanzan 200MB si lo va a usar para conectarse a internet?

El plan de Movistar está un poco mejor. El de $760 por mes (unos 35 dólares americanos), tiene 500MB de navegación. No es una maravilla, pero supongo que para usarlo desde el teléfono debería alcanzar. Si alguien lo quiere para usarlo de modem y conectarse desde el PC, seguramente se quede corto.

Entonces me decidí, y lo fuí a comprar... Pregunté en dos tiendas de Movistar hace unos 20 días, en ninguna de las dos sabían nada, no tenían ni el precio de los planes. En ese momento pregunté también por teléfono a Movistar, y me dijeron que tenía que preguntar directamente en las tiendas.

Ahora esta semana volví a preguntar, ahora en la casa central de 18 y Andes, y dice que ya está agotado.

Mi duda es si efectivamente lo quieren vender...

La otra alternativa es comprarlo sin contrato, desbloquearlo y usarlo con Ancel, pero el precio del aparato se va a más de 1.000 dólares comprándolo acá. Se de gente que lo ha traído de Estados Unidos por menos de 400...

¿Puede ser tan complicado conseguirlo?

miércoles, 16 de septiembre de 2009

XIX Encuentro Internacional GeneXus, mañana del día 3

¿Qué podríamos ver en GeneXus?

Se hablaron de varios temas que están investigando en Artech para incorporar a GeneXus, entre ellos:

  • Aplicaciones Multy-tenant, sería solo cambiar una propiedad en el modelo y GeneXus se encargaría de agregar el TenentId en todas las tablas que lo necesiten, y filtro en todos los programas que lo requieran.
  • Herencia, ahora ya se puede resolver con subtipos, pero están pensando en algo más declarativo.
  • Dominios extendidos, que pueda tomar los valores "estáticos" del dominio enumerado pero además pueda tomar valores dinámicos de una tabla.
  • Implicit data selectors, es algo que habían hablado de agregarlo a la X pero al final no entró, permite definir un data selector que se usa siempre que se recorre la tabla correspondiente, a menos que explicitamente se diga que no se quiere usar, por ejemplo, para recorrer siempre los clientes activos.
  • Transaction inicialization, permitiría cargar los datos de una transacción mediante un mapeo definido a priori, por ejemplo para inicializar la factura a partir de la orden de compra.
Evolución del lengiuaje GeneXus
Se presentaron también algunas líneas que están trabajando, para tener más semántica en la KB y lograr lenguajes más declarativos:
  • Dominios: los dominios van a poder tener una UI, una especificación de lo que se debe hacer en la reorganización y comportamiento. Por ejemplo, el dominio TimePeriod, se representaría gráficamente como dos campos date, en la reorganización debería crear dos campos (inicio y fin del período) en vez de uno, y podría tener una función que diga si una fecha está comprendida en el período.
  • Módulos: los objetos van a pertenecer a un módulo como públicos o privados (mencionaron una tercer opción pero no dijeron cual... ¿internal?), de un módulo a otro solo se van a poder usar los objetos públicos, y se van a poder importar bases de conocimiento como si fueran módulos.
  • User interface, hacerla más declarativa, por ejemplo diciendo que tipo de pantalla es (trabajar con, master-detail, etc.)
Además Gastón mostró una foto de este blog, de la nota que hablaba del pasaje de parámetros en GeneXus. :)

Futuro de las aplicaciones RIA con GeneXus
Se habló de AJAX y como GeneXus genera código utilizando esta tecnología, y se comentó que de momento no tienen pensado trabajar en generadores Silverlight o Flex, ya que con AJAX se tienen las mismas características.
Además se contó como implementaron el generador Ruby, que hicieron un generador de HTML separado del generador del lenguaje, lo que les permitiría generar código para otras plataformas como ser iPhone o Android. Están investigando fuertemente este tema y posiblemente haya algún generador móvil en el futuro.
REST web services
La primer parte de la charla fue una explicación de que es REST, que fue un poco pesada.
Después se comentó como piensan generar web services REST en GeneXus, que básicamente consiste en exponer business components y data providers como web services REST.
En principio no me queda demasiado clara la necesidad, se podría usar para exponer datos para usar en algún mashup. En todo caso si alguien lo necesita aparentemente va a ser muy simple de usar.

martes, 15 de septiembre de 2009

XIX Encuentro Internacional GeneXus, días 1 y 2

Y se vino el encuentro GeneXus...

Estoy tratando de hacer un seguimiento más o menos en vivo en twitter, pero no da para escribir mucho, así que acá van los comentarios de las charlas que he ido.

Estado del arte de MDD (Model Driven Development)

No me convenció demasiado la charla, esperaba algo más concreto, me resultó demasiado teórica y poco aplicable.

En realidad como GeneXus ya aplica varios de los conceptos de MDD, no parece algo que nos cambie demasiado el paradigma de desarrollo.

GeneXus en el desarrollo, GXTest en el testing

Fue una charla donde se explicaron algunos conceptos y se hizo una demo de GXTest.

La herramienta en general es muy buena, tuve la oportunidad de hacer algo de beta test de la misma, y es altamente recomendable.

La sala estaba llena con gente parada en el fondo, lo que demuestra que el testing en general y GXTest en particular han logrado llamar la atención.

Compartiendo fuentes de datos: Data Providers

Se mostraron algunos casos de uso para los Data Providers y como pretenden sustituir a los Procedures en las áreas donde son utilizables.

Lo más interesante es que en la Evolution 1 agregaron un Data Provider Generator que puede generar el Data Provider para inicializar datos de una o varias tablas, tomando los datos de Freebase.com.

Keynote de Nicolás Jodal

La charla "deportiva" de Jodal estuvo buena, creo que vale la pena verla.

Extendiendo GeneXus con Programación Orientada a Aspectos (AOP)


Se presentaron los conceptos de AOP. El tema es interesante, y la principal ventaja parece ser que permite separar distintos aspectos de la programación del código de la aplicación, como ser temas de seguridad, auditoria, etc.

La solución mostrada parece ser un poco compleja para quienes programan en GeneXus, ya que los "aspectos" hay que programarlos (o declararlos) usando un lenguaje con una sintaxis propia

Sería muy bueno poder definir estos aspectos desde GeneXus, eso le daría mucha potencia y sin duda lograría mucha más adopción.

Además de mencionó el producto Certus, que aplica estos conceptos.

Creando User Controls con GWT y GeneXus X Ev1

El tema es interesante, pero la charla no me dejó mucho...

Se presentaron algunos conceptos teóricos y después se mostró algo de código y un ejemplo de un User Control en GeneXus, pero me parece que le faltó un enfoque un poco más práctico.

GeneXus X: ¡Rich Internet Applications Ya!

Estuvo interesante, se mostró una aplicación RIA hecha con GX: un lector de RSS.

Además se presentaron varios conceptos de como encarar el desarrollo de aplicaciones RIA, que pueden resultar útiles.

La conclusión es que con GeneXus se pueden hacer aplicaciones muy interactivas usando User Controls, como por ejemplo GeneXus Server.

Como lograr discusiones de calidad

Creo que esta charla vale la pena verla. No tiene nada que ver con GeneXus pero las ideas comentadas fueron muy interesantes.

Un motor de reglas de negocio dinámicas inserto en el ecosistema GeneXus

La gente de Artech está trabajando en dar la posibilidad de definir reglas dinámicas, que pueden ser modificadas sin cambiar los programas y son evaluadas en tiempo de ejecución.

El lenguaje para definir las reglas aparentemente sería definible en la KB, con lo que el usuario final (el experto del dominio) usaría un lenguaje muy parecido al lenguaje natural.


Por lo que mostraron el tema está todavía muy verde, pero parece ir bien encaminado. Ya veremos a donde llega.

Tracing, profiling, debugging... recursos útiles para la salud de una aplicación

Esperaba otra cosa, pensé que a lo mejor hacían algún anuncio, pero no, la charla fue un repaso de las distintas técnicas para analizar los distintos errores que se pueden presentar en la aplicación, con un enfoque sobre todo hacia .Net.

Además de técnicas se mostraron algunas herramientas, unas integradas a GeneXus (como el trace o el debugger) y otras externas.

Lo más interesante me resultó el profiler que tiene incorporado la versión Evolution 1, que permite medir los tiempos de ejecución de cada objeto GeneXus y dentro de cada objeto, los tiempos de cada sentencia.

Extender GeneXus programando en GeneXus

Básicamente se presentó GX4GX, que es un conjunto de objetos externos que permiten acceder a la KB programando directamente en GeneXus. Es la tecnología con la que desarrollaron GeneXus Server.

Además se mostró como será la forma de extender GeneXus Server.

Muy interesante, habrá que probarlo...

Collaborative proyects 2.0

Se hizo el lanzamiento de la versión 2 de los collaborative projects.

Además se presentaron algunas tecnologías que se pueden usar para trabajar en grupos dispersos geográficamente, con especial énfasis en Second Life. Se ve que todavía no entiendo muy bien cual es la ventaja de Second Life...

jueves, 27 de agosto de 2009

Escuchar música en Internet

En Internet hay unos cuantos sitios que permiten escuchar música on-line. Últimamente he usado unos cuantos de estos servicios, así que dejo acá una reseña de cada uno.

Pandora
Pandora fue el primer servicio que usé, pero lamentablemente ahora no está disponible en Uruguay, así que hace tiempo que no lo uso.

Uno podía elegir una canción o un artista, y reproducía música similar a la seleccionada. La coincidencia en su momento era muy buena, capaz que ahora lo comparo con los demás y no me parece nada espectacular.

FineTune
FineTune es un sitio que permite crear listas de reproducción eligiendo para cada una las canciones que quiero. Tiene dos restricciones: 1) las listas deben tener al menos 45 canciones, y 2) no pueden haber más de tres canciones de un determinado artista en la lista.

Este servicio todavía lo sigo usando, tiene la ventaja que hay una aplicación de escritorio, con lo que no es necesario tener el navegador abierto en este sitio.

Tiene una especie de recomendación, aunque siempre me pareció bastante malo, por la música que selecciona. La forma de obtener recomendaciones es crear una lista de menos de 45 temas, y pedirle que los complete.

Deezer
Deezer tiene la ventaja que con respecto a los dos anteriores, que se pueden elegir las canciones a escuchar sin ningún tipo de restricción, salvo la evidente de que la canción esté disponible.

Lo usé bastante poco porque me pasó varias veces seguidas que no encontré lo que estaba buscando, así que lo dejé de usar.

Last.fm

Last.fm es un buen servicio enfocado más que nada a la parte social de escuchar música. Lo usé un tiempo, pero tenía algunas restricciones en la versión grátis, y como en realidad FineTune era una buena alternativa, no lo seguí usando.

YouTube
Técnicamente YouTube no es para escuchar música, pero la realidad es que tiene mucha variedad, aunque para algunas cosas tiene restricciones de acceso.

En realidad la mayor contra que tiene es que consume más ancho de banda que los demás servicios porque también muestra el video, pero puede ser una buena opción si se busca una canción determinada.

Grooveshark
Grooveshark hace poco que lo estoy usando, unas dos semanas, pero es el mejor servicio que he encontrado hasta ahora.

Permite escuchar la música que quiera, en el orden que quiera, sin ningún tipo de restricción.

Además tiene una funcionalidad de recomendación de música que es muy buena, al menos en los casos que he probado.

No se cual es el negocio ni cuanto va a durar, pero por ahora, funciona muy bien.

Conclusión
Sin duda que hay muchas opciones para quienes quieren escuchar música en Internet, y seguramente van a haber muchas más y cada vez con menos restricciones.

Cada uno de los servicios mensionados tiene sus particularidades, algunos tienen cosas mejores que otros, pero todos son buenas opciones.

¿Alguien escucha música en Internet? ¿Qué servicio usan?

miércoles, 5 de agosto de 2009

Pasaje de parámetros entre objetos GeneXus

Acá dejo dos sugerencias con respecto al pasaje de parámetros entre objetos GeneXus:
  • parámetros opcionales
  • parámetros nominados
Parámetros opcionales

Muchas veces pasa que se agregan parámetros a un objeto GeneXus, porque se precisa pasarlos desde uno de los llamadores, pero no queremos que el resto de los programas llamadores cambien.

Lo que hacemos hoy es modificar todos los llamadores, agregando un nuevo parámetro con un valor que sería el valor por defecto.

Sería bueno tener la posibilidad de definir que un parámetro es opcional e indicarle cual es el valor por defecto. La definicón podría ser algo así:
parm(in:&par1, in:&par2=0, out:&result);
En este ejemplo el parámetro &par2 sería opcional, y si no se especifica el valor que se usaría en el objeto sería cero, que es el valor que se le da por defecto.

La invocación podría ser así, si se quiere usar el valor por defecto:
&result = Programa.udp(1)
o así, si se quiere especificar otro valor:
&result = Programa.udp(1, 2)
Parámetros nominados

Otra característica que tienen los parámetros en los objetos GeneXus  es que son posicionales.

Como está hoy no hay problema, pero si se permitiera tener parámetros opcionales, se podría plantear el problema que quiero pasarle solo uno de los N parámetros opcionales, lo que no se podría hacer a menos que justo le quiera pasar el primero de la lista.

Algo así:
parm(in:&par1=0, in:&par2=0, in:&par3=0);
¿Cómo hago para pasarle un valor distinto de cero solo a la variable &par2?

La solución podría ser indicarle el nombre del parámetro en la invocación. La sintaxis puede variar...
Programa.call(@&par2=1)
La @ es para indicarle que es el nombre del parámetro y no una variable en el contexto del programa llamador...

jueves, 23 de julio de 2009

Mensajes y formato de strings

Ahora que descubrí la función Format() en GeneXus y que la empecé a usar... creo que se le podría hacer una mejora.

La mayoría de las veces, cuando armamos un string, lo queremos para mostrar un mensaje. Muchas veces es para pasárselo a la función msg() o a la función error().

Algo así:
&mensaje = Format('El pedido número %1 fue confirmado', PedidoId.ToString())
msg(&mensaje)
o simplemente
msg( Format('El pedido número %1 fue confirmado', PedidoId.ToString()) )
Sería más práctico e intuitivo, que las funciones msg() y error() recibieran una cantidad variable de parámetros y se comportaran como la función Format().

El código quedaría entonces más simple:
msg( 'El pedido número %1 fue confirmado', PedidoId.ToString() )

lunes, 13 de julio de 2009

Mejoras al lenguaje en C# 3.0 y 4.0

Antes de empezar, conviene aclarar que no me considero un experto en C# ni mucho menos, pero sí tengo algo de experiencia con el lenguaje. De hecho podría decir que C# es mi segundo lenguaje después de GeneXus...

El uso que le he dado principalmente ha sido para desarrollar extensiones de GeneXus o aplicaciones que usan GXPublic. Alguna vez hice algo en ASP.Net pero nada demasiado sofisticado.

El tema es que para el uso que le doy habitualmente, me alcanza con la funcionalidad que tiene Visual Studio 2005, que funciona con C# 2.0, y por lo tanto me he estado perdiendo de las nuevas funcionalidades en C# 3.0 (VS2008) y 4.0 (VS2010, todavía en beta).

Son varias las cosas nuevas en C# 3.0 (LINQ, object initializers, anonymous types, etc.), el artículo de Wikipedia sobre C# explica bastante bien que es cada una de estas cosas.

Hay otras dos funcionalidades nuevas que me gustaron mucho cuando las leí en este artículo de Jomo Fisher (del año 2005, estoy un tanto atrasado): lambda expresions y extension methods. Vale la pena leerlo.

Lo de las expresiones lambda (si reconocen el nombre es porque lo vieron en algún curso de programación funcional) viene como a confirmar lo que decía Paul Graham en Hackers and Painters: que los lenguajes de programación tienden a ir incorporando funcionalidades de LISP...

La otra reflexión es que parece que ahora en C# se podría implementar el algoritmo MapReduce de Google, como lo explica Joel Spolsky en su blog. También vale la pena leerlo.

En C# 4.0 que por lo que se todavía está en beta, agregan soporte para tipos de datos dinámicos, para poder utilizar código generado a partir de lenguajes con tipado dinámico (como ser F# o IronPython). Básicamente el tipo dynamic lo que hace es posponer la resolución de tipos al momento de ejecución.

Otra cosa que está buena son los parámetros opcionales y parámetros por nombre (named parameters, cada uno lo traduce lo mejor que puede...), que permite asignar valores por defecto a algunos de los parámetros que luego no son necesarios en la invocación, y permite pasar los parámetros en cualquier orden siempre que se indique cual es cual por su nombre.

En fin... mucha cosa interesante, hay que tratar de mantenerse actualizado.

martes, 7 de julio de 2009

Global.asax

El problema
Estamos migrando un sitio que estaba generado en .Net en un Windows Server, a uno nuevo generado en Java en un Linux.

El tema es que con el cambio, las URLs cambian, pasan de ser de tipo
http://host/sitio/pagina.aspx?parametros
a ser de tipo
http://host:puerto/sitio/servlet/pagina?parametros
 Entonces, como hacer la migración de forma razonable, sin que haya problemas con los links que llegan al sitio.

Posibles soluciones
Habían varias posibles soluciones:
  • sacar el sitio viejo y en su lugar poner una página de error 404 (not found) con un link al sitio nuevo
  • poner que el IIS haga un redirect al sitio nuevo, pero ahí no se si funciona cuando se accede a una URL que no es la página por defecto
La solución final
En APS.NET existe un archivo de nombre Global.asax, que define algunos métodos que se ejecutan en distintos momentos, como por ejemplo cuando se levanta el sitio, cuando llega un request de una página, cuando se termina de procesar un request, etc.

En particular el evento que me interesa en este caso es el que se dispara cuando se hace un request a una página, ya que ahí puedo hacer el redireccionamiento con inteligencia, mandando al usuario a la página que quería ir con los parámetros que le pasó, pero en el otro sitio.

El archivo Global.asax quedó algo así (*):
<%@ language="C#" %>
<script runat="server">
void Application_BeginRequest(Object sender, EventArgs e)
{
    string request = Request.Url.PathAndQuery;
    int pos = request.LastIndexOf('/');
    request = request.Substring(pos+1);
    request = request.Replace(".aspx", "");
   
    string url = @"http://host:8080/sitio/servlet/" + request;
   
    Response.Redirect(url);
}
</script>

(*) En realidad es un poco más complicada la solución final ya que el host es distinto según se esté dentro de la intranet o fuera, pero eso no viene al caso...

martes, 30 de junio de 2009

Valor "Empty" para atributos con dominio en GeneXus

Supongamos que tengo un dominio ESTADO, definido como Char(3), que puede tener valores {'ING', 'ABI', 'CER'} (ingresado, abierto, cerrado).

Si fuera una KB nueva posiblemente usaría un dominio enumerado con {ingresado=0, abierto=1, cerrado=2}. Pero no es el caso, y además no siempre es posible elegir los valores que va a tener un dominio, puede depender de otra aplicación o ser una base de datos que ya tiene valores.

El problema que tengo, es que si defino una variable o un atributo basados en ese dominio, el valor "empty" (como en IsEmpty() o en SetEmpty()) es '', que no es un valor válido para el dominio.

Estaría bueno poder definir cual es el valor "empty" de un dominio... Este valor además sería el "initial value" por defecto para los campos nuevos basados en dicho dominio, y sería el valor con el que se graban los registros nuevos cuando no se referencia el atributo (y se tiene la propiedad "initialize not referenced attributes" en "yes").

lunes, 29 de junio de 2009

Tecnología de votación

En el día de ayer, en Uruguay tuvimos elecciones internas, donde cada partido político decide cual será el candidato a presidente en las próximas elecciones de octubre, así como la representación de cada sector dentro de cada partido.

En estas elecciones había 17 candidatos a la presidencia en 8 partidos, y se presentaron unas 2.500 listas. Listas de papel, de las cuales la mayoría terminan en la basura. De algunas dicen que se imprimieron 2 millones...

La votación se hace por circuito electoral, según el número de credencial de la persona. Creo que habían unos 6.000 circuitos habilitados para estas elecciones. Cada circuito tiene tres personas que integran la mesa, más un policía de custodia.

La votación se realiza entre las 8:00 y las 19:30, y una vez terminada se abre la urna, se cuentan los votos, y se llevan al lugar designado por la Corte Electoral (en Montevideo el Estadio Centenario).

Esa es una explicación bastante resumida de como funcionan las elecciones, a lo que quiero llegar, es que me resulta demasiado complejo, demasiado burocrático. La maquinaria que es necesario movilizar para hacer una elección es demasiado pesada.

Hoy en día, con la tecnología que tenemos, ¿no se podría hacer de forma mucho más simple? Capaz que lo que sigue puede resultar disparatado para algunos, pero yo no lo veo tan difícil de implementar.

Una opción sería hacer la votación por SMS... Sí, por SMS. ¿Por qué no? Que cada uno registre un número de celular ante la Corte Electoral, y que vote desde ese número. Para que el voto sea secreto, al momento que llega el mensaje a la corte se debería separar la persona que lo envía (que tiene que quedar registro que votó para que no vote dos veces) del voto en sí. (*)

Otra opción sería tener terminales de votación en lugares de fácil acceso. Se me ocurre farmacias, locales de cobranza (Abitab, Red Pagos, etc.) o cajeros automáticos, que seguro hay en todas las ciudades del país. Habría que complementarlo con mesas de votación en las zonas rurales. La votación no sería un domingo como es ahora, sino que podría ser un día entre semana (o varios días) en el horario que están abiertos habitualmente estos locales. La Corte Electoral tendría que cambiar todas las credenciales por algo que tuviera una banda magnética o un chip con la información del votante.

Puede haber otras opciones...

Me parece que cualquier cosa que agilice el proceso de votación sería bueno. Gracias a que se evitaría toda la complejidad de la infraestructura de votación, se podría hacer algo mucho más dinámico. Se podrían hacer consultas a la ciudadanía sobre ciertos temas, con bastante frecuencia sin que eso genere gastos adicionales. Pasaríamos a tener un modelo de democracia mucho más directa.

(*) Calculo que no sería algo así como "voto pepe", "voto qki" o "voto pedro", sería algo más formal...

jueves, 25 de junio de 2009

Objetos que devuelven más de un valor en GeneXus

En GeneXus no tenemos el concepto de función como tenemos en Java o en C#, donde tiene que haber un tipo de datos que es el que devuelve, como en:
private int foo() { return 1; }
Por el contrario, en GeneXus los parámetros de un objeto pueden ser de entrada, salida o entrada/salida, en cualquier cantidad y orden. (*)

Por ejemplo, podría tener una función que dado un producto me devuelve el saldo en cantidad y en importe, de dicho producto en el depósito. (**)

La regla parm sería por ejemplo:
parm(in:ProductoId, out:&SaldoCantidad, out:&SaldoImporte);
Pero entonces, ¿cómo invoco ese programa?. Hay varias opciones, puede ser con call, o incluso con udp...
call(PGetSaldoProducto, ProductoId, &SaldoCantidad, &SaldoImporte)
o
&SaldoImporte = udp(PGetSaldoProducto, ProductoId, &SaldoCantidad)
En una nota hace un tiempo, hablando sobre la legibilidad del código, comentaba sobre la ventaja de usar udp en vez de call... Pero en este caso las dos opciones son malas.

Creo que sería bueno tener una sintaxis como tiene por ejemplo Python para asignar listas de valores... En Python una lista separada por comas es una tupla, que se puede devolver en una función o asignar. Por ejemplo:
# defino la funcion
def foo():
    a = 1
    b = 2
    c = 3
    return a,b,c

# la invoco
d, e, f = foo()   # resultado: d=1, e=2, f=3
En GeneXus, si tuvieramos la posibilidad de usar esta notación, podríamos escribir:
&SaldoImporte, &SaldoCantidad = udp(PGetSaldoProducto, ProductoId)
lo que deja bien claro que la intención de la invocación es cargar el valor de las dos variables de la izquierda...

---------------------------------------
(*) Si bien los parámetros pueden tener cualquier orden, creo que es altamente recomendable dejar los parámetros de salida al final.

(**) Los motivos para tener una función que devuelve más de un valor pueden ser muchos y muy variados. En este caso también se podrían hacer dos funciones, con lógica muy parecida, pero que devolviera una la cantidad y otra el importe. La ventaja de tenerlo así es que se optimiza la performance, porque hay que hacer la recorrida en la base de datos una sola vez.

martes, 23 de junio de 2009

Formato de strings: función Format vs concatenación

Algo que hago con bastante frecuencia, es armar textos que se componen de una parte fija y otra que toma valores de variables o atributos. Por ejemplo, cuando se quiere mostrar un mensaje.

En GeneXus hay por lo menos dos opciones para generar estos textos:
  1. usando la concatenación de strings con el operador +
  2. usando la función Format, que creo que se agregó en GeneXus 9.0
  3. hay una tercer forma que descarto de entrada, que es con la función Concat...
Pero entonces, ¿cuál es la mejor opción?

Con respecto a la legibilidad del código, creo que ambas opciones son buenas, puede haber algún caso que una de las dos quede mejor que la otra.

La ventaja que tiene la función Format es cuando tenemos que traducir la aplicación usando el objeto Language, porque queda todo el texto en un solo item del objeto.

Por ejemplo, el texto "El pedido número NNN fue confirmado", usando la concatenacion de strings queda
&mensaje = 'El pedido número ' + PedidoId.ToString() + ' fue confirmado'
con lo que al traducirlo tenemos que traducir los dos textos por separado:  'El pedido número ' y ' fue confirmado'...

Si usamos la función Format, nos queda
&mensaje = Format('El pedido número %1 fue confirmado', PedidoId.ToString())
con lo cual tenemos un solo literal.

Puede haber algún caso donde tal vez no se pueda usar la función Format, por ejemplo en una regla error() en una transacción, pero en todos casos donde se pueda, creo que conviene usar la fución Format...

viernes, 12 de junio de 2009

When duplicate y campos con índice unique

Si en GeneXus (9.0) se tiene una tabla con un índice unique y se hace un for each que actualiza el campo del índice, al especificar da un warning que dice:
spc0070: No When duplicate code found to handle possible duplicate condition when updating [Atributo]
La documentación del comando for each en el Wiki, dice lo siguiente con respecto al when duplicate:
When duplicate: This clause only makes sense in procedures (because it has to do with updates); it is analyzed below. This clause will be executed if, within the body of the For Each (code1), you try to update an attribute that is a candidate key (it has a unique index) and a record with that value already exists. GeneXus uses the unique index to ensure the uniqueness of that candidate key and in case it finds duplicates, if this clause is programmed in the For Each command, it will execute its code: code2. If the clause is not included, and you try to update an attribute that is a candidate key and a record with that value already exists, no code will be executed.
El problema con esto, es que en un mismo for each puedo estar actualizando más de un campo que tenga índice unique, con lo cual no se cual es el campo donde dio el error.

El código para manejar este error, entonces debería primero hacer otro for each filtrando por cada uno de los campos con índice unique para ver cual es el que falló, y luego hacer nuevamente el update de todos los demás campos. La lógica puede quedar bastante complicada...

Una alternativa a esto que se me ocurre, es que el when duplicate pueda tener una lista de atributos que componen un índice unique, y que cuando se trata de grabar una tupla y da clave duplicada, vaya al when duplicate que corresponda.

Es más, GeneXus podría ser más inteligente, y que cada when duplicate sea un manejador de errores, que se llame para cambiar los valores de los atributos involucrados en ese when duplicate antes de hacer el update...

Capaz que la idea no quedó muy clara, voy a poner un ejemplo...

Tengo una tabla con campos:
(A*
 B
 C
 D)
que tiene índices unique por {B} y {C,D}.

Podría tener el siguiente comando for each:
for each
    where A = &A

    B = &B
    C = &C
    D = &D
when duplicate B
    B += 1
when duplicate C, D
    C = &D
    D = &C
endfor
¿Qué haría este código? Intenta hacer el update con valores [&B, &C, &D]. Si no puede porque B está repetido, entonces va al when duplicate B, calcula el nuevo valor de B, e intenta hacer el update con [&B+1, &C, &D]. Así hasta que no falle más por B... Si además falla porque los campos C, D están repetidos, entonces va al when duplicate C, D, e intenta hacer el update con [&B, &D, &C].

Hoy no hay una forma medianamente elegante de hacer esto. Porque en el when duplicate primero tengo que identificar que campo fue el que dio el error, y después volver a hacer el nuevo update con los nuevos valores, por lo que quedaría una especie de actualización recursiva.

miércoles, 3 de junio de 2009

No hay peor comentario que el comentario que está equivocado

¿Qué tiene mal este código?
for each // Me fijo cantidad de la entrada
where MstId = &MstId2
    if MstTpo = 'R'
        &MstCntR = MstCnt
    else
        &MstCntS = MstCnt
    endif
endfor
Para el que lo ve así, a simple vista, no tiene nada mal. Los que leyeron el título de la nota pueden tener alguna pista.

¡Lo que está mal es el comentario! Porque &MstId2 no es una ENTRADA, es una SALIDA. Claro que el que no conoce el contexto no tiene forma de saberlo, y ahí está el peligro.

Yo estoy a favor de poner comentarios que expliquen lo que hace el programa, pero los comentarios tienen que estar bien, si no, es peor tener comentarios que no tenerlos.

Porque alguien podría leer el for each y quedarse con la idea que toma la cantidad de la entrada, cuando en realidad se queda con la de la salida.

En conclusión, más vale no tener comentarios que tener comentarios equivocados...

martes, 2 de junio de 2009

GeneXus Server

Ayer Gustavo Carriquiry publicó en su blog algunas fotos de pantalla del nuevo GeneXus Server.

Hoy ya está on-line para probarlo en http://gxserver.genexusx.com/genexusserver.

La verdad que está muy bueno. Se puede navegar por la KB (aunque por ahora no se puede editar) y ver los objetos y sus propiedades.

No se si está basado en el Citrus Proyect, pero parecería como que sí.

Es bueno ver como una idea que había propuesto en el 2006 en este blog parece ir tomando forma :)

Actualización (3/5/09 8:54): Gastón Milano publicó una nota en su blog contando que la interfaz Web para GX Server la implementaron con GeneXus. ¡Espectacular!

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.

jueves, 30 de abril de 2009

¿Qué se dice de GeneXus en Twitter?

Ayer Armin escribió un artículo contando como usa Twitter para enterarse de las cosas que se dicen de GeneXus.

Pero entonces, ¿qué se dice de GeneXus en Twitter?

Se puede buscar el término "genexus" en Twitter Search, que además permite suscribirse a los resultados por RSS (ya lo hice), con lo cual es fácil monitorear lo que se está diciendo. La técnica sirve para cualquier otra búsqueda...

Los "twiteos" (gorjeos?) de la última semana, sacando los de los usuarios @genexus y @gxnews_:
horaciosoca: GeneXus (genexus.com) comunica novedades & soporte de productos en Twitter (un buen "enfoque" del asunto) http://tr.im/k4TW
about 6 hours ago
apanizza: Armin is tweeting gx news: @arminbachmann http://bit.ly/5p7u6 (expand), also check @genexus for news going into the XIX user meeting !
about 11 hours ago
arminbachmann: @arielmilani ... pq no trabajas con GeneXus X? es muuuucho mejor. hay una trial de la X con menos limites que la 9.
about 23 hours ago
jean_dreyer: Estudando GENEXUS!
1 day ago
asantibanez: dolor de cabeza con Genexus.. queriendo ir a casa..
1 day ago
arminbachmann: @arielmilani No entiendes algo de @GeneXus? puedo ayudarte?
1 day ago
arielmilani: Genexus... i hate you #caralhofilhadaputa
2 days ago
calcetin_huacho: yap, genexus time.
2 days ago
pedrogk: congreso de Genexus del 6 de mayo en Ciudad de México se pospone hasta nuevo aviso
2 days ago
ealmeida: Malhumorado, porque no logro un night build que funcione en la GeneXus X Ev1 (beta) y queria probar a fondo las K2bTools
3 days ago
apanizza: Late in a friday at the genexus office: http://bit.ly/o4wp9 (expand)
5 days ago
gxsoft: DBF+CDX to SQL Finished, ready to DBRet 1.2 (GeneXus Tool)
5 days ago
ealmeida: Jugando con MSBuilds Task y GeneXus X.
7 days ago

martes, 28 de abril de 2009

Montevideobus.com

Me acabo de enterar que existe el sitio Montevideobus.com que usa Google Maps para trazar el recorrido de los ómnibus de Montevideo entre dos puntos seleccionados.



Realmente está muy bueno, y por las pruebas que hice, me resultó mucho más usable y ágil que la Guía Digital de Montevideo, que casi nunca funciona.

Además permite ver el recorrido completo de las líneas de ómnibus.

¡Felicitaciones a la gente de Montevideobus.com!

martes, 21 de abril de 2009

Hackers and Painters

Estuve leyendo el libro Hackers and Painters de Paul Graham, que tiene varias cosas interesantes.

El libro es básicamente un conjunto de ensayos que no tienen demasiada conexión entre sí, que tratan mayoritariamente de temas relacionados al desarrollo de software.

Dejo los links de los ensayos que me resultaron más interesantes, en el orden que aparecen en el libro, por si alguien los quiere leer:
En Beating the averages, comenta sobre los lenguajes de programación y como hay lenguajes más avanzados que otros. También comenta que para alguien acostumbrado a un determinado lenguaje, es fácil ver cuales son los lenguajes menos potentes, pero que es muy difícil distinguir cuales son los lenguajes más avanzados, porque las funcionalidades que lo hacen más avanzado resultan desconocidas.

En Revenge of the nerds, dice:
We know that Java must be pretty good, because it is the cool, new programming language. Or is it? If you look at the world of programming languages from a distance, it looks like Java is the latest thing. (From far enough away, all you can see is the large, flashing billboard paid for by Sun.) But if you look at this world up close, you find that there are degrees of coolness. Within the hacker subculture, there is another language called Perl that is considered a lot cooler than Java. Slashdot, for example, is generated by Perl. I don't think you would find those guys using Java Server Pages. But there is another, newer language, called Python, whose users tend to look down on Perl, and more waiting in the wings.

If you look at these languages in order, Java, Perl, Python, you notice an interesting pattern. At least, you notice this pattern if you are a Lisp hacker. Each one is progressively more like Lisp. Python copies even features that many Lisp hackers consider to be mistakes. You could translate simple Lisp programs into Python line for line. It's 2002, and programming languages have almost caught up with 1958.
En el libro (no en el ensayo que está en internet de donde copié el texto) menciona también a Ruby como el siguiente paso entre Python y Lisp.

Entonces... ¿Lisp? ¿En serio? ¿No era un lenguaje funcional? ¿Alguien usa Lisp para hacer cosas "en serio"? Parece que sí.

En la facultad hice un curso de introducción a la programación funcional, que trabajábamos con Haskel. Como cultura general me pareció interesante, pero no parecía algo demasiado práctico...

Así que habrá que ver un poco que es Lisp y para que sirve. Si alguien tiene lectura para recomendar, se agradece. A Perl, Python y Ruby también les quisiera entrar, tendría que tener días más largos...

lunes, 20 de abril de 2009

GXPublic Applets

Si bien es cierto que con GeneXus X deja de existir, para quienes seguimos trabajando con GeneXus 9.0 GXpublic sigue siendo una herramienta muy valiosa.

A lo largo de los años, han ido surgiendo necesidades que son difíciles o imposibles de resolver usando solamente GeneXus, por lo que hemos ido desarrollando pequeñas (por eso lo de applets del título) aplicaciones que usan GXPublic y que resultan de utilidad en el desarrollo.

Algunas de estas aplicaciones son públicas y se pueden obtener de GXOpen, otras no, son desarrollos internos que nunca vieron la luz. Algunas se podrían llegar a necesitar también en GeneXus X, otras ya están integradas, no tienen sentido o hay una alternativa que ya existe.

A continuación detallo las que más uso...

KBQuery

KBQuery en una aplicación que permite ejecutar consultas SQL sobre una KB GeneXus.

Ya había escrito sobre esta herramienta acá, así que no voy a decir mucho más, salvo que me resulta sumamente útil.

GXLGenerator

En el ciclo de desarrollo que tenemos en Concepto, todos los cambios de programación que se hacen quedan asociados a una solicitud, y a su vez a una solicitud se le adjunta un GXL con los objetos modificados.

El nombre de la aplicación dice casi todo, lo que hace es generar un texto con formato GXL a partir de una lista de nombres de objetos y su tipo. Además chequea que el objeto exista en la KB, para que no haya posibilidad de que quede un objeto que no existe.


KVCVSP - Control de versiones (sin pretensiones)

Esta aplicación es parte de las KBTools. Tiene una interfaz gráfica, pero para KBs grandes no resulta práctica, porque demora mucho.

Lo que hace esta aplicación es distribuir en la noche (mediante un proceso batch agendado) todos los objetos modificados desde la última distribución, dejando el XML en un directorio determinado.

Cada archivo generado tiene la forma tipo_nombre_fecha.xml, por ejemplo: PRC_Prueba_200904201534.xml.

De esta forma, queda toda la historia de cambios de todos los objetos. Usando el comparador de distributes que viene con GeneXus 9.0, se puede comparar de forma muy fácil la versión actual de un objeto con una versión anterior.

Claro que para GeneXus X deja de tener sentido, porque ya tiene la historia de los objetos incorporada.

Neptuno.net

El origen del nombre de esta aplicación desconozco de donde viene, ya que la versión original no es mía. Neptuno estaba hecho en GeneXus/Visual Basic, y funcionaba con la versión 8.0 de GeneXus. Neptuno.net es una variante del programa original pero escrito enteramente en C#.

Lo que hace ese programa es mostrar un "call tree" a partir de un objeto dado, mostrando pintados de rojo aquellos objetos que hacen commit o rollback.

El objetivo es poder encontrar problemas de integridad transaccional a partir de un objeto, que es algo que para hacerlo "a mano" resulta muy tedioso.

Las cosas que toma en cuenta son:
  • que el programa tenga commit o rollback en el código
  • que tenga la propiedad commit on exit y haga algún cambio en la base de datos (procesa el sp0 correspondiente)
  • si ejecuta en una nueva UTL asume que está bien.
Tiene muchas cosas para mejorar, por ejemplo la interfaz de usuario, la performance, o podría tener un botón que recorriera el árbol en profundidad y se parara en el primer nodo con problemas. Pero para una primer versión, cumple con su función y resulta sumamante útil.


CodeReviewr

Esta es la última incorporación y todavía estoy tratando de decidir si sirve o no...

El objetivo es poder hacer code review de los últimos cambios (objetos modificados ayer) por parte de todo el equipo de desarrollo.

El programa busca en la KB los objetos con una determinada fecha de modificación, y usa los distributes generados por el control de versiones (KBCVSP) para comparar la versión actual del objeto con la versión inmediatamente anterior, usando el comparador de distributes de GeneXus 9.0.

La revisión de código no es algo que hagamos sistemáticamente, pero en las pruebas que he hecho sirvió para detectar algunas cosas...



viernes, 17 de abril de 2009

Diez años con GeneXus

Por estos días, se están cumpliendo 10 años que empecé a trabajar en Concepto (la primera vez) y por lo tanto con GeneXus.

En aquella época todavía era estudiante (estaba empezando 4º año en la Facultad de Ingeniería) y lo curioso es que en realidad no buscaba trabajo... fue algo que surgió la posibilidad, vine a la entrevista y quedé.

En realidad con GeneXus empecé un poco antes, a fines de febrero o principios de marzo del 99, porque antes de empezar a trabajar hice el curso.

La versión que había era la 6.1, que no tenía "syntax coloring" en eventos y subrutinas (no me acuerdo en las reglas) y hasta donde se no generaba web. Ni hablar de generar .Net que ahí ni siquiera existía...

Cuando arranqué trabajé un par de meses generando para AS/400, pero (por suerte) después pasé a trabajar con Visual Fox Pro y C/SQL para los procesos más complicados.

Y después de eso salté a la beta de la 7.5 (nunca pasé por la 7.0) y seguí haciendo beta-test de las siguientes versiones: 8.0, 9.0 y X. A la X ev1 todavía no le he podido entrar, pero ya le llegará la hora :)

jueves, 26 de marzo de 2009

Lenguajes fuertemente tipados vs. lenguajes no tipados

En el mundo existen dos tipos de programadores: los que les gustan los lenguajes fuertemente tipados (strongly-typed) y los que les gustan los lenguajes no tipados (weakly-typed). Y no se hablan...

Yo soy del primer grupo, creo que por una cuestión de cuales son los lenguajes que he usado: desde Pascal en la facultad, pasando por C, C++, Java, C#, hasta GeneXus. Definir de qué tipo de datos es una variable me resulta de lo más natural.

No quiero ponerme en la postura de discutir cual opción es mejor, porque claramente se puede lograr lo mismo con cualquier tipo de lenguaje, pero hay cosas en los lenguajes no tipados que no me convencen.

El otro día tuve que revisar un programa escrito en PHP en busca de un posible bug, y la verdad que no saber de que tipo es una variable es algo que me choca.

Por ejemplo, si tengo una invocación (puede estar mal la sintaxis) de la forma:
$var->methodName($arg1, $arg2, $arg3);
si no se de que tipo es la variable $var, ¿donde busco la definición del método methodName?

A mi por lo menos me gusta saber con que tipos de datos estoy trabajando...

Tambiénme choca que se puedan hacer cosas como (puede estar mal la sintaxis):
$a = 1;
...
$a = 'Hola' + $a;
...
$a = new HttpClient('www.example.com');
...
$a = $a + 1;
pero bueno, se supone que esa es la ventaja de no tener chequeos estrictos en el tipo de datos, ¿no? Me parece que permitir saltearse el chequeo de tipos es algo que puede provocar más bugs.