Sobre la generación de código

Quisiera hoy tratar un tema, que de alguna manera lo trato en cada momento en que tengo oportunidad. No es un tema esencial, quizás, dentro del desarrollo de código, pero me parece importante tratarlo, por un tema digamos táctico: hoy por hoy, dada la situación de una serie de tecnologías, “frameworks” y estilos arquitectónicos, pienso que es indispensable estar advertido de este tema. Me refiero a la generación de código. Recorramos una introducción, que nos ponga en perspectiva, que nos muestre algunas causas de la situación actual, y que apoyen la necesidad de la generación de código.

Antes alguna aclaración: es un tema que me importa. Déjenme entonces, revolcarme en la explicación, detenerme en ejemplos y aclaraciones, pasar de un tópico a otro, enumerar detalles y volver al tema principal, divertirme con alguna chanza, referirme a alguna experiencia personal olvidable, o ponerme serio en alguna frase. Y si en alguna parte parezco merecer la internación en instituto mental, y el chaleco de fuerza, les recuerdo que hasta ahora, no lastimé a nadie, y estoy tomando la medicación diaria…. ;-)

No sé si podré transmitir todo lo que quiero expresar. Ludwig Wittgenstein escribió, en una introducción a su Tractatus Lógico-Philosophicus, alguna frase como “Lograría su cometido si complaciera aunque sólo sea a un lector que lo comprenda”. Espero no ser tan oscuro como el joven Ludwig, y que algo de lo que escriba se entienda y sirva a alguien.

El tema me importa: espero que se note.

Todo cambia

Recuerdo mis primeros pasos en el desarrollo de software. Tuve que desde perforar tarjetas, graboverificar datos, hasta trabajar con ensamblador de un venerable IBM 360, o un RPG que apenas llegaba a RPG II. Decenas de líneas de código en DATA DIVISION fueron escritas en planillas de programación. Tuve que escribir incomprensibles comandos de Job Control Languages, para hacer que el más mínimo programa pudiera ejecutar. Luego aparecieron por aquí, en mi pais, Argentina, los mini computadores, cada uno con su propio sistema operativo, y sus propios lenguajes y herramientas. Solo con los años, dejé las tarjetas perforadas, por un teclado en una máquina personal. Tuve que escribir en varias variantes de COBOL, en Fortran, en Algol, y hasta en APL (algo que no lo deseo a nadie, ni siquiera a un fanático de Haskell). Asistí al despertar del CP/M, su versión en red, un primer IBM PC, un Xenix de Microsoft, y varios compiladores C. Trabajé con Turbo Pascal, con Turbo C, y con un DBase que apenas abría dos tablas a la vez. Apareció un día una Lisa de Apple, así como al tiempo una Mac, algo llamado mouse, Microsoft contesta con Windows, y …. Puedo seguir un par de párrafos más. Lo que quiero transmitir, más que descubrir ante Uds que nací en el milenio pasado, es destacar, llamar la atención sobre un tema: la tecnología cambia. Si alguien piensa que la tecnología que tiene ahora entre manos, será “the ultimate solution”, me temo que tengo que decirle: mentira. Todo cambia. Podemos discutir las razones: la evolución de la tecnología, la innovación que empujan los nuevos jugadores, el avance en los requerimientos de los propios clientes, y demás. Pero la realidad es una: todo cambia.

La complejidad

Una vez asentado ese hecho (no una opinión, no una visión relativa, no una teoría, sino un hecho), pasemos a otro. A medida que aparecen nuevas tecnologías, requerimientos (por ejemplo, ya no hay solo ventanas gráficas, tenemos páginas web, otras presentaciones, texto a voz, pequeños dispositivos….), y formas de hacer sistemas, vemos que todo conspira para que cada sistema que encaremos, sea cada vez más complejo, o por lo menos, más largo y grande de construir. Ya es raro encontrar un sistema que pueda desarrollar un programador en solitario: cualquier sistema no trivial implica un equipo de trabajo, y el diseño, creación, ensamble, prueba de multitud de artefactos. Ya no es un simple formulario en Clipper: cada sistema implica parva de elementos a manejar, construir, relacionar.

Podríamos discutir si esto lo llamamos complejidad, o simplemente largura. Pero de alguna forma, Dorothy, ya no estamos más en Kansas: la creación de software, se complicó.

No somos vulcanos

¿Recuerdan al Señor Spock, de Viaje a las Estrellas? Como vulcano, podía analizar todo, y manejar ingentes cantidades de información, y seguir con la razón hacia adelante, resolviendo todo problema. No somos vulcanos. Mientras un vulcano, me imagino, puede escribir un sistema completo como un todo, nosotros, como humanos, no podemos “manejar” más de ocho o nueve temas al mismo tiempo. La construcción de software es una actividad humana que implica la mayor cantidad de niveles de detalle: tenemos que ser capaces de ver la arquitectura general del sistema, hasta estar en el detalle del último procedimiento almacenado, o la serialización de un mensaje en forma eficiente para transportar en un servicio web. Esa en la razón de la aparición de arquitectura, patrones y otras soluciones: son soluciones que ayudan a superar nuestras limitaciones humanas. Un sistema con capas o sin capas, es de igual de complejo para un procesador. Es por y para nosotros, los humanos, que los sistemas se organizan, se parten, se analizan y diseñan. Es por nosotros, que la arquitectura de software apela al viejo “divide y vencerás”. Es por nosotros, que tenemos patrones. Es por nosotros, que adoptamos en programación estructurada la abolición del GOTO (noten que cualquier procesador tiene GOTO, y que todo ejecutable, tiene miles de GOTO: la desaparición de esta “infame” construcción ocurrió a nivel humano, a nivel de los lenguajes que manejamos, los procesadores ni se enteraron del problema).

Cada año que pasa, es más evidente que necesitamos ayuda para construcción de software. No podemos solos.

Software que genera software

