# Domain-Driven Design

## Summary


Writing software involves software architects and programmers. They understand software concepts, tools and implementation details. But they may be disconnected from the business and hence have an incomplete understanding of the problem they're trying to solve. **Domain-Driven Design (DDD)** is an approach towards a shared understanding within the context of the domain.  

Large software projects are complex. DDD manages this complexity by decomposing the domain into smaller subdomains. Then it establishes a consistent language within each subdomain so that everyone understands the problem (and the solution) without ambiguity.  

DDD is object-oriented design done right. Among its many benefits are better communication, common understanding, flexible design, improved patterns, meeting deadlines, and minimizing technical debt. However, DDD requires domain experts, additional effort and hence best applied for complex applications.

## Discussion

### What do you mean by 'domain' in the context of domain-driven design?

Domain can be defined as "a sphere of knowledge, influence or activity." For example, *Accountancy* is a domain. An accountant is someone who knows this domain well. She is considered a domain expert. She's perhaps not a programmer and therefore can't build an accounting software. But she can advise developers on the intricacies and workings of the domain. 

Consider the domain of air traffic. A developer might imagine that pilots decide on the route (a sequence of 3D points) to a destination. A domain expert might clarify that routes are pre-determined and each route is actually a ground projection of the air path. 

To better manage complexity, a domain can be broken down into **subdomains**. In the e-commerce domain, *Payment*, *Offer*, *Customer* and *Shipping* are possible subdomains. 

Domain is the business or problem to be solved. Model is the solution. Likewise, subdomains in the problem space are mapped to **bounded contexts** in the solution space. 


### Could you explain the relevance of bounded contexts?

Consider the terms *Member* and *Payment* used in a country club. For some stakeholders the terms relate to club membership fees; for others, they're about tennis court booking fees. This disconnect is an indication that the domain is not really one and indivisible. There are subdomains hiding in there and they're best modelled separately. Bounded contexts are the solution. 

When a model is proposed for a subdomain, it's applied only within the boundaries of the subdomain. These boundaries in the solution space define a bounded context. When teams understand the bounded contexts, it becomes clear what parts of the system have to consistent (within a bounded context) and what parts can develop independently (across bounded contexts). Bounded contexts therefore imply a clear **separation of concerns**. 

Without bounded contexts, we'll end up with a single large complex model of many entities and relationships. Entities will get tightly coupled. The end result is often called a **Big Ball of Mud**. 

Bounded contexts may overlap or may be neatly partitioned. Bounded contexts often relate to one another and this is captured in a **context map**. 


### What is meant by the term Ubiquitous Language?

A developer might state that "a database was updated and triggered an SMTP service." A domain expert unfamiliar with such technical jargon will be left confused. **Ubiquitous Language (UL)** is an attempt to get everyone to use words well-understood within the bounded context. Using UL, the developer would now state that "the pizza was delivered and a coupon was sent to the customer." 

UL must be consistent and unambiguous. It should evolve as understanding of the domain changes. A change in language implies a change to the model. In fact, the model is not just a design artifact used just to draw UML diagrams. Model is the backbone of the language. Within a bounded context, use the same language in diagrams, writing, speech and code. 

To create an UL, have an open discussion, analyze existing documents, express the domain clearly, and define an agreed glossary. Glossary alone won't help. Use it consciously to arrive at a common understanding of the model. 


### How should I implement Universal Language in my code?

Since documents can get outdated quickly, code is an enduring expression of Universal Language. 

Adopting UL in **naming convention** leads to clean readable code. The purpose of variables, methods, classes and APIs become easier to see. We call this **intention-revealing interfaces**. Example names that follow UL are `TaskReservation`, `ReservationAttempt`, `IsFulfilled`, `BookSeats`, `Reservation`, and `Confirm`. In fact, there are tools to check if names in code follow the domain's defined vocabulary. *NDepend* is one such tool. 

Without UL, a shared understanding is hard to achieve and teamwork suffers. Even among technical folks, one may refer to `coupon` in an API but call it `Discounts` in the backend. Another mismatch is when a checkout workflow is mapped to `RideCommerce` service. Perhaps, this was documented somewhere but the documentation was not read by everyone. 

Any code refactoring mustn't happen without discussion using the UL. For example, discussion could involve these questions to clarify concepts: "When you say `User`, do you mean `Driver`?" or "Do you think a `Coupon` is applied to the `BookingAmount`, or is it added?" 


### Could you describe some essential terms of DDD?

From a comprehensive online DDD glossary, we describe some essential terms:  

    + **Entity**: An object that has attributes but primarily defined by an identity.
    + **Value Object**: An object with attributes but no identity.
    + **Aggregate**: A cluster of objects treated as a single unit. External references are restricted to only one member, called the *Aggregate Root*. A set of consistency rules applies within the aggregate's boundaries.
    + **Factory**: A mechanism to encapsulate and abstract away the details of creating a complex object. A factory ensures aggregates are initialized to a consistent state.
    + **Repository**: A mechanism to encapsulate storage, search and retrieval from a collection of objects. Its implementation is not a domain concern.
    + **Service**: A stateless functionality that renders its service via an interface, typically used when a workflow doesn't fit the current model.

