> ## Content Index
> Fetch the complete content index at: https://blog.ifirestone.dev/llms.txt
> Use this file to discover other available public pages before exploring further.

# Migrar de un sistema legacy a microservicios sin documentación ni control total
- URL: https://blog.ifirestone.dev/migrar-de-un-sistema-legacy-a-microservicios-sin-documentacion-ni-control-total/
- Published: 2026-10-31T13:00:00.000Z
- Updated: 2026-10-31T13:00:00.000Z
- Description: Cómo reemplazar un sistema legacy que no puedes leer del todo, cambiar ni apagar: aprende primero su comportamiento real, rodéalo con una fachada strangler y demuestra que los nuevos servicios igualan a los viejos antes de hacer el corte.
- Author: Ivan Firestone
- Tags: microservices, architecture, legacy, migration, #spanish

> Cómo reemplazar un sistema legacy que no puedes leer del todo, cambiar ni apagar: aprende primero su comportamiento real, rodéalo con una fachada strangler y demuestra que los nuevos servicios igualan a los viejos antes de hacer el corte.

Imagina una empresa cuya tienda en línea lleva doce años funcionando sobre una sola aplicación. Los autores originales se fueron hace mucho. El wiki describe una versión del sistema que ya no existe. Un módulo lo escribió un proveedor y llega como una librería compilada de la que nadie tiene el código fuente. Y aun así la tienda procesa pedidos todos los días, y el negocio repite lo mismo que dijo el año pasado: "funciona, no lo rompas".

Entonces alguien escribe "migrar a microservicios" en el roadmap.

