Principios del Desarrollo Guiado por Pruebas

Antes de comenzar quiero decir que los fines de semana intentare hablar sobre tópicos que pueden resultar un poco mas avanzados que lo que se esta mostrando en los tutoriales que se publicaran entre semana ( esto es hasta que los tutoriales sean de nivel avanzado). Pero quiero dejar este espacio como un lugar en el que puedo ventilar un poco el material que he ido investigando y tener una charla de tu a tu contigo mi querido lector.

Ya que he aclarado esto vamos a hablar sobre TDD.

Tengo algo que confesar, soy un converso tardío al mundo del Desarrollo Guiado por Pruebas (Test Driven Development o TDD) pero debo decir que se ha convertido en uno de mis principales puntos de interés en el desarrollo técnico de mi carrera como programador y es uno de los puntos primordiales al desarrollarnos como profesionales del desarrollo de software.

Parafraseo a Robert C. Martin (el Tio Bob) en sus charlas sobre Clean Code y Clean Architecture cuando dijo que “la diferencia entre programadores e ingenieros de software es el profesionalismo … y es imposible hablar de profesionalismo sin pruebas automatizadas“.

Qué es el Desarrollo Guiado por Pruebas?

Primero que nada, algunos de ustedes se preguntaran que es este TDD del que estoy hablando (o del que he estado twitteando en los últimos meses), pues bien el proceso del Desarrollo Guiado por Pruebas consiste en entender que en todo proyecto de desarrollo de software profesional deben existir dos tipos de código a desarrollar:

  • Código de Producción. Es el código que estamos acostumbrados a desarrollar, es aquí donde implementamos la funcionalidad del programa, clase o método que se nos este solicitando.
  • Código de Prueba. Es donde desarrollamos las pruebas automatizadas del sistema; este es un principio que puede ser nuevo para algunos programadores que están acostumbrados a realizar pruebas manuales o dejar las pruebas automatizadas en manos de los Testers. Existen tres tipos de pruebas primordiales que se desarrollan en un proyecto de software de TDD:
    • Pruebas Unitarias (Unit Tests). Estas pruebas se encargan de evaluar un punto especifico del código, ya sea un método en especifico o una propiedad, esta prueba se realiza de forma aislada al resto de los programas o clases que conforman el sistema. La idea radica en que todas las dependencias externas deben ser capaces de simularse y probar es el comportamiento de lo que verdaderamente desarrollamos (no pruebes lo que no hiciste, dicen los gurus), esto garantiza que la velocidad de las pruebas sea significativa ya que todo debe correr en memoria.
    • Pruebas de Integración. Estas se encargar de validar el funcionamiento de nuestros programas con dependencias externas, como por ejemplo el sistema de archivos, el entorno de red, los manejadores de bases de datos, etc. Al interactuar con estos elementos y esperar por su respuesta los tiempos tienden a ser mayores que los que obtenemos directamente de las pruebas unitarias.
    • Pruebas de Aceptación. Son similares a las pruebas de integración en que simulan el entorno completo pero su propósito es simular escenarios reales de uso del código y determinar que el comportamiento sea el esperado en un caso real, el cual debe cumplir directamente los requerimientos de las características especificadas del sistema. Creo que la definición que mas me ha gustado es que las pruebas de aceptación prueban qué hace el sistema, mientras que las unitarias prueban cómo lo hace.

Cómo implemento el TDD?

Pues una vez que tenemos clara esta separación en los diferentes tipos de código hay tres reglas que debemos seguir casi religiosamente al momento de desarrollar software:

  1. No se puede crear nada de código de producción a no ser que exista una prueba unitaria que verifique el mismo (la clave consiste en entender en que consiste una buena prueba unitaria).
  2. Se escribirá una prueba unitaria que falle (la falla de compilación cuenta como falla de la prueba), para luego elaborar el mínimo de código de producción necesario para que la prueba pase (en mi opinión esta es la regla mas difícil de adherirse luego de muchos años de desarrollo en forma tradicional).
  3. Una vez la prueba tenga una resolución satisfactoria se puede proceder a optimizar el código, siempre y cuando no se incluya mas funcionalidad que aquella requerida por la prueba (al entrelazar las diferentes pruebas vemos como esta parte se convierte en algo vital para descubrir la forma en la que nuestra código puede optimizarse).

Podemos ver el proceso ilustrado en el siguiente diagrama

Ciclo TDD

Ciclo TDD

Obviamente el proceso no es la respuesta a todos los problemas de programación y hay algunos casos de excepción; por ejemplo, aquellas casos en los cuales no hay mayor ganancia con la implementación de pruebas unitarias (clases con solo getters y setters pueden obviarse) o en algunos casos puntuales en los cuales las pruebas unitarias deben sustituirse por pruebas de integración (que en realidad son casos mínimos), pero en la mayoría de los casos el manejar lo que se conoce como “Probar Primero (Test First)“a través de pruebas unitarias es la mejor practica.

