What Is Domain-Driven Design?
Aligning Software With the Business It Models
Software has a tendency to drift from the business it is supposed to model. It starts clean, but over time the code stops reflecting how the business actually works. Features get added in the wrong place. The same concept is called different things by different people. Business rules end up scattered across service methods, utility classes, and database queries.
Domain-driven design is a response to that drift. It is a set of principles and patterns for building software that stays aligned with the business as both grow and change. Eric Evans introduced it in his 2003 book, which is still the primary reference for the subject.
This series builds all its examples around an online learning platform. Students enroll in courses, work through lessons, submit assignments, and earn certificates. Instructors create and publish content. It is a domain complex enough to make the patterns meaningful without requiring specialist knowledge to follow along.
This article covers the foundational ideas before any patterns are introduced. Understanding why DDD exists is more useful than memorizing what the patterns are.
The Problem With Software That Ignores the Domain
Imagine an online learning platform. Students browse a course catalog, enroll, watch video lessons, submit assignments, and eventually earn a certificate. Instructors create courses, upload content, and review submissions.
In a typical codebase, this might all live in a CourseService with methods like getCourse, enroll, submitAssignment, and issueCertificate. The class grows. It talks to half a dozen repositories. Business rules are implemented as a mix of database queries and conditional logic. When a new requirement arrives, such as changing how certificates are issued, nobody is quite sure what will break.
The problem is not the size of the class. The problem is that the code does not reflect how the business thinks about itself. The business has a clear model: a student progresses through a course, completes requirements, and earns recognition. The code has a service that does things to records.
Ubiquitous Language
One of the most practical ideas in DDD is ubiquitous language: a shared vocabulary between developers and domain experts that is used consistently in conversation, documentation, and code.
On the learning platform, a domain expert might talk about a student “completing” a course. If the developer models this as status = DONE in the database, there is already a mismatch. When the domain expert asks why a student who finished all lessons but did not pass the final assessment is showing as “complete”, the developer has to translate between two different mental models to answer.
Ubiquitous language means the code uses the words the domain expert uses. Not status = DONE but enrollment.complete(). Not UserCourseProgressRecord but Enrollment. When the code and the conversation use the same words, misunderstandings surface faster and the model is easier to evolve.
A mismatch between the language and the code is a signal that the model is wrong. The fix is not to rename the variable; it is to understand why the names diverged and correct the model.
The Domain Model
A domain model is a structured way of thinking about the problem, expressed in code. It captures the rules and concepts of the business, not the mechanics of storing data or serving HTTP requests.
This is where DDD is frequently misunderstood. A domain model is not a database schema with some methods added. It is not a set of Java beans with getters and setters. It is an attempt to capture how the business actually works, in terms that both developers and domain experts can reason about.
On the learning platform, the domain model might express that a student cannot receive a certificate for a course they have not completed, that a course cannot be published without at least one lesson, and that an assignment can only be submitted during the enrollment period. These are business rules, and they belong in the domain model.
Instead of a service method checking whether a student has met the requirements before issuing a certificate, the enrollment itself knows whether it is complete. The service does not make that judgment; it asks the model. That shift is what a domain model actually means in practice.
A domain model that only holds data and delegates all logic to service classes is called an anemic domain model. It looks like object-oriented design but behaves like procedural code. The rules exist, but they are scattered and implicit.
Focus on the Core Domain
Not all parts of a business are equally important. An online learning platform lives or dies by the quality of its courses and the learning experience it provides. That is the core domain, the part that differentiates the business from its competitors.
But the platform also needs to handle payments, send email notifications, and manage user accounts. These are necessary but not what makes the business special. A competitor could use the same payment processor and the same email service. These are supporting or generic concerns.
DDD calls these distinctions out deliberately. The core domain deserves the most careful design, the most collaboration with domain experts, and the most investment in keeping the model accurate. Supporting domains get a simpler approach. Generic domains can often be handled by off-the-shelf solutions.
This distinction matters because it shapes where you invest your design effort. Spending it on notification delivery rather than course progression means building complexity where it adds the least value.
Strategic and Tactical DDD
DDD operates at two levels.
Strategic DDD deals with the big picture: how to divide a large domain into manageable parts, where the boundaries between those parts should be, and how the parts relate to each other. Tactical DDD deals with the internals of one part: how to model the concepts inside a single boundary, how to enforce business rules, and how to represent state changes.
Most introductions to DDD jump straight to the tactical patterns because they are more concrete. Aggregates, value objects, and repositories are tangible things you can implement. But the strategic patterns are what make the model manageable as the system grows. Getting the boundaries wrong at the strategic level will cause problems that no amount of tactical refinement can fix.
When DDD Is Worth It
DDD adds cost. It requires close collaboration with domain experts. It produces more code than a simple CRUD application. The domain model needs to be maintained as the business evolves.
The investment pays off when the domain itself is complex, when the business rules are what the software is really about, and when the model is expected to change as the business grows. A course progression system with prerequisites, cohort-based scheduling, and adaptive assessments is a reasonable candidate. A settings page with a handful of toggles is not.
For simple applications, a straightforward layered architecture and a database-mapped model will serve just as well and require much less overhead. DDD is not a default starting point; it is a deliberate choice for domains where the complexity justifies it.
What Comes Next
The next article introduces subdomains and bounded contexts. These are the strategic tools that let you divide a large domain into parts with clear responsibilities and independent models, and they are where most of the real design decisions in DDD are made.
This article is part of the Domain-Driven Design series
- 1. What Is Domain-Driven Design?