14 de octubre de 2011

TDD is not a testing technique, it's a design technique

Esta es una pequeña entrada para comentar sobre la reciente publicación de Mark Seemann "The TDD Apostate".

En realidad, no es que quiera debatir lo expresado por Seeman en su blog. En realidad, estoy de acuerdo en la gran mayoría de lo que ahí expresa. Sin embargo, un sentimiento de incomodidad me recorría mientras leía su artículo: "claro, ¡eso es obvio!" decía para mis adentros una y otra vez. Y la razón de ello es bastante clara ahora: TDD es una herramienta valiosísima para un desarrollador. Es quizás la técnica más importante que ha llegado al mainstream del desarrollo de software en los últimos 10 años—si tan solo más personas la usáramos—pero ¡no es una bala de plata!

Parece ser que algunas personas siguen con la obsesión de buscar la nueva técnica o tecnología o invento o aceite de víbora que cure todos los males del desarrollo de software–seguramente que los gerentes y directivos de las grandes empresas tienen puestas sus esperanzas en ello. Otras por el contrario, desean que estos nunca se resuelvan y por el contrario, hacer mucho dinero vendiendo aceite de víbora. Ambos son intereses legítimos. Sin embargo, también habemos muchos programadores que vivimos soñando con estos remedios mágicos. Pensamos en lo difícil que es nuestro trabajo y en cómo nos gustaría descubrir un truco nuevo que nos permitiera resolver nuestros problemas y dedicar nuestro hermoso tiempo a navegar por internet y a jugar con nuevos gadgets.

Sin embargo, es preciso no perder de vista que el desarrollo de software es una actividad inherentemente humana y por consiguiente, difícil de automatizar y simplificar. Es ante todo una actividad creativa, que de algún modo se encuentra en algún punto entre escribir una novela de misterio y elaborar los planos de un rascacielos.

El punto del sr. Seeman es que la Programación Dirigida por Pruebas por sí misma no es una buena forma de diseñar software: de acuerdo. Recuerdo hace años haber leído en algún lugar que los impulsores de XP predicaban el no-diseño, que todos los males se podían arreglar mediante YAGNI y refactoring y no-sé-qué otras estupideces por el estilo. Cualquiera que haya leído el libro de Martin Fowler sabrá que eso no es verdad ni de lejos.

Sin embargo, muchos pseudo-programadores y otros perezosos fuimos seducidos por el llamado de la sirena: nos dejamos embaucar por las falsas promesas de aquellos que ni entendían ni les interesaba la verdadera intención tras el movimiento ágil y hallamos en estas frases propagandísticas una justificación para nuestro descuido. Otros solo entendimos el mensaje a medias, lo suficiente para poder hablar con grandilocuencia de ello, pero sin jamás llegar a aplicarlo. Algunos más escuchamos los cantos de júbilo de aquellos que abrazaron con entusiasmo el movimiento y fueron los primeros en superar los problemas iniciales y recoger sus primeros frutos. Aquello parecía ser demasiado bueno para ser cierto. Y así era.

Si bien es cierto que la TDD nos aporta un sinnúmero de ventajas, no se trata de ninguna panacea. Kent Beck nos dá una pista de la importancia de la TDD al comentar que "si pudiera convencer a los equipos de desarrollo de adoptar solo dos prácticas de XP, estas serían TDD y la programación en parejas".

El maestro Ward Cunningham dijo hace años:

"Programar las pruebas primero no es una técnica de verificación, es una técnica de diseño"

Fijémonos que nunca menciono que fuera "la única técnica de diseño" ni "la técnica definitiva de diseño". Y la razón es clara: El escribir primero la prueba y después el código nos permite expresar de forma concreta las ideas que tenemos acerca del código que estamos a punto de escribir. Es como dibujar un pequeño boceto en una servilleta, excepto que este boceto es ejecutable y nos indica inmediatamente si al poner en marcha la idea que expresamos lo hemos hecho de forma correcta de acuerdo al entendimiento que tenemos del problema hasta ese momento.

Pero por otro lado, ¿qué arquitecto en sus cabales construiría un edificio basado únicamente en un boceto en una servilleta? Al hacer TDD de forma natural nos enfocamos de forma intensa en la clase/función/historia que estamos implementando en el momento. Eso significa que si es lo único que hacemos para diseñar nuestro software, inevitablemente terminaremos con un montón de bocetos en servilletas que no necesariamente forman un plano completo de nuestro edificio. O por lo menos, tal vez no uno en el cual nos gustaría vivir.

Aunque los ingenieros, arquitectos, médicos, etc. tengan a su disposición una gran cantidad de técnicas y tecnologías que faciliten e incluso automaticen las partes más mecánicas de su trabajo, ninguno de ellos puede olvidarse de toda la base teórica que durante tantos años y con tanto esfuerzo adquirieron. No es casualidad que algunas de figuras más notables impulsores de la TDD como Kent Beck, Ward Cunningham, Martin Fowler o Robert C. Martin sean también figuras destacadas en el ámbito de los principios y patrones de diseño.

Si la TDD fuera suficiente, no haría falta conocer los principios SOLID, los patrones de diseño de los GoF o los patrones GRASP, entre muchos otros.

Si, como desarrolladores debemos abrazar la TDD o como mínimo, alguna otra disciplina equivalente como por ejemplo el Diseño por Contrato (DbC). Hoy en día decir que practicamos TDD debería ser tan obvio como decir "si, cuando programo escribo código", debe ser una práctica core de nuestro oficio. A nadie debería sorprender, e incluso me atrevo a decir que a nadie debería enorgullecer el decir "yo practico TDD", pero si debería ser motivo de vergüenza lo contrario.

Sin embargo, TDD es solo el inicio. Recordemos que XP consta de 12 prácticas (o 13, dependiendo de la edición del libro que tengan):

La programación en parejas, el diseño simple, la metáfora, el refactoring, la propiedad colectiva del código, todas son prácticas que contribuyen a mantener la visión a gran escala del sistema en perspectiva, aún cuando nos concentremos en una sola unidad de software a la vez. Si no estamos en un proyecto/equipo que practique XP, esto hace aún más apremiante que debamos hacer nuestra tarea y conocer más allá de los meros detalles sintácticos de mi código, si no su participación y sus consecuencias como parte integral de un todo. Como se menciona en GoF:

"Los Patrones de Diseño... proveen puntos de llegada para nuestros refactorings."

¿Cómo sabremos cuando hemos arribado a nuestro destino si no sabemos cual es este destino?

En resumen: no, TDD no es una técnica completa ni infalible ni mucho menos a prueba de tontos para el diseño de software; es eso sí, una técnica valiosísima para diseñar unidades de código, mantenerlas limpias, cohesivas y débilmente acopladas con el resto del mundo. ¿Acaso no son estas propiedades deseables del todo?, ¿Acaso no son estas retribución más que suficiente a la disciplina que aplicamos todos los días al practicar TDD?

Citando a Michael Feathers:

He encontrado [también] que al tratar de escribir Pruebas Unitarias en proyectos existentes que no son de XP, para proporcionar un andamiaje para el cambio, se deshierban las dependencias, los problemas de instanciamiento, etc. Sólo puedo creer que si cada clase se desarrolla primero en un arnés de prueba, donde todas las dependencias explícitas, las cosas irán mejor. Ha sido mi experiencia en las cosas más bien pequeñas que he hecho, siguiendo el ejemplo de XP.

Saludos