Trabajar con legacy code. ¿Es seguro en entornos ágiles?

Compartir esta publicación

Share on facebook
Share on linkedin
Share on twitter
Share on email

Introducción

Muchas empresas, quieren aplicar metodologías ágiles en sus proyectos, pero al principio de la mayoría de los proyectos de coaching ágil, nos encontramos con que las aplicaciones de nuestros clientes no están debidamente cubiertas con ningún tipo de pruebas automatizadas. 

En la mayoría de los casos, la organización no tiene planes de deshacerse de esas bases de código y empezar de cero, lo que significa que tenemos que diseñar un plan para abordar el eterno problema de la calidad del código heredado.

¿Cómo tratan los equipos de éxito el código heredado para estabilizar la calidad y mejorar la entrega general del producto? Este será el tema principal de este artículo. 

Cuando trabajamos con código heredado

Llamamos código heredado a cualquier código que no esté cubierto por pruebas automatizadas. Por difícil que parezca, puede que te des cuenta de que actualmente estás escribiendo código heredado para los próximos meses.

Aunque seas tú quien lo escriba, el mes que viene, nadie recordará exactamente para qué se creó este trozo de código, sólo que podemos minimizar si tenemos una gran unidad, integración y pruebas de aceptación.

En un entorno ágil, las pruebas son la documentación más importante. He visto en algunas organizaciones en las que se informaba de más de tres errores críticos por equipo de desarrolladores a la semana, lo que destruye cualquier posibilidad de seguir un plan en el sprint.

Los desarrolladores tienen la idea de que arreglar errores es aburrido, agotador y deprimente. Describir los escenarios y escribir las pruebas automatizadas antes de desarrollar una historia de usuario garantiza que todos tengan la misma visión de lo que hay que desarrollar. Estas actividades no sólo minimizan la necesidad de escribir nuevos bugs debido a la reelaboración o a los escenarios no contemplados, sino que también, y es el objetivo más importante, se ve como una parte necesaria del desarrollo de aplicaciones robustas.

Cuando trabajamos con código heredado, los tipos de pruebas más valiosos son las pruebas de aceptación (pruebas de caja negra). No necesitamos tener un código bien escrito; no hay dependencia para empezar a escribir pruebas automatizadas contra la interfaz de nuestra aplicación. Cuando queremos empezar a escribir pruebas unitarias/de integración: el código probablemente estará acoplado, no es compatible con los principios SOLID. Escribir nuestra primera prueba unitaria puede ser un dolor de cabeza.

No sólo escribimos pruebas de aceptación, sino que también aprovechamos esta red de seguridad creada con las pruebas de aceptación, y empezamos a refactorizar nuestro código base.

Esta refactorización debería centrarse en permitir la escritura de pruebas unitarias y de integración o la reescritura de componentes con muchos errores. 

El objetivo es no sólo embellecer o simplificar la lectura del código, sino también obtener resultados de esta inversión. Decidimos escribir pruebas automatizadas porque creemos que va a traer un beneficio: menos errores reportados, lo que lleva a menos dinero perdido para nuestra organización a causa de esos errores.

¿Qué estrategia debemos seguir para seleccionar una parte del código para las pruebas de escritura?

En alguna bibliografía podemos encontrar una pequeña guía para ayudarte a decidirlo:

Tipo de prueba Descripción Tiempo de desarrollo Tiempo de ejecución Bugs cubiertos
Test unitarioCubre un método de una clase, utilizando mocks para falsear el comportamiento de otras clases/métodos utilizados desde el método probado.BAJO: Minutos.
BAJOBAJO. Sólo es eficaz para detectar errores cuando alguien cambia el código del método sin considerar todos los casos posibles.
Test de integraciónCubre un método en una clase, sin mocking. En realidad, llama a los otros objetos, y si es necesario, carga accesorios (datos falsos) en el almacenamiento de datos.MEDIA: Más larga que una unidad, quizás más de una hora.MEDIAMEDIA. Eficaz para detectar código en un rango más amplio que las pruebas unitarias.
Prueba de aceptación automatizadaLa misma prueba que haría un usuario contra nuestra aplicación, pero realizada por una máquina.ALTO: Dependiendo de la tecnología, quizás más de una hora por escenario.
ALTOALTO. Detectará cualquier error o problema.

