El código no cuenta toda la historia
Un artículo de Rafa G. Blanes
No hace mucho publiqué en GitHub un pequeño repositorio de nombre Red Entities, un simple pero eficiente object-mapper de consultas, actualmente compatible con Sqlite y varios sabores de MySql.
Lo he retomado para validarlo con la última versión de Node y además porque quiero incluir compatibilidad con PosgreSQL y Sql Server, sobre todo ahora que estoy terminando de documentar Mantra Framework para liberarlo.
Y lo curioso (e interesante), es que a pesar de haber desarrollado yo mismo ese proyecto software, me ha costado un poco de trabajo volver a asumirlo, aunque está bien soportado por tests y hasta me atrevería a decir que el diseño es sencillo pero robusto y eficiente, y tampoco es una librería de tamaño grande, ni mucho menos.
Tardé algo de tiempo de recordar cómo estaba implementado el mecanismo de inyección de dependencias, cómo lo dejé preparado todo para incluir nuevos conectores de acceso a otro tipo de bases de datos y cosas por el estilo.
Aunque está documentado a nivel de API, con la suficiente información para que cualquiera lo pueda usar en un proyecto en Node, este es uno de los grandes problemas a los que nos enfrentamos en el desarrollo de software, sobre todo en proyectos más o menos complejos y grandes, y que se vuelve todavía peor cuando el diseño es deficiente y hay mucha deuda técnica acumulada; esto es, leer el código, por bien que esté estructurado y desarrollado, no te permite comprender la visión de conjunto de todo el proyecto con facilidad.
Para comprender bien un proyecto software, el código no es suficiente.
No estoy hablando de entender lo que hace una clase, o un método concreto dentro de ella, o incluso una librería de pequeño tamaño, sino de toda aquella información sobre la que se ha desarrollado el proyecto, con la que se han tomado decisiones y que no está reflejada claramente en el código, puesto que la forma y estructura de éste es consecuencia de lo primero.
Se podrá pensar que en el código está todo: clases, módulos, archivos de configuración; sin embargo, existe mucha más información que no está ni puede estar en él y que es imprescindible para comprenderlo por qué el proyecto se hizo de ese modo y para qué, más aún cuando llega el momento en que otros desarrolladores distintos de los originales lo tienen que asumir.
Esto, precisamente, ha sido algunas de las peores experiencias profesionales que recuerdo: haber tenido que retomar proyectos realizados por otros (que ya ni siquiera estaban en la organización para la que trabajaba). Recuerdo uno en concreto en java y otro en php, con miles de líneas de código y con varios años de desarrollo y evolución y con muchísima deuda técnica, y sin ningún tipo de documento de soporte: el código y punto.
Semanas de trabajo para comprender no solo lo que se había hecho por el momento, sino por qué, y sin posibilidad de preguntar a los autores, tan solo tú, el proyecto y mucha imaginación.
Retomar un trabajo hecho por otros suele ser en software una auténtica pesadilla que, en el mejor de los casos, puede llevar bastante tiempo, tan solo para comprender el proyecto suficientemente bien como para modificarlo y evolucionarlo.
Ahora bien, una vez que crees que lo has comprendido y puedes añadir cambios o hacer modificaciones, ¿de qué modo?, ¿con qué criterio en coherencia con lo que ya hay hecho?, ¿hay alguna razón desconocida por la que los antiguos desarrolladores hicieran algo concreto que tú habrías hecho de otro modo?
Lo que suele ocurrir es lo siguiente: llega un nuevo desarrollador que tiene que retomar un proyecto que no conoce y cuyos autores ya no están; se esfuerza en comprender lo que hay, cómo y por qué, pero, como digo, le falta mucha información y, si consigue echar a andar el proyecto finalmente, lo hará a su modo, seguramente añadiendo un nuevo estilo de diseño al anterior, modificando cosas sin saber por qué se hicieron de ese modo, modificando quizá el diseño original (o añadiendo uno nuevo), violando los criterios de la arquitectura (sin saberlo), aumentando así la falta de coherencia entre otros males.
Multiplica esto por varias manos diferentes y ya lo tenemos todo para un buen plato de código espagueti.
O sea, una situación bastante común en nuestro sector.
Me pregunto, ¿se puede evitar? Sobre todo, ¿se puede evitar sin necesidad de una documentación costosa y exhaustiva?
Para comprender bien un proyecto software, no solo es necesario que el código sea legible, con buena cobertura de pruebas, bien organizado, con clases o métodos sencillos, sin redundancias, limpio, sin deuda técnica, todas estas cosas que ya sabemos y de las que hablo mucho en mis libros, en concreto en El Libro Práctico del Programador Ágil.
Sobre todo en proyectos complejos y grandes, te pueden surgir preguntas del tipo siguiente:
- ¿Cómo es la arquitectura del sistema?
- ¿Qué criterio se ha usado para organizar los assets del proyecto? ¿Es coherente ese criterio en todo el proyecto?
- ¿Cuál es la intención de diseño en esto y aquello?
- ¿Cómo se crea un entorno de desarrollo y de testing?
- ¿Qué flujo de trabajo es necesario para ejecutar todas las pruebas (si es que existen, claro)?
- ¿Hay control de versiones? ¿Y cómo se sigue?
- ¿Cómo se han resuelto ciertos requisitos no funcionales como la escalabilidad, restricciones, la seguridad, etc.?
- ¿Dónde está localizada la configuración?
- ¿Están las librerías actualizadas?
- ¿Es compatible el proyecto con la actualización de las librerías de las que depende o hay alguna excepción?
- ¿¡Por qué ese trozo de código está comentado!?
- ¿Hay en algún sitio un diagrama de clases con su relación? Si lo hay, ¿estará actualizado?
- ¿Por qué se usó esa librería en lugar de esa otra más popular? ¿Había alguna razón para ello?
- ¿Qué criterios de usabilidad se siguió para la interfaz de usuario?
- ¿Cómo se compila el proyecto o se pone en funcionamiento? ¿Qué dependencias hay?
- Si el proyecto está dividido en capas o tiers, ¿dónde se localizan en el codebase?
- ¿Cómo se escala el proyecto en un despliegue real?
- Si existen bases de datos, ¿es su modelo suficiente para comprender su diseño?
Y un larguísimo etcétera. Si te fijas, muchas preguntas que para cualquier proyecto conocen bien los desarrolladores que trabajan en él desde el comienzo o desde hace mucho tiempo, pero para un recién llegado, esa información tan importante no existe salvo que alguien se la cuente. Claro, para el que lleva trabajando en ese proyecto un año, todo lo anterior es trivial, lo tiene todo en su cabeza a falta de documentación, sin darse cuenta de la cantidad de decisiones, asunciones y normas no escritas con las que se trabaja cada día... al margen de la misma naturaleza del código.
Esta dificultad suele aumentar cuando el proyecto lo han estado desarrollando las mismas personas durante años y no se han preocupado de simplificar y mucho menos de documentar nada, puesto que es tanto el conocimiento del mismo que tienen que no lo creen necesario, sin saber que esto precisamente puede ser un gran problema para quienes lo tengan que retomar en el futuro (y en ese futuro lejano, puede que sean ellos mismos quienes se encuentren la patata caliente después de haberlo olvidado casi todo).
Uno de mis mantras preferidos en software viene a decir algo así como que...
"Siempre tenemos que programar para que los demás comprendan lo que hemos hecho y por qué".
Pero añado algo más: no solo a nivel de código, sino también a nivel del proyecto en su globalidad.
Sin ir más lejos, recientemente he visto de primera mano la dificultad de asumir un proyecto de bajo nivel por personas nuevas en un equipo. Tanto es así y hasta tal punto puede llegar la dificultad, que en ocasiones es casi imposible asumirlo de modo que hasta se plantea la necesidad de volver a hacerlo desde cero, si es que la empresa se lo puede permitir, claro está.
Es cierto que el manifiesto ágil dice en uno de sus puntos:
"Working software over comprehensive documentation (software que funciona sobre una documentación exhaustiva)"
Pero esto se ha interpretado mal: no quiere decir que no se documente absolutamente nada, sino que es más importante darle prioridad a que el software funciona que a crear documentación excesivamente exhaustiva, pero de ahí a documentación cero... Esto tenía mucho sentido en una época en donde esas metodologías pesadas te obligaban a presentar auténticos volúmenes con cientos de páginas con diagramas UML, etc. (que, por otra parte, nadie leía).
¿Hay entonces un camino intermedio entre no documentar nada y sobredocumentar?
¿Cómo documentar correctamente un proyecto software para que todo lo anterior no ocurra? Dicho de otro modo, ¿cómo se puede contar la historia completa sin caer en el error de documentar demasiado e innecesariamente y que no sea un coste excesivo en el proyecto?
En ocasiones se cree que lo único útil a documentar debe ser la arquitectura (si es que alguien se ha encargado de plantearla o existe un rol de arquitecto, claro), las APIs, y poco más; como he dicho, todo eso es necesario pero no suficiente.
A continuación propongo una serie de documentos que entiendo que, de existir, son un mínimo para que cualquiera pueda retomar un proyecto software con mucha menos dificultad y con menos dolores de cabeza (nota, apenas unas cuantas páginas como mucho para cada uno de estos documentos):
- Contexto: indica de qué va el proyecto, para qué clientes, etc.
- Vista funcional: indica a grandes rasgos, las características más importantes del proyecto.
- Atributos de calidad: indica cómo se han resuelto los requisitos no funcionales del sistema (escalabilidad, rendimiento, i18n, l10n, monitorización y mantenimiento, etc.)
- Restricciones: ¿hay restricciones?, ¿cuáles?, ¿cómo se han abordado?
- Despliegue: indica cómo desplegar el proyecto en un nuevo entorno.
- Modelos de datos
- Principios: ¿qué principios se han seguido en el desarrollo? Por ejemplo, ¿se usa un ORM, está dividido en componentes desacoplados? ¿Cuál es la política de trazas de log o gestión de excepciones? ¿Se usa SOLID? ¿Cómo está implementado en el codebase?
- Configuración: ¿cuáles son los parámetros de configuración y dónde se encuentran?
- Log de decisiones: indica cuáles han sido las decisiones de diseño o tecnológicas más relevantes.
- Operación y soporte: ¿cómo se realiza la operación del sistema y se da soporte al mismo?
- Guía de usuario.
- Entorno de desarrollo y de tests: indica cómo crear desde cero un nuevo entorno de desarrollo y de tests.
- Y, por supuesto, el documento de arquitectura.
Según el tipo de proyectos, puede que parte de esta información no sea necesaria, pero de existir, desde luego arrojaría muchísima luz acerca de cómo y por qué se ha implementado así. Me atrevo a decir que incluir todo lo anterior para cualquier proyecto se puede quedar en un documento del orden de solo varias decenas de páginas, no más.
La curva de aprendizaje de alguien que aterriza en un proyecto ya en marcha, es un coste y un riesgo que los gestores o managers deben tener en cuenta. A mayor deuda técnica y más déficit de documentación, mayor coste y mayor posibilidad de que las nuevas incorporaciones añadan todavía más deuda técnica.
Ahora que precisamente, en el momento de escribir esto, estoy cerrando una versión de producción de Mantra Framework, me doy cuenta de que incluir en un apartado la documentación anterior que tenga más sentido para el proyecto, es en realidad, algo relativamente sencillo y poco costoso de realizar. Además, documentando, he descubierto detalles que he mejorado y varias inconsistencias que también he resuelto. Esto es, en cierta medida, documentar te ayuda a mejorar el proyecto.
Pero ya sabemos, a los desarrolladores, eso de documentar, como que siempre intentamos dejárselo a otros...
Ahora en serio, un proyecto profesional no se puede dar por cerrado si no se entrega ese mínimo de documentación que indicaba más arriba y que cuesta realizar mucho menos de lo que imaginamos.