Este artículo sigue a esa tienda hipotética por las partes de una migración que los diagramas habituales se saltan: no saber qué hace realmente el sistema, no tener permiso para cambiarlo y tener que superar algo que lleva años probado en batalla. Si todavía estás decidiendo si los microservicios son el destino correcto, empieza por [Arquitectura Microservicios](https://blog.ifirestone.dev/arquitectura-de-microservicios/) y [Monolito modular o microservicios: un marco para decidir sin dogmas](https://blog.ifirestone.dev/monolito-modular-o-microservicios-un-marco-para-decidir-sin-dogmas/). Aquí damos la decisión por tomada y preguntamos cómo sobrevivirla.

## La reescritura que parecía un plan

El primer instinto es empezar de cero: construir el sistema nuevo al lado del viejo y cambiar cuando esté listo. Tienta porque promete dejar atrás el desorden.

Falla por una razón que no tiene nada que ver con la calidad del código. Mientras se construye el sistema nuevo, el viejo sigue cambiando: correcciones de errores, reglas de precios, un ajuste regulatorio. El objetivo se mueve. El equipo termina manteniendo dos sistemas sin terminar ninguno, y el cambio se convierte en un solo evento grande e irreversible que no se pudo probar con tráfico real.

La alternativa tiene nombre: la **higuera estranguladora** (*strangler fig*), descrita por Martin Fowler en [Strangler Fig ](https://martinfowler.com/bliki/StranglerFigApplication.html?ref=blog.ifirestone.dev) y documentada en el [Azure Architecture Center](https://learn.microsoft.com/en-us/azure/architecture/patterns/strangler-fig?ref=blog.ifirestone.dev). Como la enredadera que crece alrededor de un árbol, el sistema nuevo envuelve al viejo y lo reemplaza pieza por pieza, mientras el viejo sigue atendiendo a los usuarios. Cada paso es pequeño y reversible. Esa propiedad es la que hace posible todo lo demás en este artículo.

Pero un strangler necesita saber dónde cortar. Y para eso, la tienda primero tiene que responder una pregunta incómoda.

## ¿Qué hace realmente el sistema viejo?

Sin documentación confiable, la fuente de verdad es el sistema en ejecución. El código te dice lo que puede hacer; producción te dice lo que hace. No son la misma lista.

El equipo empieza escuchando, más o menos en este orden:

1. **Capturar tráfico real.** Los logs de acceso, los del API gateway o un proxy delante de la aplicación legacy muestran qué endpoints se llaman, con qué frecuencia y con qué payloads. Los endpoints que nadie llama desde hace un año son candidatos a eliminarse, no a migrarse.
2. **Leer la base de datos como un contrato.** Las tablas, las llaves foráneas, los triggers y los procedimientos almacenados suelen guardar reglas de negocio que nunca llegaron al código de la aplicación. Un trigger que descuenta stock cuando se inserta un pedido es una funcionalidad, aunque ningún desarrollador recuerde haberlo escrito.
3. **Listar los consumidores ocultos.** Jobs nocturnos, hojas de cálculo que consultan la base de datos directamente, un socio que llama a un endpoint no documentado. Son los clientes que se rompen en silencio.
4. **Escribir pruebas de caracterización.** Michael Feathers llama *characterization tests* (en *Working Effectively with Legacy Code*) a las pruebas que registran lo que el código hace hoy, bien o mal. Envías entradas conocidas, guardas las salidas, y desde entonces cualquier cambio de comportamiento se hace visible.

> Las pruebas de caracterización no dicen que el comportamiento legacy sea correcto. Dicen que es el comportamiento del que dependen hoy tus clientes. Si una rareza es un error o una funcionalidad es una decisión de negocio, y es mucho más barato tomarla antes de la migración que después.

Al final de esta fase la tienda tiene algo que nunca tuvo: una descripción escrita y ejecutable de su propio sistema. Solo ahora puede elegir qué extraer primero.

## Cortar donde no puedes editar

Aquí aparece el segundo problema. Supón que la tienda quiere mover los pagos a su propio servicio. El paso obvio es cambiar el código legacy para que llame al servicio nuevo en lugar de a su módulo interno de pagos. Pero el equipo no puede: el módulo es un binario del proveedor, o el proceso de release de la aplicación legacy tarda meses, o nadie se atreve a tocar el archivo.

Cuando no puedes cambiar el interior, trabajas por fuera. Hay tres costuras que no requieren editar el código legacy:

- **El borde.** Pon una fachada, como un reverse proxy o un API gateway, delante de la aplicación legacy. Al principio reenvía todo. Luego, ruta por ruta, envía peticiones específicas al servicio nuevo. Los usuarios ven las mismas URLs; la fachada decide quién responde.
- **Los datos.** Si el servicio nuevo necesita datos que son de la base de datos legacy, no la consultes directamente desde el servicio nuevo. Captura los cambios con *change data capture* o una exportación estilo outbox y aliméntalos al servicio nuevo, para que el esquema legacy siga siendo un detalle de implementación.
- **La capa de traducción.** El sistema legacy habla su propio dialecto: códigos de estado raros, un registro de cliente con cuarenta columnas, fechas guardadas como texto. Una **capa anticorrupción** (*anti-corruption layer*, un término de Domain-Driven Design) traduce entre ese dialecto y el modelo limpio del servicio nuevo. Sin ella, el diseño legacy se filtra a cada servicio nuevo y acabas reconstruyendo el sistema viejo en piezas más pequeñas.

```yaml
# Reglas ilustrativas de gateway: la fachada es dueña de la decisión de enrutamiento
routes:
  - path: /api/payments/**
    target: payments-service   # nuevo
  - path: /**
    target: legacy-app         # todo lo demás, sin cambios

```

La fachada también le da a la tienda su red de seguridad. Si el servicio nuevo de pagos se comporta mal, volver atrás es un cambio de enrutamiento, no un despliegue.

El primer servicio ya corre detrás de la fachada. La siguiente pregunta es la que le importa al negocio: ¿es tan bueno como lo que reemplazó?

## Superar a un sistema con doce años de pruebas

Los sistemas legacy tienen una ventaja fácil de subestimar: los ha golpeado cada pedido extraño, cada tormenta de reintentos, cada reporte de fin de mes. El servicio nuevo, en comparación, no ha sido probado en el mundo real. "Código más limpio" no es un argumento que sobreviva al primer incidente.

Por eso la tienda trata la paridad como un requisito con evidencia, en cuatro pasos:

1. **Medir primero la línea base del legacy.** Percentiles de latencia, tasa de errores, throughput en el pico y el costo de operarlo. No puedes afirmar que igualas algo que nunca mediste, y un monolito viejo en una red local suele ser más rápido por petición que un sistema distribuido con saltos de red.
2. **Definir "al menos igual de bueno" por capacidad.** En pagos importan más la corrección y la idempotencia que la velocidad pura. En la búsqueda de productos importa más la latencia. Escríbelo como objetivos de nivel de servicio (SLO) antes de construir.
3. **Correr en modo sombra.** La fachada envía cada petición real al sistema legacy, que responde al usuario, y una copia al servicio nuevo, cuya respuesta solo se registra. Compara las dos respuestas. Las diferencias son errores del servicio nuevo o comportamiento no documentado del viejo, y ambos conviene encontrarlos antes de que afecten a un cliente.
4. **Mover el tráfico gradualmente.** Usa feature flags o enrutamiento ponderado: una parte pequeña del tráfico, luego más, vigilando los SLO en cada paso. El camino legacy se mantiene vivo hasta que el nuevo haya aguantado un ciclo de negocio completo, incluidos los momentos incómodos como el cierre de mes.

El modo sombra tiene costos que conviene decir. Las peticiones duplicadas no deben duplicar efectos secundarios, así que una llamada de pago en sombra necesita un modo "dry run" o un sandbox. Y necesitas observabilidad real en ambos lados antes de que nada de esto funcione: trazas, métricas y logs que puedas correlacionar.

## Lo que esto te cuesta

Una migración así es más lenta e incómoda que una reescritura en el papel. Sé honesto con la factura:

- **Dos sistemas a la vez.** Durante un buen tiempo operas, parchas y aseguras ambos. El sistema legacy no se abarata mientras lo reemplazas.
- **Una fachada de apariencia permanente.** El gateway y la capa anticorrupción son componentes extra que hay que operar. Algunos sobrevivirán a la migración.
- **La complejidad de los sistemas distribuidos** llega con el primer servicio, como se describe en [Arquitectura Microservicios](https://blog.ifirestone.dev/arquitectura-de-microservicios/) : fallos de red, versionado, monitoreo entre servicios.
- **No todo debe moverse.** Algunos módulos son estables, cambian poco y no tienen problemas de escala. Dejarlos en el núcleo legacy, detrás de la fachada, puede ser el estado final correcto.

Depende del sistema, pero un resultado común es un núcleo legacy más pequeño que se queda, rodeado de un puñado de servicios que se ganaron su independencia.

## Conclusión

La tienda del principio creía que su problema era la tecnología vieja. Los problemas más difíciles resultaron ser el conocimiento que faltaba, el acceso restringido y una vara de prueba muy alta. Cada uno tiene una respuesta práctica: aprender el comportamiento real desde producción, trabajar por el borde, los datos y una capa de traducción en lugar de editar lo intocable, y tratar la paridad con el sistema legacy como algo que se mide, no que se supone.

Si enfrentas una migración así, un primer paso concreto es pequeño: pon un proxy delante de la aplicación legacy, reenvía todo y empieza a leer los logs. En una semana aprenderás más sobre tu sistema que lo que el wiki te ha dicho en años.