Implementing Domain Driven Design with Microservices

This post is about Microservices and Domain Driven Design (DDD), how to apply DDD to Microservices architectural style, what are the pitfalls to be aware of, and many other aspects. If you need a quick refresher or intro to DDD, then you may refer to Simple Domain-Driven Design – Building Blocks. Here is a series of posts about Microservices that elaborate more on the topic.

What’s the challenge?

When we talk about applying DDD to microservices, what do we exactly mean? What is challenging in applying DDD to microservices? The answer lies in the microservices properties, where each microservice is:

  • Independent and complete unit of functionality
  • Independent unit of development
  • Independent unit of deployment
  • Independent unit of scale
  • Does not directly expose data storage
  • Provides APIs to access its functionality
Microservices Architecture diagram
Microservices Architecture diagram

While in DDD, we have to deal with different levels of granularity:

  • Entity and Value Object
  • Aggregate Root
  • Bounded Context
  • Application
Domain Driven Design levels of granularity
Domain Driven Design levels of granularity

Having Microservice as independent and self-contained matter on one side and different levels of granularity in DDD on the other side raises a question. On what DDD granularity level do we build Microservices? Should we build a microservice per bounded context? Or may be per Entity, or somewhere in the middle? Obviously not a microservice per application or else we end up with SOA or Monolith architecture style.

The independence and self-contained nature of Microservices, on the one hand, contrasts with the different levels of granularity in Domain-Driven Design (DDD), on the other. This raises a question: at what granularity level of DDD should we build Microservices? Should we build a microservice per bounded context? Or maybe per Entity, or somewhere in the middle? Obviously not a microservice per application or else we end up with SOA or Monolith architecture style.

The main problem we are going to solve in this post is to decide what the right granularity for microservices is.

What’s the right granularity?

The short answer is “It depends…”. Yes, there is no definite answer; however, we can still figure things out. Let’s look closely at each level of granularity and find the advantages and disadvantages of creating microservices at that level.

Application

This level signifies the entire application. In case the entire application domain model fits nicely into a single service or into a monolith, then maybe we don’t need to design a system with a microservices architectural style. With the application growing, we may decide to migrate to microservices; however, doing so prematurely may turn into a huge problem. It is hard to predict how our domain model is going to evolve in the future; therefore, prematurely splitting into microservices may create a lot of problems with further refactoring. Moving domain objects between microservices is not as easy as within a single service or a monolith.

Bounded Context

Bounded Context as Microservice
Bounded Context as Microservice

Bounded context may be a good candidate for a microservice. It is naturally isolated from other bounded contexts, each is based on its own model and ubiquitous language dialect. Bounded contexts communicate through interfaces, APIs, isolation layers, etc., and have clear boundaries. However, when a bounded context is large, it is unreasonable or even impossible to use it as a basis for a single microservice.

There are teams that own a single domain model, hence a single bounded context. Under any circumstances, these teams would be able to pack the entire model in a microservice. So, a bounded context can be used as a boundary for a microservice, but only when the model is small so that the microservice is indeed micro.

Aggregate Root

Aggregate Root as Microservice
Aggregate Root as Microservice

The short answer is an aggregate root may be the best option to build a microservice around. By definition, an aggregate root encapsulates business logic and rules, all complexities associated with storage and retrievals of entities and value objects. It is responsible for maintaining the model’s invariant and exposes its functionality to the outside world through an interface. All of this resembles pretty well what microservices are about.

The technique of creating a microservice from an aggregate root is usually simple and straightforward. An aggregate root already exposes an interface, so we can take the interface and expose it through microservice APIs.

Create a Microservice based on Aggregate Root
Create a Microservice based on Aggregate Root

Entity and Value Object

Entity as Microservice
Entity as Microservice

Value Objects are domain objects with no identity. It’s hard to imagine a case when it’s reasonable to have a microservice around a value object, so there is no need to discuss it further.

Entity is a domain object that has an identity. Even though the identity is valid within an aggregate root, it’s still possible to build a microservice around the entity exposing CRUD operations. However, it doesn’t mean that we should. In most cases, a microservice per entity becomes an overkill and negatively impacts the reliability and performance of the entire system. How?

Well, microservices communicate over the network, and network calls are neither as reliable nor as fast as in-process calls. Excessively fine-grained microservices tend to increase the amount of network communication, making the entire system slower and less reliable.

Another disadvantage is increased complexity and maintenance cost. Having a lot of tiny microservices makes it extremely difficult to comprehend the system as a whole and navigate through dependencies. The entire system becomes more like a monolith, or even worth, distributed monolith.

Increased coupling is another downside. With microservices per entity, it’s quite probable to end up with cohesive entities being split apart into different microservices. Increased coupling results in a need for orchestrated deployments of coupled microservices, which is quite opposite to one of the main advantages of the microservices architectural style – independent deployments of each microservice.

Coupling of Microservices at the level of Entities
Coupling of Microservices at the level of Entities

Summary

So… at what DDD granularity level can we create microservices? Practically speaking, the best option to try is at the Aggregate Root level. In a few cases, a Bounded Context is a reasonable option too; however, an Entity is rarely a good choice. When making a decision, it is not always possible to go strictly by Aggregate Root. Sometimes, more than one Aggregate Root may become a microservice, and that is OK, as long as we maintain the properties of microservices.

Think of drawing microservice boundaries somewhere between Bounded Context and Aggregate Root.

Somewhere between Bounded Context and Aggregate Root
Somewhere between Bounded Context and Aggregate Root

When we make design choices, we need to be consciously aware of our goal. Any design decision is a tradeoff to minimize complexity. Why? Complex systems are expensive to maintain, take significant time to introduce new features, and are risky to make changes. That is the basic idea behind any architecture and design decisions, including where to draw microservice boundaries.

Reading List

Domain-Driven Design: Tackling Complexity in the Heart of Software, by Eric Evans. Great book to start with DDD. Explains complicated concepts in easy to understand fashion with real-life examples.
Implementing Domain-Driven Design, by Vaughn Vernon. Goes deeper into DDD and focuses on applying DDD while designing and implementing software.
Monolith to Microservices: Evolutionary Patterns to Transform Your Monolith, by Sam Newman.
Microservices Patterns: With examples in Java, by Chris Richardson.
Posts created 30

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Related Posts

Begin typing your search term above and press enter to search. Press ESC to cancel.

Back To Top