Module 12 · Enterprise level (capstone)

Lesson 52 — Clean/Hexagonal and DDD applied

The TicketFlow domain at the center and infrastructure at the edge.

Published
In this lesson
  1. Exercise 1 — The hexagonal audit
  2. Exercise 2 — The value objects
  3. Exercise 3 — The Reservation aggregate
  4. Exercise 4 — The DDD decision
  5. Exercise 5 — The ubiquitous language
  6. Submit

TicketFlow's pure domain, with the cost in view. No solutions.md before submitting.

Exercise 1 — The hexagonal audit

  1. Draw (ASCII) your current architecture with the hexagonal rings: domain / application / ports / adapters. Which arrow points OUTWARD from the domain (the Model in the service? settings imported in services?).
  2. The ports: list your repo's Protocols (Clock, Gateway, Repos...): are any ports missing (email? 23's rate limiter?)? Add the missing one and 33's fake implementation.
  3. The arrows rule: grep -rn "import.*models" services/ and grep -rn "from django" domain/ — the second must be empty after the course. The first: decide what stays (00b's active-record pattern?) and document it.

Exercise 2 — The value objects

  1. Implement Money and SeatRef (§2) with their invariants and the pure unit test (no Django, 33): the different currency raises, the invalid seat raises, the correct sum.
  2. The missing business VO: Percentage (the org's commission, 0-30% with validation) or TimeRange (the event with start<end). Implement the one you use and migrate ONE service to it.
  3. The VOs' cost: measure the impact on 25's serializer: does the DTO accept Money or convert it? Where does the conversion live (the mapper? the serializer?) and why NOT in the domain?

Exercise 3 — The Reservation aggregate

  1. Extract Reservation to the pure domain (§3): 00b's state machine in the class, confirmar()/expirar()/cancelar(motivo) with the transitions as methods, no Django.
  2. The bidirectional mapper (adapters/mappers.py) and 25's repository adjusted: get() returns DOMAIN (with the seats loaded: the full aggregate), save() persists from the domain. What happened to lazy-loading? Is the repo's prefetch_related now mandatory? Document the consequence.
  3. The domain test: the aggregate's unit suite runs WITHOUT a DB: pytest tests/unit/domain -q in <1 s. How many tests did you migrate from integration to pure unit? Which ones STAY in integration (the lock? the outbox?)?

Exercise 4 — The DDD decision

  1. Write the ADR "Partial DDD in TicketFlow" (48): what it extracts (VOs, the Reservation aggregate), what stays (CRUD in the ORM), the measured cost (the mappers, the weeks), and full DDD's trigger (53's second service? the rules > N?).
  2. The counterfactual: estimate (49) FULL DDD for your repo: how many weeks? What would it really gain? Which lines of 51's model would pay that bill? The honest answer: is it worth it TODAY or not?
  3. The border with 53: which modules of the modular monolith would be the "bounded contexts" (tickets vs payments vs events?)? Draw the context map with its own language (the ubiquitous per context): does "reserva" mean the same in payments as in tickets?

Exercise 5 — The ubiquitous language

  1. The language audit: list the names in your code that do NOT speak the business (XDataModel? process_stuff?) and rename them to the domain's language. The test: the business owner (51: the pitch) reads your classes' names and understands half of them — do they?
  2. The Anti-corruption layer: the gateway's payload (or 17's webhook): where does settled get translated to PaymentSucceeded? If the foreign vocabulary reached the domain (an if status == "settled" in services?), move it to the adapter.
  3. The glossary: create docs/reference/lenguaje.md with the domain's 15 words (reserva, expira, confirma, tarjeta regalo, comisión...) and their exact ONE-line definition — the vocabulary shared between the business and the repo (48's doc that 51 promised).

Submit

Paste the hexagonal ring, the VOs with tests, the Django-free aggregate with its mapper and the partial-DDD ADR. Next: Lesson 53 — Modular monolith vs microservices.