Mostrando las entradas con la etiqueta TDD. Mostrar todas las entradas
Mostrando las entradas con la etiqueta TDD. Mostrar todas las entradas

lunes, enero 17, 2011

Prólogo del Libro: "Diseño Ágil con TDD" de @carlosble

Erase una vez que se era, un lejano país donde vivían dos cerditos, Pablo y Adrián que, además, eran hermanos. Ambos eran los cerditos más listos de la granja y, por eso, el gallo Iván (el gerente de la misma) organizó una reunión en el establo, donde les encargó desarrollar un programa de ordenador para controlar el almacén de piensos. Les explicó qué quería saber en todo momento: cuántos sacos de grano había y quién metía y sacaba sacos de grano del almacén. Para ello sólo tenían un mes pero les advirtió que, en una semana, quería ya ver algo funcionando. Al final de esa primera semana, eliminaría a uno de los dos.

Adrián, que era el más joven e impulsivo, inmediatamente se puso manos a la obra. "¡No hay tiempo que perder!", decía. Y empezó rápidamente a escribir líneas y líneas de código. Algunas eran de un reciente programa que había ayudado a escribir para la guardería de la vaca Paca. Adrián pensó que no eran muy diferentes un almacén de grano y una guardería. En el primero se guardan sacos y en el segundo, pequeños animalitos. De acuerdo, tenía que retocar algunas cosillas para que aquello le sirviera pero bueno, esto del software va de reutilizar lo que ya funciona, ¿no?.

Pablo, sin embargo, antes de escribir una sola línea de código comenzó acordando con Iván dos cosas: qué era exactamente lo que podría ver dentro de una semana y cómo sabría que, efectivamente, estaba terminada cada cosa. Iván quería conocer, tan rápido como fuera posible, cuántos sacos de grano había en cada parte del almacén porque sospechaba que, en algunas partes del mismo, se estaban acumulando sacos sin control y se estaban estropeando. Como los sacos entraban y salían constantemente, no podía saber cuántos había y dónde estaban en cada instante, así que acordaron ir contabilizándolos por zonas y apuntando a qué parte iba o de qué parte venía, cada vez que entrara o saliera un saco. Así, en poco tiempo podrían tener una idea clara del uso que se estaba dando a las distintas zonas del almacén.

Mientras Adrián adelantaba a Pablo escribiendo muchas líneas de código, Pablo escribía primero las pruebas automatizadas. A Adrián eso le parecía una pérdida de tiempo. ¡Sólo tenían una semana para convencer a Iván!

Al final de la primera semana, la demo de Adrián fue espectacular, tenía un control de usuarios muy completo, hizo la demostración desde un móvil y enseñó, además, las posibilidades de un generador de informes muy potente que había desarrollado para otra granja anteriormente. Durante la demostración hubo dos o tres problemillas y tuvo que arrancar de nuevo el programa pero, salvo eso, todo fue genial. La demostración de Pablo fue mucho más modesta, pero cumplió con las expectativas de Iván y el programa no falló en ningún momento. Claro,todo lo que enseñó lo había probado muchísimas veces antes gracias a que había automatizado las pruebas. Pablo hacía TDD, es decir, nunca escribía una línea de código sin antes tener una prueba que le indicara un error. Adrián no podía creer que Pablo hubiera gastado más de la mitad de su tiempo en aquellas pruebas que no hacían más que retrasarle a la hora de escribir las funcionalidades que había pedido Iván. El programa de Adrián tenía muchos botones y muchísimas opciones, probablemente muchas más de las que jamás serían necesarias para lo que había pedido Iván, pero tenía un aspecto "muy profesional".

