Ingeniería de software ágil: XP y TDD I

Nos hemos vuelto total y absolutamente dependientes del software, por ello, hablamos de Ingeniería de software ágil en esta serie de artículos. El software es la sangre vital que hace que podamos funcionar como sociedad. Este tema es recurrente en los talleres y clases que imparto porque muchos de los participantes se dedican al desarrollo de software y siempre terminamos debatiendo y comentando sobre las habilidades que necesitan los equipos ágiles para construir soluciones de buena calidad de forma rápida y predecible—más o menos predecible.

Que quede claro: no hay atajos. La única forma de ir rápido—sobre todo a largo plazo—es cuidando la calidad de la solución técnica. Producir código basura no nos hace ir más rápido.

Por el contrario, aumenta la deuda técnica y eso provoca que vayamos cada vez más lento, perdiendo agilidad, como un coche de juguete que se va quedando sin pilas… hasta que se detiene completamente.

La ingeniería de software, como rama de especialización, genera mucha controversia: ¿es una ciencia?, ¿es un arte? Es una disciplina que se ocupa del diseño, desarrollo, mantenimiento y validación del software.

Se puede decir que la ingeniería de software se divide en varias fases: análisis de los requisitos, diseño, implementación, pruebas y mantenimiento. Existen diferentes metodologías y técnicas y herramientas que se aproximan a esas fases de manera diferente para garantizar la calidad y el cumplimiento de los requerimientos.

Hay quienes abordan todo el proceso con mucha planificación y un enfoque bastante rígido. Otras voces sostienen que el diseño y desarrollo de software tiene mucho de arte y poco de ingeniería.

Hay que ser pragmáticos y encontrar un equilibrio entre disciplina, adaptabilidad, agilidad, principios y estándares de buen diseño, innovación, tener un equipo bien preparado y buenas prácticas.

En cualquier caso, la calidad es un aspecto fundamental de la buena ingeniería de software. Pero hay que tener en cuenta que la calidad es traicionera: quien no la tiene, la ansía, quien la tiene a veces la descuida, aunque sepa que es una ventaja, y quien la ha tenido desde siempre aprende que hay que atenderla e invertir en ella continuamente.

Vuelta al futuro con Extreme Programming (XP)

En ingeniería de software ágil—enfatizo lo de ágil—no se ha inventado mucho últimamente y las mejores prácticas siguen vigentes y tienen su origen en Extreme Programming (XP).

La principal contribución de XP al mundo del desarrollo de software es una colección de prácticas interdependientes que se utilizan para producir software de calidad y al mismo tiempo crear un entorno y ritmo de trabajo sostenibles para los equipos, para que puedan ser más efectivos.

El siguiente diagrama corresponde al Círculo de la Vida de XP y muestra todas estas prácticas.

El Círculo de la Vida está compuesto por tres anillos concéntricos. El externo está formado por las prácticas más cercanas a las áreas de negocio y se parece mucho a Scrum. El anillo intermedio agrupa las prácticas más cercanas al equipo, cómo se autoorganizan y comunican. El tercer anillo, el más interno, define las prácticas necesarias para obtener el máximo nivel de calidad técnica:

  • Test Driven Development: asegura que toda la base de código tiene pruebas automatizadas.
  • Refactoring: asegura la mejora y refinamiento continuos de la solución.
  • Pair-programming: compartir conocimiento, revisar y colaborar para innovar y mejorar la solución técnica.
  • Simple Design: menos es más. Crear un diseño mantenible que emerge durante el desarrollo.

Automatiza con Test-Driven Development (TDD)

TDD es un tema tan amplio que se han escrito libros enteros sobre él. Es una forma muy disciplinada de programar que consiste en trabajar en ciclos que se componen de tres actividades muy interrelacionadas: escribir código, probar (escribir y ejecutar los tests) y refactorizar.

Cada ciclo puede resumirse en cinco pasos muy simples:

Los ciclos van muy rápido y son una oscilación continua entre la escritura del test y del código. Por supuesto, cuando una persona se enfrenta a TDD por primera vez lo ve como un ejercicio invasivo y como una interrupción de los procesos de pensamiento. Pero después de un tiempo, esta práctica se convierte en un hábito y no se puede trabajar de otra forma. Es adictiva.

Las pruebas también son una forma de documentación. Los tests son tal vez la forma más perfecta de documentar el código porque muestran cómo usar e invocar el sistema. No son una documentación ambigua: pueden ejecutarse y están sincronizados en todo momento con la implementación—algo que es complicado de lograr con las formas tradicionales de documentación. Cada prueba es un fragmento minúsculo e independiente que describe y valida la manera en que funciona un trozo de código.

Los pasos de cada ciclo son realmente simples y los beneficios son enormes. Teniendo en cuenta el impacto que tiene el software en nuestras vidas—y los riesgos que implica tener software de poca calidad—deberíamos plantearnos que TDD se recogiera en alguna ley y que se convirtiera en práctica obligatoria… ¿por qué no?

Refactorizar sin piedad para no atragantarnos con la deuda técnica

Todo cambia y evoluciona. Hay cosas que mejoran con el paso del tiempo—como el buen vino. Pero el software, en general, envejece bastante mal. El diseño y la arquitectura de los sistemas se desmejoran con el tiempo, se vuelven más difíciles de mantener.