Llegados a este punto, es probable que estés preparado para trabajar en el plan para probar nuestro código heredado. Aquí hay algunos pasos que no deberías saltarte.

Paso 1: Elige tu stack tecnológico

¿Qué herramientas, lenguaje de programación o marcos de trabajo vas a utilizar para escribir tus pruebas? Esta es la arquitectura básica de sus pruebas y, como tal, será realmente difícil de cambiar si toma la decisión equivocada. En este punto, le sugiero que involucre a su Director de Tecnología (CTO) o a los líderes técnicos para tomar esta decisión. Es importante contar con las personas adecuadas.

Paso 2: Preparar una suite de integración continua

Nuestras pruebas deben ser ejecutadas después de hacer el commit en su herramienta de integración continua (CI). La ejecución de todas nuestras pruebas no debería llevar más de 10 a 20 minutos o el tiempo mínimo para que los desarrolladores realicen una revisión del código en un commit relacionado con una pequeña historia de usuario. Estas pruebas deben escribirse de la forma más independiente posible. No deben ser frágiles; la configuración, el desmontaje y la propia lógica de las pruebas deben estar bien diseñados para garantizar que las diferentes pruebas que se ejecuten simultáneamente no den falsas alertas. Deberíamos estar preparados para paralelizar la ejecución. 

Paso 3: Defina los niveles de prioridad de sus aplicaciones

La prioridad debe ser acordada por toda la organización (este punto es muy importante). Intente mantenerla lo más sencilla posible. Lo ideal es tener sólo tres niveles de prioridades (Alta (P1), Media (P2), Baja (P3)).

Por ejemplo:

Los incidentes de alta prioridad deben cumplir al menos una de estas condiciones:

– El sistema no funciona

– Sistema gravemente dañado

En este caso, pondremos toda nuestra energía en este incidente en cualquier momento y no pararemos hasta que hayamos resuelto el incidente y finalmente hayamos arreglado el error de código que está causando este problema.

Impacto medio. La aplicación puede funcionar con una funcionalidad limitada:

  • Sistema dañado

En este caso, planificaremos este fallo para que se solucione durante el siguiente sprint. Se priorizará con el resto de historias de usuario

Impacto bajo. La aplicación funciona correctamente; sin embargo, no hay ningún defecto estético o no crítico:

  • Sistema ligeramente afectado

Este caso se arreglará eventualmente, en algún momento de acuerdo con nuestra política de errores

Todas las partes implicadas deben estar de acuerdo con esta lista. También debe incluir ejemplos reales para los diferentes niveles de prioridad.

¿Qué se va a automatizar? Incidencias catalogadas como de alta prioridad o componentes que cambian frecuentemente en nuestra aplicación, estos grupos son claros candidatos a la automatización.

Paso 4: Enumerar las características de su producto

Define las características de alto nivel y asígneles prioridades. Si a una característica se le asigna P1, profundiza en ella. Comienza a dividir las funcionalidades o a crear nuevas funcionalidades dentro de la característica P1 como historias de usuario. Asigna una prioridad a cada una de esas historias de usuario.

Si una característica es P2, pero es una parte de su aplicación que cambia con frecuencia, nombre la característica P2UP. Para esas P2UP, escriba las historias de usuario contenidas en esa característica. De nuevo, asigne prioridades a cada historia de usuario.

Cualquier característica con una prioridad P1 o P2UP es aquella para la que se escribirán pruebas automatizadas. En este punto, si planeas ejecutar pruebas de regresión (manualmente) antes del lanzamiento, deberías describir todos los escenarios. Si no tiene previsto hacerlo, puede describir los escenarios como parte de la automatización de cada historia de usuario.

Paso 5: Desarrollar pruebas de aceptación