En los ochenta, me comentaron una idea: cuando uno arma una herramienta de software, sería bueno que nos ayude a generar más software. No solamente armar herramientas para otros, sino que de alguna forma, cada esfuerzo que hagamos en armar algo, nos ayude, potencie, las capacidades de seguir haciendo. Esto permite que cada tiempo que invertimos, de alguna forma nos vuelva en provecho a nuestro trabajo, y por otra, ejercitar el “dog fooding”: comer la comida del perro, usar las propias herramientas, para apreciar las ventajas y limitaciones de lo que producimos.

Ese consejo lo comencé a aplicar en mis primeros programas en Lattice C, para PC. Necesitaba escribir rutinas que pasaban de una estructura de datos a un sistema de archivo indexado que había armado en un venerable assembler. No quieran imaginar la cantidad de código que eso implicaba. Luego, necesité pantallas de ingreso de datos, que manejaran el cursor, posicionamiento en una consola de texto, ingreso de campos y demás. Armé una librería de ingreso y manejo de campos. Pero igual cada pantalla era gran cantidad de código. Entonces, recordando el consejo del párrafo anterior, se armó un generador ese código en C. El propio generador estaba escrito en C. Epifanía: la creación de gran parte de un sistema, que era un trabajo tedioso, lleno de probables errores, quedó reducida a minutos.

Algunos de Uds lo habrán experimentado: descubrir algo que nos ayuda enormemente en el trabajo de cada día. Pero ¿cuál era el problema de esa solución? Solo funcionaba para lo que yo necesitaba. Si quería generar otra cosa, tenía que cambiar mucho del código original. Igualmente, con un grupo, pasamos la librería original a Xenix, y notablemente, siguió produciendo código para ese sistema operativo.

Pero la tecnología cambiaba. Llegó un momento, en que era más fácil usar las nuevas IDEs (entornos de desarrollo), que generar el código de esa forma. Pero siempre me quedó en la cabecita, la idea de volver a esa herramienta.

Pero destaquemos algo: la idea de software generando software, no es nueva. Es una idea que aplicamos cada vez que ejecutamos un compilador. Veamos el esquema: escribimos nuestros programas en un lenguaje de nivel más alto que el de la máquina. Pero luego, no vamos pasando de ese lenguaje a binario a mano: no estamos generando los bits (que de eso se compone un ejecuble) manualmente en un archivo. No señor. Apelamos a una herramienta.

Creando sistemas con tecnologías

Si Uds. trabajaron muchos años en alguna tecnología (llámese Clipper, Visual Fox, Visual Basic, Java o .NET), habrán llegado al punto de ser “proficient”, de ser capaces de armar sistemas no triviales, manejando sin titubear cada detalle de la tecnología que eligieron. Claro, esa capacidad lleva su tiempo adquirirla. Pero habrán resuelto cómo armar los clásicos ABMs (altas, bajas y modificaciones), accesos a bases de datos, reportes, presentación de menúes, login de usuario y otros. Así hacíamos el sistema S1, luego el S2, y cuando nos encargan el sistema S3, tomamos el S2 como base, y lo vamos cambiando, para no generar el S3 desde el principio.

Eso que hicimos por años se puede resumir:

- Dada una tecnología, la vamos conociendo (aprendiendo cada propiedad de cada control en Visual Basic, o cada método de la API de ADO, DAO, JDBC o lo que nos venga…)

- Dado los sistemas que nos toca construir, vamos solucionando los distintos elementos (cómo acceder a datos, cómo ingresar una entidad, dónde colocar las validaciones…)

- Cuando tenemos un nuevo sistema, nos basamos en lo que ya construímos

Frameworks y librerías

Próximo paso que algunos dimos: luego de haber resuelto los puntos del párrafo anterior, se nos ocurre:

- Armar una librería de clases, que resuelvan lo que hacemos repetitivamente en cada sistema

- O adoptamos algún framework, ya sea de Visual Fox, el de Lothka para Visual Basic, ya sea las recomendaciones de Sun para un J2EE, o Struts, o Spring, o cualquier otro, que alguien haya hecho, para solucionar algunos temas que no queremos armar nosotros.

Pero armar una librería de clases es trabajoso. Y cuando finalmente la conseguimos, cambia la tecnología. Ejemplo: durante años, aprendimos cómo trabajar con Visual Fox. Luego, armamos la librería de clases que nos va a solucionar todo lo que hagamos de ahora en más con ese tecnología. Luego, la realidad se ríe, y aparece la web, Java, multiplataforma, .NET y todo lo demás, y nuestra inversión en la librería, bien, pueden imaginar donde podemos ponerla.

No vamos mejor si adoptamos una librería de otra gente. Al principio, la librería parece maravillosa. Pero al tiempo, no soluciona todo. Y cuando cambia la tecnología, resulta que la librería ya no es soportada. De nuevo, a empezar desde cero, o casi cero.

Arquitectura y patrones

Por lo menos, alguien piensa en cómo hacer sistemas: en los estilos arquitectónicos, en descubrir patrones (soluciones a problemas, que se pueden aplicar en distintos contextos) y demás. Estudiamos esos conceptos, ilusionados por encontrar la “silver bullet”, la bala de plata que mate todos los vampiros que amenazan todo nuestro esfuerzo de creación de software.

Pero si examinan cualquiera de esos principios, implican algo: un montón de trabajo. La necesidad de partir los sistemas (nacidos de la complejidad, de nuestras limitaciones como humanos), hacen que cada trabajo que encaremos, implique la generación de multitud de elementos: desde una capa de presentación, hasta una capa de datos, desde una fachada de servicio, hasta un gateway de grabación de entidades, desde una service interface tecnológica, basada en servicios web, hasta conversores de entidades a mensajes y viceversa.

De nuevo, tenemos soluciones, pero mucho trabajo.

Look ma, no code

