lunes, 3 de abril de 2017

¿Como hacer una Kata TDD en una simulación de Scrum?

Mi compañera Marisa y yo hemos ideado una simulación basada en la Kata Test Driven Development (TDD): Example Walkthrough de Viktor Farcic. Combina la Kata con una simulación de Scrum.

En la fase preparatoria se constituyen los diferentes equipos del ejercicio, recomendable de 3 a 4 miembros, y cada uno de ellos prepara su tablero. Los equipos se forman por mesas y es muy aconsejable equilibrar el conocimiento, que el expertise esté balanceado y haya expertos de java en cada uno de ellos. El tablero debe de tener el diseño de la imagen que sigue y el equipo lo cuelga cerca de su mesa. Para cada requisito del ejercicio han de prepara un post-it y colocarlo en la columna "Pila de producto".
Tablero para la Kata TDD con Scrum
La simulación trata de hacer 3 sprints, con todas sus reuniones, para que el equipo desarrolle la calculadora descrita en el ejercicio de la Kata. El trainer o profesor hace de Propietario del Producto para resolver dudas del ejercicio. El ciclo de reuniones será como sigue:
  • 5 minutos para la planificación de sprint: el equipo decide donde hacer el corte en la pila de producto y llevarse los post-its correspondientes a la columna de "Pendiente". Cada post-it lo han de marcar con el sprint para el que ha sido planificado, así podremos ver el sprint para el que estaba previsto cada requisito y el sprint en el que se ha completado.
  • 25 minutos de construcción en los que el equipo construye la calculadora en base a los requisitos. ¡Atención! El equipo ha de construir los requisitos en el orden del ejercicio y de uno en uno, y lo hace ante un solo ordenador a modo de mob programming, lo que implica que cada 5 minutos aproximadamente el teclado rota de miembro. Los requisitos finalizados pasan de la columna "En curso" al área correspondiente al sprint en la columna "Hecho". ¡Atención! Un requisito no está finalizado sin la correspondiente refactorización.
  • Para la revisión de sprint se lleva el workspace a un ordenador con proyector, usualmente el del profesor, y cada equipo hace la demo de lo que han construido ante los demás equipos que actúan a modo de interesados.
  • Finalmente 5 minutos para una retrospectiva en la que cada equipo busca una sola acción de mejora para el siguiente sprint.
Evolución de los tableros a lo largo de los 3 sprints de la Kata con los alumnos del CSD de marzo de 2017
Las instrucciones de la Kata TDD que siguen son la traducción del post Test Driven Development (TDD): Example Walkthrough de Viktor Farcic. Tanto en su post como al final de este, en el área de descargas, se pueden ver las soluciones a cada uno de los requisitos.

Ciclo TDD
El proceso TDD descansa en una forma de desarrollo que depende de la repetición de un ciclo muy corto. Primero el programador escribe un caso de prueba, que verifica una funcionalidad, y después escribe la cantidad de código mínima necesaria para pasar ese caso de prueba. Finalmente refactoriza el código para que sea un código que cumpla estándares de calidad.

Los pasos que se siguen son:
  • Crear la prueba
  • Ejecutarla y comprobar que falla
  • Escribir código que pase la prueba
  • Refactorizar el código
  • Repetir esto hasta obtener el código con el nivel de calidad deseado
Seguido mostramos el enunciado de cada requisito/iteración del ciclo TDD. Se debe de leer cada requisito e intentar buscar una solución. Tengamos en cuenta que la forma de probar e implementar no es única, por lo tanto hay más de una posible solución.

El ejercicio trata de crear una calculadora que sea capaz de sumar los números que hay en una cadena de caracteres con el método sumar(String números) con la siguiente funcionalidad:
  • El método puede recibir 0, 1 o 2 números y devolverá su suma. Por ejemplo son válidas las cadenas "", "1" o "1,2". Para la cadena vacía debe devolver un 0.
  • Permitir que el método maneje una cantidad de números ilimitada.
  • Permitir que para separar los números venga un salto de línea marcado por una "n" en vez de una coma. Por ejemplo la cadena "1n2,3" es válida y debe devolver un 6.
  • Permitir distintos delimitadores. Para cambiar el delimitador empezar con una cadena que contenga el delimitador de la siguiente manera "//[delimitador]\n[números…]". Por ejemplo: "//;\n1;2" debe de devolver un 3.
  • Todos los escenarios deben ser soportados. Es decir, delimitador coma, delimitador salto de línea y delimitador cambiado.
  • Si se invoca al método sumar con números negativos, este debe lanzar una excepción "los negativos no están permitidos" y mostrar los números negativos erróneos.
  • Los números mayores de 1000 se deben de ignorar, de forma que 2+1001=2.
