Thursday, October 6, 2011

El problema que reside en definir un problema.

Resulta paradógico que cuánto más se intenta acotar y documentar el sistema a desarrollar, más tiempo es necesario para ello y por tanto más cambiarán las necesidades reales a las que se dedicará.

 La captura de especificaciones ‘congela’ el mundo al momento en que se establecen o bien genera lagunas que fuerzan a la toma de decisiones sobre suposiciones. Esto produce un desfase entre la necesidad real y la solución generada dado que durante su fabricación la realidad  ha cambiado y los detalles no documentados son fuente de imprecisiones.

En un enfrentamiento cara a cara contra la realidad, lo más probable es que ésta salga victoriosa a no ser que la sigas de cerca y te amoldes, negocies los cambios. La agilidad es una buena estrategia en el mundo del desarrollo actual.

La falta de calidad se debe directamente a la incapacidad del software para cumplir las necesidades reales, a esto se añade que el número de defectos sea muy alto y una baja mantenibilidad, responsable del alto coste de la corrección de errores y el añadido de nuevos requerimientos , otro pez que se muerde la cola.

Los defectos son fuente de costes no deseados, convirtiendo los sistemas en inestables, impredecibles o incluso en inútiles. Pueden dar lugar a pérdidas en lugar de beneficios. Las pruebas extensivas permiten reducir la probabilidad de fallo, he ahí su importancia y razón de ser.


Medir la mantenibilidad no es tarea fácil, es bien conocido que está directamente relacionada con la calidad del código (siempre y cuando el código se haya realizado con la mantenibilidad en mente), pero ¿qué distingue un mal código de uno bueno?  debemos reflexionar sobre ello.

Una técnica habitual en la agilidad para obtención de requisitos consiste en que el cliente, o bien alguien que lo represente, mantenga una lista de requerimientos. De esa lista se toman subconjuntos de entradas dividiendo cada una de ellas en tareas que pasan a formar parte de otra nueva lista de seguimiento de la iteración, donde las tareas se priorizan a partir de los criterios del cliente y del equipo de desarrollo. Comúnmente la duración de un ciclo ha de ser corta, desde unas horas a un par de semanas, permitiendo realizar seguimientos bastante precisos del esfuerzo realizado.

La toma de requerimientos no es tarea fácil, determinar la necesidad verdadera es una necesidad principal. Debemos cuestionarnos una y otra vez: ¿Estamos realmente cubriendo la necesidad real? Es perfectamente posible solucionar necesidades innecesarias de una forma completamente artística, cosa que debemos evitar pues dispara los costes y no mejora en nada la calidad del producto, de hecho es muy probable que ésta disminuya.

Dada una nueva característica debemos esclarecer:
  • En qué consiste exactamente.
  • Qué se interpone en nuesto camino de añadirla al producto.
  • Darle un nombre claro.
  • Determinar cómo solucionarlo.
No debemos olvidarnos de la ergonomía , una característica perfectamente funcional pero difícil de utilizar es inútil para el cliente.

Tuesday, October 4, 2011

El Ciclo de Trabajo en TDD

En el ciclo de vida clásico en cascada las pruebas son posteriores al diseño y la codificación, esto implica que un fallo en las pruebas conlleva una vuelta atrás al paso de codificación o bien, retroceder dos pasos y tener que modificar nada menos que el diseño, los costes por retroceso son conocidamente altos. La idea principal de TDD es anteponer las pruebas a todo el proceso, por tanto un fallo en las pruebas no supone una vuelta atrás y se reduce su coste dado que los pasos de codificación y diseño se subordinan a ellas. Por otro lado también se invierte el orden de la codificación y el diseño, dado que de la codificación que supera las pruebas en ciclos repetidos un buen diseño debiera emerger de forma natural, claro está que deben controlarse los índices de calidad.




El objetivo inicial de una prueba es, curiosamente, que falle. En el mundo TDD una prueba que falla se representa con un icono rojo y una que se supera con uno verde. Dada una nueva característica implementamos la prueba, creamos el código justo y necesario para enlazar con la prueba y.. nos vamos a rojo. Tenemos algo muy valioso entre manos, nada menos que una prueba que falla conectada con un esqueleto de un código que no funciona, que es mucho más que no tener nada. Ahora nuestro objetivo es generar el código necesario para irnos a verde, prueba superada. Repitiendo el proceso una y otra vez veremos cómo las pruebas nos dirigen hacia la implementación final en pequeños pasos de integración.

Dos temas importantes se quedan en el aire y que veremos más adelante:
  • Maneras de enlazar con las pruebas.
  • Controlar la acumulación de código de mala calidad de un ciclo de pruebas al siguiente.

Por tanto, el ciclo de trabajo en TDD se puede representar por:

1) Escribir una prueba que falle.

2) Escribir código que supere la prueba.

3) Integrar el código eligiendo el mejor diseño que respete todas las demás pruebas anteriores.


Siguiendo este ciclo de trabajo conseguiremos que emerja un buen diseño, el código generado será demostrable ( pues tenemos pruebas de ello ), se tendrán garantías de respetabilidad del sistema en su globalidad siendo el diseño modular y cumplirá estar altamente cohesionado y bajamente acoplado. Claro está que todo ello depende directamente del tercer paso con el que vuelvo a repetir que es sumamente necesario:
  • Controlar la acumulación de código de mala calidad de un ciclo de pruebas al siguiente.
Las técnicas utilizadas para garantizar la calidad del diseño y el código asociado se denominan técnicas de Refactorización, contenido que veremos más adelante y que bien pueden ser tratados como un tema a parte.