Otra solución intentada, es generar pantallas, páginas, funcionalidad en “runtime”, en ejecución. Cansados de las mismas páginas y menúes, y otros elementos, decidimos poner cómo es el formulario y qué tabla actualizar, en metadata. Esta metadata puede estar en XML on en una base de datos, o donde decidamos.

Pero es muy dificil producir un sistema que contemple todo. Sólo algunas pantallas se podrán armar dinámicamente en ejecución. Y dependiendo de la tecnología, habrá que aprender y probar miles de detalles de reflection, creación dinámica de controles, y más. Y cuando al final terminamos de hacer algo potable en ASP, aparece ASP.NET 1.x. Y cuando finalmente creamos controles con ASP.NET 1.x, aparecen master pages y otros controles, en ASP.NET 2.x. Lo mismo si creamos controles “on the fly” para JSP, y luego aparece JSF.

No es una solución que me desagrade, pero notemos que implica de nuevo, una montaña de trabajo, que puede quedar obsoleta en cualquier momento.

Aprendiendo, aprendiendo

Ya sea que pasamos de Visual Fox a .NET, ya sea que conocemos .NET pero queremos aprender conceptos de arquitectura, ya sea conocemos arquitectura, pero queremos manejar un framework como NHibernate o Struts, ya sea conocemos EJB y queremos aprender EJB3, todos esas necesidades de aprendizaje, o la mayoría, son causadas por lo que vimos hasta acá: el cambio permanente, el aumento de la complejidad, y la necesidad de seguir creando software que esté a la altura de lo que los demás están construyendo.

Yo dicto cerca de una docena de clases por semana, de temas tan diversos como PHP, PHP5, patrones, estilos arquitectónicos, Java, JSP, Struts, Spring, Hibernate, EJB2, Jboss, Tomcat, JSF, .NET, Ajax, Windows Workflow Foundation, y me falta abarcar corte y confección y estamos hechos. Veo llegar asistentes a los cursos, y trato de convencerlos que el curso no es del tema que dice el título del curso: no es aprender un tema, que dentro de seis meses va a cambiar. Trato (no siempre lo consigo, debido a limitaciones de mi expresión), de hacer ver que todos esos temas, son tecnologías para resolver problemas. Y trato de advertir, percatar, cuáles son los problemas, y las causas de que tengamos esos problemas. Trato de transmitir, que si vienen a un curso C1, y no ven más allá del tema, dentro de seis meses van a venir al curso C2, que será una simple actualización del anterior, con las mismas esperanzas que albergaban al estudiar C1. Trato de convencerlos de que no vengan más a otro curso: que cada tecnología pasa, lo importante está en otro lado.

Quisiera que cada asistente viera, entonces, más allá del tema circunstancial del curso. Aprender una tecnología, sin pensar más allá, es casi una pérdida de tiempo.

Todos mis cursos, son iguales: no trato de enseñar el tema, sino algo más, algo que trasciende el tema que sirve de excusa al curso. Espero que este “post” ayude a poner en claro algunos puntos que trato de transmitir. También, me sirve para poner en claro mis propias ideas, y, algo que quizás no se dan cuenta, me permite explayarme, regocijarme, sin necesidad de hablar durante horas (ya estoy viejito, me cansa hablar y hablar, disculpen y tengan piedad…;-)

Cabecitas, y más cabecitas

De vez en cuando, aparezco en alguna consultar. El año pasado, me tocó visitar un piso lleno de gente, con computadoras personales en cada escritorio: todos desarrollando. El piso era inmenso, no había paredes, y veía a todo el mundo inclinado sobre sus teclados y pantallas. Sólo se veían las cabecitas.

Pero al acercarme, a ver qué hacía cada grupo, encontré lo que temía: varios estaban generando artefactos, que bien podrían delegarse a que un sistema los genere: cantidad de código repetitivo, que bien podría ser generado automáticamente.

No sé cómo será en su pais. Acá en Argentina, hay cantidad de grupos de desarrollo que necesitan programadores Java. Estoy convencido que la necesidad de esos programadores, es debido a la escasa productividad de muchas herramientas de desarrollo de Java. Un Eclipse pelado, no es un Visual Studio. Y en Java, hay multitud de subtecnologías para elegir, cada una con su propia complejidad. Vayan sino a ver un archivo de configuración de Struts o Struts2, un mapeo del Hibernate, o un archivo de configuración de Spring, o un ejb-jar de Enterprise Java Beans. Se los regalo: son obra del diablo. Claro, hay plugins, y demás utilitarios para generar algo de eso. Cada uno trabaja a su manera, sin colaborar con lo demás que nos toque.

Creo que mucho de esa fuerza de programación, se podría aprovechar de forma más eficiente. Creo que a veces, programamos, de la misma forma que cosechábamos hace un siglo el trigo: llamábamos a una multitud de gente, le dábamos una hoz a cada uno, y a trabajar. Hoy una cosechadora hace el mismo trabajo. Recordemos alguna historia de las fábricas japonesas: cuando se automatizó gran parte de la línea de producción, ¿hubo despidos? No, se utilizó la gente, no para apretar tornillos, sino para controlar la calidad, y encargarse de las tareas que no podía realizar un simple robot.

Herramientas y agentes

J.P.Plauger, mítico programador, creador de compiladores, empresas y libros, me llamó la atención, en una artículo suyo de hace ya más de una década, sobre algo que pasó en la historia humana: por un lado, aparecieron herramientas, cosas que usamos, para hacer lo que queremos hacer, pero de forma más fácil. Pero también aparecieron en su tiempo, los agentes: otros organismos que hacen ellos, lo que no queremos hacer nosotros. Desde animales de carga, hasta, me temo, esclavos humanos.

Hoy, en desarrollo de software, tenemos muchas herramientas. Pero aún la mejor IDE, nos obliga a sentarnos enfrente, y armar las ventanas arrastrando de a uno los botones. ¿No se podrá delegar gran parte de ese trabajo en un agente de software? Un generador de código puede ser más que un wizard, o un activo de una “software factory” de la IDE de moda: puede ser un sistema experto, que tome decisiones, que dado un modelo, llegue más allá de lo automático. Tal vez, este es el aspecto más oscuro de explicar ahora en este “post”. Recuerden: podemos conseguir más que una herramiente, un agente. Algo más sobre “inteligencia artificial” más abajo.