Es quizás complicado presentar la idea de escribir la prueba antes de desarrollar el código, se bien que suena totalmente extraño, impractico y una perdida de tiempo (yo de hecho lo consideraba así) para aquellos que están acostumbrados a la manera tradicional de desarrollar software ya que la practica común es cubrir alguno escenarios con pruebas automatizadas y manuales luego de generar el código.

He descubierto que este efecto de percepción de lentitud tiene dos causantes primordiales:

  1. Como programadores estamos acostumbrados a escribir mucho código de producción, pero no tenemos la habilidad de crear pruebas (y mas aún las unitarias que son algo restrictivas) con la misma agilidad; es necesario considerar un poco la situación antes de hacer el código de la prueba e imaginar los diferentes usos posible de ese código que estamos probando. Como todas las habilidades de un desarrollador, esta no se adquiere de la noche a la mañana y el tiempo que tardamos en aprenderla y reestructurar las pruebas que venimos haciendo o cambiar de tecnologías de prueba puede hacerse engorroso pero te puedo asegurar que no es tiempo perdido.
  2. Por otra parte, hay un factor de dispersión de atención ya que estamos constantemente intercambiando nuestra vista entre las pruebas y el código de producción que puede hacer que se sienta algo pesado al principio; igualmente te digo, es algo de pura percepción y a lo que solo toma un poco de tiempo acostumbrarse.

En qué me beneficio como programador al utilizar TDD?

Creo que el mayor beneficio es un cambio total en la actitud y la manera en la que interactuas con el código.

Para ilustrar lo que quiero decir, mira las siguientes imágenes

I have no idea why my code works

“No tengo ni idea porque funciona mi código”

Los estados del programador

Los estados del programador

Aunque parezca un chiste contra los informáticos (ja ja bro), la verdad es que es una gran realidad a la que mas de una vez nos enfrentamos los programadores, o por lo menos puedo asegurar que a mi me paso; al ver como nuestro código evoluciona sin control, y no hay indicadores que nos permitan descifrar que hace nuestro código con precisión en cada uno de los diferentes métodos; esto genera miedo al cambio, y conforme es necesario agregar funcionalidades al sistema, sentimos cada vez mas temor ya que no sabemos que podemos dañar con cada cambio que introducimos en nuestros sistemas, esto sin hablar siquiera de la idea de modificar código que ya existe y que sabemos puede ser optimizado o la idea de editar código desarrollado por alguien mas.

El tío Bob llama a esto “ser secuestrados por nuestro propio código“.

La idea es que el código que utilizas, sea o no de tu autoría, responda a tus ordenes, no que seas sumiso a lo que hace días, semanas o meses pareció una buena idea y ahora quizás ya no lo sea; que seamos capaces de atacar con certeza y decisión todo el código al que nos enfrentemos y que podamos responder sin mayor inconveniente a las consecuencias de nuestros actos.

En mi opinión esta es la mayor ganancia que obtenemos al adoptar la metodología de TDD.

Puedo dar testimonio de que en mi proyecto mas reciente(que ha sido la recreación con TDD de otro proyecto en el que ya trabaje) he sido capaz de alterar la manera en la que mis clases operan, optimizando y mejorando el diseño que había concebido de manera iterativa y sin preocupaciones; si tengo una idea, simplemente la introduzco en el código y valido que las pruebas se ejecuten de forma satisfactoria. Como por ejemplo

La tranquilidad de ver la barra verde

La tranquilidad de ver la barra verde

 


Creo que por ahora es suficiente, hay mucho mas de los que se puede hablar como por ejemplo el Desarrollo Guiado por Comportamiento (BDD) o Desarrollo Guiado por Pruebas de Aceptacion (ATDD), cómo desarrollar buenas pruebas unitarias (una habilidad escencial para el TDD) o los diferentes frameworks de pruebas disponibles para los diferentes lenguajes, y estoy seguro que hablaremos de todos ellos en su momento, pero por ahora espero por lo menos haberte dejado con la intriga para explorar mas sobre el tema del TDD.

En nuestro siguiente post sobre TDD creo que nos enfocaremos en como detectar y erradicar los olores en nuestras pruebas unitarias.

Lo se, a mi también me pareció raro al principio.

Hasta la próxima.

Anuncios
Esta entrada fue publicada en Blogging y etiquetada , , , , , , , , , . Guarda el enlace permanente.

Una respuesta a Principios del Desarrollo Guiado por Pruebas

  1. Pingback: Creando Buenas Pruebas Unitarias | MondongoSoft

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s