El quid de la cuestión es la deuda técnica acumulada. Si no se toman medidas, eventualmente el código se convierte en un infierno imposible de mantener. Con el tiempo las entregas de nuevas funcionalidades y correcciones empiezan a consumir esfuerzos exponenciales—aquí es justo cuando muchos managers se desesperan por los retrasos y deciden añadir más mano de obra al equipo, y esto empeora la situación aún más. Es así de duro. Es así de triste. Con el tiempo la situación va a peor.

Un tipo específico de deuda técnica son los Code Smells (código que apesta). Sin ser necesariamente errores, los code smells son síntomas o indicadores de que algo no está bien: hay código duplicado, métodos obsoletos o bloques demasiados largos. También un uso excesivo de patrones de diseño. Poca cohesión. Alto nivel de acoplamiento.

¿Hay esperanza? ¿Es posible evitar la parálisis progresiva producida por estos problemas?

El antídoto es la práctica de Refactoring (refactorización). Refactorizar consiste en mejorar la estructura interna de la solución técnica (código, diseño, arquitectura) preservando el comportamiento externo—especificado por las pruebas.

Es una práctica propuesta por XP que sirve precisamente para prevenir la situación de parálisis anterior. Refactorizar la solución continuamente es otro buen hábito de los equipos ágiles—y como debería ocurrir con TDD, ¡debería convertirse en una ley!

Las prácticas de XP están interrelacionadas. Para poder refactorizar sin riesgos necesitamos una red de seguridad: tenemos que contar con una batería completa de pruebas automatizadas que nos permitan validar el impacto de los cambios a medida que los hacemos—asegurar que no hemos roto nada.

Con las pruebas automatizadas producidas por TDD es posible hacer cambios y limpiar el código sin miedo. Sin límites. De forma rápida y profesional.

Los cambios que se hacen durante la refactorización van desde un simple renombrado de variables, métodos, funciones y clases para mejorar la legibilidad del código hasta una reorganización completa de bloques de código. Las funciones grandes se dividen en varias más pequeñas.

Las clases con muchos métodos se reorganizan como muchas clases más reutilizables, con mayor cohesión y pocos métodos. Las dependencias se invierten y se reduce el nivel de acoplamiento entre los elementos. Y mientras todo esto ocurre, las pruebas siguen funcionando correctamente porque esa es la premisa de esta práctica: cuando refactorizamos el sistema debe continuar funcionando sin errores.

El mismo enfoque de pequeños cambios incrementales puede aplicarse para actualizar el diseño, ajustar la arquitectura o la plataforma. En estos casos hablamos más bien de una reestructuración del sistema y no siempre es posible que el sistema continúe funcionando—en muchos casos es necesario también restructurar las propias pruebas. Estos cambios, que son más profundos y de mayor impacto, pueden llevar días, semanas o meses de trabajo.

Pero el concepto es el mismo en ambos casos: trabajar en un proceso continuo para mejorar el sistema y así mantener a raya la deuda técnica. La agilidad del equipo está en juego. Por eso mismo estas actividades no deberían planificarse; deberían ser parte de la forma de construir software del equipo.

Simple Design: la belleza y atracción de lo simple

Menos es más. Simple Design (diseño simple) es el objetivo que perseguimos con la práctica de Refactoring. Pero ¿qué es un diseño simple en el desarrollo de software? Kent Beck lo define como aquel que cumple con estos principios:

Cuanto más complejo es un diseño técnico, mayor es la carga cognitiva para el equipo—la cantidad de esfuerzo mental para realizar una tarea o procesar información. A mayor carga cognitiva, mayor es el trabajo y el tiempo que deben dedicar los desarrolladores a entender y aplicar cambios en el sistema.

Esta práctica representa la búsqueda del Santo Grial en diseño técnico porque se trata de encontrar ese delicado equilibrio entre el diseño simple de la solución (las propiedades anteriores) y la complejidad de los requerimientos de los clientes y usuarios. Es la búsqueda constante que se manifiesta a través de las actividades de refinamiento y refactorización.

Un aspecto importante de un diseño simple es que va emergiendo a medida que el equipo construye la solución y aprende sobre las necesidades de los usuarios. En muchos casos, lo mejor es esperar hasta el último momento responsable para tomar ciertas decisiones técnicas.

Esta forma incremental de trabajar es muy diferente al enfoque más tradicional de la arquitectura de software que busca definir y diseñar de manera más intencional toda la solución de antemano—con una bola de cristal. Esto es más arriesgado porque muchas veces se toman decisiones que realmente son apuestas hechas a ciegas.

Y hemos llegado al final de esta parte del artículo dedicado a la ingeniería de software ágil. ¡Pero no hemos terminado! En el próximo artículo veremos la última práctica de XP relacionada con la calidad: Pair Programming y también repasaremos Behavior-Driven Development y algunos otros aspectos y herramientas que los equipos ágiles incorporan para asegurar que la calidad está siempre bien arriba.

En nuestro catálogo de formaciones, en SAFe Agile Software Engineering abordamos todos estos temas dentro un marco para escalar el trabajo de varios equipos de colaboran para construir soluciones complejas.


Seguir leyendo…

Únete a nuestra comunidad

#AlwaysLearning

Formación

  • Sensibilización en la importancia de las e-Competences
  • Capacitación Técnica y en Gestión de la Tecnología
  • Formación a medida
  • Adaptación de contenidos propios a formación presencial y online
Buscar

Solicitar Información

Request Information