### Could you explain entities and value objects?

Entities and value objects both follow principles of object-oriented design. They both encapsulate data (attributes) and behaviour (methods). The key difference is that an entity is distinguished by its **identity**, which must be unique within the system. On the other hand, value objects are descriptive with no conceptual identity. 

When we say that two entities are the same, we mean that their identities match, with possibly different attributes. When we compare two value objects, we're only checking if their attributes match. Thus, entities use **identifier equality** and value objects use **structural equality**. 

An entity has a **lifecycle**. Its form and content can change but not its identity. Identity is used to track the entity. Value objects are ideally **immutable**. 

In a banking application, transactions are entities, each with a unique transaction number. The amount transacted is a value object. A cheque's date may differ from the date of clearing but entries are always reconciled not by date but by the cheque number. This is an example of comparing entities by identities rather than by attributes. 


### Could you explain the concept of aggregates in DDD?

When a cluster of entities or value objects control a significant area of functionality, it's easier to abstract them into a single consistent unit. This is the **aggregate pattern**. One way to identify aggregates is to look at common transactions and the entities that get involved. 

Since an aggregate is a cohesive unit, it's best to ensure consistency by using a single **aggregate root** for all updates. Changing a child entity independently will break consistency since the root is unaware of such direct updates. 

As an example, consider two aggregates *Buyer* and *Order*. *Order* has as entities Order and OrderItem; and Address as a value object. However, all external interactions are via the Order entity, which is the root. This entity refers to the root of the *Buyer* by identity (foreign key) . 

Keep an aggregate on one server and allow aggregates to be distributed among nodes. Within an aggregate, update synchronously. Across aggregate boundaries, update asynchronously. Often, NoSQL databases can manage aggregates better than relational databases.


### Could you share some tips for practising DDD?

Objects with hardly any behaviour represent poor application of object-oriented design. They're little more than procedural-style design. This anti-pattern is called **Anemic Domain Model**. Instead, put business logic in domain objects. Other DDD anti-patterns to avoid include repetitive data access objects (use repositories instead), fat service layers, and classes that frequently access other classes' data. 

Adopt a **layered architecture** to avoid details of application, presentation or data persistence from creeping into the domain layer.  

Analyze the problem domain before deciding if a concept should be an entity or a value object. Don't link a value object to an entity, which would require an identity for the value object. Instead, the value object can be inlined into the entity. 

Difficulties in implementing an aggregate usually indicates a modelling problem. Instead, attempt to refine the model. 

If an operation doesn't fit the current model, evolve the model. Only if that's not possible, consider introducing a service. Since services represent activities, use verbs rather than nouns in naming. Indeed, DDD is not for perfectionists. It's okay if the model can't handle some special cases. Use services rather than a leaky or confusing abstraction. 

## Milestones

1960

Software engineers recognize from the late 1960s that procedural languages are inadequate in handling the growing complexity of software projects. When *Simula 67* is released in 1967, it becomes the first **object-oriented programming (OOP)** language. Concepts of OOP and OOD reach maturity in the early 1980s. 

Sep  
1997

Foote and Yoder observe that while there are many high-level software architectural patterns, what's really prevalent in industry is "haphazardly structured, sprawling, sloppy, duct-tape and bailing wire, spaghetti code jungle." They call this the **Big Ball of Mud**. Code is dictated by expediency than design. The mantra has been, "Make it work. Make it right. Make it fast." Popular practices include immediate fixes and quick prototypes. Programmers work without domain expertise. No thought is given to elegance and efficiency of code. 

2003

Eric Evans publishes a book titled *Domain-Driven Design: Tackling Complexity in the Heart of Software*. Evans is credited for coining the term **Domain-Driven Design**. This is also called the "Blue Book". 

2009

At QCon, Phil Wills presents a case study about how The Guardian website was almost completely rebuilt following the principles of DDD. He mentions some key points: domain experts got more involved; they kept the model flexible to changes even when deadlines were met; they focused on core subdomains while leveraging on off-the-shelf software for the rest. 

May  
2011

The term **microservices** gets discussed at a workshop of software architects near Venice, to describe a common architectural style that several of them were exploring at the time. An application is decomposed into loosely coupled services, each being self-contained and managing its own data. From the perspective of DDD, a microservice maps to a subdomain and bounded context. 

2013

Vaughn Vernon publishes a book titled *Implementing Domain-Driven Design*. This is also called the "Red Book". 

Sep  
2017

Eric Evans notes at the *Explore DDD* conference that DDD remains relevant today, fourteen years after he coined the term. Many tools have come to support and adopt DDD. Though DDD is not about technology, it's not indifferent about technology. With technology's support, we can focus on building better models. He gives some examples. NoSQL databases make it easier to implement aggregates. With modern functional languages, it's easier to implement immutable value objects. Microservices have come to represent bounded contexts. 

Jan  
2019

A report published by InfoQ shows DDD in *Late Majority* stage of technology adoption. This is proof of its effectiveness in software development. This stage implies that more than half the software folks have adopted DDD and the skeptics are starting to adopt them too. Only a year earlier, DDD was in the *Early Majority* stage.