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

Lección 52 — Clean/Hexagonal y DDD aplicados

El dominio de TicketFlow en el centro y la infraestructura en el borde.

Publicada
En esta lección
  1. Ejercicio 1 — La auditoría hexagonal
  2. Ejercicio 2 — Los value objects
  3. Ejercicio 3 — El agregado Reservation
  4. Ejercicio 4 — La decisión DDD
  5. Ejercicio 5 — El lenguaje ubicuo
  6. Entrega

El dominio puro de TicketFlow, con el costo a la vista. Sin solutions.md hasta entregar.

Ejercicio 1 — La auditoría hexagonal

  1. Dibuja (ASCII) tu arquitectura actual con los anillos hexagonales: dominio / aplicación / puertos / adaptadores. ¿Qué flecha apunta HACIA FUERA del dominio (¿el Model en el servicio? ¿settings importado en services?).
  2. Los puertos: lista los Protocols de tu repo (Clock, Gateway, Repos...): ¿faltan puertos (¿el email? ¿el rate limiter del 23?)? Añade el que falte y la implementación fake del 33.
  3. La regla de las flechas: grep -rn "import.*models" services/ y grep -rn "from django" domain/ — el segundo debe ser vacío tras el curso. El primero: decide qué queda (¿el patrón activo-record de la 00b?) y documéntalo.

Ejercicio 2 — Los value objects

  1. Implementa Money y SeatRef (§2) con sus invariantes y el test unitario puro (sin Django, la 33): la moneda distinta lanza, el asiento inválido lanza, la suma correcta.
  2. El VO del negocio que falta: Percentage (la comisión del org, 0-30% con validación) o TimeRange (el evento con start<end). Implementa el que uses y migra UN servicio a él.
  3. El costo de los VOs: mide el impacto en el serializer del 25: ¿el DTO acepta Money o lo convierte? ¿Dónde vive la conversión (¿en el mapper, en el serializer?) y por qué NO en el dominio?

Ejercicio 3 — El agregado Reservation

  1. Extrae Reservation al dominio puro (§3): la máquina de estados (00b) en la clase, el confirmar()/expirar()/cancelar(motivo) con las transiciones como métodos, sin Django.
  2. El mapper bidireccional (adapters/mappers.py) y el repositorio del 25 ajustado: get() devuelve DOMINIO (con los seats cargados: el agregado completo), save() persiste desde el dominio. ¿Qué pasó con el lazy-loading? ¿El prefetch_related del repo es ahora obligatorio? Documenta la consecuencia.
  3. El test del dominio: la suite unitaria del agregado corre SIN BD: pytest tests/unit/domain -q en <1 s. ¿Cuántos tests migraste del integrado al unitario puro? ¿Cuáles SE QUEDAN en integración (¿el lock? ¿el outbox?)?

Ejercicio 4 — La decisión DDD

  1. Escribe el ADR "DDD parcial en TicketFlow" (48): qué extrae (VOs, agregado Reservation), qué queda (CRUD en ORM), el costo medido (los mappers, las semanas), y el trigger del DDD completo (¿el segundo servicio del 53? ¿las reglas > N?).
  2. El contrafáctico: estima (49) el DDD COMPLETO para tu repo: ¿cuántas semanas? ¿Qué ganaría de verdad? ¿Qué líneas del modelo del 51 pagarían esa factura? La respuesta honesta: ¿vale o no vale HOY?
  3. La frontera con el 53: ¿qué módulos del monolito modular serían los "bounded contexts" (¿tickets vs payments vs events)? Dibuja el mapa de contextos con su lenguaje propio (el ubicuo por contexto): ¿"reserva" significa lo mismo en payments que en tickets?

Ejercicio 5 — El lenguaje ubicuo

  1. La auditoría del lenguaje: lista los nombres de tu código que NO hablan el negocio (¿XDataModel? ¿process_stuff?) y re-nómbralos al idioma del dominio. El test: el dueño del negocio (51: el pitch) lee los nombres de tus clases y entiende la mitad — ¿la entiende?
  2. El Anti-corruption layer: el payload de la pasarela (o del webhook del 17): ¿dónde se traduce settled → PaymentSucceeded? Si el vocabulario ajeno llegó al dominio (¿un if status == "settled" en services?), muévelo al adaptador.
  3. El glosario: crea docs/reference/lenguaje.md con las 15 palabras del dominio (reserva, expira, confirma, tarjeta regalo, comisión...) y su definición exacta de UNA línea — el vocabulario compartido entre el negocio y el repo (el doc del 48 que el 51 prometió).

Entrega

Pega el anillo hexagonal, los VOs con tests, el agregado sin Django con su mapper y el ADR de DDD parcial. Después: Lección 53 — Monolito modular frente a microservicios.