Concepts: a reading path
Summary. These pages explain the ideas this kit is built on: Domain-Driven Design (strategic and tactical), the layered architecture and its dependency rule, messaging and consistency between bounded contexts, the cross-cutting concerns, clean code and testing. They teach and give the reasons; the rules themselves are stated once, in the architecture reference, and each page links to them by rule id. Every page can be read on its own in a few minutes. Read in order, they form a path from "what is a domain" to "how do I test this", using one example throughout: an appointment scheduling application.
The running example
Section titled “The running example”Clients book appointments with practitioners. Five bounded contexts are built, and identity is bought:
| Context | Classification | Owns |
|---|---|---|
appointments |
core | booking, rescheduling and cancellation rules; no practitioner is booked twice |
availability |
supporting | the open slots, computed from calendars and booked appointments |
calendars |
supporting | the working hours and time off of each practitioner |
notifications |
supporting | confirmations and reminders, through email and SMS providers |
analytics |
supporting | occupancy and no-show statistics |
| identity | generic | an OpenID Connect provider; no context in the code |
How they depend on each other, upstream to downstream, as the worked example of the context map finds it:
The example application of the repository, examples/scheduling,
is a smaller cut of the same domain that runs; several pages quote its code.
1. Strategic design: where the boundaries are
Section titled “1. Strategic design: where the boundaries are”Read these first. They decide everything that follows, and they are decisions of people, not of tools.
- Domain and subdomains: core, supporting, generic, and how to classify.
- Bounded context: what a boundary is and the tests that find one.
- Ubiquitous language: the glossary, and why it is written before the code.
- Context map: the relationship patterns between contexts, when each fits and what it costs.
- Context map: a worked example: from a plain statement of needs to the map of the scheduling application.
2. Tactical design: what is inside a context
Section titled “2. Tactical design: what is inside a context”- Entities and value objects: identity versus value.
- Aggregates: the consistency boundary, one transaction, reference by id, sizing.
- Domain building blocks: domain event, domain service, repository, factory.
- Invariants, permissions, validation: three different things, three places.
- Anemic model: how to recognise one, and when a thin model is fine.
- State machines: the lifecycle of an aggregate declared once, asked by the aggregate, drawn in its CONTEXT.md.
3. Architecture: how the code is arranged
Section titled “3. Architecture: how the code is arranged”- Layers and the dependency rule: hexagonal, onion and clean architecture, what they share and where they differ.
- Ports and composition: ports as abstract classes, the composition root, declarations by decorators or explicit wiring.
- CQRS: command and query buses as used here; event sourcing is a separate choice, per aggregate. The presentation layer comes with it: one controller class per route, route groups, guards at the edge and permissions on the use case; and representations, field access and forms: one schema answered in JSON, XML or CSV, fields reserved to some callers, forms described by the server.
- Modular monolith: one deployable, real modules.
4. Messaging and consistency: how contexts collaborate
Section titled “4. Messaging and consistency: how contexts collaborate”- Domain and integration events: the two kinds and what separates them.
- Transactional outbox: why publishing straight to a broker loses or invents events, and the relay strategies.
- Delivery and idempotency: at-least-once, idempotent consumers, the processed-event store, ordering.
- Eventual consistency: explained to a product person.
- Sagas and process managers: what the kit provides and what it does not.
- Event versioning: changing a contract that others consume.
- Event sourcing, per aggregate: when an aggregate keeps its events instead of its state, what it costs, and how to move one to it and back.
5. Cross-cutting concerns: what surrounds the use cases
Section titled “5. Cross-cutting concerns: what surrounds the use cases”- Authentication and authorization: roles, attributes, relationships, with a decision table.
- Authorization in practice:
@Requires, the middleware, theAuthorizerport and policies, followed through one command. - Actor and execution scope: who acts, explicitly, and what every unit of work carries.
- Multitenancy: one deployment, many customers, and no read or write that crosses from one to another.
- Audit trail: who did what, recorded from outside the use cases.
- Observability: tracing, logs, metrics, error reporting, and the correlation id that ties them.
- Resilience: retry, timeout, circuit breaker, bulkhead, cache, and how each one fails.
- HTTP caching: what to cache at which layer, who may keep an answer, and never a decision of authorization across actors.
- Scheduled jobs: work triggered by time, and why it must be idempotent.
- Background jobs: work a use case hands to a worker, enqueued in its transaction, run at least once.
- File storage: files in a storage and never in the database, the order that keeps both consistent, signed links.
- File import and export: a design, not built yet: a large file read or written by a background job, row by row, between the queue and the file storage.
6. Code and tests
Section titled “6. Code and tests”- Clean code: naming, small functions, stepdown, comments, testability by construction.
- Testing strategy: fakes rather than mocks, builders, contract tests, the four levels.
Shorter paths
Section titled “Shorter paths”- A product person or a newcomer to DDD: 1, 2, 3, 5, then 19.
- Before writing a first use case: 3, 7, 9, 12, 14, 36.
- Before making two contexts talk: 4, 16, 17, 18, 21.
- Before keeping an aggregate as its events: 7, 16, 17, 21, 22.
- Before serving several customers from one deployment: 23, 25, 26.
- Before putting the system in production: 23, 24, 28, 29, 30, 31, 32, 33, then the tools pages.
Limits and when not to use it
Section titled “Limits and when not to use it”These pages describe one opinionated way of applying the patterns, the one this kit enforces. Other valid applications exist (event sourcing, a separate read database, aggregates persisted as documents), and several pages say where the kit stops. The patterns themselves have a cost: for a small tool with little business logic, most of sections 2 to 4 is more than the problem needs, and each page has a "Limits and when not to use it" section that says so in its own terms.
See also
Section titled “See also”- Documentation index
- Architecture reference: the normative rules
- Methodology: the same ideas as a sequence of steps
- Configuration