Domain Specific Languages

Vimos que una estrategia, como la empleada en la compilación, implica:

- un lenguaje de alto nivel

- una herramienta que pase de ese lenguaje a algo que entienda la máquina

Hace un tiempo, aparece el concepto de DSL (Domain Specific Languages). En lugar de usar un lenguaje que modele en alto nivel algo genérico (como algunos pretenden con UML), se pueden inventar lenguajes que modelen, expresen, las necesidades que tenemos y que haya herramientas que, interpretando, procesando esos modelos expresados en un lenguaje específicamente orientado al dominio a solucionar, vayan generando el artefacto final necesario para pasar del modelo de alto nivel a algo más cercano a la máquina.

Alguien puede pensar que nunca usó un DSL. Creo que podría estar equivocado. Veamos un par de casos. Tomemos el lenguaje SQL. Un comando como

select * from employee

nos soluciona un conjunto de detalles, que antes, con un sistema indexado (un ISAM, un venerable Btrieve, y otros), implicaba programar un cursor, obtener cada estructura de registro, pasarla a una estructura de memoria, recorrer programáticamente un índice, recordar que el campo nombre está en tal posición, y más y más detalles. Vean cómo el lenguaje SQL es un DSL: no es un lenguaje genérico. No sirve para hacer sistema cualesquiera. Nadie escribe formularios en SQL o hace cálculos científicos o rutinas recursivas. Sólo está dedicado a solucionar el tema de acceso a datos. Pero ha sido lo bastante potente y flexible, para que hoy lo hayamos adoptado en cada recoveco de nuestros sistemas. Detengámonos en esos puntos:

- No es genérico, es específico de un dominio

- Es flexible

- Hace lo que necesitamos hacer, por nosotros

Segundo caso de DSL: un lenguaje no tiene que ser un lenguaje textual. Tomemos el caso de un DSL exitosísimo, que cambió la forma de programar en Windows. Es el caso del diseñador de formularios del venerable Visual Basic del milenio pasado. Vean cómo dibujando un formulario, Visual Basic se encarga de armar lo que nos hubiera llevado páginas y páginas de código C++. Algunos de Uds. recordarán la alienación que era codificar un simple “Hello, World”, con Visual C++, siguiendo las recomendaciones del bueno de Petzold. Visual Basic nos liberó de eso. Alguien podría haber pensado: no hace lo mismo que C++, no es tan eficiente, no permite ser tan flexible… Bullshit…. Visual Basic nos ayudó por más de una década, con un DSL gráfico.

Algunos generadores de código

Algunos de Uds ya habrán experimentado con utilitarios de generación de código. En un próximo párrafo, mencionaré lo que yo pediría a un generador. Pero veamos ahora algunas limitaciones.

Primero: el generador sólo genera lo que él quiere. Típico de generadores “profesionales”, que sólo producen lo que los creadores del generador imaginaron. Es difícil, y en algunos casos, imposible, extenderlo más allá de lo que hacen actualmente. Variante de esto: sólo genera código para entidades, o sólo para una tecnología, o sólo para EJB, o sólo para…. y puedo seguir. Claro, la herramienta soluciona el problema, y al comienzo estamos chochos de haberla encontrado. Pero advertiría desde ahora, que encontrarán limitaciones.

Segundo: el generador sólo parte de un modelo predeterminado (típicamente de una estructura de tablas de base de datos). Creo haberlos convencido que hay más bajo el sol que generar entidades y mapeadores. Hay colecciones inmensas de artefactos que tenemos que generar en cualquier sistema no trivial. Y seguirán apareciendo, por lo menos, en el futuro cercano. Si el generador sólo está pensado para partir de un modelo determinado, nos limita en lo que podemos pedirle. La historia nos ha mostrado, que siempre necesitamos algo más.

Tercero: el generador es cerrado, no se puede aprovechar e integrar en sistemas nuestros, o no entrega el código de base, o no permite armar plantillas y demás auxiliares.

Puedo seguir enumerando problemas. Mencionemos uno más: hay quien menciona que utilizó generadores de código, pero sólo lo usa para generar el código inicial de un sistema, y luego ya modifica el código generado, y no puede regenerar sin perder los cambios que hizo. Sugerencia: pongan en claro qué artefactos se generan automáticamente, y cuáles son los generados manualmente. Cuando Uds compilan un ejecutable, y necesitan cambiar un algoritmo, no van y cambian los bits del .exe. No: van al modelo, al lenguaje de programación, lo cambian y compilan de nuevo. Lo mismo deberíamos conseguir algún día, con generación de código. Como no podemos generar todo, debemos tener la disciplina de decidir cuáles artefactos son generados por el utilitario, y cuáles son los artefactos nuestros. En algunos casos, en los repositorios de código, en un CVS, cuando se trabaja en grupo, NO SE GUARDA lo generado automáticamente: solamente se guarda el modelo, y lo generado manualmente. Esto refuerza la responsabilidad de no tocar ese código automático: cualquier cambio manual que hagamos sobre ellos, no se guardará en el repositorio común.

El camino del demonio

Quisiera insertar ahora, en este momento, una advertencia. Todos podemos hacer un generador de código, o utilizar alguno ya armado. Algunas de las características deseables, fueron apareciendo en la discusión, y quedará más claro en la próxima sección. Pero levanto la mano para que no sigan un camino: XSLT.

Podrá ocurrírseles, en algún momento, que el modelo inicial, la metadata de partida, se encuentre en XML. Creo que es una elección pragmática: luego, más adelante, ese modelo se puede dibujar, crear con utilitarios más simpáticos o gráficos, pero un buen XML sirve como un DSL para un dominio que querramos manejar.

