Welcome to this blog post series about concepts and patterns of domain driven design (DDD). Although the original book about DDD [Eva04] was written almost 15 years ago, I only recently stumbled upon an article about it on the internet [Sch17]. This read drove my interest in DDD, and I started to dig deeper, read the original book, watched some conference recordings and started to experiment.
In my opinion, DDD captures the common sense of software design and makes it explicit. I’ve seen many advanced software engineers implement the concepts and patterns of DDD which have never heard of Eric Evans and his book. That’s why I would like help to spread the word and write this series.
This posts shall give an overview of what DDD is all about. The further posts of the series will dig deeper into the concepts and patterns.
Introduction to DDD
Eric Evans does a great job defining DDD at his keynote speech at the explore DDD 2017 conference. I highly recommend you watch it. On the first slide he defines four fundamental concepts of DDD as follows:
- Focus on the core complexity and opportunity in the domain
- Explore models in a collaboration of domain experts and software experts
- Write software that expresses those models explicitly
- Speak a ubiquitous language within a bounded context
The first point is about putting the domain in the center of software and focus on it. Everything else should be built around the domain and may be replaced without affecting the core functionality. Different people have different names for an architecture like this for example “Clean Architecture”, “Onion Architecture” or “Hexagonal Architecture”. The core idea is always the same: Use dependency inversion to put the domain at the center.
The second point is about requirements and how we best gather them. It states that we should explore the models with domain experts. This advice aligns nicely with agile methodologies that recommend close interaction with the business (the domain experts).
Once we know the domain model what do we do with it? In DDD we implement it directly in code. This is possible because DDD defines patterns to build our domain model which can be implemented in code too. The model can then be used by higher-level controllers to execute use cases.
The last concept is: Speak a ubiquitous language within a bounded context. The same language should be used through conversations, the domain model and in code. The ubiquitous language allows us to communicate effectively and prevents misunderstandings. The strategic pattern “Bounded context” aims to divide software along the domain boundaries. Ubiquitous language is always valid within a given context.
Basic DDD patterns can be divided into two kinds of patterns: tactical and strategic. Tactical patterns are used while modeling the domain and in code. Strategic patterns are more high level and are used to structure the software on an architectural level. We will go into the details of each pattern through the series. Therefore I list them only very briefly here.
Tactical Patterns (or building blocks in original DDD terms):
- Entity – Similar to objects in classic object-oriented design but with a focus on identity over time.
- Value Object – Immutable entity identified by its attributes.
- Factory – Super pattern for some of the GoF creational patterns.
- Service – Stateless object which encapsulates domain logic that cannot reasonably put on an entity or value object.
- Aggregate – Encapsulates multiple entities and value objects.
- Repository – Library for obtaining access to aggregates.
- Module – Structure objects on a higher level to reduce cognitive overload.
Strategic patterns and concepts:
- Bounded context – Define boundaries around domain areas and reflect them in software.
- Context Map – Model of the different bounded contexts of the system.
- Model Integrity Patterns – Ways to model the connections between multiple bounded contexts.
- Core Domain – Find the part of your model where the most business value lies and distill it into the highest priority context.
Supple design is the concept of designing the software in a way that feels natural when developing and maintaining it. The following patterns give some advice on how to achieve this property of software.
- Intention-revealing interfaces – Give the elements of software meaningful names, use the ubiquitous language
- Side-effect-free functions – Prefer functions that return results instead of manipulating some state
- Assertions – State post-conditions of operations and invariants of classes explicitly
- Conceptual Contours – Decompose elements of software into cohesive units
- Standalone Classes – Minimize dependencies to reduce the mental load
- Closure of operations – Where possible operations should return the same type as their argument(s)
- Declarative design – If possible use a declarative design/program style
Don’t worry if these very short descriptions leave some question marks in your head. These are concepts that cannot simply be explained in one or two sentences. I will try to explain them in the further posts of these series. Meanwhile, if you are curious, see this article for a bit more information.
Distillation of the Core
Distillation of the core domain enables us to focus on the most valuable part of our domain model. Evans touches multiple patterns or strategies of how to approach the distillation.
- Generic Subdomains – Extract subdomains that are not the main reason you build the system
- Domain Vision Statement – High-level vision of the system that helps to define the core domain
- Highlighted Core – Define which parts of model belong to the core but without extracting it (yet)
- Cohesive Mechanisms – Identify parts of the model that form a general know mechanisms
- Segregated Core – Remove supporting functionality from core objects
- Abstract Core – Aim for abstract core concepts that specialized subdomains can use
Large-scale structure concepts organize the system on a component or layer level. It guides developers on where to find functionality and where to place a new one.
The large-scale structure is not the same as classic architecture. It is driven by the domain and should, therefore, be based on domain concepts rather than technical concerns.
- Evolving order – Let the large-scale structure evolve over time
- System metaphor – Look for an overarching metaphor of the system and make it explicit
- Responsibility Layers – Organize the domain model across multiple layers
- Knowledge level – Allow configuration of core operations from a knowledge level
- Pluggable component framework – Abstract core with a plugin infrastructure
Wrap up / Final Thoughts
It seems that DDD consists of many concepts and patterns. However, don’t be scared, many of the overlap and together form a domain-centric way of thinking about software design.
When we take a look at our profession as a whole, DDD is concerned only with a small part of our responsibilities. Recently I read a blog post by Bob Martin where he reviews the XP process. He writes that metaphor in XP became DDD. The metaphor is only one of twelve practices in XP.
[Eva04] Eric Evans: Domain-Driven Design – Tackling Complexity in the Heart of Software (homepage)
[Sch17] M. Schimak: Domain-Driven Design? Na klar, das „blaue Buch“! – Mit „DDD“ (Domain-Driven- Design) zur gemeinsamen Sprache für Business und IT (http://www.sigs.de/public/os/2017/03/Schimak_OS_03_17_hdtz.pdf)