1 / 14
jul. 2017

Una pregunta un poco filosófica. ¿Cuál es el objetivo principal de TDD? Lo que quiero decir es ¿qué aporta escribir los test antes? ¿Es una manera de asegurarse de escribirlos ya que al dejarlos para después es posible que nunca se escriban? ¿O es más porque así los tests guían el diseño?

Utilizando TDD sabes claramente cuando has terminado de implementar una funcionalidad en concreto, porque empezaste definiéndola desde el punto de vista del cliente. Cuando los tests pasan de estar en rojo a estar en verde, sabes que has terminado y puedes refactorizar tranquilamente. Esta perspectiva, además, conduce a un mejor diseño de las APIs, en mi opinión.

Por supuesto, llegar a este ideal lleva tiempo y aprendizaje. Se pueden implementar diseños terribles y dejar las cosas a medias utilizando TDD, pero a mí personalmente, me parece una muy buena forma de desarrollar software si se hace de forma disciplinada. También me encanta la forma en que el TDD da una sensación de progresar todo el tiempo según vas añadiendo tests y haciéndolos pasar, hace que escribir los tests sea bastante más divertido de lo que es haciéndolo a la inversa.

Una buena guía es tirar con la pregunta filosófica un paso atrás, cuál es el objetivo de escribir tests? Me quedo con la respuesta de Sarah Mei: https://twitter.com/sarahmei/status/86893977145165824017

Si partimos de esas razones y lo mezclamos con TDD:

  • Correctness: asegurarse de que lo que estamos implementando es lo correcto puede ser abordado desde varias ópticas. Estar la más cerca posible del user/business/consumer es una buena manera. Al hacer el test nos ponemos el sombrero del consumidor que nos permitirá confrontarnos a la pregunta: es esto lo que me han pedido? Al hacer el test antes nos ahorramos la pérdida de tiempo de implementar algo incorrecto.

  • Regressions: no existe diferencia entre escribir antes o después los tests para esta dimensión.

  • Design support: depende de cómo de orgánico sea nuestro diseño y la experiencia que tengamos creando código modular, focalizado, extensible... En algunas situaciones la guía que nos proporcionará no es muy grande, siendo sinceros.

  • Documentation: similar razonamiento a correctness.

  • Refactoring support: no hay diferencias entre antes y después.

Este análisis es desde el punto de vista del testing y la implementación. La dimensión metodológica es igual o más importante:

  • Baby steps: ir poco a poco es fundamental para ahorrar energía cognitiva.
  • Red-green-refactor: ciclos cortos de feedback minimizan perdidas de tiempo.
  • Vaguería: hacer tests o refactorizar puede dar pereza si estamos en modo estresado. Hacer los tests antes, siguiendo el loop mítico, nos 'obliga' a ser buena gente, incluso aunque no nos apetezca.

En común @_Raul_Avila y @felipefzdz decís que TDD ayuda a implementar lo que realmente quiere el cliente, a ponerse en su lugar. En sí ayuda o no a el diseño no estáis muy de acuerdo :smiley:

En el resto de puntos a lo mejor no hay mucha diferencia entre hacer TDD o escribir los test después. Todo esto lo preguntaba porque he notado que ahora mismo me resulta más fácil a veces escribir los test después. Pero en ciclos cortos también, porque si lo dejo para mucho después... no los hago.

Más o menos :slight_smile: Me juego la carta del depende, a veces ayuda y a veces no.

Lo que es impepinable es que TDD no sustituye el pensar. Puede ayudar a que surjan las epifanías, pero no es cuestión de poner el autómatico en plan escritura libre.

Desde mi experiencia, y llevo unos años ya haciendo TDD/BDD..., siempre ayuda. Nunca se ha de dejar de pensar, de lo contrario no seríamos más que unos "pica teclas".
Al contrario de lo que parece, has de pensar, y mucho, al escribir los tests. No se trata de "probar" cosas al hazard y listos, sino que los tests han de expresar lo que hace el negocio. Por lo tanto, no es solo escribir el test, sino alinearlo con la regla de negocio que queramos probar y, para más inri, que sea expresivo y que quien lo lea entienda cómo funciona este.
Al menos, según mi experiencia, siempre me ha sido muy útil tenerlos, tanto para centrarme en lo que he de hacer como para estar seguro de lo que hago.

