Legacy code. Guía básica de supervivencia

Legacy code

La verdad es que no estoy muy seguro por donde empezar a escribir esta entrada. Después de darle alguna vuelta creo que lo idóneo es empezar por la situación que me ha motivado a redactar estas líneas.

Hace algunas semanas me han incorporado (subrayo lo de me han) a un proyecto que se está convirtiendo en uno de los retos mas complicados que me he enfrentado en estos años como desarrollador de software. Se trata de un proyecto software con solera, pero que sigue en producción, y parece ser que cumpliendo su propósito. Efectivamente el reto al que me refiero es al legacy code. No es la primera vez que tengo que lidiar con código heredado -ni será la última- pero en esta ocasión estoy disfrutando (nótese la cursiva) de cosas que jamás pensé que tendría que ver, y mucho menos tocar. Ante esta situación, y antes de que el desánimo me pueda, he vuelto a recordar ciertas lecturas, que recomiendo, como son: working effectively with Legacy Code, Clean Code y Refactoring Improving the Design of Existing Code.
A pesar de mi buena predisposición, he de confesar que en estos últimos días me estoy viendo sobrepasado, e incluso una mañana he tenido que salir a tomar aire fresco, pues estaba mareado de tanto if-else-if. Por tanto me he decidido a escribir este post como terapia.

Vaya por delante que tengo el máximo respeto por los desarrolladores que antes que yo han lidiado con el proyecto. Estoy seguro de que cada línea de código (hasta el último punto y coma) que hay tiene su motivo, que aunque yo no lo vea en aquel momento que alguien lo escribió seguro que si tenía su sentido.

A continuación resumiré, como afronto la situación descrita, y lo que yo creo me ayuda a sobrevivir con el Legacy Code (recomiendo leed este enlace).

A que me estoy enfrentando

Antes de tan siquiera mirar una sola línea de código, lo que me gusta es hacerme una idea general del proyecto. En este sentido "abro las orejas" y escucho todo lo que tengan a buena estima contarme sobre el mismo: tiempo que lleva, tecnologías usadas, entorno de desarrollo (equipo y herramientas), quien es el cliente, plazos de las entregas (si los hubiese), donde está el código fuente, etc.
Lamentablemente en la mayor parte de los casos la información proporcionada es escasa, y se espera a que mirando en la bola de cristal se vaya descubriendo. Además eso de heredar código parece que conlleva que el antecesor no estará disponible para consultarle dudas, o no se acordará.

Una vez tenemos información suficiente, lo siguiente es descargar el código fuente (del repositorio  de control de versiones ¡estupendo!). Espera, espera, no toques nada. Antes vamos a mirar las métricas de control de calidad del código fuente (sonarQube, PMD, ya sabéis lo normal).

Una vez analizado el código con las herramientas que ayudan a ello, a mi me gusta verlo por mi mismo; es decir,  navego en los paquetes, miro las clases, los ficheros de configuración, estructura, dependencias, ... Una pasada por lo alto para tener una visión global de la organización del código, incluso comentarlo con otros compañeros, para valorar la calidad percibida.

Con las tres cosas que he mencionado anteriormente ya me puedo hacer una idea por lo alto de a que me estoy enfrentando. Por poner un ejemplo en el proyecto que me ha empujado a escribir esto, la situación es bastante desalentadora (al menos para mi): miles de líneas de código, cientos de clases java, otro puñado de javascript, ficheros de propiedades, jsp, ANT. En cuanto a las métricas solo voy a mencionar una: hay clases (y no pocas) con una complejidad ciclomática superior a 50 (algunas mas de 80).

Manos a la obra

Ya me he familiarizado con el proyecto, he dedicado horas (incluso días) a ponerme al día (es decir he viajado al pasado mas de 10 años) con el framework en que se desarrolló, la arquitectura de la aplicación, y puedo compilar y ejecutar en un entorno de desarrollo. Aún tengo alto desconocimiento del negocio y de la tecnología pero ha llegado la hora, estoy preparado para meterle mano a lo que sea. Eso si, con muuuucho cuidado, vaya a ser que rompa mas de lo que arregle.

Tengo presente que algunas de las técnicas descritas en los libros que mencioné, no va a ser viable aplicarlas (refactorizar, o mejorar el código existente implicaría excesivo riesgo). Ante esta situación me armo de paciencia y empiezo a acometer las tareas que se me encargan. Estas tareas se dividen en dos tipos:
  1. Corregir bugs (errores). Dentro de lo malo esto es lo menos malo. Vas en plan detective hasta que encuentras ese pedacito de código que no hace lo que se espera, lo cambias, cruzas lo dedos y a ver si funciona, por supuesto este es un proceso cíclico hasta que deja de producirse el error descrito en la tarea. En un código con una media de complejidad cliclomática superior a 40 esta tarea es cuanto menos dura.
  2. Implementar nuevas funcionalidades. Aquí es donde se complica la situación. No conoces muy bien el negocio, y estás como quien dice empezando a tocar el código, que tampoco es que domines. En este caso si que se pueden aplicar algunas técnicas, para intentar que el código nuevo sea un poco mas legible (mantenible), y aislar en la medida de lo posible del código heredado. Estoy en ello (de verdad), pero en esta ocasión no me está resultando nada sencillo.
Visto así tampoco parece para tanto, pero ahora viene lo bueno: el tiempo que me está consumiendo realizar las tareas es bastante elevado,  y el desgaste mental al que me estoy viendo sometido es horrible.

Podría ser peor

Efectivamente podría ser peor, y de hecho lo es. Porque aunque algunas veces la calidad percibida, es subjetiva, en este caso ya me avisó de que la aplicación iba a ser difícil de probar, ante la ausencia de test unitarios, funcionales, de integración y ni mencionar los tan famosos smoke Test.

Parece ser que la moda del TDD es algo reciente, y en la herencia del código no van incluidas las pruebas. Esto supone un incremento en el tiempo de puesta en producción, ya que además de probar las correcciones o nuevas funcionalidades, se debería comprobar que no se ha "roto" otra cosa.

Reglas básicas de supervivencia

Paciencia, esa es la regla básica para sobrevivir al código heredado. La necesitaras para entenderlo, corregirlo, mejorarlo y si tienes suerte migrarlo. Aunque la verdadera suerte es no heredarlo 😥.

Lee y relee los libros que he mencionado antes, y algunas lecturas mas. Al menos te darás cuenta de que no eres el único pringado que tiene que lidiar con estas cosas.

Y la regla de oro es que no hagas a los demás lo que no quieras que te hagan a ti. Así que cuando estés programando piensa en los demás, y piensa en ti mismo, quien sabe si al cabo de un tiempo heredarás tu propio código.

Como no quiero alargarme mucho voy a dejarlo aquí. Ya estoy pensando en la siguiente entrada: Legacy Framework.

Voy a terminar pidiendo disculpas por el código que dejo en herencia, aunque intento que sea el mejor posible, soy consciente de que no siempre es así. Para quien le toque solo tengo que decirle un par de cosas: paciencia y a refactorizar.


Y tu ¿Sabes de alguna técnica que te ayude a sobrevivir al Legacy Code? cuéntamela, me vendrá muy bien.

Comentarios