DDD Tactics

🗓️
•
🔄
•
⏳ 5 min

This is part of a series, start here!



From Eric Evans 2003 book, this approach to software design aims to couple the design of a system to the business domain it operates in.

This is to say, a system design should reflect the business logic for which it was created.

He broadly separates Tactical from Strategic design. In this post, we’ll go over some concepts from the former.

Layers

Broadly speaking, four main layers are considered in this architecture:

If ‘EBI architecture’ doesn’t ring a bell, you might want to start here.

Entities / Value Objects

Concrete representations of very basic Domain concepts.

They differ on mutability and identity.

Entity

An employee might change their role within the company, that doesn’t make it a different employee.

Apart from their name, you’ll likely identify them by some sort of ID, so a change in their attributes doesn’t change their identity.

So we would say an employee is an Entity in our system.

Value Object

A phone number on the other hand does not change. Or rather, if it does, we are talking about a different phone number.

It wouldn’t really make sense for a phone number to have an ID: The object is identifiable by its attributes.

Thus, things like phone numbers, email addresses, etc. are Value Objects (VO).

Rich Domain

While in general, Entities have IDs and VO don’t, not all cases are so clear-cut as these.
The context and Domain will dictate which to use in a given situation.

It’s also important to remember that neither should be anemic: they should encapsulate as much logic as reasonably possible (usually all logic regarding their individual behavior).

Aggregates

Conceptual elements made up of multiple Entities and/or VO, which only have meaning or make sense together.

The concrete representation of this element is the Aggregate Root. This serves as a gateway to the rest of the elements enclosed within the Aggregate (Entities and VO).

The Aggregate Root should be the only way of accessing those elements, especially when modifying their state.

It’s not hard to imagine such a structure getting out of hand. Prevent this from happening by:

All logic pertaining multiple Aggregates should be delegated to a Domain Service.

Services

Stateless objects that perform Domain-specific operations that escape the boundary of the Aggregate. Based on their scope, there are two kinds:

To be clear, the scope should grow the further away we go from VO:

VO < Entity < Aggregate Root < Domain Service < Application Service < Module

If communication is needed between Modules, the Application Services should talk to one another Without accessing other Domain objects from different Modules.

Domain Events

A decoupled way for different parts of the system to indirectly interact with one another.

These usually materialize into a Pub/Sub structure:

Publisher

There are at least two ways of approaching who should be in charge of event publishing:

Subscriber

Event subscribers look a bit like controllers, just limited in scope within our Domain.

They both ingest the primitive types of their respective input and use them to run the relevant use case.

Where controllers receive requests, subscribers receive events, but in essence you can think of their role as equivalent in practice, just with different scopes and implementation.

So for example, a generic Subscriber interface signature might look something like:

public interface DomainEventSubscriber<DomainEvent>

Where the implementation looks like:

public class DoStuffOnCustomEvent implements DomainEventSubscriber<CustomEvent>

CustomEvent might, for example, implement or extend from DomainEvent.

Repositories

They abstract concerns about data storage and other infrastructure.

Ideally, there will be one Repository per Aggregate Root, and it should only be called by the relevant Application Service/s as part of a use case orchestration process.

They usually take the form of a domain leaning interface with concrete implementations based in the specific infrastructure at hand.
This is more or less borrowed from Ports and Adapters.

More to come

By now this is probably sounding like a big ball of jargon with not much of an architecture behind it, no real intention or plan.

We’ll go over the Strategic side if DDD in a later post.

Also read


Other posts you might like