Pero no se les ocurra que podrán generar lo que quieran con XSLT (transformaciones de XML). XSLT es el camino del demonio. Para cualquier cosa no trivial, es algo que complica el universo, de una forma no predecible. Es como tratar de rascarse la oreja izquierda con el pie derecho. Poder se puede, pero les va a costar. Trabajar con XSLT es como un problema de ingenio. ¿Recuerdan el acertijo de tener un bote, dos orillas, y en una una oveca, una lechuga y un lobo, y sólo caben dos en el bote, aparte de uno? Bien, algo así es tratar de manejar XSLT para generar código. “Forget it”, XSLT caca…. ;-)

Hacia un generador de código

¿Qué le pediríamos entonces, a un generador de código? Gran pregunta, intentemos algunas respuestas:

- Que genere código que hubiéramos generado nosotros: si genera código inentendible, estamos en mal camino. Ese es el problema de varios wizards y demás herramientas: hacen lo que ellas quieren, no lo que nosotros queremos.

- Que genere cualquier texto que nos imaginemos que necesitamos: no basta que genere lo que el generador de código decida. Debe ser lo bastante flexible, para que podamos generar lo que querramos: desde una simple entidad, a un mapeo de Hibernate, desde una página web, hasta un mensaje de Windows Communication Foundation, desde el archivo de configuración de Struts, hasta el interminable ejb-jar.xml que nos pide el JBoss versión 17.84 que tengamos el año que viene.

- Que parta de un modelo simple, o compuesto, pero libre: no que parta de una base de datos, y sólo genere entidades y mapeadores. Necesitamos más flexibilidad. Ya vimos los que nos pasa en la vida real: todo cambia, necesitamos multitud de artefactos. Cualquier inversión en un generador de código que no permita incluir un modelo libre, me parece riesgosa. Creo que como prueba ácida, le pediría a un generador, que permita, desde un modelo libre, generar todo programa “Hello, World” que se nos ocurra. Si una herramienta no puede obtener ese resultado, estamos en el horno.

- Que permita escribir los templates, plantillas que querramos, y generarlas en grupo, en serie, en paralelo, o como querramos. Tanto el orden y enumeración de artefactos a generar, como las plantillas, como la toma de decisiones (generar de tal forma o no), debe estar bajo control del utilitario, y bajo control nuestro.

- Que permita generar desde un modelo, al cambiarlo, de forma fácil: si para generar los artefactos, por un cambio en el modelo, hay que dar cuarenta pasos, de nuevo estamos en problema. Compilar hoy es una tecla. Lo mismo debe ser la generación de código.

Dunga dunga un ratito

De alguna forma, un generador de código ideal no estará atado a una tecnología. Siempre habrá alguna “better mousetrap”, siempre alguien inventará alguna nueva forma de hacer algo, siempre habrá un ruso con insomnio, o un hindú sin novia, que no tiene otra cosa que hacer que crear algo nuevo, ya sea en forma de librería, framework, patrón, o estilo arquitectónico. Un generador de código debe ser agnóstico de la tecnología, de las modas, de las soluciones actuales y futuras.

El generador de código que adoptemos, debe poder adaptarse a lo que querramos hoy y mañana y pasado mañana. La estrategia es: no importa la tecnología, el patrón o el framework que aparezca, nuestro generador deberá aprovecharse de lo que surja. Es lo que llamo la estrategia “dunga dunga”: si aparece una nueva tecnología T1, le hacemos “dunga dunga” a T1, si aparece un nuevo framework PiruloStruts, adaptamos nuestras plantillas a aprovecharse de ese framework, “dunga dunga” a PiruloStruts. Es como un maestro de aikido: siempre habrá alguien más fuerte, sólo hay que utilizar la fuerza del otro, para vencerlo.

Mi corazoncito

Claro, los que asistieron a algunas de mis charlas, ya conocen el final: tengo mi propio generador de código, el proyecto de código abierto AjGenesis. Lo pueden bajar, probar, examinar, integrar, modificar, hagan lo que quieran. Pero no digan que no les mostré la luz… ;-) ;-)

Se basa en:

- Tener un modelo totalmente libre, que hoy está serializado en archivos XML.

- Plantillas que generan artefactos de texto

- Tareas programables, que cargan los modelos, ejecutan lo que uno quiera, y son invocables desde programas nuestros, desde la línea de comando, o desde un utilitario como el NAnt.

Entonces, se arma uno o varios modelos, que expresan lo que Uds quieran de su sistema, de forma independiente de la plataforma, y luego, adosándole modelos (uno o varios, de nuevo libres), que indican la tecnología a usar, y escribiendo las plantillas que Uds. quieran, generan lo que se les ocurra.

Pueden leer sobre el modelo libre que usa en:

Generando Código- Hello World con AjGenesis

(como el modelo está serializado en texto… adivinen… se puede generar desde el mismo generador!!!). Esto implica:

M1 (de alto nivel) ===> Templates+AjGenesis ==> M2 (de nivel medio) ==> Templates+AjGenesis ==> Mn….. ==> Artefactos de texto finales

¿Se entiende? Si uno tiene pensado un modelo M, bien puede generarlo desde otro modelo que alguien traiga: por ejemplo, desde la estructura de base de datos, o desde un gráfico UML serializado en XMI, o lo que se invente mañana. Sólo es cuestión de generar el modelo desde el cual queremos partir. Hoy lo generamos manualmente: pero tengo algunos intentos promisorios, para que el modelo que necesite, se genere desde otro modelo que tengamos más a mano.

(Notablemente, ahora, muchos generadores de código más “profesionales”, están adoptando esta estrategia: modelo libre…. vieron la luz… :-) ;-)

Pueden ver algunos ejemplos no triviales:

Generando aplicaciones con AjGenesis

