The specification pattern is something I’ve been writing about since 2016. Today, I’d like to talk about it in the context of the DDD trilemma.

1. Specification pattern

To recap, you can think of specifications as of domain classes that categorize other domain classes. A specification answers the question of whether a domain object meets some criteria.

The main benefit of the Specification pattern is that you can reuse that knowledge (of whether a domain object meets some criteria) in different scenarios and therefore adhere to the Don’t Repeat Yourself principle.

Here are the typical use cases for this pattern:

  • Data retrieval — Querying objects from the database that meet the criteria

  • In-memory validation — Checking that an object in the memory meets the criteria

  • Creation of a new object — Creating a new (arbitrary) object that meets the criteria

  • Bulk updates — Modifying a bunch of objects that meet the criteria

2. Domain Model Purity

Domain model purity (which I wrote about in this article) is a guideline advocating for removal of certain types of dependencies from the domain layer:

  • Explicit references to out-of-process dependencies, such as StudentRepository or IStudentRepository.

  • Non-referentially transparent dependencies, such as DateTime.Now property.

Domain model purity is a special case of the Separation of Concerns principle.

The purpose of the Separation of Concerns is to strip the domain layer of any responsibilities other than domain modeling itself and thus keep that layer as simple as possible.

Another special case of the Separation of Concerns is the principle of Persistence Ignorance. Persistence Ignorance states that domain classes should not be impacted by how they are persisted in the database.

These 3 principles — Domain Model Purity, Separation of Concerns, and Persistence Ignorance — are quite similar, and for most practical purposes can be used interchangeably.

For those interested in details, here is a diagram that shows how to categorize different types of violations in the domain layer:

But again, all 3 principles can be used pretty much interchangeably.

3. DDD trilemma

Finally, the DDD trilemma states that you can’t have all 3 of the following attributes:

  • Domain model encapsulation (aka completeness) — When all the application’s domain logic is located in the domain layer, i.e. not fragmented.

  • Domain model purity — When the domain layer doesn’t have out-of-process dependencies.

  • Performance, which is defined by the presence of unnecessary calls to out-of-process dependencies.

You have 3 options here, but each of them only gives you 2 out of the 3 attributes:

  • Push all external reads and writes to the edges of a business operation — Preserves domain model encapsulation and purity but concedes performance.

  • Inject out-of-process dependencies into the domain model — Keeps performance and domain model encapsulation, but at the expense of domain model purity.

  • Split the decision-making process between the domain layer and controllers — Helps with both performance and domain model purity but concedes encapsulation. With this approach, you need to introduce decision-making points (business logic) in the controller.

Here’s this trilemma in one picture:

4. Specification pattern and DDD trilemma

It’s interesting to look at the Specification pattern from a DDD trilemma perspective.

The Specification pattern violates the Persistence Ignorance principle by design. That’s because 2 out of the 4 of its use cases (data retrieval and bulk updates) target the database:

The objective of this pattern is to encapsulate the domain knowledge related to specific properties of your domain classes.

Can you tell which part part of the trilemma diagram the Specification pattern occupies?

☝☝ This one.

The specification pattern is a perfect representation of the DDD trilemma. It deliberately chooses domain model encapsulation over purity.

It’s not to say that I agree with this choice. I strongly believe that domain model purity is more important than encapsulation, which is part of the reason why I don’t use the Specification pattern that much.

But still, it’s a good case study that helps understand the trade-offs various patterns make. It also shows how great of a framework the DDD trilemma is — a lot of well-known dilemmas and patterns can be represented using that framework.

--Vlad

https://enterprisecraftsmanship.com


Enjoy this message? Here are more things you might like:

Consulting and training — I offer consulting and group training for organizations on Unit Testing and Domain-Driven Design. Reply to this email with the word "consult" to discuss.

Unit Testing Principles, Patterns and Practices — A book for people who already have some experience with unit testing and want to bring their skills to the next level.
Learn more »

My Pluralsight courses — The topics include Unit Testing, Domain-Driven Design, and more.
Learn more »