Test Driven Development (Desarrollo dirigido por las pruebas)

Ultimamente, aquí y allá estoy oyendo hablar del llamado Test Driven Development o Desarrollo guiado por las pruebas como nueva metodología de desarrollo.

Dejadme que os explique un poco como funciona el asunto. La metodología se basa en que el desarrollo de los test guie el desarrollo de la aplicación, de esta forma lo primero que hacemos es planear que necesita hacer la aplicación y en función de ello desarrollamos test para cada una de las funciones, de esta forma disponemos de una prueba para cada función (no os entusiasmeis demasiado con esto ...)

El siguiente paso evidentemente es desarrollar la funcionalidad que consigue pasar ese test, y por tanto, funcionalidad hecha y medianamente probada... perfecto.

La descripción de la metodología tiene más pasos y más guías para el desarrollo y como realizar cada paso. La página de la wikipedia tiene más información para los interesados (que espero que después de leer este artículo sean pocos).

Alrededor de esta metodología han surgido bastantes frameworks de distintos tipos: unit testing frameworks (para facilitar la creación de pruebas), mocking frameworks (para facilitar la creación de drivers para aquella funcionalidad que aún no tenemos), Inversion of control frameworks (que interceptan ciertas llamadas y permiten introducir nuestro código en determinados lugares), etc

Estos frameworks son tremendamente útiles, en su medida, para ayudar a testear nuestras clases, nuestras librerías. Permiten desarrollar determinados test, comprobar automáticamente que determinadas cosas funcionan y en general ayudan muchisimo al desarrollador.

Pero volvamos al desarrollo guiado por las pruebas.

Si uno se para a pensar en el nombre, solo en el nombre, debería encendersle una luz roja de alarma. ¿Desarrollo guiado por las pruebas? ¿En serio?

Prueba es algo que se utiliza para comprobar que algo funciona. Cuando tenemos una duda sobre si algo funciona correctamente, lo probamos. Es su meta, si las pruebas tuvieran metas.

Por tanto, ¿como vamos a dirigir el desarrollo por las pruebas? Realmente, si nos paramos a pensar esto es lo que estamos diciendo:

"Tengo que desarrollar una clase que comprima un stream de datos dados. En lugar de hacerlo lo que voy a hacer es desarrollar primero la prueba y luego ya desarrollo la clase."

Hay cosas que si las dices suficientemente rápido suenan extremadamente bien pero a mi no deja de sonarme a aquello de "¿Vives para trabajar? o ¿trabajas para vivir?". Es importante no confundir los conceptos.

El primer problema que nos encontramos se cita en la propia wikipedia (en inglés): No es muy útil para realizar pruebas sobre lógica que trabaja contra bases de datos. Bien, la mayor parte de las aplicaciones de hoy en día funcionan contra una base de datos, desde las más pequeñas hasta las más grandes con lo que comenzamos con una restricción bastante importante.

El segundo problema nos lo encontramos cuando empezamos a trabajar en el mundo real, no en el mundo ficticio en el que parecen trabajar algunos académicos (y algunos profesores de universidad, que no todos). En el mundo real hay entregas, plazos, recursos asignados y sobre todo, en el mundo real, hay pasta de por medio.

Una de las lecciones más importantes que he aprendido en el mundo empresarial es que en el mundo de la programación, esto en lo que trabajamos, es un negocio; hay que hacer las cosas lo mejor posible, pero nunca olvides que es un negocio. Esto, entre otras cosas, significa que si no entregas no te pagan, por lo que liarse a desarrollar pruebas para hacer un producto perfecto y con una metodología perfecta no te da dinero cuando el producto no se entrega.

Otra de las verdades del mundillo es que los tiempos procuran ajustarse al máximo (si, a veces demasiado), por eso, cuando los comerciales negocian con el cliente, y suele ser gente que realmente no tiene mucha idea de lo que habla a nivel bajo, no puede estimar (y no se espera que lo hagan) exactamente cuanto va a tardar algo, e incluso aunque sean capaces o tengan una información perfecta por parte de los desarrolladores... lo importante es vender. Si tienes un contrato de un par de millones de euros, por ejemplo, no vas a dejarlo ir porque el cliente lo quiere un par de meses antes de lo que crees que podrás hacerlo, lo coges, lo vendes, y luego ya veremos. A fin de cuentas, en muchas ocasiones al cliente al final le saldrá mejor darte otros dos meses que tirar 2 años de desarrollo.

Por todo lo anterior, que para cada desarrollo que tienes que hacer tengas que gastar un tiempo precioso en desarrollar pruebas antes siquiera de empezar a implementar requisitos tiene delito. Que algo que debería tomar 50 horas toma 65 porque estamos realizando una pruebas antes puede parecer poca cosa pero si ampliamos eso a un proyecto de verdad, de 7000 horas al menos, nos encontramos con que nos tiramos 2100 horas desarrollando pruebas, o traducido, un hombre durante un año implementando pruebas.

Y ojo, no confundamos, aunque implementemos pruebas eso no elimina el testeo posterior, es decir, integración, sistema, etc. Ni por supuesto garantiza que todo lo que hagamos lo hagamos bien.

Por otro lado tenemos el hecho de que desarrollar pruebas, sin importar las ayudas que tengamos con frameworks de esto y de lo otro, está sujeto a errores puesto que desarrollar no deja de ser desarrollar. ¿También debemos desarrollar pruebas para las pruebas? ¿He mencionado lo increiblemente dificil (sino imposible) que resulta desarrollar pruebas para aplicaciones multihilo?

Solo puedo hablar en mi experiencia, aunque no he encontrado todavía a nadie usando con éxito está metodología en un proyecto grande, y en esa experiencia las pruebas se realizan para lo que falla, o para lo que presenta dudas, es decir, creas pruebas cuando las necesitas, no como regla general. Y en esta tarea los frameworks como nUnit son extremadamente útiles.

En conclusión, lo más novedoso no siempre es lo mejor, que esté en la wikipedia no garantiza nada y menos aún que haya muchos libros sobre él. Desarrolla pruebas para aquello que es necesario probar, fundamentalmente yo suelo orientarme por las siguientes guías:

  • Que haya algun fallo y tengas localizado la clase o el sectores de código en las que se localiza el error o crees que hay un error.
  • Que no estés demasiado seguro de un fragmento de código y el desarrollo de una prueba para él sea menos compleja en la detección de posibles fallos que la revisión de código y el debug a mano.
  • Que sospechemos la presencia de un memory leak en el código.
  • Cuando estemos desarrollando una biblioteca de clases es muy recomendable desarrollar pruebas para los interfaces externos de la biblioteca. Las bibliotecas sufren optimizaciones a menudo, por lo que es muy útil poder comprobar de forma fácil que los programas que las utilizan siguen funcionando correctamente después, es decir, que no nos hemos cargado nada.

La realidad es que es inviable codificar pruebas para todo, sencillamente es demasiado y poco realista.

10
Average: 10 (2 votes)
Your rating: None