Skip to content

Domain ​

The domain is the model of the business: its objects, its rules and what happens to them. It lives in domain/ and imports nothing but the domain and @alveolus/core.

Why ​

When the rule "an order cannot be placed empty" sits in a controller, a SQL query and a cron job, each copy drifts and nobody knows which one is right. When it imports an ORM or a framework, it cannot be read or tested without them.

The fix

The rules live in one place, in plain TypeScript classes named after the business. Everything else calls them.

How the blocks fit together ​

Order · aggregateOrderrootOrderLineentityOrderIdvalue objectOrderPlaceddomain event · recordedEmptyOrderdomain error · returnedOrderLimitdomain servicechecksOrdersrepository · load, saveClockport · outside worldOrderSummaryview · read by queries
1ModelAn aggregate groups entities and value objects behind a root that keeps the rules.
2OutcomesA change records a domain event; a refusal returns a domain error.
3Outside worldRepositories and ports say what the domain needs, in its words. Adapters do the rest.

The building blocks ​

Building blockWhat it isUse it when
AggregatesA group of objects changed together through one root, which keeps their rules.Some rules must hold after every change.
EntitiesAn object defined by its identity, inside an aggregate.A part of an aggregate changes over time and must be told apart.
Value objectsAn immutable value compared by its attributes, and the typed identifiers.A number or a string has rules or a unit: an amount, an email, an id.
Domain eventsSomething that happened in the domain, in the past tense.Something else must react to a change.
Domain errorsAn expected business failure, returned as a value.A business rule refuses a request.
Domain servicesA stateless operation that belongs to no single object.A rule needs several aggregates and belongs to none.
PortsWhat the domain needs from the outside world, in its own words.The domain needs the time, an id, a payment, another context.
RepositoriesHow aggregates are loaded and saved, and how views are read.An aggregate must be stored, or a query must read data.
ViewsWhat a query returns.A screen or an API needs data shaped for reading.

See also ​

Released under the MIT License.