Iván no supo qué hacer. La propuesta de Pablo era muy robusta y hacía justo lo que habían acordado. La propuesta de Adrián tenía cosillas que pulir, pero era muy prometedora. ¡Había hecho la demostración desde un móvil! Así que les propuso el siguiente trato: “Os pagaré un 50% más de lo que inicialmente habíamos presupuestado, pero sólo a aquel de los dos que me haga el mejor proyecto. Al otro no le daré nada.”. Era una oferta complicada porque, por un lado, el que ganaba se llevaba mucho más de lo previsto. Muy tentador. Pero, por el otro lado, corrían el riesgo de trabajar durante un mes completamente gratis. Mmmmm.
Adrián, tan impulsivo y arrogante como siempre, no dudó ni un instante. "¡Trato hecho!", dijo. Pablo explicó que aceptaría sólo si Iván se comprometía a colaborar como lo había hecho durante la primera semana. A Iván le pareció razonable y les convocó a ambos para que le enseñaran el resultado final en tres semanas.

Adrián se marchó pitando y llamó a su primo Sixto, que sabía mucho y le aseguraría la victoria, aunque tuviera que darle parte de las ganancias. Ambos se pusieron rápidamente manos a la obra. Mientras Adrián arreglaba los defectillos encontrados durante la demo, Sixto se encargó de diseñar una arquitectura que permitiera enviar mensajes desde el móvil hasta un webservice que permitía encolar cualquier operación para ser procesada en paralelo por varios servidores y así garantizar que el sistema estaría en disposición de dar servicio 24 horas al día los 7 días de la semana.

Mientras tanto, Pablo se reunió con Iván y Bernardo (el encargado del almacén) para ver cuáles deberían ser las siguientes funcionalidades a desarrollar. Les pidió que le explicaran, para cada petición, qué beneficio obtenía la granja con cada nueva funcionalidad. Y así, poco a poco, fueron elaborando una lista de funcionalidades priorizadas y resumidas en una serie de tarjetas. A continuación, Pablo fue, tarjeta a tarjeta, discutiendo con Iván y Bernardo cuánto tiempo podría tardar en terminarlas. De paso, aprovechó para anotar algunos criterios que luego servirían para considerar que esa funcionalidad estaría completamente terminada y eliminar alguna ambigüedad que fuera surgiendo.Cuando Pablo pensó que, por su experiencia, no podría hacer más trabajo que el que ya habían discutido, dio por concluida la reunión y se dispuso a trabajar. Antes que nada, resolvió un par de defectos que habían surgido durante la demostración y le pidió a Iván que lo validara. A continuación, se marchó a casa a descansar. Al día siguiente, cogió la primera de las tarjetas y, como ya había hecho durante la semana anterior, comenzó a automatizar los criterios de aceptación acordados con Iván y Bernardo. Y luego, fue escribiendo la parte del programa que hacía que se cumplieran esos criterios de aceptación. Pablo le había pedido ayuda a su amigo Hudson, un coyote vegetariano que había venido desde América a pasar el invierno. Hudson no sabía programar, pero era muy rápido haciendo cosas sencillas. Pablo le encargó que comprobara constantemente los criterios de aceptación que él había automatizado. Así, cada vez que Pablo hacía algún cambio en su programa, avisaba a Hudson y este hacía, una tras otra, todas las pruebas de aceptación que Pablo iba escribiendo. Y cada vez había más. ¡Este Hudson era realmente veloz e incansable!.

A medida que iba pasando el tiempo, Adrián y Sixto tenían cada vez más problemas. Terminaron culpando a todo el mundo. A Iván, porque no les había explicado detalles importantísimos para el éxito del proyecto. A la vaca Paca, porque había incluido una serie de cambios en el programa de la guardería que hacía que no pudieran reutilizar casi nada. A los inventores de los SMS y los webservices, porque no tenían ni idea de cómo funciona una granja. Eran tantos los frentes que tenían abiertos que tuvieron que prescindir del envío de SMS y buscaron un generador de páginas web que les permitiera dibujar el flujo de navegación en un gráfico y, a partir de ahí, generar el esqueleto de la aplicación. ¡Eso seguro que les ahorraría mucho tiempo! Al poco, Sixto, harto de ver que Adrián no valoraba sus aportaciones y que ya no se iban a usar sus ideas para enviar y recibir los SMS, decidió que se marchaba, aún renunciando a su parte de los beneficios. Total, él ya no creía que fueran a ser capaces de ganar la competición.

