Cómo ser ágil sin enterrarse en deuda técnica

Usar Scrum al 100% no basta, es necesario complementarlo con unas prácticas técnicas que lo hagan sostenible a largo plazo.

Rubén Antón 8 Julio 2019

Esta es una ponencia que di en la Semana Informática 2019 organizada por el Colegio Oficial de Ingeniería Informática de la Comunitat Valenciana. La exposición iba acompañada de una comunicación escrita que sintetiza las principales ideas desgranadas en la misma, puedes encontrarla más abajo.

Comunicación

La agilidad está en auge. Siendo Scrum la metodología de elección para la mayoría de organizaciones que buscan sumarse a la transformación. Pero pocos son los que leen la letra pequeña: Scrum evita deliberadamente recomendar unas prácticas técnicas que hagan sostenible la entrega de valor en los ciclos cortos que propone. Delega dicha responsabilidad en el equipo, que, desconociéndola, suele pasarla por alto.

Así, el equipo se entierra poco a poco en deuda técnica. Conforme pasa el tiempo, cada vez es más costoso añadir nuevas funcionalidades. Con cada cambio, surgen defectos en partes que antes funcionaban correctamente. Lo que conduce a un ambiente enrarecido, rotaciones de personal y re-escrituras que siguen el mismo desenlace.

Efecto de la deuda técnica
Efecto de la deuda técnica

Afortunadamente, existe un tratamiento: unas prácticas que permiten desarrollar software de manera iterativa e incremental. Manteniéndolo bien testeado, bien diseñado, enfocado en la funcionalidad y listo para ser desplegado en cualquier momento.

Testing automatizado

El primer paso es el testing, piedra angular que permitirá evolucionar el diseño del sistema adaptándolo a los cambiantes "requisitos". Por ello, se hace necesario asegurar el valor entregado por medio de una suite de regresión automatizada. Dado que es inaceptable que la adición de nuevas funcionalidades rompa las antiguas.

Cada historia de usuario debería ir acompañada de unos criterios de aceptación. Ejemplos concretos y ejecutables acordados tras una conversación entre negocio y desarrollo. Posteriormente, una vez automatizados, se convierten en test de aceptación.

Pirámides de test
Comparación pirámide de test

A su vez, los programadores, a medida que desarrollan, los complementan con test unitarios, de integración y de contrato. Estos sostienen la arquitectura y protegen la valiosa lógica de negocio. El objetivo es perder el miedo a realizar cambios en el código existente.

Diseño incremental

Por otro lado, el diseño deja de ser una fase, como pasaba en el modelo en cascada, para convertirse en una actividad. Se invierte en él cada día ajustándolo a las necesidades actuales del sistema.

Diseño ágil
Diseño en un contexto ágil

Para ello se hace uso de técnicas de refactoring: modificaciones en el diseño del código existente que no cambian el comportamiento observable del mismo. Pequeños cambios que mantendrán el sistema funcionando correctamente y reducirán el coste que supone modificarlo.

Existen dos momentos clave para refactorizar. Uno, antes de añadir una funcionalidad: al observar que esta será difícil de absorber por el sistema, se buscará facilitar su introducción. Otro, después de añadirla: si el diseño se resiente, se aliviarán las posibles tensiones que haya provocado.

Integración y Entrega Continua

Finalmente, sólo queda por recorrer la última milla: integrar el nuevo incremento en el producto, asegurando que todo sigue funcionando correctamente, y entregarlo al usuario final. Puesto que esto ocurrirá al menos una vez cada iteración, deja de ser viable hacerlo de una forma manual.

Última milla
La "última milla"

La integración continua permite mantener el sistema listo para ser desplegado en cualquier momento. Al contrario de lo que muchos piensan, no se trata de una herramienta, si no de una actitud. Consiste en integrar varias veces al día. Ya que cuanto más se tarde en hacerlo, más costará y más impredecible será su coste.

Cada vez que un desarrollador integre un cambio, se desencadenará el proceso de build. Automáticamente se construirá el sistema al completo y se correrán todos los test en 10 minutos o menos. La restricción temporal es clave, puesto que si se tardase más, se integraría mucho menos a menudo. Para terminar, se desplegará en un entorno similar al de producción. Disminuyendo así el riesgo y convirtiendo en algo trivial la consecución de una entrega continua.

Integración Continua
Integración Continua

En definitiva, estas cuatro prácticas representan el santo grial del desarrollo iterativo. Lo más importante es que se refuerzan entre sí. El diseño incremental se apoya en el testing automatizado; la integración continua nos da la confianza de que los cambios están listos para ser entregados; y junto con la entrega continua está garantizado que vamos a ser capaces de desplegar muy a menudo, de manera rápida y segura.

Como resultado, recuperaremos la confianza de negocio. Dejaremos de suponer un cuello de botella y seremos capaces de mantener una velocidad sostenible de manera indefinida.

Recursos de interés

Puesto que el tiempo era limitado y el público objetivo muy amplio no pude entrar tan en detalle como me gustaría. Las ideas expuestas están fuertemente influenciadas por Extreme Programming (XP) y Continuous Delivery (CD). A continuación dejo algunos enlaces por si quieres profundizar en alguna de las prácticas:


Si te has quedado con alguna duda, siempre puedes contactarme a través de mi email: ruben@rubocoptero.com.

Como no tengo comentarios en el blog, me encantaría continuar la conversación en Twitter. ¡Todo feedback es bienvenido! Si crees que hay algo que se puede mejorar me ayudarías muchísimo.