Decision tree
Purpose: pick the correct path before writing code.
Master flowchart
Decision table
| Question | If yes → | Docs |
|---|---|---|
| Only this module’s data and rules? | Golden Flow + optional repository port | Golden flow, Ports |
| Need peer data/validation before continuing? | Sync ACL | ACL, Transactions |
| Peer should react after we finish (no return needed)? | Domain Event | Events, Delivery |
| Multi-step cross-module with compensations? | Orchestration (saga-lite) | Orchestration |
| Cross-context list/dashboard? | Projection or ACL read — not ORM joins | Reads |
| Same technical helper already needed by a second module? | Promote to Shared | Shared kernel |
| Same business concept needed by a second module? | ACL / Events — never Shared | ACL |
| Evolving a façade or event? | Treat as published contract | Contracts |
Illustrative examples
| Feature | Bridge | Why |
|---|---|---|
| Create Ordering draft | Local + repository | No peer required for core write |
| Ordering checks stock | ACL to Warehouse | Need availability now |
| Ordering validates member tier | ACL to Directory | Need eligibility now |
| After fulfilled, finalize stock | Event to Warehouse | Side effect after success |
| Transaction wrapper used by many modules | Shared port | Technical, multi-module |
Implementation order (practical)
- Write the Use Case + Application DTO for the owning module.
- If I/O needed → add port + fake/in-memory in tests, then persistence adapter.
- If peer needed sync → add local ACL port first (Use Case compiles), then adapter.
- If peer needed async → define Domain event payload, dispatch via Shared dispatcher, write consumer listener + inbound Use Case.
- For events: add
eventId+ idempotent consumer handling. - Run architecture boundary tests and feature tests on the host.
Next: anti-patterns · cookbook.