Desde un modelo inventado para el ejemplo, se producen aplicaciones completas en VB.NET 1.x, VB.NET 2, C# 1.x, C# 2, JSP, usando patrones de Business Entities/Business Components a la Microsoft, o usando Domain-Driven Design de Evans, usando MySql o SQL Server, usando Gateways, Data Mappers, o Hibernate, o NHibernate. O lo que vuestra imaginación quiera: el cielo es el límite.

Ese modelo del ejemplo, hoy se genera manualmente. Tengo utilitarios, basados en AjGenesis, que generan ese modelo, desde un modelo más esquemático. Y estoy trabajando para generarlo desde otras fuentes. Si el modelo a usar se puede expresar en texto, PUEDE SER GENERADO por el propio sistema, más un sistema experto. No imagino una aplicación más inmediata de la “inteligencia artificial”. Imagino agentes inteligentes, que colaboren en una red compartida, cada uno generando parte del modelo, cada uno consumiendo algo que otro produce, y colaborando, para generar un sistema… Sí, ya sé, tengo que tomar la píldora verde, en lugar de la roja… ;-)

Más artículos sobre generación de código en:

Generación de Código

Pero no tiene mucha documentación. Si Ud. lo encuentra útil, le pediría:

- Escribir, comentar sobre su experiencia, en la web (lo que no está bajo Google, no existe…:-)

- Compartir los templates, o por lo menos, comentar cuáles creó, para qué, y sus resultados

Estoy trabajando en tener un repositorio de templates en la web, para poder catalogarlos, y que otros usuarios puedan (no es obligación) publicar las plantillas o modificaciones que le resulten útiles.

Generadores de código más “armados” (pero me parece, sinceramente, menos flexibles), desde:

http://www.codegeneration.net/

Más allá de la generación de código

Hay que tener claro algo: la generación de código es sólo una solución pragmática a la situación actual. No implica abandonar todo pensamiento crítico, toda esperanza de mejora en la creación de sofware. Creo que vamos por buen camino: tenemos arquitectura, patrones, vamos conociendo cada vez más, cómo generar software de calidad. Estamos, creo, en una etapa aristotélica de nuestra disciplina: estamos ordenando conocimientos, clasificando datos, comenzando a darnos cuenta de cuáles son los esquemas, relaciones, problemas esenciales. Pero nos falta aún encontrar a un Galileo o Newton de los sistemas (mi natural modestia, me impide señarlar a un candidato que tengo “in pectore”… ;-).

Conclusión

Estudien cómo hacen los sistemas. Consigan dominar la tecnología que tienen entre manos. Descubran lo común a todo lo que hacen. Y en algún momento, adopten alguna herramienta, que les ayude a generar automáticamente lo mismo, que Uds. hubieran generado. Dedicar la inteligencia y el tiempo, donde el tiempo y la inteligencia se necesitan. Dejemos de escribir palabras de lenguaje: creemos software.

La mejora herramienta está entre nuestras orejas, apliquemos la neurona, generación de código, vermuth con papa fritas, y good show!

Angel “Java” Lopez
http://www.ajlopez.com/

This entry was posted in 1389, 1390, 2643, 3463, 6145. Bookmark the permalink.

