Durante siete módulos hemos construido piezas: límites y datos (módulo 2), contratos y eventos (3), código (4), despliegue (5), operación (6) y seguridad (7). En cada una aparecía TechCorp como ejemplo, pero nunca hemos contado la historia entera en orden: qué hizo el equipo primero, qué después, qué se torció por el camino y con qué resultado. Esta lección es ese relato, el que el cierre del módulo 7 anunciaba: cómo se ejecutó la migración paso a paso. Es un caso de estudio, no una lección de técnica: cuando una fase use el strangler fig, la outbox o el canary, remitiremos a la lección donde se explica en lugar de repetirla, y no escribiremos código (los servicios que faltan se implementan en 08-02 y el sistema completo se despliega en 08-03).

Recorreremos los ~13 meses ficticios de la migración (julio de 2025 a agosto de 2026): la fase 0 de deberes previos, las seis fases de extracción en el orden decidido en 02-02 (catálogo, inventario, notificaciones, pagos, pedidos, clientes), el apagado del monolito, una tabla cronológica, las métricas antes y después, los costes reales y tres tropiezos que conviene conocer para no repetirlos. Todas las fechas, cifras y nombres son inventados, pero verosímiles para una tienda de 3.000 pedidos diarios y 25 técnicos.

Contenido

  1. Punto de partida y plan (julio de 2025)
  2. Fase 0: los deberes previos (julio–septiembre de 2025)
  3. Fase 1: catálogo, la primera extracción y el primer Black Friday (septiembre–noviembre de 2025)
  4. Fase 2: inventario, el primer consumidor de eventos (diciembre de 2025–enero de 2026)
  5. Fase 3: notificaciones, el correo fuera del proceso (febrero de 2026)
  6. Fase 4: pagos, dinero y cautela (marzo–abril de 2026)
  7. Fase 5: pedidos, la saga sustituye a la transacción (mayo–julio de 2026)
  8. Fase 6: clientes y el apagado del monolito (julio–agosto de 2026)
  9. Tabla cronológica de la migración
  10. Métricas antes y después
  11. Costes reales y lo que salió mal
  12. La arquitectura final

  1. Punto de partida y plan (julio de 2025)

En julio de 2025 Marta presenta a dirección el plan que salió del análisis de 01-04 y 01-05: techcorp-shop es un monolito Node.js/Express sobre una única PostgreSQL con cinco problemas medibles (despliegues de jueves con 4 de 12 reversiones, 50 minutos sin vender en el Black Friday anterior, un 20 % del tiempo en coordinación, la fuga de memoria del correo que tumbó los cobros y la tabla atributos_producto). La propuesta no es "reescribir la tienda", sino extraer seis servicios uno a uno, con la tienda vendiendo, en el orden de 02-02: catálogo → inventario → notificaciones → pagos → pedidos → clientes.

Tres condiciones que Marta pone y que gobiernan todo lo que sigue:

Condición Consecuencia práctica
La tienda no se para. Ningún corte planificado de más de unos minutos; ninguna campaña en riesgo. Todo se hace con strangler fig y branch by abstraction (02-02) y con vuelta atrás por configuración.
Cada fase aporta valor visible en menos de un trimestre. El catálogo va primero porque resuelve el problema más caro (las caídas de campaña) con el menor riesgo.
Máximo dos tecnologías de base de datos y un solo lenguaje. PostgreSQL + MongoDB (02-04); Node.js 20 en todos los servicios (04-01).

Y una regla de Luis que aparecerá en cada fase: "si se hace más de una vez por servicio, se automatiza antes del segundo" (04-01, 05-03). Es la que convierte una migración de seis servicios en algo que un equipo de 25 personas puede sostener.

  1. Fase 0: los deberes previos (julio–septiembre de 2025)