Requisito 1: El método sumar puede aceptar 0, 1 o 2 números separados por una coma:
  1. Escribir un caso de prueba que compruebe: si se reciben más de 2 números la función lance una excepción, si se reciben 2 números devuelva true y si se recibe una cadena que contiene un carácter no numérico lance una excepción.
  2. Escribir la función sumar que sea capaz de superar estos 3 casos de prueba.
 Requisito 2: Para la cadena vacía el método devolverá 0:
  1. Escribir un caso de prueba que compruebe que cuando se invoca el método sumar con la cadena vacía devuelve un 0.
  2. Modificar el método sumar para que devuelva 0.
Requisito 3: El método devolverá la suma de números:
  1. Añadir los casos de prueba para comprobar que el método sumar es capaz de devolver un número cuando es invocado con un número, o de sumar dos números cuando es invocado con 2 números.
  2. Modificar el método sumar para que o devuelva un número o sume dos.
Requisito 4: Permitir que el método sumar maneje una cantidad indefinida de números:
  1. Añadir un caso de prueba para comprobar que el método sumar es capaz de sumar por ejemplo los números 3,6,15,18,46,33. Ojo hay que quitar el caso de prueba que comprueba que si se envían más de dos números se lanza una excepción.
  2. Modificar el métodos sumar para que pueda sumar estos números. Ojo, hay que quitar la excepción que devuelve cuando recibe más de 2 números.
Requisito 5: Permitir que el método sumar maneje saltos de línea entre los números, además de comas:
  1. Añadir el caso de prueba que compruebe que un salto de línea (n) se acepta como separador de números dentro de la cadena.
  2. Modificar el método sumar para que tenga en cuenta que el delimitador puede ser una coma o una n.
Requisito 6: Permitir el uso de distintos delimitadores:
Para cambiar el delimitador, al principio de la cadena se incluirá de lo siguiente "//[delimitador]\n[numeros…]" por ejemplo "//;\n1;2" debería ser tomado como los números 1 y 2 separados por el delimitador ";".
  1. Incluir un caso de prueba para comprobar que cuando se envía la cadena "//;\n1;2", el resultado de la suma es 3.
  2. Modificar el método sumar para que contemple este caso. El resto de los casos deben seguir funcionando.
Esta vez hay un montón de código que refactorizar. Partimos el código en 2 métodos. El método inicial analiza la cadena buscando el delimitador y después llama al método sumar con los parámetros cadena y delimitador para que sume los números. Como disponemos de módulos de prueba para comprobar que todo sigue funcionando, no hay problema con todos estos cambios (refactorización). Si algo va mal los test encontrarán el problema.

Requisito 7: Si hay números negativos se lanzará una excepción:
Llamar al método sumar con un número negativo lanzará una excepción "los números negativos no están permitidos" y se mostrarán los números negativos enviados en el mensaje.
  1. Incluir un caso de prueba para probar que para la cadena ("3,-6,15,-18,46,33"), se lanza una excepción en la que en el mensaje se incluyen los números -6 y -18. 
  2. Modificar la calculadora para que lance la excepción en el caso de que la cadena contenga números negativos.
Requisito 8: Los números más grandes que 1000 deberían ser ignorados:
Por ejemplo: sumar 2 + 1001 = 2.
  1. Incluir un caso de prueba para comprobar que los números mayores de 1000 no se suman
  2. Modificar el método sumar para que no sume los números mayores de 1000
Requisito 9: Los delimitadores pueden ser de cualquier longitud:

Cuando el delimitador tenga más de un carácter se usará el formato: “//[delimitador]\n”. Ejemplo: "//[-]\n1-2-3" que debe de devolver un 6.

Requisito 10: Permitir delimitadores múltiples:

Utilizar el siguiente formato: "//[delimitador1][delimitador2]\n". Ejemplo "//[-][%]\n1-2%3" que debe de devolver un 6.

Requisito 11: Asegúrese de que también puede manejar múltiples delimitadores con longitud más larga que un carácter.
Por ejemplo “//[--][%%]\n1-2%3” debería devolver 6.
Revisión de sprint, equipo a equipo muestra los requisitos construidos en el sprint
Mis agradecimientos a los alumnos del curso de mayo de 2017
Dale una oportunidad a TDD

A menudo a los principiantes en TDD el proceso les parece apabullante. Una de las quejas más comunes es que TDD relentece el proceso de desarrollo. Esto es cierto al principio, toma un tiempo hacer las cosas de esta nueva forma y coger velocidad, sin embargo después de un poco de práctica el proceso acaba ahorrando tiempo de desarrollo, consigue mejores diseños, fuerza la refactorización, incrementa la calidad y la cobertura de código y asegura que el software está probado. Otro gran beneficio es que los test son documentación sobre lo codificado, y de esta forma la documentación siempre está actualizada.

TDD provoca que el programador se centre en su tarea, codificando solo aquello que es necesario. Además en último término hace que los programadores hagan mejor su trabajo.

Descargas / Downloads
Mis agradecimientos a Viktor Farcic por su post original y a Marisa por la traducción y la facilitación del ejercicio.

No hay comentarios:

Publicar un comentario