¿Han pensado en este concepto? Un programador en la Argentina es un analista, un codeador, una persona que resuelve problemas. A veces incluso es organizador, anticipador, y se prepara para lo que viene. Toma decisiones y colabora junto a los demás para realizar sus tareas.
En cambio un generador de código es una máquina boba de escupir código. Es un mono que programa a una velocidad rampante. Pero no sabe ni qué está programando, ni qué está escribiendo. Él sólo escupe código. Para eso lo inventaron, y para eso está. No realizará análisis ni tomará decisiones.
Quien puede hacer eso es quien usa al generador de código como una herramienta. El decide qué debe crearse y cómo.
Ahora, todo esto me parece correcto pero quedándonos con sólo esta idea nos podríamos confundir un poco. Podríamos pensar que el código que se "escupe" puede ser redundante y sin reutilización. ¡Total, se re-hace en un segundo!. Es una de las principales premisas que veo en los generadores de código empresariales. Hacen un código desastroso, con casi ninguna herencia ni orientación a objetos, porque igualmente lo podemos re-generar con los cambios en un segundo. El tema es que nos encontramos con los siguientes problemas con el código una vez generado.
La reutilización no se tuvo en cuenta, por ende se hace difícil utilizarlo el código hecho en un futuro.
Por ejemplo, generamos automáticamente las clases de acceso a datos. Lo que no se tuvo en cuenta es que dicho código utilice algún framework ORM propietario o de terceros, cosa de que el código sea más reutilizable y legible.
Por ejemplo, quizás estas clases de acceso a datos se generan con SQL Server en la cabeza, y cuando necesitamos pasar a Oracle tenemos que ir a re-generar el código (en el mejor de los casos!). Y cuando re-generamos nos encontramos con que:
- El comportamiento del código es diferente
- Interfaces desactualizadas o incompatibles.
- Hay métodos que recibían objetos de un tipo y ahora reciben de otro
- La nomenclatura de procedures y parámetros que está utilizando es diferente al implementado
- Los scripts SQL generados tienen errores
- Los templates de generación de código nunca se probaron
O sea que podemos caer en una situación incómoda. En realidad nosotros deberíamos tener una clase de LÓGICA de acceso a datos. De ahí viene el nombre "DAL". Data access LOGIC. Pongo LÓGICA en caps porque para mí eso significa que debe manejar "cómo" se deben acceder los datos y de qué forma se traducen a entidades/objetos del sistema. Para mí NO debe tener detalles de bajo "qué" están dichos datos.
Utilicemos clases de acceso a datos inteligentes, como si las hubiera programado un programador decente. Que utilicen un framework que nos permita cambiar la base de datos simplemente cambiando la configuración, no re-generando todo el código.
Terminamos con un archivo donde "tocar" y un archivo donde "no tocar"
Esta también es típica. Para una clase nos genera dos archivos de partial class, donde uno tenemos un cartel gigante que dice "NO MODIFICAR". Esto para mí es un conocidísimo anti patrón. Tener 2 archivos para una clase es un tema. Tener 100 archivos para 50 clases es otra.
Otra cosa que he visto a veces es que todo el código generado lo pegan en un sólo archivo universal (que a veces alcanza las decenas de miles de líneas de código) y luego es un desastre regenerar algo. Esto es obviamente una respuesta poco pensada al hecho de darse cuenta que tener tantos archivos que no se pueden pisar es inútil.
Lo cierto es que nuestros generadores deberían ser inteligentes. Tomar el código que deben reemplazar y listo. No que debamos regenerar todo y pisar los fuentes, eso es medio negrada. Simple y puede ser efectivo si se controla como corresponde, pero a la larga trae problemas.
Para lograr esto tendríamos que tener metainformación sobre las clases generadas. Y qué mejor para eso que Reflection!. En .NET al menos podemos consultar cómo está compuesta una clase, y luego el generador puede decidir qué reemplazar y qué no, y ante un código que no sabe que hacer, dejarnos la decisión a nosotros.
Esto nos permitiría, además, pensar en regeneraciones parciales de clases. El código que debe crearse debe tener la menor cantidad de correspondencias privadas internas entre métodos y propiedades posibles, sin sacrificar la cohesión y la reutilización.
De repente algunos eslabones de la cadena de archivos generados no sirve
A veces, por la arquitectura seleccionada, algunos eslabones no sirven para nuestro sistemas. Imaginemos, por ejemplo, que nuestro generador nos crea unos webservices que luego llama desde la UI, por decir una boludez. Quizás nuestro sistema posee una arquitectura donde la UI se comunica directamente con la capa de negocio. Por ende, estaríamos teniendo que realizar un trabajo manual de adaptación sólamente para nuestro sistema.
Lo que deberíamos tener es una configuración de cómo se interconectan las capas generadas. Cada capa tiene sus propios templates que generan sus archivos, pero sería bueno que nuestro generador reconozca la configuración que nosotros deseamos, y nos genere las dependencias correctamente con nuestra arquitectura. Entonces puedo generar que la UI se enlace a WebServices, o que la UI se enlace a Negocio, o que la UI se enlace a la base de datos (horrible) según me convenga a mí. Y eso sólo con unas configuraciones. Es más fácil de armar de lo que parece.
Tomamos decisiones de arquitectura basándonos en nuestras herramientas y no en nuestros conocimientos
Este punto es importantísimos. Supongamos que creamos un generador de código que nos crea las siguientes capas:
- Capa de Acceso a datos
- Capa de Entidades
- Objetos Estáticos tipo Facade que se comunican con la base de datos (una especie de Negocio pero con una implementación fea)
- UI en archivos ASPX que se comunican sólamente con los objetos estáticos.
Cuando nuestros profesionales analicen y decidan "che, tengo una arquitectura mucho mejor", no la podrán aplicar hasta re-escribir los templates (en el mejor de los casos) o el generador de código. Los proyectos iniciarán y habrá una desmotivación por no poder aplicar una mejor arquitectura solucione los problemas de esta arquitectura auto-generada, simplemente por temas de tiempo (Que probablemente perdamos mas adelante).
Y así podríamos seguir mencionando problemas de los generadores de código actuales. Lo mejor sería tener un generador compuesto por pequeñas partes que nosotros podamos ir mejorando de forma independiente, manteniendo ciclos de desarrollo cortos, como para poder irlo mejorando seguido, y no tener que esperar a tener 3 meses con poco trabajo, que generalmente nunca ocurre. Todos los software se actualizan constantemente. Pero los de uso interno rara vez. ¿No habrá un problema ahí?
Los dejo con esta idea.