La primera decisión importante fue no extraer nada durante tres meses. Los cuatro prerrequisitos de 01-04 (CI/CD, contenedores, observabilidad, cultura de propiedad) no existían, y extraer un servicio sin ellos habría producido un monolito distribuido operado a mano. Lo que se hizo:

  • Organización. Los equipos "back-end / front-end / sistemas" se reorganizaron en los cuatro equipos de 02-01: Experiencia de compra (catálogo y clientes), Pedidos (pedidos e inventario, con Luis), Pagos y comunicaciones (pagos y notificaciones) y Plataforma (gateway, Kubernetes, CI/CD, observabilidad). Cada equipo, dueño de sus áreas dentro del monolito desde el primer día: la ley de Conway aplicada antes de tocar el código.
  • CI para el monolito. El ci.yml de 05-03 en su versión mínima: pruebas en cada PR, imagen Docker del monolito (Dockerfile multi-stage de 05-01) publicada en ghcr.io/techcorp/techcorp-shop:sha-…. La suite de 40 minutos se paralelizó a 12. Todavía se desplegaba los jueves, pero con una imagen reproducible.
  • Kubernetes y el gateway. Plataforma levantó el clúster (05-02), desplegó el monolito en él (tres réplicas, sondas de 03-05) y puso el gateway del puerto 8080 delante con todas las rutas apuntando al monolito (03-04). Durante seis semanas el gateway no hizo nada más que reenviar y registrar: es el requisito del strangler fig de 02-02, "la fachada existe antes de la primera extracción".
  • Observabilidad mínima. Logs estructurados con pino enviados a Loki, métricas RED del gateway y del monolito en Prometheus, un panel en Grafana (06-01). Sin trazas aún.
  • El monolito modular. La matriz tabla × área de 02-02 había destapado que crearPedido escribía en stock y en pagos sin ser su dueño. Antes de mover nada, el equipo de Luis creó dentro del monolito los módulos almacen.reservar()/almacen.liberar() y pagos.registrarCobro(), y crearPedido pasó a invocarlos en lugar de escribir SQL ajeno. Fue el trabajo menos vistoso de la migración y el que más la aceleró: cuando llegaron las fases 2 y 4, la costura ya estaba hecha.
  • @techcorp/comun-http v0.1 (04-01): logger, X-Request-Id, errores RFC 7807, rutas de salud. Se adoptó primero en el monolito, para que el primer servicio naciera con la misma cara.

Resultado de la fase 0 (30 de septiembre de 2025): ningún servicio extraído, ningún problema de negocio resuelto todavía… y una plataforma sobre la que las seis fases siguientes se apoyarían sin volver a discutir herramientas.

  1. Fase 1: catálogo, la primera extracción y el primer Black Friday (septiembre–noviembre de 2025)

servicio-catalogo (3001, MongoDB) se construyó tal como se ve en 04-02, con la plantilla plantilla-servicio-node recién creada. La secuencia fue la de 02-04 §6, y merece verse con fechas porque es el molde de todas las demás:

