Tabla de contenidos
En el capítulo anterior escribimos un generador de formularios para ingreso de datos. Si bien se trata sólo de un ejemplo, hay varias cosas que podemos observar:
Se genera mucho código redundante en cada clase. Por ejemplo, los métodos estáticos para crear elementos gráficos.
No queda claro como hacer uso de las clases generadas. Lo único que tenemos es un conjunto de campos privados y un método Save
que no hace nada.
La solución natural al primer problema es mover estos métodos comunes a otra clase. Debemos tratar de mantener el código generado lo más prolijo posible, eliminando las redundancias. El código en común puede proveerse junto al código generado, pero a medida que aumente la complejidad del generador de código será necesario proveer más y más servicios predefinidos.
Estos servicios predefinidos pueden encapsularse en un ensablado. El código generado dependerá, entonces, de esta librería.
El segundo problema (el uso del código generado) es más complejo. Lo mejor es establecer una arquitectura que tenga en cuenta la generación de código como parte del ciclo de desarrollo. En algunos casos, es posible separar completamente el código generado del código escrito a mano; un caso típico es la generación capas de acceso a datos: el código que implementa la lógica de negocios (que está escrito a mano) puede hacer uso de una librería completamente autogenerada, la cual puede ser descartada y sobreescrita cada vez que el modelo cambia.
En otros casos, esto no es tan fácil. Un ejemplo es la generación de interfaces gráficas: es posible generar una versión inicial de la interfaz gráfica de una aplicación, pero lo más probable es que estas ventanas deban ser modificadas para cumplir con los requerimientos del sistema. Es muy difícil establecer un esquema tal que al cambiar el modelo, sea posible volver a generar la interfaz sin perder las modificaciones hechas por el programador. En estos casos, el generador de código se comporta como un wizard que genera una única versión inicial del código, y luego se desentiende de su mantenimiento.
Teniendo en cuenta estos desafíos, podemos encarar la tarea de escribir un generador de código que genere a partir de un modelo un sistema informático completo, incluyendo los mecanismos para su compilación. Lo más eficiente en este caso es escribir varios generadores, uno por cada capa.
La arquitectura del código generado estará pensada de manera tal que todas sus piezas calcen a la perfección, dejando lugar para que los programadores añadan funcionalidad o restrinjan el comportamiento del sistema. Deberán minimizarse, siempre que sea posible, los casos donde el generador cree sólo la versión inicial de un fichero que el programador pueda modificar; las interacciones entre el código generado y el código escrito a mano podrán ser mediante mecanimos de herencia o composición.
Como ya se mencionó, es altamente probable que el código generado haga uso de librerías escritas por los mismos desarrolladores del generador.
(C) 2005, Rodolfo Campero.