Ejercicio: interpretación de métricas de test y cobertura

Amo las métricas, creo que es un efecto colateral de la búsqueda de la mejora continua. Para mejorar es necesario medir, pero con medir no basta, hay que saber qué medir y luego hay que interpretar lo medido para poder accionar al respecto.

Hoy quiero compartir un actividad que hicimos esta semana con mis alumnos de Ingeniería de software en UNTreF. La dinámica fue simple, dado un proyecto tomamos los gráficos de evolución de tests y cobertura generados por Jenkins y los analizamos para generar hipótesis a partir de ellos. Invito a los lectores a sumarse a este ejercicio, analicen los gráficos e intenten extraer información de ellos. Comparto un poco de contexto que les puede resultar útil para el análisis: el proyecto en cuestión es un modelo (o sea pura lógica, sin UI ni base de datos), los desarrolladores son alumnos universitarios que tenían que trabajar con 2 consignas:

  1. Hacer el desarrollo usando TDD
  2. Hacer integración commiteando al repositorio central (en el mainline) luego de cada nuevo test verde.
  3. Si el build se rompe, se para la línea hasta que sea arreglado

analisis_1

Aquí va mi análisis y con mis hipótesis/conclusiones (=>):

  • En el build #10 se agregaron 10 tests => no respetaron la consigna 2
  • Pero a pesar del agregado de tests la cobertura disminuyó => posiblemente por el agregado de código de dominio sin los correspondientes tests => violación de la consigna 1
  • En los siguientes builds (#11,#12 y #13) la cantidad de test aumenta de a uno y también se evidencia un aumento en la cobertura.
  • En los builds #14 y #15 se evidencian nuevamente saltos grandes en la cantidad de tests y de la mano de ello también un aumento de la cobertura.
  • Entre los builds #15 y #18 la cantidad de tests se mantiene constante y lo mismo ocurre con la cobertura => esto podría indicar pasos de refactoring.
  • En el build #19 disminuye la cantidad de tests y con ello la cobertura => esto podría deberse a un cambio en el código de dominio que no fue acompañado completamente por la correspondiente actualización de test.
  • Finalmente la cantidad de tests se mantiene constante en los últimos builds pero la cobertura disminuye => me hace pensar en agregado de código sin los correspondientes tests.

¿algo que agregar?

Notas de mis actividades en Colombia

Por estos días me encuentro en Girardot, una bonita ciudad ubicada a unas 2 horas al sur de Bogotá. Estoy participando de diversas actividades enmarcadas en el Foro de Ingeniería en Sistemas organizado por la Universidad Piloto al cual fue invitado por gentileza de ingeniero Elkin Forero.

La primer actividad que facilité fue una sesión de Programación Orientada a Objetos en la cual hice un breve repaso de los hitos que han marcado la evolución del paradigma y sus implementaciones. (diapositivas aquí)

Otra sesión, ya un poco más avanzada fue un taller de TDD, del que participaron alumnos de la carrera de sistemas. Trabajamos con Java, JUnit y Eclipse. Me gustó mucho como salió la sesión. El código del ejemplo inicial está disponible aquí.

Aprovechando mi visita a la región, el ingeniero Wilson Gordillo me invitó a realizar una ponencia en la Universidad de Cundinamarca. Asistieron a dicha actividad unos 180 alumnos y docentes de distintas instituciones. En este caso hablé sobre la definición de “proyecto exitoso” y la visión de los métodos ágiles al respecto (diapositivas aquí). Luego de la disertación hicimos la dinámica de la fábrica de aviones de la que participaron unas 80 personas y que nos permitió reflexionar sobre cuestiones como spikes, estimación y definition of done.

Aún me quedan por realizar algunas actividades más antes de mi regreso a casa, entre ellas la continuación del taller de TDD que comienza en breves minutos.

Continuará…

 

BDD, ATDD y SBE ¿es todo lo mismo?

En la actualidad nos encontramos con estos 3 acrónimos que en muchas ocasiones son utilizados como sinónimos y cuya diferencia no es del todo clara. Más aún, en Una Mirada Ágil los mencionamos a modo informativo sin entrar en mayor detalle pues consideramos que en esencia todos apuntan a lo mismo: la importancia central del trabajo colaborativo entre técnicos y la gente del negocio para especificar la funcionalidad a construir utilizando ejemplos concretos. Y también todas ponen el aspecto colaborativo por encima del aspecto técnico (ejecución automatizada).

Personalmente creo que las principales diferencias radican en que cada uno de estos términos surgió como consecuencia de distintas líneas de trabajo que se desarrollaron en paralelo con distintos protagonistas, todos ellos trabajando principalmente desde la industria y bajo un paradigma de desarrollo ágil. Más allá de los argumentos que pueda tener cada uno de los protagonistas para insistir con su terminología creo que adicionalmente hay una cuestión natural de “orgullo” (y posiblemente también de negocio/marketing) que en cierto modo dificulta la unificación de terminología. Como suele decirse: “Cada maestro con su librito”.

Más allá de esto quisiera dedicar algunas líneas a cada propuesta en particular:

Behaviour-Driven Development (BDD)

Este es el término posiblemente más utilizado en la actualidad, muy asociado a la familia de herramientas Cucumber y cuyo mayor referente es Dan North. El mismo North define BDD como:

BDD is a second-generation, outside-in, pull-based, multiple-stakeholder, multiple-scale, high-automation, agile methodology. It describes a cycle of interactions with well-defined outputs, resulting in the delivery of working, tested software that matters. 

Resalto aquí el hecho de considerar BDD una metodología lo cual es posiblemente la mayor diferencia (a nivel de marketing al menos) con las otras técnicas.

Acceptance Test-Driven Development (ATDD)

Sin duda el punto inicial de todo esto fue TDD, cuya concepción original por Kent Beck era levemente distinta a la actual. Inicialmente Beck hablaba tanto de prueba unitarias como de usuario (customer tests en términos de XP), pero con el correr del tiempo el término TDD fue tomando una connotación unitaria, o sea, en la actualidad TDD se interpreta casi exclusivamente como UTDD (Unit Test-Driven Development). De ahí la necesidad de utilizar el término ATDD para referirse explícitamente a un ciclo de más alto nivel en el cual está involucrada la gente de negocio. Una curiosidad es que Beck en su libro TDD by Example menciona ATDD, pero como acrónimo de Application Test-Driven Development en lugar de Acceptance que es el término utilizado en la actualidad.

Specification by Example (SBE)

Este es el término impulsado por Gojko Adzic y personalmente es el que más me gusta. No porque proponga algo muy distinto, sino simplemente por la terminologia que propone. En el prefacio de su libro Specification by Example Gojko propone una terminología y explica porque la terminología alternativa comúnmente utilizada no le resulta apropiada.

Finalmente no quiero dejar de mencionar que hay algunos otros términos que también suelen utilizarse como sinónimos y que en esencia son lo mismo pero cuya popularidad es mucho menor. Entre ellos se encuentran Story Test Driven Development (STDD) y Example-Driven Development (EDD).

BDD, ATDD y SBE ¿es todo lo mismo? Si.

Real-world TDD

El viernes pasado me tocó trabajar en una funcionalidad relativamente simple. Dada una aplicación de gestión de proyectos que tiene la capacidad de recibir mails (chiliproject) me pidieron que le agregue la capacidad de rutear los mails de entrada a uno u otro proyecto dependiendo de cierto algoritmo. Cuando estaba por empezar a desarrollarla pensé: “este es un excelente ejemplo para mostrar el uso de TDD en un contexto real”. Entonces abrí mi software de grabación y me puse trabajar. El resultado es este video que muestra cómo resolví parte del problema usando TDD. Espero lo disfruten.

Cómo enseñamos TDD

TDD es una práctica cuyo punto clave es la secuencia de pasos que se siguen para obtener la solución. En Algo3 explicamos la teoría y luego la ponemos en práctica haciendo dojos en las clases. También les damos ejercicios a los alumnos y les pedimos que los resuelven haciendo TDD, pero la realidad es no tenemos forma de asegurarnos que hayan arribado a la solución usando TDD. Hay algunas situaciones observables que pueden sugerir que la solución no fue generada utilizando TDD (por ejemplo si la solución tiene baja cobertura es muy posible que no se haya utilizado TDD o al menos no se lo haya utilizado correctamente o todo el tiempo). Al mismo tiempo todos los ejercicios de programación que resolvemos en clase procuramos hacerlo usando TDD. Finalmente evaluamos su conocimiento sobre TDD con alguna pregunta en el examen. Creo que es un enfoque bastante integral y razonable para el contexto de la materia, donde es común que tengamos más de 40 alumnos por curso. Pero es posible que haya mejores enfoque para otros contextos.

Sin ir más a lejos, yo mismo en UNQ estrené este cuatrimestre un enfoque distinto. Cabe aclarar que el contexto de UNQ es distinto, en primer lugar es una materia de ingeniería de software donde se supone que los alumnos ya vieron algo de TDD. Al mismo tiempo, la cantidad de alumnos es mucho menor, suelen ser alrededor de 10. Finalmente la dinámica de la materia es distinta: no tenemos separación explícita entre teoría y práctica y tampoco tenemos exámenes formales. Lo que hacemos (o mejor dicho lo que hemos hecho este cuatrimestre) es explicar TDD haciendo TDD, de una, explicando la teoría sobre la misma práctica. Luego les damos a los alumnos algunas katas para resolver y les pedimos que graben un screencast mientras van resolviendo la kata. Esto nos permite observar cómo los alumnos aplican la técnica paso a paso y detectar si algo no fue correctamente entendido.

La polémica: TDD está muerto

Recientemente David Heinemeier Hansson, creador del framework Rails, publicó un artículo titulado TDD is dead, long live testing que causó cierto debate con referentes de la disciplina. Incluso Uncle Bob y Kent Beck dedicaron incluso algunas líneas a la cuestión.

Personalmente creo que TDD es una práctica muy útil, la uso a menudo, pero no todo el tiempo ni para todo. Me gusta y suelo usar  TDD cuando tengo que escribir lógica negocio. Generalmente no uso TDD cuando tengo que escribir lógica de presentación y cosas por el estilo.

Lo que destaco de este intercambio de opiniones es que me ha dado material para trabajar con mis alumnos :-).

Clasificación de Pruebas

Existen distintas clasificaciones para las pruebas de software. Desde el punto de vista de cómo se ejecutan, podemos clasificar las pruebas en manuales o automatizadas.

 

Por otro lado, desde el punto de vista de qué es lo que prueban, yo suelo clasificarlas en primera instancia en unitarias o no-unitarias.

 

La prueba unitaria prueba un componente en concreto. Esto implica aislar al componente bajo prueba de sus dependencias. Pues si no lo aislamos y la prueba falla, no tendremos la certeza de si la falla se debió a un error en el componente bajo prueba o si se debió a un problema en una de sus dependencias. Es aquí, donde entran en juego los llamados Test Doubles que no ayudan a aislar el componente bajo prueba.

 

Por su parte, dentro de lo suelo llamar pruebas no-unitarias, entran todos los demás tipos de pruebas, las cuales implican probar la interacción entre distintos componentes. En este tipo de pruebas los componentes ya no están aislados y por ello algunas personas las llama pruebas de integración. En este grupo están tanto las pruebas de aceptación, como las de stress y cualquier otra prueba que implique la interacción en distintos componentes. Dado que hay mucho que decir sobre este tipo de pruebas, dedicaré otro post exclusivo.