Semana Paso Técnica (lección)
1–3 (sep) Servicio con GET /v1/productos en sus tres formas y contrato OpenAPI. Pruebas de componente y contrato. 04-02, 04-05
4 Carga inicial con scripts/migrar-catalogo.js (idempotente, upsert): 41.000 productos y sus atributos clave-valor convertidos en documentos. 02-04 §6
5–6 (oct) Sincronización: el monolito publica producto.actualizado en RabbitMQ (su primer evento) y Catálogo lo consume. RabbitMQ entra en producción aquí. 03-02
7 Comparación en sombra: el monolito lee de las dos fuentes y registra discrepancias. Se encontraron 212 productos con precio distinto (redondeo del script) y 3 eventos perdidos por un reinicio: se corrigió el script y se relanzó (idempotente). 02-04 §6
8 Corte de lecturas: el gateway enruta /api/v1/productos/* a Catálogo (strangler) y crearPedido pasa a RepositorioProductosHTTP con CATALOGO_REMOTO=true al 10 %, 50 %, 100 % en tres días. 02-02 §4, 03-04
9 (nov) Corte de escrituras: el panel de administración de productos pasa a servicio-catalogo; el monolito deja de escribir en productos. 02-04
10–13 La tabla productos queda en solo lectura; retirada el 15 de diciembre, tras confirmar que solo un informe mensual la usaba (se reescribió sobre una vista de solo lectura exportada por Catálogo; en la fase 6 pasaría a la BD de lectura del apartado 8). 02-04 §6

El primer despliegue canary de TechCorp fue de Catálogo (05-04): 10 % de tráfico durante dos horas mirando el panel RED. Y el primer HPA también (06-04): minReplicas: 2, maxReplicas: 20, con la caché Redis de 30 s delante de MongoDB.

El examen llegó el 28 de noviembre de 2025. Con el catálogo separado y autoescalado, el Black Friday transcurrió así: navegación ×22 sobre un día normal, Catálogo pasó de 2 a 14 réplicas en 12 minutos, p95 de GET /v1/productos en 140 ms, y la creación de pedidos y los cobros —todavía en el monolito— no notaron nada: 0 minutos sin vender frente a los 50 del año anterior. Marta llevó ese dato a dirección y la migración dejó de discutirse. Fue también el momento en que quedó claro que el catálogo era el 70 % del coste de infraestructura de la campaña anterior: escalar solo lo que se satura costó un tercio que replicar el monolito a diez servidores.

  1. Fase 2: inventario, el primer consumidor de eventos (diciembre de 2025–enero de 2026)

servicio-inventario (3006, PostgreSQL) fue el primer servicio con estado de negocio delicado y el primero que consume eventos. Lo que cambió respecto al catálogo:

  • Modelo de reservas. El monolito solo tenía stock.reservado; el servicio nace con las tablas stock, reservas (con expira_en) y lineas_reserva de 02-04 §7.2. La reserva pasa de ser un contador a ser una entidad con estados ACTIVA/CONSUMIDA/LIBERADA (02-03) y con caducidad a los 900 s.
  • Branch by abstraction de la reserva. El módulo almacen creado en la fase 0 recibió su segunda implementación (ReservaStockHTTPPOST /v1/reservas de 03-01) y la flag INVENTARIO_REMOTO. Durante tres semanas el monolito reservó por HTTP; el SIN_STOCK seguía siendo un 409 síncrono en crearPedido.
  • El primer consumidor. Como el monolito ya publicaba eventos desde la fase 1, Inventario empezó a consumir pedido.confirmado y pedido.cancelado de la cola inventario.pedidos para consumir o liberar la reserva (03-02). Con ello llegaron la primera DLQ con mensajes (un pedido.cancelado de un pedido cuya reserva se había hecho aún por la vía SQL antigua: mensaje venenoso, sin reserva que liberar) y la primera versión de procesarUnaVez fuera de Pedidos.
  • La regla de Luis en acción. El outbox y la idempotencia de consumidores se habían escrito en Pedidos (todavía dentro del monolito) para publicar pedido.confirmado; al necesitarlos en Inventario, se movieron a @techcorp/comun-http (mensajeria/outbox, mensajeria/idempotencia) en lugar de copiarlos. Es la versión que usan los cuatro servicios de 08-02.
  • KEDA (06-04) apareció aquí: escalar Inventario por la longitud de inventario.pedidos fue más útil que hacerlo por CPU.

Las rebajas de enero (7 de enero de 2026) fueron la prueba de carga: pedidos ×3,5, Inventario de 2 a 6 réplicas, ninguna incidencia. La migración de datos de stock (12.000 filas) fue trivial comparada con la del catálogo: carga inicial, doble lectura en sombra durante una semana, corte.

  1. Fase 3: notificaciones, el correo fuera del proceso (febrero de 2026)

La extracción más corta (cuatro semanas) y una de las más agradecidas. servicios/correo.js y sus plantillas se convirtieron en servicio-notificaciones (3005), sin base de datos salvo la tabla envios para no reenviar (02-04 §7.4). Consume pedido.confirmado y pedido.cancelado de notificaciones.pedidos; el monolito dejó de llamar a correo.enviar() en crearPedido y pasó a confiar en el evento.

Dos efectos inmediatos:

  • La fuga de memoria del correo dejó de ser un problema del monolito. El fallo del proveedor de correo volvió a ocurrir el 3 de marzo de 2026 (conexiones acumuladas): esta vez el pod de Notificaciones fue reiniciado por su livenessProbe dos veces, los mensajes esperaron en la cola y en notificaciones.pedidos.reintento (06-03), y ningún cobro se vio afectado. El incidente 4 de 01-05, cerrado por diseño.
  • La respuesta de crearPedido bajó 300 ms de media: el envío SMTP ya no estaba en la petición.

Fue también la fase en que Notificaciones estrenó los reintentos diferidos con TTL y la DLQ tal como quedaron en 06-03, porque un proveedor de correo devuelve 503 con frecuencia: reintentar de inmediato era inútil.

  1. Fase 4: pagos, dinero y cautela (marzo–abril de 2026)

servicio-pagos (3003, PostgreSQL) se llevó servicios/pasarelaPago.js y devolucionesControlador.js. Fue la extracción con más revisión y menos prisa, y la que más piezas de seguridad estrenó:

  • pagos.registrarCobro()servicio-pagos con branch by abstraction y flag; el monolito seguía siendo quien pedía cobrar (síncrono, dentro de crearPedido), pero quien hablaba con la pasarela ya era el servicio.
  • Tokenización y alcance PCI (07-03): el formulario de tarjeta pasó a hablar directamente con la pasarela; TechCorp solo recibe tok_…. El alcance PCI DSS quedó reducido al servicio y a su Secret pagos-pasarela.
  • Webhook firmado POST /v1/webhooks/pasarela con HMAC, ventana temporal y webhooks_recibidos (07-02 §9): la pasarela confirma cobros y devoluciones de forma asíncrona.
  • Auditoría (07-03 §9): tabla auditoria de solo inserción para cambios manuales de estado de pago y reembolsos.
  • UNIQUE (pedido_id) en pagos y clave de idempotencia = pedidoId hacia la pasarela (06-03 ej. 1): la garantía de "un pedido, un cobro" pasó de la transacción del monolito a dos restricciones explícitas.
  • Despliegue canary obligatorio (05-04) con revisión humana del PR de promoción (05-03 §8), como corresponde a un servicio que mueve dinero.

Un dato: el equipo dedicó una semana entera a la prueba de resiliencia (06-03 §11) contra la pasarela ficticia —503, timeouts, respuestas duplicadas— antes de mover un céntimo real. Ningún cobro duplicado en producción desde entonces.

  1. Fase 5: pedidos, la saga sustituye a la transacción (mayo–julio de 2026)

La fase central, la más larga (once semanas) y la que da sentido a las anteriores. Cuando llegó, Catálogo, Inventario, Notificaciones y Pagos ya eran servicios y el monolito ya publicaba y consumía eventos: crearPedido seguía siendo una función que llamaba a los demás por HTTP y coordinaba con su transacción local. Lo que cambió:

  • servicio-pedidos (3002) tal como se construyó en 04-04: agregado Pedido, máquina de estados de 02-05, POST /v1/pedidos202, outbox con relay, consumidores pedidos.saga y pedidos.clientes.
  • La saga por coreografía sustituyó a la transacción: Inventario pasó a reaccionar a pedido.creado (en vez de recibir POST /v1/reservas síncrono), Pagos a stock.reservado (en vez de la llamada del monolito), Pedidos a pago.confirmado. La flag SAGA_ASINCRONA en el monolito permitió, durante dos semanas, que un porcentaje de pedidos siguiera la vía nueva mientras el resto usaba la antigua; el panel "Saga de pedidos" (06-01) comparaba ambos.
  • El cambio de contrato visible: POST /pedidos dejó de responder 201 CONFIRMADO y pasó a 202 PENDIENTE + polling con ETag (03-01). Fue el único cambio de la migración que exigió coordinación con el equipo de front-end y con la app móvil (a través del bff-movil, 03-04): dos sprints de aviso, cabecera Deprecation en la ruta antigua (03-06).
  • El vigilante de TIMEOUT_PAGO (06-03 §9) y el CronJob reconciliar-reservas se escribieron antes del corte, no después de un incidente: la saga por coreografía sin vigilante es una saga que se atasca.
  • Corte del strangler: /api/v1/pedidos/* al servicio el 15 de junio de 2026 al 10 %, 100 % el 19; SAGA_ASINCRONA=true en el 100 % el 26 de junio; migración de los 2,1 millones de pedidos históricos a la BD pedidos en tres noches por lotes (carga inicial idempotente + eventos de cambio de estado en sombra); retirada del código de crearPedido del monolito el 10 de julio.

Y el 22 de julio de 2026, INC-2031 (06-05 §10): un stock.reservado con lineas: null publicado por Inventario 2.3.0 atascó pagos.stock 40 minutos; 61 pedidos afectados, 38 cancelados por el vigilante. Es el incidente que dio forma definitiva a la operación: colas de reintento y DLQ a la primera para errores permanentes en Pagos, alertas DlqConMensajes y SagaTardiaBurn*, validación de eventos de salida contra el esquema AsyncAPI en Inventario, y el runbook comun/dlq con scripts/reprocesarDlq.js. Sin INC-2031, media lección 06-05 no existiría; con él, el sistema quedó como está hoy.

  1. Fase 6: clientes y el apagado del monolito (julio–agosto de 2026)

servicio-clientes (3004) fue el último por las razones de 02-02: identidad y datos personales, y cliente_id estaba en todas partes. Al ser el último, se benefició de todo lo anterior:

  • Keycloak (07-01) había entrado en producción al inicio de la fase 5, federando las credenciales de la tabla clientes del monolito para poder proteger /api/v1/pedidos/* con JWT. En la fase 6 se completó: las identidades se migraron al realm techcorp, el alta de cliente pasó a servicio-clientes, que escribe el atributo clienteId en Keycloak, y el claim clienteId viaja en el token; el monolito dejó de tener sesión.
  • clientes_ref en Pedidos (02-04) se venía alimentando con cliente.actualizado publicado por el monolito desde la fase 5; solo cambió el productor.
  • RGPD (07-03 §8): DELETE /v1/clientes/{id} → anonimización + cliente.eliminado; Pedidos borra la réplica y anonimiza direcciones antiguas.
  • GET /v1/clientes/{id} con la regla "propio cliente, operador o token de servicio con clientes:leer" (07-01 ej. 2), y POST /v1/pedidos con la comprobación clienteId del cuerpo = clienteId del token.

El apagado del monolito ocurrió el 7 de agosto de 2026. Lo que quedaba dentro en ese momento y adónde fue:

Resto en el monolito Destino
Informes de ventas y paneles de dirección (los JOIN de cuatro tablas de 02-04 §8) Base de datos de lectura techcorp-analitica (PostgreSQL) alimentada por eventos (pedido.confirmado, producto.actualizado, cliente.actualizado) con un consumidor propio; los informes se reescribieron contra ella. Es el CQRS "a escala de empresa" de 02-05.
Panel de administración interno (varias áreas) Aplicación web ligera que consume las APIs por el gateway con rol operador.
Exportación nocturna al ERP Consumidor de eventos que genera el fichero.
Tabla pedidos histórica en solo lectura Migrada a pedidos en la fase 5; la copia del monolito se conservó un mes y se archivó.
# 2026-08-07 10:30 — el último commit del monolito: el gateway deja de tener ruta comodín
kubectl -n techcorp scale deployment techcorp-shop --replicas=0     # nadie lo nota: hace tres semanas que no recibe tráfico
# 2026-08-21 — tras dos semanas a cero réplicas sin ninguna petición al comodín (métrica gateway_rutas_monolito_total = 0): borrado
kubectl -n techcorp delete deployment,service,configmap -l app=techcorp-shop

Ese scale --replicas=0 durante dos semanas antes de borrar es la última aplicación del principio de la fase 1: no tener prisa en retirar lo antiguo.

  1. Tabla cronológica de la migración

Fase Fechas Servicio Técnica principal Lecciones Riesgo principal Resultado
0 jul–sep 2025 — (monolito modular, plataforma) CI, contenedores, K8s + gateway delante, observabilidad mínima, cuatro equipos, devolver escrituras de stock/pagos a su dueño 01-04, 02-02, 03-04, 05-01/02/03, 06-01 Tres meses "sin resultados" Base para todo lo demás; suite de 40 → 12 min
1 sep–nov 2025 servicio-catalogo Strangler de /productos, RepositorioProductosHTTP + CATALOGO_REMOTO, carga inicial + eventos + sombra, HPA, Redis 02-02, 02-04, 04-02, 05-04, 06-04 Discrepancias de datos Black Friday sin caída (0 min vs 50); coste de campaña ÷3
2 dic 2025–ene 2026 servicio-inventario Reservas con expira_en, INVENTARIO_REMOTO, primer consumidor, primera DLQ, KEDA; outbox/idempotencia a comun-http 02-04, 03-01, 03-02, 06-04 Vender lo que no hay Rebajas ×3,5 sin incidencia
3 feb 2026 servicio-notificaciones Consumidor de pedido.confirmado/cancelado, reintentos con TTL + DLQ 03-02, 06-03 Correos duplicados/perdidos Fuga de memoria aislada; crearPedido −300 ms
4 mar–abr 2026 servicio-pagos Tokenización, webhook HMAC, auditoría, UNIQUE(pedido_id), canary con revisión 05-04, 06-03, 07-02, 07-03 Cobros duplicados / PCI Cero cobros duplicados; alcance PCI mínimo
5 may–jul 2026 servicio-pedidos Saga por coreografía, outbox, 202 + ETag, vigilante, reconciliación, SAGA_ASINCRONA 02-05, 03-01, 04-04, 06-03, 06-05 Sagas atascadas Pedidos desplegable a diario; INC-2031 (40 min) y su postmortem
6 jul–ago 2026 servicio-clientes + apagado Keycloak + clienteId, clientes_ref, RGPD, BD de lectura para BI 02-04, 07-01, 07-03 Datos personales Monolito a 0 réplicas el 7/8/2026

  1. Métricas antes y después

Las cuatro métricas DORA de 05-03 §12 medidas en agosto de 2026 (media de los seis servicios), más las de negocio y organización que Marta presentó a dirección:

Métrica Antes (junio 2025) Después (agosto 2026) Cómo se mide
Frecuencia de despliegue 1 cada 1–2 semanas (jueves noche), toda la tienda 11 al día en total (Catálogo 3–4, Pedidos 2–3, resto 1–2) Syncs de Argo CD por servicio
Lead time de cambios 9 días de mediana 4 horas de mediana (23 min para hotfixes) Fecha de commit → fecha de sync
Tasa de fallo de cambios 33 % (4/12 reversiones) 6 % (5 reversiones/rollbacks de 82 despliegues en julio) Incidentes o rollbacks / despliegues
MTTR 50 min (Black Friday); ~2 h de mediana en despliegues fallidos 9 min de mediana (argocd app rollback o canary-weight=0) Desde la alerta hasta el cierre
Disponibilidad de "crear pedido" 99,5 % mensual estimada (no se medía) 99,93 % (SLO 99,9 %, 06-05) SLI slo:pedidos_disponibilidad
Latencia catálogo p99 en campaña > 8 s (saturación) 280 ms SLI de latencia
Tiempo de coordinación (equipo de Pedidos) ~20 % ~7 % (revisiones de contrato y PRs de promoción) Encuesta trimestral + tiempo en PRs cruzados
Suite de pruebas 40 min (todo) 4–7 min por servicio CI
Coste infraestructura de campaña ×3,3 (diez servidores del monolito) ×1,4 (solo Catálogo e Inventario escalan) Factura del proveedor

Dos avisos honestos que Marta añadió a la tabla: el "antes" de disponibilidad es una estimación (no había SLI, que es en sí mismo un dato), y la tasa de fallo del 6 % incluye INC-2031, que fue el peor incidente del año y aun así duró menos que el mejor despliegue de jueves.

  1. Costes reales y lo que salió mal

Lo que costó. Un año de migración no sale gratis, y conviene tener las cifras (ficticias, pero de orden realista) para el ejercicio de 08-04:

Coste Magnitud Comentario
Tiempo de equipo ~40 % de la capacidad de desarrollo durante 13 meses (unas 10 personas equivalentes) La mitad en la fase 5. El resto siguió entregando funcionalidad; el negocio no se paró.
Infraestructura +35 % el primer año (clúster, RabbitMQ, observabilidad, Keycloak, entornos de staging); −20 % respecto al año anterior en campañas Con el catálogo escalado por separado, el balance neto al final del año fue ligeramente positivo por el ahorro en campañas. El coste mensual detallado está en 08-03.
Curva de aprendizaje Kubernetes, RabbitMQ, OpenTelemetry, Keycloak, Pact: cada uno costó a alguien 2–4 semanas Mitigado por Plataforma (plantillas, workflow reutilizable) y por hacerlo en orden.
Herramientas de pago Registro privado, Pact Broker gestionado, gestor de secretos Menores; se justificaron una a una.

Lo que salió mal. Tres tropiezos que el equipo cuenta sin vergüenza porque son los que más enseñan:

  1. El dual write que se intentó (fase 1, octubre de 2025). La primera versión de la sincronización del catálogo escribía la tabla productos y el documento de MongoDB en la misma función del monolito, "para no montar RabbitMQ todavía". En una semana la comparación en sombra encontró 40 productos divergentes: un timeout de MongoDB, una excepción entre las dos escrituras, y ninguna transacción que las cubriera (02-04 §6). Se tiró el código, se adelantó RabbitMQ y se publicó producto.actualizado desde la fuente de verdad. La lección se convirtió en regla escrita: una escritura, en el dueño; la copia, por eventos.
  2. servicio-descuentos, el nanoservicio (fase 4, abril de 2026). Marketing pidió cupones para las rebajas de primavera y el equipo de Experiencia de compra, con ganas de estrenar plantilla, creó un servicio con una tabla cupones y un único endpoint POST /v1/descuentos/calcular, llamado de forma síncrona por crearPedido en cada pedido. Añadió 40 ms a cada pedido, un despliegue más, una dependencia más en el camino crítico y ninguna capacidad de negocio autónoma (02-01: "¿se describe en una frase sin 'y'?" sí, pero "¿tiene datos y ciclo de vida propios?" no). En la fase 5 se reabsorbió en servicio-pedidos como módulo dominio/descuentos.js con la tabla dentro de la BD pedidos, exactamente lo que el ejercicio 2 de 02-02 había recomendado. Si algún día las promociones crecen (campañas, reglas, segmentos), volverán a salir; hoy son doce reglas y una tabla.
  3. La cardinalidad que tumbó Prometheus (fase 3, febrero de 2026). Un consumidor de Notificaciones etiquetó http_requests_total con la ruta sin plantilla (/v1/pedidos/ped-3f9a1c2b en lugar de /v1/pedidos/{id}) y otro añadió pedidoId como etiqueta a un contador. En cinco días Prometheus pasó de 60.000 a 2,4 millones de series y el pod murió por memoria; durante 25 minutos no hubo métricas ni alertas. La corrección (06-01 §11): etiquetas solo con valores acotados, ruta desde req.route.path, una regla de linting de métricas en comun-http y un límite sample_limit en el scrape. Es el motivo por el que la métrica pedidos_cancelados_total lleva motivo (cuatro valores) y nunca pedidoId.

Y un cuarto, menor pero frecuente: durante dos meses convivieron el ci.yml de 80 líneas copiado en tres repositorios con tres pequeñas diferencias; el workflow reutilizable de 05-03 §11 llegó "antes del cuarto", no "antes del segundo". La regla de Luis también se incumple a veces.

  1. La arquitectura final

Así queda TechCorp en agosto de 2026, con el monolito apagado. Comparado con el diagrama de 01-05 §7 (el objetivo) hay tres diferencias: no hay Istio (05-05: evaluado y pospuesto; mTLS con Linkerd cuando lo pida la auditoría de Pagos), sí hay una BD de lectura para analítica, y Redis, Keycloak y la pila de observabilidad tienen nombre propio.

flowchart TB
    subgraph Externo
        WEB[tienda-web / bff-movil :3010]
        PSP[Pasarela de pago]
        SMTP[Proveedor de correo]
    end
    WEB -->|HTTPS + JWT| ING[Ingress api.techcorp.example<br/>cert-manager]
    ING --> GW[API Gateway :8080<br/>requiereToken, rate limit]
    KC[Keycloak realm techcorp] -. JWKS .-> GW
    GW -->|/api/v1/productos| CAT[servicio-catalogo :3001<br/>HPA 2-20 + Redis]
    GW -->|/api/v1/pedidos| PED[servicio-pedidos :3002<br/>canary]
    GW -->|/api/v1/clientes| CLI[servicio-clientes :3004]
    PSP -->|webhook HMAC| PAG
    CAT --> MDB[(MongoDB catalogo)]
    PED --> PGP[(PG pedidos)]
    CLI --> PGC[(PG clientes)]
    INV[servicio-inventario :3006<br/>KEDA 2-10] --> PGI[(PG inventario)]
    PAG[servicio-pagos :3003<br/>canary] --> PGG[(PG pagos)]
    NOT[servicio-notificaciones :3005] --> SMTP
    PAG --> PSP
    PED -->|GET productos / clientes| CAT
    PED --> CLI
    PED <-.-> MQ[(RabbitMQ techcorp.eventos<br/>amqps, vhost techcorp)]
    MQ <-.-> INV
    MQ <-.-> PAG
    MQ -.-> NOT
    MQ -.-> ANA[consumidor analitica] --> PGA[(PG techcorp-analitica<br/>informes / BI)]
    CLI -.->|cliente.actualizado / eliminado| MQ
    subgraph Plataforma
        OBS[Prometheus · Grafana · Loki · otel-collector · Jaeger]
        ARGO[Argo CD ← techcorp/plataforma]
        VAULT[Vault + ESO]
    end

Lo que no se ve en el diagrama y es tan importante como lo que se ve: las NetworkPolicies deny-all de 07-04 (a Inventario solo le habla Pedidos; solo Pagos sale a Internet), los SLOs y las once alertas de 06-05, los runbooks en techcorp/plataforma/runbooks/, y cuatro equipos que despliegan sin pedir permiso a nadie.

Errores Comunes y Consejos

  • Saltarse la fase 0. Es la tentación más fuerte ("empecemos por algo visible") y la que más caro se paga: sin gateway no hay strangler, sin CI no hay confianza, sin observabilidad no hay diagnóstico. Tres meses de deberes ahorraron un año.
  • Extraer el core primero. Pedidos fue el quinto porque dependía de todos; extraerlo primero habría producido un monolito distribuido con cinco llamadas al monolito por pedido.
  • Borrar lo antiguo el día del corte. La tabla productos en solo lectura durante seis semanas y el monolito a cero réplicas durante dos evitaron dos incidentes seguros (el informe mensual y una integración olvidada).
  • Medir solo al final. El "antes" de disponibilidad es una estimación porque no se medía. Instrumenta el monolito antes de tocarlo: es tu línea base y tu argumento ante dirección.
  • Confundir tropiezo con fracaso. El dual write, el nanoservicio y la cardinalidad costaron días, no meses, porque cada uno se detectó con una herramienta que ya existía (sombra, panel RED, alerta de Prometheus caído). El objetivo no es no equivocarse: es equivocarse barato y aprender por escrito.
  • Consejo: guarda una tabla cronológica como la del apartado 9 desde el primer día, con la columna "riesgo principal" rellena antes de empezar cada fase. Es la mejor herramienta de comunicación con negocio y el mejor material para el postmortem del proyecto.

Ejercicios

Ejercicio 1: Reordenar con otra restricción

Imagina que TechCorp hubiera tenido, en julio de 2025, una auditoría PCI obligatoria en enero de 2026. ¿Cambiaría el orden de extracción? Propón un orden alternativo, indica qué fase se adelanta y a qué coste, y qué parte de la fase 0 pasaría a ser imprescindible antes de esa fase.

Ejercicio 2: Diagnosticar un tropiezo

Un equipo cuenta que, durante su migración de un catálogo, "los datos del servicio nuevo se desincronizaban de vez en cuando y nadie sabía por qué". Con lo aprendido en las fases 1 y en el apartado 11: enumera las tres causas más probables, la herramienta que las habría detectado y la técnica que las evita.

Ejercicio 3: Leer la tabla de métricas

Con la tabla del apartado 10: (a) ¿qué métrica demuestra que la fase 1 resolvió el problema 2 de 01-05? (b) ¿por qué la tasa de fallo del 6 % es mejor aunque en número absoluto de despliegues fallidos (5 en julio) sea mayor que antes (4 en un trimestre)? (c) ¿Qué métrica de la tabla es la que menos fiable y por qué?

Soluciones

Ejercicio 1. Sí: Pagos pasaría del cuarto al segundo puesto (tras Catálogo), para que en enero la pasarela, la tokenización, el webhook HMAC, la auditoría y el securityContext/NetworkPolicies de Pagos estuvieran aislados en un servicio con alcance PCI mínimo. Coste: Pagos se extraería con branch by abstraction desde el monolito (como en la fase 4 real) pero antes de que existiera Inventario, así que seguiría cobrando por llamada síncrona desde crearPedido más tiempo, y su consumidor de stock.reservado se escribiría más tarde (doble trabajo en el adaptador). Además, el equipo estrenaría canary y revisión humana con el servicio más delicado, en lugar de entrenar con Catálogo. De la fase 0 pasarían a imprescindibles antes de Pagos: la retirada de la escritura en pagos desde crearPedido (pagos.registrarCobro()), la gestión de secretos (07-04: el Secret pagos-pasarela no puede vivir en un YAML) y las NetworkPolicies de "solo Pagos sale a Internet".

Ejercicio 2. (1) Dual write: el monolito escribe en las dos fuentes sin transacción común; una excepción o timeout entre ambas deja copias divergentes. Lo detecta la comparación en sombra; lo evita "una escritura en el dueño + eventos" (02-04 §6). (2) Eventos perdidos: el productor publica sin outbox (o el consumidor hace ack antes de escribir) y un reinicio pierde mensajes. Lo detecta la sombra y la métrica outbox_pendientes/mensajes sin ack; lo evita el outbox transaccional (02-05 §7) y ack tras procesar (03-02). (3) Eventos desordenados o duplicados que pisan un valor nuevo con uno viejo. Lo detecta la sombra (discrepancias intermitentes que "se arreglan solas" al siguiente cambio); lo evita procesarUnaVez + comparación por actualizadoEn (04-04 ej. 2). Añadido: un script de carga inicial no idempotente que se relanzó a medias (duplicados o valores antiguos); lo evita upsert (02-04).

Ejercicio 3. (a) "Latencia catálogo p99 en campaña" (> 8 s → 280 ms) y sobre todo el dato de negocio del apartado 3: 0 minutos sin vender el 28/11/2025 frente a 50; el coste de campaña ×3,3 → ×1,4 confirma que se escala solo lo que se satura. (b) Porque la tasa se mide por despliegue y el número de despliegues se ha multiplicado por más de 20: 5 fallos de 82 (6 %) frente a 4 de 12 (33 %). Además, cada fallo afecta a un servicio, se detecta en un canary al 10 % y se revierte en minutos (MTTR 9 min), frente a revertir toda la tienda tras dos horas. Es la relación DORA de 05-03: más despliegues pequeños → menos fallo y menos MTTR. (c) La disponibilidad "antes" (99,5 %): es una estimación retrospectiva, porque el monolito no tenía SLI; y en menor medida el tiempo de coordinación, que se basa en encuestas. La propia tabla lo advierte: sin medición previa no hay línea base fiable, y esa es una lección en sí misma.

Conclusión

La migración de TechCorp no fue una reescritura sino trece meses de extracciones ordenadas sobre una fase 0 de deberes que no produjo ningún servicio y lo hizo posible todo: cuatro equipos dueños de sus áreas, CI y contenedores, un clúster con el gateway delante como fachada del strangler, observabilidad mínima y un monolito modular en el que crearPedido dejó de escribir en stock y pagos. Después, cada fase resolvió un problema concreto de 01-05 con las técnicas de los módulos anteriores: Catálogo (carga inicial, eventos, sombra, flag, HPA) y el primer Black Friday sin caída; Inventario (reservas con caducidad, primer consumidor, primera DLQ, KEDA); Notificaciones (el correo fuera del proceso, fin de la fuga que tumbaba cobros); Pagos (tokenización, webhook HMAC, auditoría, canary con revisión); Pedidos (la saga por coreografía con outbox y vigilante en lugar de la transacción, el 202, e INC-2031 como maestro); Clientes (Keycloak, clienteId, RGPD) y el apagado del monolito con la analítica trasladada a una base de datos de lectura. Las métricas cuentan el resultado —de un despliegue quincenal a once al día, de 9 días a 4 horas de lead time, del 33 % al 6 % de fallos, de 50 a 9 minutos de recuperación, 99,93 % de disponibilidad de "crear pedido"— y los tropiezos (el dual write, servicio-descuentos, la cardinalidad) cuentan lo que costó aprenderlo.

Este relato ha remitido constantemente a código que ya existe (servicio-catalogo de 04-02, servicio-pedidos de 04-04, el gateway de 03-04 y 07-01) y a cuatro servicios que hemos descrito pero nunca escrito: Inventario, Pagos, Notificaciones y Clientes. La siguiente lección los implementa de forma condensada pero completa, con la misma plantilla y la misma librería, cierra el mapa de eventos y sigue el pedido ped-88213 por los seis servicios reales, base de datos a base de datos y cola a cola.

Curso de Microservicios

Módulo 1: Introducción a los Microservicios

Módulo 2: Diseño de Microservicios

Módulo 3: Comunicación entre Microservicios

Módulo 4: Implementación de Microservicios

Módulo 5: Despliegue y Orquestación

Módulo 6: Monitoreo y Mantenimiento

Módulo 7: Seguridad en Microservicios

Módulo 8: Casos de Estudio y Ejemplos Prácticos

© Copyright 2026. Todos los derechos reservados