No vamos a apuntar inicialmente a un porcentaje específico de cobertura de código en términos de pruebas unitarias o de integración. Nuestro objetivo inicial es cubrir el 100% de P1 automatizado y el 100% de P2UP. La mejor manera de escribir las pruebas de aceptación automatizadas es utilizando cualquier implementación de Gherkin, aunque hay implementaciones en muchos lenguajes de programación.

BDD - Gestión de pruebas

En esta etapa, deberías tener un backlog de automatización de pruebas ya priorizado. Recuerda que es un backlog vivo, porque a cada nueva función que escribas hay que asignarle una prioridad. 

Si una nueva historia de usuario es P1 o P2UP, también debe ser automatizada y si el tiempo lo permite, debe automatizar el resto de los escenarios de prueba. 

Cada equipo define cómo realizar el trabajo en un sprint, lo ideal es que todos los miembros del equipo dediquen tiempo cada sprint a automatizar algunas pruebas. Sin embargo, la única persona que trabaja en las pruebas automatizadas carga con la responsabilidad de garantizar la calidad del producto. Esto suele conducir a peores resultados.

En cuanto se decida a escribir pruebas automatizadas, empiece a hacer un seguimiento del impacto que tiene su trabajo. 

A continuación se presentan algunas correlaciones especialmente interesantes para comprobar su impacto:

  • Entre las pruebas ejecutadas antes de cada lanzamiento y los nuevos errores P2 reportados
  • Entre las pruebas de aceptación automatizadas y los infartos de final de carrera
  • Entre las pruebas ejecutadas antes de cada lanzamiento y el porcentaje de tiempo dedicado cada sprint al desarrollo de nuevas características
  • Entre las pruebas unitarias/de integración y los errores detectados en su suite CI

Escribir pruebas unitarias o de integración

Una vez que haya creado una red de seguridad con sus pruebas de aceptación automatizadas, puede refactorizar las partes más defectuosas de su aplicación. En este punto puedes empezar a hacer crecer tu código de automatización.

Conseguir una cobertura de código del 100 por cien con pruebas de integración/unidades es muy complejo en las aplicaciones heredadas y no siempre merece la pena el esfuerzo. 

El objetivo principal es centrarse en cubrir las funcionalidades con pruebas de aceptación automatizadas y escribir sólo pruebas de unidad/integración para aquellas partes de la aplicación que se cambian con frecuencia.

En general, los desarrolladores aspiran a conseguir una cobertura del 100 por cien en la unidad/integración. Sin embargo, dependiendo del tamaño de tu aplicación, y de las circunstancias actuales, no vale la pena dedicar tiempo a escribir esas pruebas para las partes no críticas o que nunca cambian. Es más inteligente escribir pruebas unitarias/de integración para aquellas partes de la aplicación que son críticas y que cambian continuamente, lo que nos lleva a las historias de usuario definidas como P1 o P2UP.

Conclusión

Cuando nos encontramos con Código Legado, debemos diseñar un plan que garantice la calidad de ese código, y sólo podemos garantizarlo si lo cubrimos con TESTs automatizados. Para definir las partes del código que vamos a automatizar, primero debemos dividir nuestra aplicación en sus funcionalidades y establecer una prioridad para ellas. Por el momento sería suficiente con garantizar la cobertura del código de las funcionalidades categorizadas como más prioritarias o de las funcionalidades que incluyan componentes que cambien con frecuencia, ya que en la mayoría de los casos no tendremos tiempo de conseguir una cobertura del 100% de todo nuestro código.

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Suscríbete a nuestro boletín de noticias

Recibe actualizaciones de los últimos descubrimientos tecnológicos

Acerca de Apiumhub

Apiumhub reúne a una comunidad de desarrolladores y arquitectos de software para ayudarte a transformar tu idea en un producto potente y escalable. Nuestro Tech Hub se especializa en Arquitectura de Software, Desarrollo Web & Desarrollo de Aplicaciones Móviles. Aquí compartimos con usted consejos de la industria & mejores prácticas, basadas en nuestra experiencia.

Posts populares
Descarga Grow Professionally: Inside Apiumhub's Dev Team

¿Estás orientado a Datos?

Construyamos tu éxito juntos.

Contáctanos

¿Tienes un proyecto desafiante?

Podemos trabajar juntos