Domain-Driven Design
A visual walkthrough of strategic and tactical design, using one running webshop as the example throughout.
Click the image to enter
Strategic design
Where the walls go
Every piece of software serves a business. The problem space is that business, split into the parts it is made of. The solution space is the software, split into walled-off models. Strategic design is deciding where those walls go.
Subdomains
Core, supporting and generic
Not every part of the business deserves the same effort. Each subdomain gets a type: core parts are built with care, supporting parts are built simply, and generic parts are bought. Select a part of the map to see why.
Webshop domain
Ubiquitous language
One word, many meanings
Inside a bounded context, the domain experts, the team and the code share one precise language. The same word can mean something else in the next context, and that is fine: the wall keeps each meaning intact. Pick a word to see what it means behind each wall.
What it costs
Bounded contexts
A model is only true inside its wall
A bounded context is a wall around one model and one language. It is usually owned by one team, with its own code and its own data. Inside the wall every word means one thing. Everything outside has to come in through a door. Point at, tap or tab to any part of the Sales context below to see what it is.
Context map
How the contexts relate
Step back and every wall in the webshop is on one map. Each line is a relationship between two contexts. In most of them one side is upstream: what it decides flows down to the downstream side, which has to live with it. The patterns say how the two sides deal with that. Select a line to see why it was chosen here.
Highlight a pattern
Relationships
Doors in the wall
Anticorruption layer, open host service, published language
Three of the patterns on the context map are doors: the places where a message crosses a wall. An anticorruption layer translates a foreign model on the way in. An open host service offers one stable way in for everyone. A published language fixes the shape of what crosses. Follow one real message through each door and see how it changes on the way.
Zoom in
Into the Sales context
The context map shows every wall from the outside. That is where strategic design stops: it decides where the walls go, who owns what is inside them and how the contexts talk through their doors. How a model is built behind its wall is tactical design. Pick one wall on the map, Sales, and step through it.
Tactical design
Inside a bounded context
Strategic design drew the walls between contexts. Tactical design is about what lives inside one of them, and about the few doors that let anything in or out.
Layers
Layers inside a context: ports and adapters
Inside the Sales wall the code is arranged in rings. The domain model sits in the centre. Application services around it are the doors for use cases. Adapters on the outside connect to the world: web pages, the database, the message bus and other contexts. The domain owns the ports, the interfaces its adapters implement, so every dependency points inward. Point at, tap or tab to a part to see what it depends on, and why.
Composition explorer
Who is allowed to touch what
Everything in the Sales context lives behind a wall. Point at, tap or tab to a box to see what it holds, what it points to, and what may point to it. The coral boxes are doors: the only ways through a wall. On a narrow screen the drawing shows one wall at a time: tap a wall inside it to open it, and use the path above the drawing to go back out.
Building blocks
Eight shapes, eight kinds of door
Each building block has its own way of keeping the outside world out. Once you know the door, you know how it may be used.
public sealed class Order
{
private readonly List<OrderLine> _lines = new();
public OrderId Id { get; }
public CustomerId CustomerId { get; } // another aggregate, by id
public OrderStatus Status { get; private set; }
// The door: every change goes through the root
public void AddLine(ProductId product, int quantity, Money price)
{
if (Status != OrderStatus.Draft)
throw new DomainException("A placed order can't be changed.");
_lines.Add(new OrderLine(product, quantity, price));
}
}
Reference rules
Allowed and forbidden
Every rule here has the same shape: reach past an aggregate's root and the wall stops you, with a blocked sign to show it; go through the root, its door, and it lets you in. Each pair shows the forbidden path next to the allowed one, with a one-line C# hint.
Transactions
One transaction, one aggregate
An aggregate is a consistency boundary, and a transaction is what makes that boundary real: one transaction loads, changes and saves exactly one aggregate. Step through placing an order and watch the boundary open around Order, close when it is saved, and never reach around anything else.
What happens when
Back out
Back out through the wall
Everything so far has been inside one wall. The last thing to follow is the way out. Nothing reaches into Sales for an order, and Sales hands nothing of its model out: what leaves is an event, written in a language both sides agreed on, and the other side turns it into its own words.