Mientras tanto, Pablo le pidió un par de veces a Iván y a Bernardo que le validaran si lo que llevaba hecho hasta aquel momento era de su agrado y les hizo un par de demostraciones durante aquellas 3 semanas, lo que sirvió para corregir algunos defectos y cambiar algunas prioridades. Iván y Bernardo estaban francamente contentos con el trabajo de Pablo. Sin embargo, entre ellos comentaron más de una vez: "¿Qué estará haciendo Adrián? ¿Cómo lo llevará?".

Cuando se acercaba la fecha final para entregar el programa, Adrián se quedó sin dormir un par de noches para así poder entregar su programa. Pero eran tantos los defectos que había ido acumulando que, cada vez que arreglaba una cosa, le fallaba otra. De hecho, cuando llegó la hora de la demostración, Adrián sólo pudo enseñar el programa instalado en su portátil (el único sitio donde, a duras penas, funcionaba) y fue todo un desastre: mensajes de error por todos sitios, comportamientos inesperados... y lo peor de todo: el programa no hacía lo que habían acordado con Iván.

Pablo, sin embargo, no tuvo ningún problema en enseñar lo que llevaba funcionando desde hacía mucho tiempo y que tantas veces había probado. Por si acaso, dos días antes de la entrega, Pablo había dejado de introducir nuevas características al programa porque quería centrarse en dar un buen manual de usuario, que Iván había olvidado mencionar en las primeras reuniones porque daba por sentado que se lo entregarían. Claro, Adrián no había tenido tiempo para nada de eso.

Moraleja:

Además de toda una serie de buenas prácticas y un proceso de desarrollo ágil, Pablo hizo algo que Adrián despreció: acordó con Iván (el cliente) y con Bernardo (el usuario) los criterios mediante los cuáles se comprobaría que cada una de las funcionalidades estaría bien acabada. A eso que solemos llamar "criterios de aceptación", Pablo le añadió la posibilidad de automatizar su ejecución e incorporarlos en un proceso de integración continua (que es lo que representa su amigo Hudson en este cuento). De esta manera, Pablo estaba siempre tranquilo de que no estaba estropeando nada viejo con cada nueva modificación. Al evitar volver a trabajar sobre asuntos ya acabados, Pablo era más eficiente. En el corto plazo, las diferencias entre ambos enfoques no parecen significativas, pero en el medio y largo plazo, es evidente que escribir las pruebas antes de desarrollar la solución es mucho más eficaz y eficiente.

Sitio Web: http://www.dirigidoportests.com

Descarga: http://www.dirigidoportests.com/wp-content/uploads/2010/02/disenoAgilConTdd_ebook.pdf

martes, agosto 17, 2010

No escribo pruebas unitarias porque... (manual de excusas)

Siendo alguien que vive los beneficios de hacer TDD, creo profundamente en el desarrollo guiado por pruebas. Esta práctica agrega un nuevo nivel de calidad y madurez al desarrollo de software, y sin embargo todavía no es la técnica más usada en los proyectos de software. Cuando hay que elegir entre características, tiempo y calidad, siempre sufre la calidad. No queremos agregar tiempo extra para hacer pruebas, y tampoco queremos comprometer las características que vamos a entregar. Si no se pusieron como objetivo hacer TDD al iniciar el proeycto, es dificil hacerlo después.

Todos escuchamos excusas para no hacer TDD, pero nadie las juntó mejor que "Pragmatic Unit Testing in Java With JUnit", de la serie Pragmatic Bookshelf. Hace un par de años que leí ese libro, y desde entonces creo que no hay forma que un desarrollador responsable pueda leer este libro sin entender que las pruebas unitarias son uno de los aspectos más importantes del desarrollo de software.

