Mi amigo Guillermo me remitió un email hace poco en el que detallaba un concepto que ya conocía hace tiempo, pero que no había visto tan bien explicado hasta el momento (sí, tenía que haber leído antes a Cunningham), el tema era: La deuda técnica en scrum, ¿lo revisamos?
En resumen y tal y como lo enunció Ward Cunningham:
Hacer código de mala calidad a toda prisa, es como pedir un crédito: puede que obtengamos un beneficio a corto plazo pero si tenemos que seguir desarrollando ese código, tarde o temprano tendremos que pagar todo el tiempo que nos habíamos ahorrado y los intereses. Refactorizar código mal escrito es siempre más difícil que escribirlo bien desde el principio.
No digo que programar rápido sea causa de programar mal pero sí que programar de forma táctica y centrado solo en la tarea actual para hacer que nuestro problema se resuelva sin tener visión en el conjunto del programa y los demás elementos, nos puede hacer perder la estrategia general del desarrollo y hacer nuestro diseño muy complejo. Un diseño complejo termina siendo mucho más costoso de aprender para nuevos desarrolladores y de modificar, corregir, adaptar o ampliar para todos en general.
Un código escrito mal por acelerar el proceso de entrega o por no tener suficiente tiempo para adaptar ese nuevo código al resto del sistema acarrea una carga que va aumentando a medida que pasa el tiempo. Son los intereses de esa deuda que hemos adquirido y que seguiremos pagando tardando más tiempo del necesario en implementar nuevas características que si hubiésemos invertido una cantidad de tiempo mayor al principio.
Escrito mal no quiere decir que el código no funcione o no cumpla su cometido sino que el nivel de calidad interna es muy baja. Uno de los motivos de que esto suceda es no tener una visión global del sistema y su estrategia tomada en el diseño.
La programación táctica y la estratégica
En el libro A Philosophy of Software Design, John Ousterhout nos define dos conceptos importantes a tener en cuenta en términos del diseño de un sistema: programación táctica y programación estratégica. Mientras que la programación táctica se centra en obtener un resultado lo antes posible solo centrándose en obtener el código funcionando que se necesita, la programación estratégica incluye la revisión del diseño del sistema e implementar ese código de forma coherente al sistema que se está desarrollando permitiendo una coherencia que permita abordar fácilmente ese código en siguientes sesiones.
El extremo de los programadores centrados únicamente en ser tácticos se conoce como los tornados tácticos, esos programadores que están muy bien considerados por sus jefes porque resuelven los problemas y obtienen una solución de forma rápida pero que son odiados por sus compañeros porque son los encargados finalmente de reparar el desastre y la desolación que dejaron a su paso en un código muy difícil de entender y muy difícil de mantener.
¿Cuándo es bueno contraer deuda técnica?
Contraer deuda técnica no tiene porqué ser necesariamente negativo. En ciertos aspectos y momentos, sobre todo cuando desarrollamos un PMV podemos necesitar contraer esa deuda. En estos casos puede llegar a ser extremo porque una prueba de concepto (PoC del inglés Proof of Concept) puede suponer crear un prototipo de usar y tirar necesitando desarrollar desde cero y en otra tecnología diferente el producto una vez se han validado las hipótesis.
La deuda técnica suele ser negativa principalmente cuando no se reserva tiempo para corregir o pagar esos intereses y se continúa desarrollando ese prototipo de forma evolutiva pero sin una estrategia clara, solo de forma táctica y aumentando así la deuda en lugar de reduciéndola.
¿Cuándo no es buena idea contraer deuda técnica?
Contraer deudas no es buena idea, da igual el tipo de deuda de que se trate. Pero es peor aún si contraemos esta deuda por necesidad de tiempo y en previsión de que no vamos a disponer nunca de más tiempo. Es decir, cuando contraemos una deuda normalmente es para alcanzar un bien, en este caso un lanzamiento, en perjuicio de tener que pagar una cantidad mayor a lo largo de un tiempo definido. Si no dispones de suficiente dinero y no lo vas a tener en el futuro, no deberías contraer esa deuda. Simple.
Pero en tecnología no se ve tan simple porque es un poco más abstracto. Cuando contraemos una deuda técnica estamos pagando en calidad interna para obtener un tiempo extra necesario para una salida al mercado o el lanzamiento de una versión necesaria en una cierta fecha. Si esto se debe a tener un calendario muy apretado y vamos a tener que repetir este proceso de forma continua, la calidad llegará un momento que sea tan baja que pensemos que reescribir el proyecto es una gran idea.
¿Cómo invertimos en lugar de gastar?
Invertir significa emplear un tiempo extra al tiempo normal de desarrollo para refactorizar. La refactorización es una herramienta fundamental y normalmente se incluye dentro de los ciclos de desarrollo ágiles a modo de sistema de colores:
- Rojo: se implementa un prueba en el código sobre una nueva característica o un fallo reproducido y este test falla. Cumple su misión porque demuestra que el código actual no cumple con ese requisito.
- Verde: implementamos el código necesario para obtener la ejecución de nuestras pruebas limpias. Aquí hacemos el código necesario, nos centramos en resolver el problema y nada más. No es tampoco bueno caer en la sobreingeniería.
- Azul: revisamos el nuevo cambio en consonancia con el resto del sistema para comprobar que sigue siendo coherente. Pueden sucederse oportunidades de refactorización y debemos aprovecharlas en este momento. Aquí es donde se emplea la inversión de tiempo.
¿Por qué no realizar la acción de Verde y Azul de forma única? ¿No sería más rápido? En realidad no. Cuando nos centramos en corregir un problema tenemos en mente ese problema y las posibles soluciones a implementar. Podemos probar unas soluciones u otras y finalmente elegiremos la que más encaje con los requisitos dados. Si intentamos pensar en la coherencia de ese código con el resto, posibles generalizaciones o modificaciones de otras partes del código o peor aún, pensamos en el futuro y posibles formas de evolución de ese código, podemos encontrarnos en un momento de sobrecarga cognitiva.
La carga cognitiva es la cantidad de información sobre el sistema que tenemos en mente a la hora de realizar el trabajo. Cuanto más complejo sea el sistema, más esfuerzo mental conllevará simplemente mantener el contexto en nuestra cabeza para poder realizar cambios y mejoras. A este respecto, ya en 1971 David Parnas escribió en un artículo titulado On the Criteria To Be Used in Decomposing Systems into Modules (Sobre los Criterios a Utilizar en la Descomposición de Sistemas en Módulos) la importancia de la modularización refiriéndose a la ocultación de datos como un mecanismo para poder simplificar y acelerar el desarrollo.
Al igual que las metodologías ágiles señalan la importancia de descomponer las tareas hasta ser tan evidentes que su estimación es sencilla y el tiempo a emplear relativamente mucho menor, la descomposición del sistema ayuda centrarnos en la tarea a resolver cuando estamos trabajando para conseguir nuestro objetivo verde. Sin embargo, debemos concentrarnos un poco más en la visión de alto nivel una vez estemos en el objetivo azul para poder eliminar incoherencias entre nuestra solución y lo ya existente.
Una técnica bastante empleada es marcar el código en nuestra fase verde para ir sobre estas cuando entremos justamente en la fase azul.
Conclusiones
Recuerda que contraer deuda siempre tiene un riesgo, la mayoría de las veces es mejor evitarla e invertir un poco de tiempo en mantener la vista estratégica generando un buen diseño, no obstante, hay veces que debemos contraer esa deuda y adaptar nuestro ciclo de desarrollo posterior para pagarla y volver a un buen nivel de calidad interna de nuevo. No hay problema si podemos permitirnos invertir ese tiempo extra poco a poco.
Recuerda también que la acumulación de deuda termina por decrementar tanto la calidad del proyecto que muchos, aún habiendo escrito el proyecto ellos mismos lo llaman legacy.
¿Y tú has tenido que lidiar con un mal llamado proyecto legacy? ¿cómo pagas tu deuda técnica cuando la adquieres? ¿nos hemos dejado algo atrás? ¡Déjanos tu comentario!