Sponsor: Do you build complex software systems? See how NServiceBus makes it easier to design, build, and manage software systems that use message queues to achieve loose coupling. Get started for free.
I often read comments about how Domain Driven Design is too complicated or overkill. Then there are others new to DDD that want to apply it, especially the technical patterns, everywhere. So the question is, should you use Domain Driven Design? The answer is somewhere in the middle. Let me explain.
YouTube
Check out my YouTube channel where I post all kinds of content that accompanies my posts including this video showing everything that is in this post.
Large System
First, let me define some context on what I’m going to refer to in the rest of this post. When talking about the design of a system, I’m talking about a large enough that affects many different roles/people/departments within an organization. Even if that organization is small, there are people that were different hats and have different roles within it.
So what I’m referring to in this post isn’t about a small application with a minimal feature set. Rather it’s a larger system that has various business capabilities for many different roles within an organization.
As a concrete example, that I’ll use for the rest of this post, let’s say we are building a system for a food delivery service. I’m naive to food delivery, however, I do have a background in transportation so the intent of using this example is everyone has likely used a food delivery service so you can probably get the high level.
Within this system, there are going to be various capabilities we need to provide. We have some CRM for managing all our customers, some type of ordering for customers to place orders, HR for managing the drivers who deliver the food, and the actual delivery of food from restaurants to customers.
Boundaries
One of the good things that came out of Microservices was the acknowledgment of boundaries. Each boundary defines its capabilities and the data that it owns.
The key thing here however is that not all boundaries are created equally. Meaning that different boundaries serve different purposes and have different levels of value within the overall system.
Some boundaries are more supporting role to the core of the business domain. In the example above, CRM and HR may be more in a supporting role for Ordering and Delivery. Supporting boundaries don’t have as much complexity based on our needs. Because of this, they may be generic enough that you can use a SaaS or 3rd party product, and possibly integrate with it.
Some other supporting boundaries might not be generic enough so you must develop them, but it can be more CRUD-driven without much complexity. In the example above, maybe we develop our own HR application but it’s just for keeping basic demographic data of the delivery drivers.
The Ordering and Delivery boundaries are where the complexity lies and is the heart of the system we are building. Based on requirements, maybe the Ordering boundary is using a relational database, and the Delivery boundary is using an Event Store.
Logical Boundaries
I mentioned that one good thing that came out of Microservices was boundaries. Unfortunately, there is the assumption that boundaries must be physical boundaries and must be deployed independently. However, the focus should be first on simply defining logical boundaries as I have above. You don’t have to develop microservices or independently deployable services. You can develop a monolith that is composed of logical boundaries.
Each boundary still owns its own data and schema. CRM and Accounting are generic and we’re leveraging external SaaS that we’re integrating with. We don’t need to build our own Accounting system or CRM, that’s not the problem or solution space.
The core of our system is likely composed of long-running business processes. When a customer orders food and we have to notify the restaurant, then have the driver pick up and deliver the food to the customer. This is a series of business processes that make up that workflow. This is where you care about Domain Driven Design. Trying to model those business processes and capture the language of our domain within our code.
In our supporting boundaries, we just don’t need to take as much analysis to model that portion of the domain. There just isn’t enough value in doing so because that’s not the solution space that we want to focus on. Those boundaries can be external or simply CRUD.
Capabilities
Since boundaries are important, how do you define what boundaries are and what capabilities do they provide?
Business processes can be specific to an individual boundary as well as span multiple boundaries. Usually, a handoff from one boundary as it completes its part starts in the next boundary.
Departments & Roles are another way of thinking about boundaries. An end-user of your system at any given time may be fulfilling a certain role for a given task. What are they trying to accomplish?
Boundaries are an authority and have the responsibility to manage or handle a certain part of the process.
Boundaries contain the knowledge of how to execute a given process. But most importantly what is its objective? What is it set out to do?
Context is King
I received this comment on a YouTube video that I thought was fitting for this post. CRUD isn’t certain types of data, like an address, name, etc. It’s about that data in a given context. If you were developing the HR module for our system, yes maybe the address for our delivery drivers is just simple CRUD. However, if we’re developing a postal/mail service, changing an address would have a lot more complexity and process with it. If you were changing your address, is it because of moving to a new location? Would something like mail forwarding be required? This would not likely be CRUD at all. In that case, there is not just “updating an address”. It’s likely more of a business concept that needs to be captured. Context is important.
Should you use Domain Driven Design?
If you’re developing a large system that has complexity at the heart, then yes, I recommend looking at some of the strategic (and tactical) patterns from Domain Driven Design. If you’re defining boundaries around capabilities and language (bounded context), guess what? You’re already doing Domain Driven Design!
If you’re writing a relatively small application without much complexity, don’t get caught up with trying to apply the tactical patterns. Notice this entire post didn’t talk about any code or patterns? That’s on purpose. Check out my post on STOP doing dogmatic Domain Driven Design
Source Code
Developer-level members of my YouTube channel or Patreon get access to the full source for any working demo application that I post on my blog or YouTube. Check out the YouTube Membership or Patreon for more info.