Los 10 mandamientos para cambiar un microservicio
- 1. No tomarás el nombre de los tests en vano
- 2. No abordarás todo el cambio en un solo paso
- 3. Honrarás la rama principal
- 4. No evitarás las puestas en producción en vivo
- 5. Usarás andamiaje
- 6. Usarás feature toggles
- 7. Aumentarás tu cobertura de tests
- 8. Recuerda limpiar el código que ya no se necesita
- 9. Cambiarás tus clientes antes de hacer una limpieza
- 10. Te asegurarás de que nadie esté usando el código antiguo
- Siguiendo los mandamientos: el camino hacia migraciones seguras
Los microservicios como término se han vuelto cada vez más populares en los últimos años y se utilizan para describir una variante del estilo arquitectónico SOA que crea una aplicación como una colección de servicios débilmente acoplados. Cada microservicio tiene su propio propósito e implementará diferentes interfaces o protocolos de comunicación. Por lo tanto, cualquier problema dentro de un microservicio requerirá una solución diferente y ad-hoc.
En mis equipos anteriores, construir microservicios nos ha proporcionado un conjunto de prácticas y técnicas estándares de la industria para ayudarnos a asegurar transiciones exitosas y sin problemas cuando se trata de una gran refactorización o cambios incrementales. Intentar proporcionar instrucciones sobre cómo abordar cada cambio es desafiante, así que hemos decidido convertir nuestro conocimiento en una guía útil: nuestros 10 mandamientos para cambiar un microservicio.
Sin más preámbulos, aquí están nuestros 10 mandamientos. ¡Síguelos de cerca!
1. No tomarás el nombre de los tests en vano
Antes de comenzar un gran cambio, es necesario tener una buena cobertura de tests (desde una perspectiva unitaria y/o de integración). ¿Estás seguro de que tus cambios no romperán nada si no puedes definir con tests qué significa “nada”? Deberías tener tus expectativas definidas y controladas automáticamente por adelantado. ¡La importancia de un buen testing previo no puede subestimarse!
Los frameworks de testing modernos como Vitest, Jest, Pytest o JUnit hacen que sea más fácil que nunca construir suites de tests completas. Además de los tests unitarios, considera implementar tests de integración y tests de contrato usando herramientas como Pact para validar el comportamiento de tu microservicio.
2. No abordarás todo el cambio en un solo paso
Aquí aplica un dicho famoso: ¿Cómo te comes un elefante? Bocado a bocado. Intentar hacer un cambio masivo de una vez es arriesgado, caótico y propenso a errores. No dejes que las fechas límite o la presión nublen tu pensamiento. La paciencia y la disciplina son clave aquí: planifica tu estrategia como un conjunto de “micro cambios” en su lugar. Cada pequeño commit será un paso extra hacia el éxito: un bocado cada vez.
3. Honrarás la rama principal
Haz varios cambios, divídelos y súbelos a la rama main del repositorio. De esa manera pensarás en hacer tus cambios inofensivos y listos para ir a producción lo antes posible. Es mejor ir a producción con código inacabado pero seguro que ramificar con una bomba de tiempo. Además, subir un commit en main hará que tus compañeros de equipo sean conscientes de lo que estás haciendo.
Este enfoque se alinea con el trunk-based development, donde los desarrolladores integran cambios frecuentemente en la rama principal, evitando el infierno de integración de las ramas de feature de larga duración.
4. No evitarás las puestas en producción en vivo
Seguir el mandamiento anterior te permitirá confirmar cambios más pequeños y seguros y ponerlos en producción con un riesgo mínimo. Es mejor realizar lanzamientos escalonados, ya que esto agregará valor más rápido y minimizará el riesgo que viene con una gran revelación. Las promociones en vivo te permiten hacer cambios lentamente y pueden darte mejoras tangibles sobre la marcha.
5. Usarás andamiaje
El andamiaje es el proceso de agregar código temporal para mantener la aplicación funcionando mientras estás cambiando algo más. No intentarías arreglar tu tejado sin andamios. Lo mismo ocurre con los microservicios. Por ejemplo, en el caso de una nueva API crearías nuevas rutas para soportar la nueva API mientras sirves peticiones a la antigua, para no romper ningún cliente. En otras palabras, haz que tu microservicio sea retrocompatible con el cambio en curso.
6. Usarás feature toggles
Si puedes controlar el comportamiento de tu microservicio mediante configuración, entonces añadirás mucha flexibilidad a tu proceso de cambio. Con interruptores de funcionalidades (feature toggles), podrías habilitar tus cambios para cada entorno, por ejemplo (para que pudieras probar tus cambios antes de ir a producción). También puedes configurar tu microservicio para soportar el cambio entre versiones por http, de modo que una entidad externa pueda cambiar la versión de tu código basándose en ciertos criterios.
Otra posibilidad es hacer que tu microservicio sea un poco más inteligente y permitir que tu feature toggle se habilite/deshabilite basándose en métricas de health check: esto te permitiría revertir a la versión anterior automáticamente si las métricas reportan muchos errores con la nueva. Finalmente, con un feature toggle más sofisticado podrías incluso especificar diferentes niveles de granularidad (por ejemplo, podrías habilitar la nueva versión solo para ciertos usuarios en un entorno dado, o desde un país individual usando un dispositivo específico).
El lado oscuro de los feature toggles
Sin embargo, los interruptores de funcionalidad tienen un lado oscuro: si tienes demasiados, o si son demasiado granulares, será difícil testear, ya que el código se comportaría de manera diferente según un número de combinaciones. Intenta mantener un equilibrio. Las plataformas modernas como LaunchDarkly o Split.io ayudan a gestionar esta complejidad, pero recuerda: los feature toggles son deuda técnica—límpialos una vez que la migración esté completa.
7. Aumentarás tu cobertura de tests
Si has seguido los mandamientos anteriores, entonces habrás terminado con versiones retrocompatibles del código, lo que significa que tendrás una versión antigua y una nueva. Deberías haber comenzado con tests para el comportamiento antiguo, pero ahora también deberías agregar cobertura de tests para el nuevo. Esto es lo que permanecerá después de completar tus cambios, así que debes asegurarte de que sea seguro.
8. Recuerda limpiar el código que ya no se necesita
No limpiar código no utilizado o redundante es una de las razones para considerar una refactorización, así que ahorra algo de tiempo ahora mientras el contexto está fresco en tu mente. Elimina el código antiguo y todo el andamiaje después de asegurarte de que usar los nuevos cambios es seguro. No dejes basura en tus servicios, es confuso y obliga a las personas a pasar más tiempo leyendo el código. Adquirir el hábito de asegurar que tu código esté limpio dará sus frutos a largo plazo.
9. Cambiarás tus clientes antes de hacer una limpieza
Por obvio que sea, tu servicio será usado por muchos clientes diferentes. Si por ejemplo has creado un cambio que rompe compatibilidad y requiere el uso de una nueva API o una nueva routing key, necesitarás hacer que todos los clientes comiencen a usar la nueva versión antes de eliminar la antigua, o comenzarán a fallar y reportar errores. Este mandamiento puede parecer simple, pero para evitar problemas con los clientes, asegúrate de hacer las cosas en el orden correcto.
La secuencia adecuada:
- Despliega la nueva versión junto a la antigua
- Migra los clientes a la nueva versión
- Monitoriza el uso de la versión antigua
- Elimina la versión antigua cuando el uso caiga a cero
10. Te asegurarás de que nadie esté usando el código antiguo
Dado que los microservicios son agnósticos respecto a quién está usando su API, no hay una forma obvia de saber si eliminar la versión antigua del código es totalmente seguro o no. Sin embargo, podrías poner algo de monitorización en su lugar, usar algo de logging o enviar métricas durante un período de tiempo razonable para observar los niveles de uso de estas funciones antiguas. De esa manera, puedes asegurarte de poder eliminar el código antiguo si ningún cliente está haciendo uso de la versión antigua.
Las herramientas de observabilidad como Prometheus, Grafana o soluciones de monitorización nativas de la nube (CloudWatch, Azure Monitor) hacen esto sencillo. Espera al menos un ciclo de negocio completo antes de declarar el código antiguo completamente sin uso.
Siguiendo los mandamientos: el camino hacia migraciones seguras
Los microservicios, y sus cambios, pueden ser obstáculos difíciles de abordar. Crear una solución ad-hoc puede ser desafiante y es importante seguir un conjunto de directrices y principios al hacer cambios para asegurar que el resultado sea el deseado, tanto para ti como para el cliente.
Estos 10 mandamientos son prácticas probadas en batalla que han ayudado a equipos a evolucionar arquitecturas complejas de microservicios sin romper producción. La clave es la disciplina: sigue estos principios incluso cuando estés bajo presión, especialmente cuando las fechas límite se acercan. Tomar atajos puede parecer tentador, pero el coste de arreglar un sistema en producción roto supera con creces el tiempo ahorrado al precipitar una migración.
Recuerda, cambiar microservicios no es un sprint: es una danza cuidadosamente coreografiada entre lo viejo y lo nuevo, entre la estabilidad y el progreso. Tus migraciones serán fluidas, seguras y predecibles si te comprometes con estos mandamientos.