Módulo 12 · Nivel empresarial (integración)

Lección 53 — Monolito modular frente a microservicios

Una decisión razonada, no una moda: cuándo trocear y cuándo no.

Publicada
En esta lección
  1. Ejercicio 1 — La matriz honesta
  2. Ejercicio 2 — La modularización
  3. Ejercicio 3 — Los contratos
  4. Ejercicio 4 — El umbral y el strangle
  5. Ejercicio 5 — La defensa
  6. Resumen del profesor

Ejercicio 1 — La matriz honesta

  1. Los números de TicketFlow: 5 microservicios = 5 pipelines (el CI del 41 ×5), 5 despliegues/semana (la cadencia cae de 2.1/día a ~0.4/servicio), 12 de las 18 features del roadmap serían distribuidas (el checkout toca tickets+payments+events), y la saga del 32 pasaría de "un caso" a "el estándar" de todo flujo entre módulos. El costo de red+timeouts+breakers (54) en cada borde: ~2 semanas de setup + el mantenimiento permanente.
  2. El mejor argumento REAL a favor: la independencia de despliegue y falla del pago — "si el checkout explota (el pico del 36), el pago NO debe caer con él" (el blast radius). Pesa más que su costo cuando: el volumen de pagos justifica su operación separada Y el PCI (56) exige frontera física Y el equipo supera 8-10 devs.
  3. El argumento contrario (la decisión): "Con 1 dev, 1 app y 50k ventas/mes, la frontera modular (2) compra las fronteras y la salida abierta por el 10% del costo; los microservicios pagarían 5 pipelines, 12 flujos distribuidos y una saga por feature. Trigger documentado: PCI o volumen ×10. Revisión: el trigger, no la moda".

Ejercicio 2 — La modularización

  1. El mapa: tickets (reserva/expiración/disponibilidad), payments (pasarela/ledger/comisiones), events (catálogo/venues), identity (auth/MFA), shared (Money, Clock, outbox, errores del 26). El utils del 24 se disuelve: lo de dominio a su módulo, lo compartido estable a shared, lo huérfano se borra (el hunting).
  2. Lo que la interfaz revela: payments usaba Ticket de tickets DIRECTAMENTE (el import escondido del cálculo de comisión) y events leía Reservation.objects (el dashboard de ocupación) — 2 violaciones reales cazadas al ESCRIBIR la interfaz: los imports que la frontera obliga a subir son el inventario honesto del acoplamiento.
  3. El CI con 12 combinaciones prohibidas (5 módulos, n×(n−1)): cazó los 2 violadores del ejercicio 2 + 1 fixture de tests que importaba models de otro módulo (migrado a la interfaz). El test de frontera es el linter de la arquitectura: sin él, la constitución es un doc bonito.

Ejercicio 3 — Los contratos

  1. El contrato síncrono:
python
def test_contrato_tickets_reservar():
    r = tickets.reservar(user, event_uuid, ["A1"], clock=FakeClock(...))
    assert isinstance(r, ReservationSummary)          # el DTO del 25: el contrato
    with pytest.raises(SeatUnavailable):              # las excepciones SON el contrato
        tickets.reservar(user, event_uuid, ["A1"], clock=FakeClock(...))

Si la firma cambia, este test (corriendo desde payments/) rompe: el contrato entre módulos es testado como el pacto entre servicios de la 35.

  1. El contrato async: PaymentSucceeded con payload mínimo {intent_id, ref, amount} (la 25: autosuficiente), consumido por tickets para CONFIRMAR. Si fuera síncrono: la transacción única se rompería (el cobro dentro de la TX de reserva = el pool del 39 sufriendo + el UNKNOWN del 32 sin reconciliación) y el receptor quedaría acoplado al emisor en tiempo real — el async compra la desacoplación temporal al precio de la eventualidad (la 32: converge).
  1. La regla (8 líneas): "Síncrono si la operación pertenece a la MISMA transacción (asiento+estado). Async si el receptor es periférico o tolera el retraso (emails, analytics, confirmación tras pago). Caso de estudio: reservar() síncrona (misma TX), PaymentSucceeded async (convergencia), PaymentFailed async (compensación)".

Ejercicio 4 — El umbral y el strangle

  1. El trigger: el PCI (56) — "se extrae payments cuando el cumplimiento exija la frontera física de los datos de tarjeta (el dominio que PAGA su operación con un requisito regulatorio) o cuando el volumen de pagos ×10 frente al resto (55: el escalado divergente). Medible: la fecha del PCI y el ratio de volumen en el dash del 46".
  1. El strangle comparado (la estimación del 49):
CON la frontera preparada (interfaces+eventos+tests): 3 semanas
  F1 (3 d)  el servicio nuevo duplica el flujo (el flag decide)
  F2 (3 d)  canary del 46 (5%→50% del tráfico al servicio nuevo)
  F3 (2 d)  100% + monolito destrona el código (11)
  F4 (3 d)  la limpieza + el contrato HTTP (14)
SIN frontera (el re-write del acoplamiento): 2-3 meses
  (los 12 flujos distribuidos, la saga en cada uno, los contratos desde cero)

El ratio 3:1-4:1 ES el valor de la modularidad de hoy: la frontera no se compra mañana, se paga en pequeñas cuotas desde hoy.

  1. Los 5 cambios que la extracción obliga (mitigados por la frontera): (1) el contrato entre módulos pasa de import a HTTP/gRPC (los tests de la 35 son el molde); (2) la saga del 32 cruza la red (los UNKNOWN de la red se añaden a los de la pasarela — el 54); (3) el outbox deja de ser tabla compartida: stream externo (30); (4) la identidad: el token interno del 18 entre servicios; (5) la observabilidad: la traza del 46 cruza servicios (el trace_id ya viaja, la 45).

Ejercicio 5 — La defensa

  1. El pitch (10 líneas): "Hoy el monolito usa 3 réplicas de las cuales 2 están para el checkout del viernes: el escalado divergente que justificaría microservicios es 1 servicio de 5. Los 12 flujos que tocarían pasan a distribuidos: cada uno con la saga del 32, el 54 y el contract del 14. La propuesta: monolito modular con fronteras testadas (hoy), el trigger PCI/volumen documentado (mañana), y el strangle con la frontera hecha (el día X): la misma salida a 1/4 del costo. Si el volumen ×10 llega, el plan ya está pagado."
  1. La respuesta en 3 frases: "Fronteras sí, física aún no: los módulos están separados por interfaz y eventos (el 52/53). Extraer ahora paga 5 pipelines y 12 flujos distribuidos por el beneficio de 1. El ADR tiene el trigger: cuando el PCI o el volumen lo pida, la extracción ya está pagada."
  1. La regla personal (extracto): "Modularidad antes que distribución; la frontera se paga en cuotas desde el día 1 (interfaz+eventos+test); el trigger del strangle se escribe ANTES de necesitarlo; la moda no es una métrica."

Resumen del profesor

  • Los microservicios no arreglan el acoplamiento: lo hacen pagable — primero la frontera conceptual (con tests), después la física si el negocio la exige.
  • El monolito modular: interfaces públicas, eventos vía outbox, FK prohibidos entre módulos, shared pequeño — el test de frontera en CI es la constitución.
  • El strangle con frontera preparada cuesta 1/3-1/4 que sin ella: la modularidad de hoy es la pre-pago de la extracción de mañana — con el trigger escrito en el ADR.