La excusa más preocupante que escucho es que es demasiado dificil probar mi código. Esto puede ser por dos motivos. Uno es que el código sea principalmente de interfaces de usuario (UI), y automatizar las pruebas de UI es muy dificil. Entiendo que la automatización de UI son bastantes complejas (¡y no imposibles!), pero se debería dedicar todo el esfuerzo en automatizar lo más posible: piensen en las pruebas de regresión. Si tienen una suite de pruebas completamente automatizada, incluyendo el comportamiento del UI, podrán hacer cambios al código con total confianza de no romper nada.

El segundo motivo de que el código es demasiado dificil de probar es que hicieron desastre con el diseño. Quizás la lógica y el código de UI están muy acoplados. Es por esto que TDD ayuda a mantener un diseño limpio, siguiendo las mejores prácticas. Usar JUnit es simple, y si puedo ejecutar toda la capa lógica por tener un diseño limpio, entonces podré probar toda la lógica que el UI va a usar. ¿Qué les falta el modelo de datos? Entonces pueden usar objetos mocks - ¡hay muchos frameworks para esto!

Para quienes todavía no leyeron el libro, les dejo un breve resumen de las excusas para no hacer TDD:

Escribir pruebas lleva mucho tiempo

Este es el principal motivo que dan los desarrolladores, y creo que se debe a cómo nos enseñan a desarrollar software. En general, nos hacen creer que la estapa de pruebas ocurre al final del proceso, y no durante todo el desarrollo.

TDD fomenta el modelo "pagar a medida que se avanza", en donde escribimos las pruebas mientras desarrollamos, por lo que no tenemos que meter tiempo al final del proceso para escribir todas las pruebas que podamos.

Y de todas formas, si no estás escribiendo pruebas a medida que avanzás, ¿cómo comprobás que el código se comporte como esperás? ¿Lo ejecutás manualmente? ¿No tiene más sentido invertir algo de este tiempo de pruebas manuales en escribir una prueba JUnit para esto? Quiero decir, en algún momento vas a tener que ejecutar esa porción de código - no va a quedar sin tocar el resto de la vida del producto.

De hecho, ocurren muchas más penalizaciones de tiempo si no se escriben pruebas unitarias. Vas a tener que gastar tiempo haciendo debug del código intentando averiguar porque algo no funciona. O vas a hacer un refactor, y luego darte cuenta que nada funciona como antes del refactor. Si tuvieras las pruebas unitarias, tendrías una base segura.

Lleva mucho tiempo ejecutar las pruebas

Si, puede llevarse bastante tiempo ejecutar pruebas que involucran a entidades externas, o pruebas de la interfaz de usuario. Pero se supone que hay más de un nivel de pruebas. Las pruebas unitarias deberían ejecutarse rápido, y podría haber un nivel de integración que también corra sin mucho impacto de tiempo. Si hay pruebas de integración que toman mucho tiempo, será cuestión de correrlas con menos frecuencia - quizás de manera nocturna. Esto no quiere decir que debemos ignorar las pruebas unitarias. Estas siempre deberían correr lo suficientemente ráipdo como para ser parte natural del proceso de software.

Mi trabajo no es probar el código

Todavía no sé en qué momento un desarrollador de software decide que puede tirar código contra la pared así nomás. Si nuestro trabajo fuera de "Codificador" quizás ahí tendríamos una mejor excusa. Pero nuestro trabajo consiste en desarrollar código que funcione, y por lo tanto necesitamos alguna forma de mostrar que nuestro código es funcional. Si a la gente de QA les cuesta encontrar bugs en nuestro código, va a ser maravilloso para nuestra reputación.

En realidad no sé cómo funciona el código, por lo que no puedo probarlo

Esta es dificil de tomar sin ser incrédulos. Si no entendemos cómo debería funcionar el código, no deberíamos empezar a programar. Primero debemos entender el requerimiento.

El libro tiene un par de excusas más, pero estos son las principales. ¿Qué excusas escucharon ustedes para no escribir pruebas?

Fuente: DosIdeas