Stack: Django/DRF · Proyecto: TicketFlow Estado: Publicada — una decisión razonada, no una moda Prerrequisito: Lección 52 — Clean/Hexagonal y DDD aplicados
Objetivos
- Comparar monolito modular y microservicios con los costos REALES de cada uno (red, datos, operación, equipo), sin el marketing de Netflix.
- Modularizar TicketFlow como monolito modular: los módulos con fronteras explícitas y el contrato entre ellos.
- Identificar los umbrales que justifican extraer UN servicio (el strangle) y el camino de salida si algún día hace falta.
1. La comparación honesta: lo que cada uno compra y cobra
| Dimensión | Monolito modular | Microservicios |
|---|---|---|
| Transacciones (10) | Una BD, ACID local | Sagas/composición eventuales (32) EN CADA flujo |
| Red entre piezas | Llamadas de función (0 ms, 0 fallos) | Latencia + timeouts + breakers (54) en cada borde |
| Datos | Un schema, joins libres | BD por servicio, duplicación + sincronización (25) |
| Despliegue | Uno (41: blue-green de todo) | N pipelines, versionado de contratos (14) |
| Operación | 1 app, 1 dash | N apps, N dash, service mesh, el 46×N |
| Equipo | 1-10 devs felices | La orquesta necesita director y músicos por servicio |
| Independencia de despliegue | Ninguna (un merge = un deploy) | Total (el gran beneficio real) |
| Fronteras | Disciplina (el linter/las reglas) | Físicas (la red las obliga) |
El punto que el marketing esconde: los microservicios NO arreglan el acoplamiento — lo hacen PAGABLE: lo que en el monolito era un mal import (el 24: la vista que consulta el ORM de otro módulo) en microservicios es una llamada de red que FALLA con latencia y retries. Si tus fronteras conceptuales son malas, las físicas las harán malas Y lentas. El orden correcto: fronteras modulares primero (hoy), fronteras físicas si el negocio las exige (mañana).
2. El monolito modular de TicketFlow: los módulos y sus fronteras
La modularización sobre lo que el curso ya hizo (los bounded contexts del 52):
ticketflow/
tickets/ # el dominio del asiento: reserva, disponibilidad, expiración (10/25/31)
payments/ # el dinero: pasarela, intent, refunds, comisiones (32/08)
events/ # el catálogo: eventos, venues, precios (00b)
identity/ # auth, MFA, roles (18-21)
shared/ # el dominio compartido: Money, Clock, outbox, el handler del 26Las reglas de frontera (la constitución del monolito modular, aplicable con tests): (1) un módulo habla con otro por SU interfaz pública (el servicio de la 24) — jamás por sus models/managers internos; (2) los eventos entre módulos van por el outbox/stream (25/30) — jamás por import directo del módulo ajeno en el flujo de negocio; (3) la BD: UN schema (por ahora) con los FK entre módulos prohibidos (la referencia es por UUID público, la 13: el FK crea el acoplamiento físico que mañana impide extraer); (4) el shared/ es pequeño y estable (el Money, el Clock): el cajón de sastre del 24 es el anti-patrón de la modularidad.
# tickets/api.py — la interfaz pública del módulo (lo que otros importan)
def reservar(user, event_uuid, seat_refs, *, clock=None) -> ReservationSummary: ...
def disponibilidad(event_uuid) -> list[SeatFree]: ...
# y el import que la constitución prohíbe (el test del CI lo caza, 41):
# from tickets.models import ReservationModel ← en payments/: PROHIBIDOEl test de frontera (el que hace la modularidad REAL):
def test_modulos_no_importan_entres_si():
with open("payments/services.py") as f:
assert "from tickets.models" not in f.read() # la interfaz o nada3. Los contratos entre módulos: síncronos y asíncronos
La comunicación entre módulos: síncrona (la función pública: el checkout de payments llama a tickets.reservar(): la transacción es UNA — el mayor regalo del monolito) y asíncrona (los eventos del outbox: PaymentSucceeded llega a tickets sin acoplamiento del emisor al receptor — la coreografía del 32). La regla de elección: síncrono cuando la operación pertenece a la MISMA transacción (el asiento y el estado de la compra); asíncrono cuando el receptor es periférico (emails, analytics) o el acoplamiento temporal es aceptable. Y el contrato de cada interfaz: testado (la 35: el test de contrato entre módulos = el pacto que el día del servicio externo será HTTP).
La decisión del equipo de 1 (el 51): el monolito modular compra el 90% del beneficio (fronteras, dominios separados, extraíbles mañana) por el 10% del costo. Los microservicios de TicketFlow HOY: 5 despliegues, 5 pipelines, la saga del 32 en CADA flujo de negocio, y 1 solo dev orquestándolo: la factura de operación supera el beneficio por un orden de magnitud.
4. El umbral de extracción: cuándo UN servicio sale
El strangle pattern (la salida progresiva): extraer el módulo cuando su contexto exige FÍSICA: (1) el ciclo de vida diverge (payments despliega 10×/día por compliance mientras tickets 2×/mes: el monolito acopla los ritmos); (2) el escalado diverge (payments necesita 3 réplicas y tickets 1: el monolito escala la caja entera, el 55); (3) la tecnología diverge (el motor de pricing en Go/C: la frontera del lenguaje); (4) la seguridad diverge (payments con acceso a PCI: la frontera del cumplimiento, el 56); (5) el equipo diverge (2 equipos que pelean el mismo repo: Conway lo decide). TicketFlow HOY: nada diverge — el trigger documentado (el ADR): "se extrae payments cuando el PCI del 56 lo exija o el volumen de pagos ×10 frente al resto".
El strangle (la extracción sin big-bang): (1) el módulo ya tiene interfaz pública (§2: la frontera hecha desde hoy); (2) el servicio nuevo DUPLICA la funcionalidad con el flag del 27 decidiendo quién sirve; (3) el tráfico migrado por porcentaje (el canary del 46); (4) el monolito destrona el código (el 11: expand-contract aplicado a la arquitectura); (5) la limpieza. La extracción de UN módulo con la frontera preparada: 2-4 semanas (la estimación del 49); sin ella: 2-4 meses (el re-write del acoplamiento escondido).
5. Lo que el monolito modular te regala HOY
La lista concreta de TicketFlow modular: el dominio del asiento (tickets) testable sin tocar el dinero (payments); el onboardinng del compañero nuevo (48): 5 módulos con ADRs vs un repo anónimo; el deploy UNO (41) con las 5 métricas DORA sanas; el costo de la nube del 42 (1 PaaS, no 5); y la salida abierta: cada módulo con su interfaz es el candidato al strangle cuando el trigger llegue — el monolito modular NO es "microservicios aplazados por pereza": es la decisión INFORMADA de pagar la red solo cuando la red pague su costo (el 51: cada pieza, su línea de negocio).
Autoevaluación
- ¿Qué compra y qué cobra cada modelo en las 8 dimensiones del §1? ¿Qué hace el microservicio con el acoplamiento que el monolito ignora?
- Enumera las 4 reglas de frontera del monolito modular de TicketFlow y qué test del CI las hace reales.
- ¿Cuándo síncrono y cuándo asíncrono entre módulos, y qué regalo del monolito se pierde al hacerlo async?
- Los 5 umbrales del strangle: ¿cuál es el más probable en TicketFlow y qué documento lo activa?
- ¿Qué pasos tiene el strangle y cuánto cambia el costo de extraer CON frontera preparada vs SIN ella?
Continúa con los ejercicios. Las solutions.md solo tras intentarlo.