The 30-minute guide to Domain Driven Design: A secret weapon to solve tough problems (Part 2)
Create better team alignment, clearly define boundaries, and design around resiliency, scalability, and customer-driven value.
Introduction: Part 2
In part one of this article, I explored the overall benefits of domain driven design (DDD): To the organization and business, to the team, and to project execution. In this second part, I’ll introduce the mechanics of DDD. This is intended to be a quick introduction — enough to get you up and running, but you’ll want to learn more on your own. Accordingly, I’ve included references to the best learning resources, from textbooks to online courses and reference material.
If you’re new, welcome to Customer Obsessed Engineering! Every week I publish a new article, direct to your mailbox if you’re a subscriber. As a free subscriber you can read about half of every article, plus all of my free articles.
Anytime you'd like to read more, you can upgrade to a paid subscription.
As I already explained in part one, the Delivery Playbook relies on DDD extensively in the design phase, particularly during ideation and early blueprinting. DDD is integral to the playbook because of its focus on creating customer value. That means you’ll need a solid understanding of event storming activities, what a “domain” and a “context” is, how to model each, why ubiquitous language is so important, and more.
The rest of this article offers an introductory look at the mechanics of domain driven design. My goal is to get you familiar enough with DDD to follow along. Before actually executing a project, you’ll want more detail. For that, check out the references at the end of the article.
Why domain driven design works
Domain driven design is a uniquely valuable design process. One of its most worthy aspects is its emphasis on modeling the business, not technical features. Its focus on business events, activities, and processes draws out how a business works and, importantly, how business activity is recorded as an immutable fact. By eschewing technical features and instead keeping a laser focus on “how things get done,” a natural synergy is created with the customer — something I wrote about extensively in part one of this article. It results in capturing what your customer really wants.
Not only does DDD create synergy with your customer; it also aligns easily with good architecture principles. It naturally isolates different business layers and processes from each other. Where many design approaches struggle to “decompose the monolith,” DDD does this spontaneously, simultaneously engineering out complexity. Each service tends toward self-sufficiency and dependencies becoming resilient, able to “carry on” in the face of failure. Services favor asynchronicity, becoming more responsive and scalable.
DDD makes separation of concerns prominent: Separating business layers and processes, separating services, designing for loose coupling and robust dependencies. Each component becomes concerned with its own responsibilities — but recognizes that some other service will own other responsibilities. It naturally creates abstractions that make each component easier to reason about.
All of this naturally leads to customer value from the start, because it creates the customer value stream up front: The activities, events, and features that really drive value in your customer’s eyes.
Designing using DDD
Domain driven design is a top-down design language. It starts at the big picture and pushes the team to think about operations, and how a business (or system, or application) records the history of those operations. From there, it starts to dive deeper into specific operations, further exploring them and expanding the underlying details of how those operations take place.
In describing how to design with DDD, I’ll follow this top-down path, starting with the activities that capture business operations, then moving on to finer-grained activities.
The core elements of domain driven design are:
Ubiquitous language. A powerful tool for discovering the relationships and boundaries between important business ideas.
Domains. A collection of related concepts, relationships, and workflows.
Bounded contexts. A collection of related entities, data, behaviors and their ubiquitous language, expressed as a unified, related model.
Events. Something that happened that matters to your business domain experts (and, somehow, ends up being recorded by the system).
Entities, value objects, aggregates. The components used to model what’s inside a bounded context.
In the following sections we’ll explore each of these, along with other elements of DDD.
Contexts and ubiquitous language
In DDD, a context is the setting in which a word or a statement appears that determines its meaning. Let’s think about that for a moment, because it’s really important to understand why context and language are so consequential.
“The setting in which a word or a statement appears that determines its meaning” essentially directs us to think about language boundaries, or changes in the way we use language. An example I like to use to illustrate this is a bank setting, an example the playbook builds on. In a bank the word “account” could mean different things. It might be a securities and trading account, where you hold stock and bonds, which is a form of equity. At the same time, “account” could refer to a loan, which is a leveraged asset — in other words, it’s a debt that you owe the bank.
Contextual changes happen all over the place. Think about the word “product” in the context of sales versus support. A sales team will care about the product as revenue, its price, and perhaps availability. None of that matters to the support team. Support will care about the product as an obligation, a service level contract they offer a customer. In this case, both sales and support are talking about the same product — but what they think of as “a product” is totally different, and precisely how they model it is very, very different!
Since a business operates across different contextual boundaries it’s natural to run into changes in language. “Product” meaning a revenue stream over here, but “product” meaning a support obligation over there. This leads to ambiguity and, quite often, confusion and complexity.
As Martin Fowler points out, an effective model of a system only works if it’s a unified model — free of ambiguity and internally consistent. But, as systems become larger, building a single, large model proves to be unwieldly. It can no longer be a unified model that’s free of ambiguity as it grows to encompass all aspects of the business. In essence, we have to choose:1
Build a single, large model that tries to be all things. An “account” that tries to be both a securities account and a loan account, or a “product” that tries to model an item in a shopping cart and a support contract.
Or, we can recognize these boundaries for what they are: A separation of concerns. Different contexts that deserve to be handled in different ways — by different components in our system.
To build a system that is not unwieldly, we choose the latter option. Instead of building one large thing, we build many small things — each small thing defined by its “bounded context.” A bounded context becomes a place where we have a unified, consistent internal model. In essence, we use business language to figure out where those boundaries are: When business words change, we recognize we have crossed from one bounded context (“product” as revenue) into a different one (“product” as service) — and, accordingly, we model this as two separate and independently simpler components.
All of this leads us to ubiquitous language. It means the language in a particular context is consistent about specific things — for instance, the word “account” will always mean exactly the same thing within a bounded context. If we define two bounded contexts, one for “loan” and one for “equity,” each is then able to talk about an “account” without ambiguity, but in their own way. In the “loan” context an account is always about debt. In the “equity” context, the same word is always about a positive cash balance. Other business contexts pair the word “account” with different meanings.
Ubiquitous language is about realizing when the meaning of certain words change and building bounded contexts at those transitions. These boundaries are a foundation for our services — each one representing a singular, unified, and unambiguous model about a specific business function. It’s a natural way to decompose a complex system into smaller parts that are easier to reason about. It helps remove ambiguity.
Use your ubiquitous language as the backbone of your model, and (as Eric Evans points out), “recognize that a change in the language is a change to the model.”2
Ubiquitous language is one of the most important aspects of domain driven design. I’ve seen many teams disregard it, thinking ubiquitous language is an afterthought. It’s not. It’s a central idea, and one of the most important design tools DDD puts in your hands. Without it, you’ll miss the contextual clues that point out where bounded contexts begin and end — and consequently, end up with something that is not a good domain driven design.
What is a “domain?”
You can think of a domain as a collection of ideas that are related to the same subject matter. In other words, a domain is essentially the context that applies to a particular concept. It represents a set of abstractions that lets you model a problem space.
For example, you might have a “loan” domain that handles all things related to lending. Inside that domain, your design would likely have several different objects or services, corresponding to logical functional areas: “provisioning,” “account” and “legal agreements.” Each one would relate specifically to borrowing, so in this context “account” represents a debt, which is how the loan domain thinks of an account.
You might model an entire domain as a single thing, but you may find that subdividing it into smaller pieces makes sense. In that case, you subdivide your domain into several different contexts — but each one is related directly to the domain. Domains can grow to include ideas, relationships and workflows, typically involving several different bounded contexts.
Domain events
Think of domain events as something that happened that domain experts care about.
Domain event modeling is therefore about: Discovering what matters to the business, and how we record the fact that it happened.
If you use the referral button below, you’ll earn free premium access to Customer Obsessed Engineering. Just three referrals will earn a free month!
Keep reading with a 7-day free trial
Subscribe to Customer Obsessed Engineering to keep reading this post and get 7 days of free access to the full post archives.