Según mi experiencia, me quedo especialmente con varias ideas:
* Ayuda a centrarnos en las reglas de negocio, pues es justo lo que estamos probando.
* Sirve de "red de seguridad", pues, cambies lo que cambies, siempre estarás seguro que no rompes con la regla de negocio.
* Facilita un diseño emergente, pues cuando refactorices seguirás alineado con la regla de negocio y podrás hacerlo con seguridad.
* Ayuda a transmitir el conocimiento, ya que expresan cómo son las reglas del negocio. Solo mirando los tests ya deberíamos saber cómo son estas reglas, y gracias a su comprobación automática, sabemos que las cumplimos.

En mi opinion, el TDD en POO ayuda mucho a una correcta segregación de interfaces, ya que te empuja a describir los contratos de las clases con la que interactúas desde el propio test, lo cual te empuja a organizar bien las responsabilidades de las dependencias funcionales y, al final, la arquitectura que acabas haciendo tiene mucho que ver con el lenguaje del negocio y muy poco con las deciones técnicas de antemano.

Si trabajas con POO y arquitecturas en las que existen objetos del dominio, el TDD pasa a tener muchímimo sentido.

dicho de otro modo, cuando me he visto usando TDD de forma más regular, puedo ver claramente como es mucho menos frecuente extraer las interfaces de las clases ya implementadas, y mucho más frecuente implementar interfaces que suplen necesidades de clases ya existentes. Puede parecer una chorrada pero al final, estás en el ABC de arquitecturas como Ports & Adapters sólamente por el hecho de centrarte en lo importante (el negocio).

En fin, poco filosófico, pero de verdad es la conclusión a la que humildemente voy llegando a base de pelearme con este tema últimamente.

A lo aportado por los compañeros añado mi granito de arena: dos de los beneficios más evidentes para mí de TDD respecto a escribir los tests después (respecto a no escribirlos ni antes ni después no hace falta comentar mucho) se resumen un una palabra: obliga:

  1. Obliga a escribir los tests. Si los vas a escribir después de tener el código vas a estar muy desmotivado porque... ¡ya sabes que el código "funciona"! Lo has probado tu mismo manualmente.

  2. Obliga a hacer el código testeable (desacoplado). Si los escribes después te vas a encontrar bloqueado por código muy difícil de testear porque no lo escribiste pensando en eso.

Sin mucho más que aportar a lo ya dicho a mi TDD sí me ayuda en el diseño entendiendo por diseño, como leí una vez, que "diseño es todo desde la estructura de clases hasta la implementación de un método". No recuerdo dónde lo leí, pero se me quedó grabado.

Con TDD escribo un test en base a lo que requiere el negocio, y luego lo que hago es pensar en los mensajes enviados entre objetos y quién debe recibirlos y en qué contexto. Por eso TDD me ayuda en el diseño para asignar responsabilidades. También me ayuda, como han dicho antes, a extraer lo antes posible interfaces y a desacoplar lo máximo posible el código creado apoyándome en hacer antes los tests. Si escribir el test antes no me es sencillo es que algo falla en el diseño, por lo que le doy una vuelta para que el test sea sencillo de crear.

Totalmente de acuerdo con todo lo que se ha dicho anteriormente. Y más de una cosa nueva he aprendido.

En mi caso utilizo algo muy parecido a TDD principalmente porque me ayuda mucho a pensar qué es lo que quiero que haga el software desde un punto de vista funcional, y no caer en el error de hacer cosas que no tienen sentido para el usuario.

Solo quería dar las gracias a todos por las respuestas y opiniones :slight_smile:

TDD me parece especialmente útil por que facilita el diseño emergente. Es decir: en situaciones en las que no tienes claro en diseño. En otros escenarios como son los de "carpintería" puede no ser la mejor opción. @ziggy lo ha descrito muy bien.