19 Responses to Sobre la generación de código

  1. Angel,

    Gracias por el AjGenesis, lo voy a probar ahora mismo y pondo en mi blog el resultado de la experiencia. Actualmente estoy usando MyGeneration, que está bueno, pero no me cierra del todo. Hace un tiempo hice un motorcito con reflection para generar select, inserts y updates a partir de entidades de datos, sumado a una clase DAL y un generador de código para hacer las entidades lograba todo el tema de persistencia, pero siempre me quedó la impresión de que iba a fallar en algún momento (lo hice hace tiempo y según recuerdo debe estar bastante feo), en fin, no sé qué te parecen este tipo de soluciones.

    Saludos, Leonardo

  2. Emilio says:

    Estoy de acuerdo con todo lo que comentas. Lo único que hecho en falta es algún comentario sobre la disciplina que engloba todo estos conceptos, el Model Driven Development (o Model Driven Software Development). También existe un estándar que aunque quizás no todos estemos de acuerdo con el, marca el camino a seguir, El Model Driven Architecture.
    Nosotros en la empresa utilizamos AndroMDA con muy buenos resultados.

    Saludos.

  3. Emmanuel says:

    Angel:

    El hecho de que hayas armado un post gigante como este demuestra tu interes en la comunidad de desarrollo de software, por eso te doy las gracias por compartir tu experiencia y conocimiento con nosotros! (sabes? todavia tengo en la biblioteca un libro de java tuyo que sacaste para users hace como diez años! :)

    Pregunta: Ya que tu apodo es “java” :), porque no utilizar StringTemplate en vez de crear tu propio generador?

    http://www.stringtemplate.org/
    http://antlr.org/about.html

    (doy por sentado que ya conoces ambos proyectos, pero de todos modos agrego el link para quien lea este comentario)

    Por otro lado, me resulta muy dificil apartar el tiempo necesario para completar la lectura de tremendo post. Un resumen y secciones mas especificas ayudarian (tenes que admitir que “Dunga dunga un ratito” es un titulo sobre el cual es dificil sacar conclusiones :). Y bueno… supongo que la conclusion es el resumen, no?

    Saludos y hasta luego!

  4. Jorge Ubeda says:

    Para Emilio: quizá Angel no comparta que MDA sea la disciplina que engloba estos conceptos. Microsoft con Visual Studio propone DSL, que pudiera englobar MDA, pero sólo estirando el significado del estándar. En todo caso, Angel me dá la oportunidad de ver aplicado en un caso el  punto de vista de Microsoft. La crítica a MDA desde el punto de DSL, es que es genérico, y que UML no sirve para representar todo. En algún punto debe haber una intersección entre el punto de vista genérico de MDA (un modelo con transformaciones a la plataforma específica) y DSL (n lenguajes en colaboración para un producto final). Mi punto de vista es que estas ideas seguirán progresando, y más adelante (siempre que las empresas lo permitan) veremos una mejor articulación, en la que un modelo genérico pueda delegar en herramientas más específicas aspectos que por otra vía sean mejor cubiertos.

    Para Ángel, me gusta tu caso desarrollado. Lo voy a estudiar, para ver su alcance y condiciones.

    SQL un DSL? no me parece atinado su uso por Microsoft como un ejemplo de un Domain Specifc Language, al menos si se propone que estos sean construíbles. Con este criterio DSL es un éxito total, vivimos rodeados de DSLs (podríamos llamar así a Visual Fox o semejantes), y no atendemos su uso propuesto actual.

  5. Rodrigo says:

    ME PARECE INTERESANTE ESTE ARTICULO SOBRE EL DESARROLLO DE SOFTWARE, EL HECHO DE TENER QUE ESTAR  HORAS Y HORAS TECLEQUEANDO LINEAS DE CODIGO EN LUGAR DE ATUTOMATIZARLAS ES REALMENTE AGOTADOR… PERO SOLO BASTARA TENER EL TIEMPO PARA DEDICARASE A DESARROLLAR UN GENERADOR DE CODIGO… EN MI ANTIGUA EMPRESA TENIA UN GENENERADOR DE CODIGO EL CUAL ME PERMITIA ENLAZAR PROCEDIMIENTOS ALMACENADOS CON .NET… ESTE SIMPLIFICAFA BATANTE EL DESARROLLO… Y POR ENDE PODIA OCUPAR EL TIEMPO SOLUCIONANDO OTROS PROBLEMAS

    CONSULTA

    QUE ES MEJOR REALIZAR CONSULTAS A TRAVES DE NHIBERNATE O POR MEDIO DE PACKAGE PLSQL

  6. Horacio says:

    Interesante artículo. Voy a probarlo.
    Por el momento uso codesmith para generar codigo y no me puedo quejar hago y deshago todo a gusto y placer.
    De todas forma siempre es bueno tener algo libre.-

    Saludos.

  7. Hernan GUaymas says:

    Angel, simplemente…sos un GENIO, hay muy pocas personas capaces de hacer lo que vos haces y de brindarlo a la gente. Muchas Gracias por tus aportes!!!

    Pensaste alguna version que incorpore JSF, ADF Faces, Spring, digamos, las ultimas tecnologias?

  8. lopez says:

    Hola gente!

    Gracias por visitar este artículo, y por los comentarios.

    Para Hernan Guaymas:
    ciertamente, aparecerán templates con Spring, Struts 1.x, Struts 2, y JSF, por lo menos, para pasar en limpio algunas pruebas de concepto. Para crear los templates, sigo los pasos:

    1) escribir una prueba de concepto, un ejemplo en la tecnologia destino, manualmente
    2) aislar lo esencial, separar lo variable, y escribir el template.

    Estoy en el paso 1 en algunas de esas tecnologias, y todavia no comence con las otras.

    Igualmente: cualquiera se puede escribir sus propios templates. Pueden visitar la lista de generacion de codigo

    http://groups.google.com/group/codegeneration?hl=es

    donde hay desarrolladores que estan estudiando el proyecto ajgenesis, generando sus propios templates.

    La idea a mediano plazo, es tener un lugar donde publicar los templates que los demas quieran publicar.

    Para Emilio: bravo que esten MDA! Y con

    http://www.andromda.org

    En particular, en mi opinión, MDA se va convirtiendo en estándar, pero necesitaba algo que partiera de un modelo sencillo y libre.

    Para Leonardo: gracias por tu propuesta de poner tu experiencia en tu blog. Necesito algo de “feedback” (cuando “posteaste” tu comentario, visite tu blog http://leomicheloni.blogspot.com pero justo ahora no pude entrar)

    Para Horacio: claro, la idea es usar generación de código, de alguna forma que nos sirva. Hay multitud de utilitarios. Usen la herramienta con la que se sientan más cómodos para conseguir el objetivo.

    Para Emmanuel: podría usar Java (de hecho, una de las reglas de decisión en el diseño de AjGenesis, es tener siempre presente que se pueda migrar a Java). El tema es que para hacer un parser y evaluar sin tipos, en un intérprete dinámico, me convenía usar algo que ya tenía hecho, que es un intérprete AjBasic, escrito en VB.NET 1.x. Pensé (y no estoy arrepentido) que entregar algo básico y fundamental del sistema (el procesamiento de templates) iba a dificultar la experimentación de alternativas. Pero en Java, podrían usar directamente Velocity, junto con Texen o Anakia.

    El haber adoptado a AjBasic, me permite poner en los templates bastante más que lo que coloco en un procesador de template prefabricado para otros escenarios y objetivos.

    Para Rodrigo: para la elección de nhibernate, influyen, supongo, varias fuerzas, que no sé si están presentes en tu caso. NHibernate permite evitar escribir el código de acceso a SQL, y cambiar, en principio, de base de datos, así como alimentar un modelo de dominio, con relaciones entre objetos, via lazy. En cuanto a packages de Oracle, deben ser más eficientes al estar precompilados, y en general, los manejadores de base de datos van armando estadísticas y planes de ejecución, para ejecutarlos rápidamente. Fíjate cuál es tu caso: necesitas modelo de dominio? necesitas control de la base? cambiarás de base? Bueno, son muchas preguntas, pero espero haberte dado una idea.

    De nuevo, gracias por leer este “post” larguísimo, y por los comentarios.

    Nos leemos!

    Angel “Java” Lopez

  9. victor viera says:

    Saludos estoy muy complacido de estar de acuerdo con su teoria. yo he realizado un escrito, claro no tan avanzado con el suyo, pero me interesa tambien este tema…
    vieravictor@hotmail.com

  10. Leandro says:

    Hola, Angel!

    Desearia saber cuales son las diferencias conceptuales entre esta GeneXus y AjGenesis si conoce GeneXus.

    Saludos,

    Leandro

  11. tonio says:

    Simplemente abrumador!!!

  12. Luis says:

    Algel:
    Esto es simplemente fabuloso…
    Decime es posible generar una aplicacion a partir de un esquema de base de datos(DataSet) en .net utilizando AjGenesis.

  13. Antonino Ferrando says:

    AJGenesis rocks!

  14. Tesis sobre Generación de Código says:

    Hola Angel, te cuento que dentro de unos meses voy a empezar a elaborar mi tesis, y el tema que pienso incluir es utilizar inteligencia artifical aplicada a la generación de código. Mi correo personal es raulmercadox@hotmail.com, si tienes información adicional para realizar mi investigación, te agradecería mucho que me la envíes.

  15. Raimundo Marconi says:

    Hola Angel, Como ya te imaginaras la necesidad de codigo en un lenguaje como COBOL, requiere que los jovenes aprendan a usar tecnicas de lenguajes secuenciales como COBOL, Fortran etc. Esta dificultad se refleja en el hecho de que buenos programadores de java tengan muy baja productividad en cobol, por eso es que pregunto a la comunidad ¿ que potencial tiene la generacion automatica de codigo con un lenguaje como COBOL?

  16. lopez says:

    Raimundo: gracias por visitar este blog y cometar este articulo.

    Interesante… Creo que hay generadores de codigo para COBOL. Ciertamente se podria hacer uno desde AjGenesis. No tengo problema en hacerlo, pero necesitaria una aplicacion de ejemplo.

    Desde un modelo podriamos generar el programa COBOL que necesitamos.

    Lo mismo podemos generar para COBOL, o para Java, o para lo que se nos ocurran. Estoy escribiendo en este blog una serie de post de justamente, como desde un modelo, ir generando cada vez mas artefactos, en distintas tecnologias.

    Nos leemos!

    Angel “Java” Lopez

  17. Reinaldo says:

    Hola Angel. Y Spring Roo ? Que te parece ?

  18. lopez says:

    Reinaldo: Spring Roo me parece interesante porque lleva de nuevo la generacion de codigo a Java. Y tiene ya artefactos para generacion listos para usar.

    Por otro lado, no parece tener un modelo central, y esta muy orientado a Java y relacionados.

    Lo que propongo es independiente de la tecnologia (Java, .NET, base de datos, NoSql, lo que venga el dia de maniana), y con un modelo. Y hasta sirve para ser independiente de la tecnologia, sin modelo, si fuera necesario.

    Tambien permite escribir el codigo que uno quiera escribir.

    Modelo(s), tareas y plantillas, permiten que “sky is the limit” ;-)

  19. Alberto Héctor Rolandi says:

    Comparto plenamente los conceptos vertidos por Ángel. Existen distintas visiones en la construcción de software. Está aquel, que como un albañil, va poniendo ladrillo sobre ladrillo para construir la pared que necesita y luego vuelve a hacer lo mismo para otra pared. Está aquel que busca en el mercado paredes similares a las que necesita, las transporta, las adapta y termina a mano el resto. Está también el que busca casas ya armadas, donde su partes encajan perfectamente y así podemos seguir con la albañilería.
    Lo cierto es que en el mundo de hoy se construye todo tipo de edificios con todo tipo de materiales y se construyen hasta islas artificiales ¡!!! …. Es imposible establecer una célula común a todas las construcciones.
    Ahora bien, si vamos por el “dunga dunga” que dice Ángel y siguiendo con el tema de la construcción, nosotros podemos aprender, desde una determinada construcción, a imitar las partes y los materiales para realizar una construcción similar. Para ello, me concentraría en estudiar las partes que son fijas y no puedo cambiar por cuestiones de estructura y que partes podría variar para darles una forma diferente.
    Siguiendo este concepto y aplicándolo al tema que nos interesa podemos decir que en toda construcción de software existe algo fijo que es la “estructura” y algo variable que es la “funcionalidad”. Cambiando los valores en lo variable obtendré otra funcionalidad.
    Entonces, la inteligencia que necesito aplicar para poder hacerle “dunga dunga” a una construcción, está en saber aislar las partes variables. A estas partes variables las podemos llamar “especificaciones” y entones a partir de estas especificaciones podemos ir cambiando la funcionalidad de la construcción.
    Ojalá, como dice Ángel, se pudiera llegar a un sistema experto que haga esto, es decir, distinguir lo variable de una construcción para poder aislarlo en especificaciones. No digo que sea imposible, pero vamos a tener que entrenarnos mucho mentalmente para poder aislar la materia fundamental de todo software, distinguir como esa materia fundamental compone su estructura y a partir de allí, estructurar las especificaciones que hacen al aspecto variable.
    Mientas tanto, podemos decir con absoluta certeza, que toda construcción de software se expresa a través de texto, es decir, tanto las líneas de programas, comentarios, colas de ejecución, etc. No son más que “texto”. El texto, analizado como tal, es una “serie” de caracteres y cada carácter será una letra, un número o un carácter especial. En toda construcción estos textos van tomando formas de estructuras que hacen a una parte fija y a otra variable. Podemos entonces, a partir de allí, construir un generador para ese tipo de construcción aislando el texto variable, llevar ese texto variable a especificaciones simples de modo que ese texto luego pueda ser regenerado con otros valores y manteniendo la integridad de la estructura. Al hacer esto, al cambiar las especificaciones estamos cambiando la funcionalidad del software para ese tipo de construcción.
    Quiere decir entonces, que por el momento, deberíamos tener un generador distinto para cada tipo de construcción. Estos diferentes generadores nos irán aportando información como para establecer a partir de allí los elementos comunes que existen en estos generadores, como por ejemplo, que manera usan para reemplazar texto, como cuidan la integridad de las construcciones, etc.
    Tampoco se nos escapa, que estos generadores también son construcciones y que por lo tanto también son alcanzados por las generales de la ley y se les puede hacer “dunga dunga”.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>