En el entorno de personas con las que trabajo existen serias dudas de que la metodología de desarrollo guiado por las pruebas o Test-Driven Development, sea ágil, en el sentido de que entienden que si se aplica de manera ortodoxa o si bien las pruebas unitarias se desarrollan después, se pierde capacidad de trabajo efectivo por parte del equipo de proyecto.
Nunca he participado en un proyecto que siga esta metodología y en los desarrollos en los que he trabajado la importancia que se le da a las pruebas unitarias es muy escasa, por lo que no puedo aportar mi experiencia para opinar sobre las bondades o no de esta metodología, de manera que me tendré que centrar en lo que he leído sobre ella.
No obstante, hay que tener en cuenta una cosa. Agilidad no es lo mismo que desarrollar más rápido o por lo menos no es su objetivo principal, ya que si bien es cierto que la aplicación de metodologías ágiles, eliminan muchos aspectos que son prescindibles en un proyecto de desarrollo de software y por lo tanto pueden optimizar tiempos de desarrollo, el objetivo último de las mismas es conseguir productos software de calidad, que proporcionen satisfacción al cliente, dentro de unos plazos y presupuestos definidos (siempre y cuando, ambos sean realistas y acordes a la naturaleza del proyecto y al nivel de calidad que se espera del producto software), es decir, que no se produzcan los factores que derivan en la crisis del software.
El desarrollo guiado por las pruebas, fue introducido (o reintroducido) por Kent Beck, creador de la metodología de programación extrema y en cierto modo la segunda es una consecuencia natural de la primera, si bien ambas pueden utilizarse sin problemas por separado.
La metodología TDD a grandes rasgos es fácil de exponer:
– Se construyen las pruebas unitarias (o se puede extender si se desea el concepto a otros tipos de pruebas de más alto nivel, siempre y cuando sea automatizable su ejecución).
Como estos casos de prueba están construidos antes desarrollarse el componente software sobre el que se va a trabajar, van a fallar a la primera. De hecho se considera necesario verificar que fallan porque si no es así, querría decir que el test está más construido (¿por qué no?) o que el componente software ya está desarrollado (en proyectos donde se trabaja con sistemas de mediana o gran envergadura y con un número de desarrolladores alto, puede pasar que el componente o módulo ya se haya implementado previamente, bien porque le ha hecho falta a un compañero para otra funcionalidad o bien porque no se ha verificado que efectivamente ese componente ya estaba desarrollado).
Para la construcción de los casos de prueba, los desarrolladores deben basarse en las especificaciones indicadas en los casos de uso o en las historias de usuario. Ahí radica la importancia que tiene la construcción de las pruebas unitarias antes del desarrollo del componente, ya que implica un mayor enfoque en los requisitos, una mayor necesidad de comprender la funcionalidad y comportamiento deseado, es decir, implica comprender el problema, conocer los resultados esperados, antes de empezar a desarrollarlo.
La ventaja de desarrollar las pruebas antes de implementar los componentes es la indicada en el párrafo anterior, es decir, enfrentarse y comprender el problema antes de empezar a resolverlo.
Si las pruebas unitarias se construyen después, no estaríamos hablando de TDD, eso es importante, por lo que lo repito, si las pruebas unitarias se construyen después se trata de otra estrategia de desarrollo de software, no de desarrollo guiado por las pruebas.
Pese a que como he comentado, no se ha fomentado en los proyectos en los que he participado la construcción de pruebas unitarias, soy de la opinión de que es favorable tener una buena cobertura de código, por lo que la existencia de pruebas unitarias, antes o después de implementar los componentes, permite detectar de manera rápida la existencia de efectos colaterales o desarrollos erróneos de métodos o clases.
¿Por qué no lo hemos fomentado? Es una suma de varios factores, por un lado pese a que entendemos los beneficios que puede proporcionar, no tenemos del todo claro su retorno de la inversión, pese a que es objetivo que la deuda técnica se reduce en proporción a la cobertura, por otro lado, los proveedores con los que hemos trabajado tampoco utilizan esta práctica en sus desarrollos. Por tanto y en resumen, la falta de experiencia nuestra y de los proveedores hace que nos más dar el paso y prioricemos otros aspectos en el proceso de desarrollo y en la calidad del diseño y de la codificación.
– A continuación se construye el componente software que debe verificar las reglas de funcionamiento definidas en las pruebas.
Una vez desarrollado, se pasa el test y si funciona adecuadamente, se pasa de nuevo todo el juego de pruebas, si hay errores, se vuelve a revisar el componente, si todo ha ido bien, se pasa a la siguiente fase.
– Una vez que se tiene un software que verifica las pruebas implementadas, se procede a su refactorización.
El objetivo de la utilización de esta técnica es evidente, desarrollar software con el menor número de fallos posible, reduciendo además los errores debidos a efectos colaterales en el desarrollo, respetando también la calidad de diseño y de codificación para favorecer la comprensión y capacidad de mantenimiento del software.
Se sabe que cuanto más tarde se detecten los errores más esfuerzo se requiere para solucionarlo, esta técnica pretende disminuir el riesgo por la presencia de errores de ese tipo, además de facilitar un código donde sea mucho más fácil trabajar, tanto para corregir esas incidencias como para contruir nuevas funcionalidades o modificar, si fuera necesario (el software es de naturaleza adaptativa), las ya implementadas.
Espero poder probar más pronto que tarde esta metodología en alguno de los proyectos en los que participo y poder verificar personalmente las ventajas que tiene la utilización de esta estrategia de desarrollo.