Domain-Driven Design: Everything You Always Wanted to Know About it, But Were Afraid to Ask

As one’s codebases grow, it is inevitable that their complexity will increase. As this happens, it tends to get more difficult to keep code organized and structured as originally intended, this is known as Software Entropy. Over numerous iterations, maintaining good separation of concerns and properly decoupling classes and modules becomes more challenging if no strict architectural guidelines are enforced.
In the traditional Model-View-Controller (MVC) architecture, the “M” layer would hold all the business logic, but would not provide clear rules on how to maintain proper responsibility boundaries. Several patterns came up to mitigate this problem, but still there was always risk of logic and responsibility leakage between components, making maintainability and stability trickier as the model evolved.
On the other hand, communication with business experts, requirements gathering, and consensus between technical and non-technical teams to properly design and implement a system that solves a business problem is a constant iterative process where things can easily get misinterpreted, and ultimately derail the project from its original goals.
Naming things, for example, has always been one of the most difficult challenges Software Developers face. We should be clear enough for other developers to understand our intentions in the code, while using appropriate naming choices that can facilitate a conversation with business stakeholders.
Domain-Driven Design (DDD) attempts to solve these challenges, by reconciling the technical and non-technical forces that collide in a software project, and proposing a set of practices and patterns that facilitate building a successful system.
So what is Domain-Driven Design?
Let’s start by defining what the word domain means in this context. I like to define it as
“A specific sphere of activity or knowledge that defines a set of common requirements, terminology, and functionality on which the application logic works to solve a problem.”
Domain-Driven Design is an approach to software design that glues the system’s implementation to a constantly evolving model, leaving aside irrelevant details like programming languages, infrastructure technologies, etc…
It focuses mainly on a business problem and how to strictly organize the logic that solves it. This approach was first described by Eric Evans in his book Domain-Driven Design Tackling Complexity in the Heart of Software.
Now that we know the definition of DDD and what its goals are, let’s dive into the three main pillars of this methodology.
Strategic Design: Splitting your design so as to not lose your mind
As the implementation evolves through many iterations, and the system’s complexity grows progressively, it can be daunting to maintain control over it. Therefore, a rigorous strategy to comprehend and control large systems is fundamental. Breaking down the model into Bounded Contexts that interact with each other — which themselves have their own unified model both in concept and in code — is an effective way to avoid complexity pitfalls.
Bounded Context
A Bounded Context is a conceptual boundary around parts of the application and/or the project in terms of business domain, teams, and code. It groups related components and concepts and avoids ambiguity as some of these could have similar meanings without a clear context.
For example, outside of a Bounded Context, a “letter” could mean two very different things: either a character or a message written on paper. By defining a boundary and context, you can determine its meaning
In many projects, teams are split by Bounded Contexts, each of them specializing on its own domain expertise and logic.
Context Mapping
Identifying and graphically documenting each Bounded Context in the project is called Context Mapping. Context Maps help better understand how Bounded Contexts and teams relate and communicate with each other. They give a clear idea of the actual boundaries and help teams visually describe the conceptual subdivisions of the system’s design.

Relationships between Bounded Contexts can vary, depending on design requirements and other project-specific constraints, some relationships will be omitted from this article with the exception of the following four:
Anti-corruption Layer:
The downstream bounded context implements a layer that translates data or objects coming from the upstream context, ensuring that it supports the internal model.
Conformist:
Downstream bounded contexts conform and adapt to upstream contexts, having to change if needed. In this case the upstream context has no interest in meeting requirements downstream.
Customer/Supplier:
Upstream supplies downstream with a service, and downstream context acts as a customer, determining requirements and requesting changes upstream to meet their needs.
Shared Kernel:
Sometimes it’s inevitable that two (or more) contexts overlap, and end up sharing resources or components. This relationship requires both contexts to be in continuous synchronization when changes are needed, therefore it should be avoided if possible.
Collaborative Modeling: Rich communication and effective collaboration
DDD proposes to model the domain effectively by doing a collaborative approach, involving all parties that hold not only technical, but business knowledge as well. As Evans describes it, the Domain Model “is not only the knowledge in a domain expert’s head; it is a rigorously organized and selective abstraction of that knowledge.”
Developers collaborate with domain experts with the intention of constantly refining the Domain Model, forcing them to learn important details and principles of the business problem they are trying to solve, instead of just producing code mechanically.
To enable this collaboration between business and technical teams, the Domain Model should use a language that joins business with technical jargon, and finds a middle ground that all team members can understand and agree on, this is called a Ubiquitous Language. Using a well-defined Ubiquitous Language will improve every interaction between tech and business teams, making them less ambiguous and more effective.
Ultimately this Ubiquitous Language will be embedded in the code.
Tactical Design: The Nuts and Bolts of DDD
Implementing associations between domain objects and describing their functionality feels easy at a glance, but proper distinction of their meaning and reason of existence should be done in a clear and intuitive way. DDD proposes a set of constructs and patterns to achieve it.
Entities
Objects that have a unique identity and possess a thread of continuity are called Entities, they are not defined solely by their attributes, but more by who they are. Their attributes might mutate and their life cycles can drastically change, but their identity persists. Identity is maintained via a unique key or a combination of attributes guaranteed to be unique.
In the e-commerce domain for example, an order has a unique identifier and it goes through several different stages: open, confirmed, shipped, and others, therefore it’s considered a Domain Entity.







