Lo que me aporta TDD

Test Driven Development


Hace tiempo que vengo queriendo reescribir nuestro libro de TDD para mejorarlo con todo lo que hemos aprendido en estos 7 años y todo el feedback que hemos recibiendo por parte de los lectores, a los cuales estamos muy agradecidos. Pero no se cuándo me podré sentar durante un puñado de meses a abordar semejante reto.

Sin embargo, los atículos y críticas destructivas que se leen sobre esta práctica de vez en cuando, tanto en inglés como en castellano, hacen que me apetezca volver a hablar de lo mucho que me aporta esta práctica.

Lo que me aporta TDD

A los programadores nos encanta el feedback rápido, todos los que disponemos de algún REPL en nuestro lenguaje, estamos encantados. En el browser es facilísimo abrir la consola para escribir una línea de JavaScript y averiguar si determinada expresión se evalúa como creemos. Igual pasa con las consolas de Ruby y de Python. Hasta para C# suelo tirar de C# Pad muchas veces, y de "Inmmediate Window" en VS. Hacer pruebas rápidas y pequeñas en un REPL es una forma de TDD a mi modo de ver. Te permite avanzar en pequeños pasos seguros. A veces practicando TDD escribo un test que poco más tarde borro, porque lo único que quería era feedback rápido, no pretendía dejar una prueba escrita.

TDD Cycle
TDD Cycle1

El otro gran beneficio que obtengo practicando TDD es la simplicidad. Soy un experto complicándome la vida, pero gracias a la regla de escribir el código mínimo para que el test pase y nada más, consigo implementaciones mucho más simples de las que me quedaban antes. El prestar mucha atención a las generalizaciones progresivas, como dice Transformation Priority Premise, hace que ahora use más veces la recursividad, en soluciones que naturalmente son recursivas. Antes simplemente me volvía loco con bucles. Un efecto secundario de ir al mínimo es que se me ocurren casos de uso que ni se me habían pasado por la cabeza, a veces casos límite. Es decir que el truco de hackear la implementación para que el test pase me hace ser consciente de casos importantes a cubrir, que quizás nunca hubiese tenido en cuenta. Por tanto me ayuda a encontrar problemas más temprano.

TDD me obliga a pensar antes de codificar. Si escojo un enfoque inside-out, tengo que haber descompuesto muy bien el problema antes para estar seguro que esa pieza de bajo nivel me va a encajar en el puzzle. Si escojo outside-in me obligo a pensar en dependencias, paso de mensajes, diseño orientado a objetos. Pienso que TDD no lleva a un buen diseño por sí, pero teniendo conocimientos de diseño, me ayuda a detectar problemas en el mismo. Por ejemplo cuando me cuesta mucho escribir un test, es porque me faltan piezas en el diseño, porque el área que estoy explorando todavía no es la más adecuada, porque estoy introduciendo demasiada complejidad.... lo tomo como una pista para replantearme el camino elegido. Y acompañado además por los micro-commits, puedo volver atrás en cualquier momento y tomar otro camino de la solución.

JB Rainsberger dice por ejemplo que cuando hace TDD prefiere usar mocks en lugar de spies, porque los dolores a la hora de usar dobles son mas evidentes y eso le da más pistas sobre su diseño (ver los comentarios del post).

Con TDD no me atasco, el avance es constante, me permite entrar en flow. No tengo que depurar! practicamente nunca tengo que depurar y cuando esto sucede es otra pista de que he dado un paso demasiado grande a la hora de descomponer el problema o de que necesito descansar porque hay un typo muy chorra que no consigo encontrar.

No vale para todo

Hay muchísimas situaciones en las que no hago TDD, por ejemplo cuando estudio una nueva tecnología o API de un tercero. Todo gira en torno al feedback, la simplicidad y la cadencia. Cuando voy a poderle sacar partido lo uso y cuando no, pues no lo uso. Igual que ocurre con cualquier herramienta de las que tenemos disponibles. A veces al introducir una pequeña funcionalidad en un código existente o al hacer un pequeño cambio, consigo ir más rápido escribiendo el código primero, probando a mano la aplicación y después dejando un test automático de respaldo. Sucede tipicamente en sistemas legacy donde los tests tardan mucho en ejecutarse o es tan dificil de añadir un test que valido la hipótesis primero probando a mano y luego ya agregando el test.

Y tu que también practicas TDD, ayúdame a recordar más beneficios, deja un comentario please ;-)


1Figure from Growing Object-Oriented Software by Nat Pryce and Steve Freeman.