Photo by Alex Smith on Unsplash.com
What is Domain-Driven Design?In 2004 Eric Evans published the book Domain-Driven Design: Tackling Complexity in the Heart of Software. In it, Evans provides a systematic approach to application design through a set of best practices and fundamental principles. As the title of the book suggests, the focus centers on the concept of the Domain.
In the context of software development, a Domain represents the subject area for the application being modeled.
"Domain: A sphere of knowledge, influence, or activity. The subject area to which the user applies a program is the domain of the software.The goal of the model is to represent the domain in a manner that can be easily understood by domain experts. The domain model represents the logical view of the domain, and the technical implementation of that model is the application.
With a DDD approach, the goal is to evolve a model of the domain which focuses on the language of domain experts but can be understood by both domain experts and developers. In DDD, The objective is to decompose the business domain into smaller sub-domains, each focusing on a different part of the problem domain. This approach aligns well with microservice architectures as we can map each sub-domain to a specific service.
Coming to terms with termsWhen discussing Domain Driven Design, it's essential to understand the basic terminology. Here are some of the key concepts:
ModelA model is an abstract representation of some portion of the application domain.
ContextA context provides the setting in which something exists to define its meaning. It is common for terms to be overloaded within the application and the context in which the term is used defines how it should be understood.
Bounded ContextA bounded context identifies an area (usually a functional area) in which the model has a particular meaning. Each model is defined in terms of this context and may have subtly different meanings than similar models in other parts of the application. The language of a particular sub-domain is used to describe the bounded context. When the language between user groups changes around a particular model,it is often a good indicator that there is a bounded context involved.
Ubiquitous LanguageThe Ubiquitous Language is the language used to describe the domain model. It forms the primary vocabulary used by all team members (technical and non-technical) regarding the application. This vocabulary is focused on business terminology and not implementation technology. By focusing on the business terminology, we avoid introducing implementation-specific jargon into the model. This implementation-free language makes it easier to understand for non-technical team members and avoids tying the language to a particular technology that may change in the future.
EntityAn entity is an object with attributes and a unique identity. Attributes describe the entity while the identity is used to provide uniqueness to distiguish between multiple entities having identical attributes. While entity attributes values may change over time, reflecting the current state of the entity, the identity is always immutable.
Value ObjectA value object is an immutable object that contains only attributes. It has no identity. Value objects with identical attribute values are functionally equivalent.
Domain EventA domain event is an object that is generated by the domain to record a discrete event that has occurred within the domain. These events are identifed by the domain experts as having sufficiently significant business value to share with other domains.
AggregateAn aggregate defines a graph of related entities and value objects that the application treats as a discrete unit.
Aggregate RootAn aggregate root is an entity chosen to serve as the top-level container that will be passed between domains. All external domains reference the aggregate root rather than its subordinate child objects.
ServiceA service is a concept that doesn't naturally model as an Entity or Value Object. A candidate service should be stateless, have an interface that does not employ components from the domain model and wouldn't fit as a value object or entity.
RepositoryA commonly implemented service type is the repository which uses a common interface to provide access to all entities within a particular aggregate collection. Methods are defined to allow for creation, modification, query, and removal of elements from the aggregate.
ModuleA module acts as a container for a set of cohesive concepts that form a logical grouping. There should be minimal coupling between different module components. Modules are used to organize components into groups of related functionality.
FactoryA factory is responsible for the creation of complex objects and aggregates. The factory isolates the creation of an object or aggregate from its client.
Context maps graphically depict the bounded contexts and their relationships using a set of simple shapes with lines connecting those contexts in which a relationship exists.
Eating the Elephant.
"When eating an elephant, take one bite at a time."
--General Creighton W. Abrams, Jr.
--General Creighton W. Abrams, Jr.
When modeling a domain, the same approach should be taken as eating an elephant. If the problem domain is large and complicated, it needs to be decomposed into smaller sub-domains that can be isolated from each other and modeled independently. These subdomains contain groups of related concepts and activities that are naturally related. An online shopping domain (top-level) could be split into product catalog, inventory, purchases, and shipping sub-domains.
Within each of these subdomains, there may exist shared concepts. In the online shopping domain, the concept of a Product may exist in multiple domains but have different representations based on the needs of the specific domain. In a product catalog, the Product may contain a collection of images of the product that the inventory and shipping sub-domains don't need. Additionally, the Product may be referred to as an SKU in the realm of inventory and shipping instead of Product.
A common mistake is to define a one-size-fits-all model of a Product and to try and use it across the application in a traditional OOP reuse pattern. This forces each sub-domain to work with a sub-optimal representation of its specific notion of what a Product is. From the DDD perspective, it is better to have multiple unique models representing each sub-domain precisely rather than reusing a shared common model. Defining unique models for a given context provides the isolation necessary for the model to evolve to reflect each sub-domains requirements.
" A class should have only one reason to change."
Single Responsibility Principle --Robert C. Martin
Single Responsibility Principle --Robert C. Martin
Each domain should contain only the operations aligned with the responsibility of the domain. Change in the internals of one domain should not force a change to any other domain.
Event-First Domain Driven DesignIn an objected-oriented world, we usually start by identifying the nouns in the domain. Starting with the nouns has the unwelcome side-effect of focusing on the structure of the domain too early in the process. Initially introduced in Russ Miles book Antifragile Software, Event-First domain modeling suggest that Events are better at capturing the application's Ubiquitous Language. Events describe what a system does instead of how the system is structured. From the collection of system events, it is easy to derive the application's structure.
ANTI CORRUPTION LAYERAn Anti-Corruption Layer is a bridge between domains that prevents one domain from leaking into another. This bridge allows each domain to use its native model, while the anti-corruption layer is responsible for translating between domains. ACLs are especially useful when integrating with both external and legacy systems to maintain domain purity (at the cost of additional translation). Implementing an ACL invests additional code (the adapter) to prevent layers from leaking into the other.
Domain ActivitiesEvery domain has a set of associated activities made up a combination of Commands, Events, and Queries. These activities comprise the API of the domain.
CommandsA command is an activity that represents a request for a domain to perform an action that results in a change in the domain's state. Each domain is free to choose to accept or reject the command request.
EventsEvents are objects generated by the domain as the result of some action that has already occurred in the domain. Events provide a mechanism to notify other domains that a change in state has occurred so they can react accordingly.
QueriesQueries represent a request for information about the state of a domain. Queries always expect a response (even if it is empty) and should never change the state of the domain.
Beyond the IntroductionThis overview of Domain Driven Design should provide you with a basic introduction to the most common DDD terminology we will be using in future articles. To explore DDD at a deeper level than has been presented here, I refer you to the definitive source which is, of course, the book Domain Driven-Design .
Here you will find a free PDF copy of Eric Evans Domain Driven Design Reference. It provides an excellent supplement to the original book.
Another great resource is Vaughn Vernon's Implementing Domain-Driven Design which as the title implies, focuses on the implementation side of the DDD equation.
There is also an active community online and at the DDD Community.