miércoles, 29 de septiembre de 2010

Toda la verdad acerca de los Tests de Unidad

Porque son tan importantes los tests de unidad?

Uno podria preguntarse que hay detrás de taaaanto rollo acerca de una de las prácticas fundamentales tanto de XP como de toda lista de Buenas Prácticas de Programación. Porque es tan importante hacer tests de unidad?. Este posteo intenta justamente responder a esa pregunta, explicando detalladamente los beneficios principales que se obtienen al hacer tests de unidad.

Esta lista no intenta ser extensiva, ni se obtienen solo al hacer Test Driven Development, TDD, ya que algunos de los beneficios se obtienen también haciendo tests de unidad "PostMorten", es decir, luego de escribir el código.

Vamos, primero, a la enciclopedia galactica:

Tests de unidad: son los tests que un programador debe escribir para testear que su código hace lo que él entendió que se le solicitó que haga, a través del documento de especificación funcional, sea una historia de usuario, caso de uso o conversación con usuarios.

Hacemos esta distinción para diferenciarlos de los tests de aceptación que son aquellos tests de más alto nivel que deben verificar que la funcionalidad desarrollada es aceptada de acuerdo a lo definido en el relevamiento con los usuarios.

Por otro lado cuando decimos que se hacen tests de unidad o TDD estamos asumiendo que se realizan correctamente y con un cubrimiento del total de código del modelo (en un framework MVC) escrito de más del 80%.

Para aquellos que quieran hacer el salto más significativo en el desarrollo de software desde la invención de la Programación Orientada a Objetos (y no estamos exagerando), los beneficios son:

El beneficio global primero y quizás más importante es que el conjunto de tests de unidad funcionan como una malla de seguridad que permite hacer cambios al código de una manera segura y órdenes de magnitud más rápida que cuando no tenemos tests. Y esto para un mundo no perfecto como el que vivimos en el cual los usuarios/la realidad/Lo-que-Sea piden cambios de funcionalidad constantemente no es poca cosa.

En detalle, los beneficios que nos proveen los tests de unidad son incontables (como los beneficios de la soja ;) :

  1. Los tests de unidad verifican que el código en realidad funciona (de acuerdo a lo que entendió el programador, vale la pena aclararlo) lo cual significa que vamos a tener menos bugs y errores.
  2. TDD fuerza a pensar en los contratos de clases y métodos antes de escribir el código, lo cual lleva a un diseño mejor y mucho más preciso de la solución al problema planteado.
  3. Los tests de unidad hacen posible mejorar iterativamente el diseño del sistema sin romperlo. Como contamos con un conjunto de tests de unidad que verifican todo lo que se puede romper, podemos aplicar mejoras al diseño de manera incremental a través de pequeños pasos de refactoring y luego verificar si funciona corriendo todos los tests. Ante un error podemos fácilmente determinar que parte del nuevo código rompió el sistema y corregirlo.
  4. No reemplazan pero complementan muy bien a los tests de aceptación y de integración.
  5. En si sirven como un conjunto de tests de regresión de bajo nivel.
  6. Funcionan como documentación y Reduce el tiempo necesario para entender el código escrito. En general nos olvidamos muy rápidamente de lo que hace el código que escribimos hace apenas unos días atrás (mas de una vez ha pasado que miramos el código asombrados pensando en el... espécimen que habrá escrito semejante zafarrancho para terminar dándonos cuenta que fuimos nosotros mismos.... y no, no digan que nunca les paso). Imaginen además cuando tenemos que entender código escrito por otros. Los tests de unidad funcionan como perfectos ejemplos de utilización del código, documentan la utilización correcta del cada método no trivial y de la relación entre las clases. Y a diferencia de la documentación no quedan desactualizados al instante porque en cuanto eso sucede uno o varios del 100% de los tests de unidad comienzan a fallar y debemos arreglarlo (o el test o el código).
  7. Reduce el costo de mantenimiento. En Lean Software Development se define el costo de un bug como el tipo de criticidad del error (bajo, medio, alto), multiplicado por el tiempo en que permanece no detectado. Tener un buen conjunto de tests de unidad permite reducir drásticamente el tiempo que lleva detectar un bug, y corregirlo. A la vez, si uno desarrolla el sistema haciendo TDD se introducirán muchos menos errores y además cuando se sucede se detectan casi inmediatamente, el error esta en lo ultimo que se cambió.
  8. Nos sacan de un viejo círculo vicioso del desarrollo de software: como tenemos miedo de realizar cambios en la estructura de un programa, hacemos las modificaciones imprescindibles mediante parches, lo que causa que el programa sea mas díficil de modificar, lo que causa que nos de miedo realizar cambios estructurales...
  9. TDD nos fuerza a a usar Pasos de Bebé y por lo tanto a pasar menos tiempo en el debugger.

Una de las objeciones principales que se hacen en contra de escribir tests de unidad es que como es más cantidad de código que hay que escribir entonces esto va a hacer que el desarrollo vaya más lento, verdad?. Esto sería verdad si fuera que nosotros, los programadores, somos una especie de taquígrafos que nos pasamos la mayor parte del tiempo tipeando en un teclado, y entonces la cantidad de teclas por minuto se contaría como productividad. Pero esto no es asi, nos pagan por pensar, por diseñar y evolucionar una solución a un dominio de problemas. Esta comprobado que la mayor parte del tiempo un programador la pasa pensando como modelar una solución y, sobre todo, buscando errores y bugs. Escribir tests de unidad sirve justamente para hacer estas dos actividades mucho mas eficientes.

Como conclusión, y aunque sea antiintuitivo, escribir tests de unidad lleva menos tiempo total que no escribirlos.

No hay comentarios:

Publicar un comentario