Service-oriented architecture (SOA) and domain-driven design (DDD) are both essential tools for software design. And, as with any device, you must understand the intent to make the most of it without risking blowing up your project.
DDD and SOA do overlap, but they’re not the same thing. In other words, DDD is not a recipe for SOA or vice versa.
Granted, you can use DDD and SOA simultaneously, so in that sense, they relate. But you cannot use an SOA to implement DDD. And most DDD design patterns do not give you SOA (with one primary exception I’ll cover later in this article).
SOA is a collection of principles, practices, and processes that help you decompose your codebase into reusable services. Commonly, services communicate via network protocols like HTTP. But an SOA is not about a network protocol. The critical aspect here is that SOA is about architecture (design), not HTTP.
Many people have shot themselves in the foot without distinguishing between SOA and DDD.
Before following blindly, isn’t it worth taking a step back and thinking things through to avoid common misinterpretations across the software industry today?
It’s pretty simple. Here’s a quick thought exercise for clarity.
So when we get down to it, isn’t the point to achieve system decomposition, service contract design, and assurance that you get the benefits of SOA rather than just spinning up arbitrary HTTP services?
Not convinced? Here’s another way to think about it.
Imagine this. You have HTTP services sprinkled throughout your solution. Are you using SOA? Not necessarily.
Without design decisions with an explicit intent, you don’t have architecture. And sprinkling services in a system for the sake of services is not a design decision.
Ticking the ‘yeah, I have some services’ box has NO value due to the lack of intent or structural design. And, it’s not SOA.
You need an intentional design to reap the benefits of SOA.
SOA services are supposed to be self-contained units of reusable functionality that you can call from anywhere within the program or service layer without needing to resolve dependencies or understand their operational scope.
Without that, you don’t have SOA.
Still, struggling to understand the difference between these two approaches?
Read on: I’ll dive a bit deeper.
Think of SOA design as planning a city. You account for different buildings, houses, and structures.
Your SOA has to support many citizens (customers/applications) doing different things at different times and sometimes in different ways.
On the other hand, Domain-driven design (DDD) is more like a hotel.
A hotel is a self-contained structure with a specific purpose. It has walls, doors, windows, and beds—all with the express purpose of providing a place where people can sleep.
A large part of DDD consists of modeling patterns to help you express your business domain in code. This entity modeling is the primary interpretation of DDD, but that’s just scratching the surface. It goes deeper than that.
You can think of a domain model as a collection of interfaces representing the real-world (or business) objects you want to model in your software.
SOA is more focused on designing how your buildings are connected.
How do your citizens get back and forth to work? How are you hooked up to the power grid? How do you organize the various activities so every building is optimal for its intended use?
In DDD, an entity is the core unit of a domain model; it is a conceptual building block that you can’t decompose into smaller parts. Examples of entities are customers, orders, and products.
On the other hand, SOA is a design pattern that focuses on how to package features, entities, and data into reusable components (aka services). SOA is used to design how your services interact.
You can also think of an SOA service as a public API, SDK, or endpoint that provides business functionality using all the entities inside. It’s a self-contained, cohesive unit that you can access remotely. But you can also call an SOA service locally (yup, even without going over HTTP).
You may find it helpful to keep in mind that the point of SOA is not remote access but structural integrity, maintainability, and sustainability.
So, hopefully, you now see that SOA is often used to house a domain model, but it is not the same as a domain model.
And it’s too easy to create an SOA with domain models that don’t adhere to the DDD principles. You can also quickly drive off a cliff and create DDD code that doesn’t stick to SOA principles. I see this all the time, especially with teams who don’t understand the nuanced distinction between SOA and DDD.
The trick to building sustainable software systems is striking an effective balance between DDD and SOA to leverage both and design scalable, maintainable, and modern software systems.
Domain Driven Design (DDD) is a design approach developed by Eric Evans.
You use DDD to create software systems that model business processes and workflows through a conceptual model. This model helps us to identify the core business entities (i.e., users, products, orders, payment methods, etc.) and their relationships with one another.
In DDD, your model is a conceptual design that helps you to understand and communicate about a problem domain. It consists of core business entities, their relationships, and operations (or business logic).
For example, an online book store model could consist of core entities such as customers, books, and orders. The relationship between the entities could be that a customer could place an order for a book.
You can implement your software models in infinitely different ways. The most appropriate implementation depends on the type of software you’re building.
The core focus of service-oriented architecture (SOA) is encapsulation.
You organize your code into modules that operate in a self-contained fashion. In other words, you design SOA services so that a change to the service should protect implementation changes from bubbling up to other components or services, also known as the SRP (Single Responsibility Principle).
You can use many architectural styles to make this happen. For example, you can use the classic three-tier architecture that underpins most other architectural patterns. This architecture consists of the presentation, business, and data layers. The presentation layer is responsible for the user interface. The business layer handles the business logic, and the data layer deals with state management.
But three-tier architecture does not give you SOA out of the box. You’ll need to break it down further to benefit from SOA design principles.
The main idea behind DDD and SOA working together is to break down an extensive software system into smaller, more manageable parts. You are designing a system of systems.
The benefit of smaller systems is that they are easier to understand, more robust, and more sustainable. This massive benefit is due to the nonlinear nature of complexity in software. Dividing your monolithic code base into just two services reduces complexity by much more than half.
With any new system, designing big and then building small is the most rational approach.
By doing this, you can create a more robust and scalable system because you reduce dependencies. You can temporally decouple services across time. And you can independently scale each of your services.
When you break down your business domain model into multiple discrete SOA services, you make it easier to create a distributed system spread across multiple servers and services.
A DDD bounded context is a domain model with a specific purpose isolated from other domain models with different goals. A DDD Bounded Context is a self-contained unit where concepts, behaviors, and terms are related to each other logically.
Sounds just like SOA, right?
Here’s the thing: each of your bounded contexts contains its own discrete domain model. This way, you can focus on protecting your code from changes in other system parts. You’ll have fewer, highly focused core entities, their relationships, and how your entities operate within a specific context.
In DDD, your entities are often nouns, and the operations are typically verbs.
For a simple example, you could encapsulate a service that provides search functionality for an eCommerce website within a search context. The core entities in this example could be items, customers, orders, and categories. This service is where you can categorize items to facilitate searching.
However, the models for customers, orders, and categories in your search service should have nothing to do with making payments. It would have its service (and bounded context) where you help customers place orders for an item.
The point is to package everything together that changes together. This follows Robert Martin’s Single Responsibility Principle (plus a few others). Each of your services has a single reason to change.
The two biggest mistakes we see junior architects make with DDD is trying to create a single domain model to cover all aspects of the business.
I remember talking with Eric Evans, who also saw this as the most significant misinterpretation of DDD.
On the other extreme, we’ll also see inexperienced engineers trying to use DDD concepts for modeling code inside a service AS a service (e.g., no bounded contexts).
But the most glaring red flag is when you see domain entities acting as discrete services. You’ll see code bases with a person service, a bed service, a hallway service, etc., all connecting over HTTP. (ouch)
I’ll talk about why this is a problem in more detail in a future post.
And, if you think about it, this situation is neither SOA nor DDD and almost guarantees design failure due to misinterpretation and not adhering to fundamental design principles (like SOLID).
Both these extreme mistakes are recipes for disaster.
And unfortunately, today, DDD has been oversimplified and misinterpreted.
As intended (with multiple bound contexts), DDD fully aligns with SOA, where each service boundary is the context. But very few teams achieve this in practice today. Most miss the deeper aspects of DDD bounded contexts altogether.
I hope you can avoid the same mistakes now that you know better.
We’ve learned that DDD and SOA are both design approaches at different scales.
They both emphasize modularity and decoupling. You achieve this by breaking down an extensive software system into smaller, more manageable parts.
The central concept behind your SOA design is the isolation of your sub-systems or services from the impact of change in other systems or services.
You can get there by declaring service boundaries (SOA or DDD Bounded Context). Inside these boundaries, you can design your service surface with a combination of SOA and DDD principles and then implement your system behavior using DDD.
If done right, your services will be reusable and able to communicate with other subsystems.
By implementing SOA, you can create a distributed system that is less coupled than a traditional monolithic system. You can also create numerous smaller subsystems that are easier to maintain, extend, and scale.
Implementing DDD makes your systems easier to understand, change, and grow. Your entities now focus on solving problems within a specific context. And, you avoid change propagating through your whole system and drastically reduce complexity.
The main point here is that domain-driven design and service orientation go hand-in-hand. You just have to use the right tool for the job at hand.
For example, you implement SOA services using the building blocks of a domain model. A domain model is a collection of information entities and the operations that relate to that information in a specific context.
Now you see how SOA is not just about using HTTP, picking some 3rd party services to use, or maintaining a catalog of services. SOA is about designing architectures that will help you organize and maintain your software system over the long term and support scaling as your business grows.
The key is to use DDD and SOA together to get the most out of each approach and produce agile systems.