Reflexiones sobre TDD

2016-08-04

Estos últimos meses he estado reflexionando sobre lo que he aprendido de TDD. Probablemente lo que hay en este post sean aquellos puntos que más me han ayudado a entender la filosofía que hay detrás. Además he tenido la suerte de dinamizar dos debates al respecto en la Software Craftsmanship de Pamplona y en el AOS 2016, lo cuál me ha permitido validar ciertas ideas y aprender de nuevas reflexiones de los compañeros de la comunidad. Así que gracias a todos por ayudarme a escribir este post!

Que hemos aprendido

TDD no es sólo testing

A menudo cuando preguntamos por las ventajas que aporta TDD en el flujo de desarrollo, la primera respuesta suele ser seguridad. Ya que tenemos una batería de tests, que nos permiten obtener feedback en cada cambio que hagamos en nuestro código. Sin duda es una ventaja bastante valiosa. No obstante, me sorprende que sea la primera en la que pensamos. Ya que esto es una ventaja de tener tests automáticos más que de usar TDD en sí.

TDD es una herramienta de diseño

El ciclo que seguimos cuando hacemos TDD se centra en los dos siguientes puntos: Keep It Simple y Baby Steps.

La simplicidad es fundamental para la vida de nuestro software. Recordemos que nuestro software ha de evolucionar o morirá. La cambiabilidad y extensibilidad de nuestro software está bastante ligada a la simplicidad. Entre más simple sea nuestro código más fácil será para el equipo comprenderlo. A veces conseguimos simplicidad usando buenos nombres, otras aislando responsabilidades, otras eliminando duplicidad…

El principal potencial de avanzar en pequeños pasos es que podemos centrar nuestros esfuerzos en una tarea sin tener que pensar en todo su alrededor. Una de las primeras reglas que aprendemos es escribir el código mínimo para pasar el test. Lo cual nos permite obtener feedback rápido y mantener nuestro código lo más simple posible para las funcionalidades que cubre.

Otro sitio en el que también encontramos los baby steps es en la separación de las fases Green y Refactor. Pasos pequeños, primero vamos a preocuparnos de que funcione y de validar lo que estamos haciendo. Una vez conseguido llega el momento de plantearnos principios de diseño tratando de asegurar un mínimo de calidad que permite que nuestro software sea más entendible, modificable y extensible. La etapa de refactor es importantísima porque es la que nos recuerda constantemente en nuestro flujo de desarrollo que sabemos y debemos hacerlo mejor. Aquí es dónde nos viene a la cabeza SOLID, 4 reglas de diseño simple, connascence, patrones de diseño…

TDD no implica buen diseño

Cuando empecé a usar TDD solía creer que gracias al flujo de desarrollo el buen diseño emergía. Pero a medida que he ido interiorizando principios de diseño y comprendiendo que es lo que consideramos un buen diseño mi opinión ha cambiado bastante.

El buen diseño no va a emerger si no entendemos que es un buen diseño. Aprender orientación a objetos, principios de diseño, patrones de diseño, clean code… para nosotros ha sido clave. Considero que empezar a usar TDD mejora nuestros diseños, pero no debemos conformarnos con eso. Es posible que los frutos no los veamos tan fácilmente ya que no solo se trata de interiorizar muchos conceptos de diseño y programación sino que también debemos mejorar nuestra aplicación y entendimiento de TDD. Cambiar el mindset e interiorizar TDD cómo práctica es algo que requiere tiempo y estudio. Una semana no es suficiente para valorar si TDD aplica a nuestra forma de desarrollar (al menos esa es mi opinión).

Esto no quiere decir que TDD no influya en nuestro diseño, quiere decir que no es el único factor que hará que mejore. Digamos que TDD es nuestra guitarra. Con dos acordes podemos tocar una canción pero si estudiamos en profundidad la música y practicamos todos los días conseguiremos ser unos virtuosos en nuestros conciertos. Básicamente se trata de que nuestros conocimientos nos permitan sacar el mayor partido de nuestras herramientas y a viceversa.

Escribimos malos tests

Nos hemos dado cuenta que es muy importante tratar nuestros tests como tratamos al resto de nuestro código. Es decir, hace menos de un año le daba menos importancia al código de tests que al de producción. Si veía duplicación me preocupaba menos, si estaba acoplado me importaba menos… Después de conversar con otros compañeros y estudiando las dificultades que solíamos encontrar llegamos a la conclusión de que todos los principios que conocemos deberíamos aplicarlos también en nuestros tests.

Creo que este es el principal problema que un desarrollador/equipo puede encontrarse a la hora de adoptar TDD. Pero esto no quiere decir que TDD no funcione, quiere decir que debemos entrenar más y estudiar como hacer nuestros tests más mantenibles. Nosotros llegamos a estar en situaciones en las que un refactor se cargaba un montón de tests. Gracias a esto entendimos que nuestro principal problema era que teníamos tests muy acoplados a detalles de implementación. Considero que la calidad de los tests que escribimos hoy ha mejorado y están haciendo su labor de darnos seguridad y permitirnos refactorizar con relativa libertad. Actualmente, en las fases de refactor nos parece tan importante refactorizar los tests como refactorizar nuestro código de producción.

Trataré de escribir otro post con ejemplos prácticos sobre lo que cosas que hemos aprendido a la hora de escribir tests. Cabe destacar que aunque pienso que han mejorado los tests que escribimos hoy, estoy seguro de que aún tienen mucho margen de mejora y me encantará recibir feedback. Ojalá dentro de un mes vea un test que he escrito hoy y no me guste para nada. Querrá decir que hemos vuelto a aprender algo sobre TDD y testing.