Skip to content
Leo Jung
Go back

[DDD Intro #25] Microservice and DDD: Is a Bounded Context a service?

Edit page

When talking about DDD, microservices often appear together. The picture of splitting Bounded Contexts, making each context a service, and giving each independent deployment and an independent database is attractive.

But Bounded Context and Microservice are not the same concept. They are related, but their starting points differ.

Bounded Context is a model boundary. It defines where a certain language and model remain consistent. Microservice is a deployment boundary. It is an execution unit that can be independently deployed and operated.

Sometimes they fit well together, but they do not always need a one-to-one correspondence.

Model boundaries and deployment boundaries

Suppose a subscription service has the following Bounded Contexts:

Member Context
Subscription Context
Payment Context
Entitlement Context
Notification Context
Settlement Context

These boundaries are divided based on model language. Member in the member context and Subscriber in the subscription context can differ. Payment in the payment context and SettlementItem in the settlement context are also different models.

These contexts can each become microservices.

member-service
subscription-service
payment-service
authorization-service
notification-service
settlement-service

But they do not have to. They can also be separated as modules inside the same application. Several Bounded Contexts can exist inside one deployment unit.

What matters is understanding model boundaries before splitting services.

Splitting services does not make it DDD

Some teams split services first while saying they are adopting DDD. They separate order service, payment service, delivery service, and member service. But inside, each service may still share the same data model, directly query each other’s databases, or use a giant Entity from a common library together.

In this case, deployment units are separated, but model boundaries are not.

There are worse cases. Services are split, but one use case requires several services to be called synchronously in sequence. A small change in one service affects several services. Failures also propagate in chains.

This is closer to a distributed monolith than to microservices.

Deployment is distributed,
changes must happen together,
data is tightly coupled,
and failures propagate to each other.

Splitting services alone cannot be considered doing DDD. The core of DDD is making the language and boundaries of models clear.

Bounded Context can be a good service candidate

This does not mean Bounded Context and Microservice are unrelated. On the contrary, Bounded Context can be a good starting point for finding microservice boundaries.

A microservice should be independently changed and deployed. To do that, its internal model must be independent. Bounded Context explains exactly that model independence.

Think about the subscription context and notification context. In the subscription context, subscription state and renewal policy are central. In the notification context, the concern is which message to send through which channel for which event.

The two contexts need to connect, but they do not need to share the same model. When a subscription is renewed, a SubscriptionRenewed event can be published, and the notification context can receive it and send a notification.

With this level of independence, the two contexts can become candidates for separate services.

One-to-one correspondence is not always good

Sometimes one Bounded Context becomes one Microservice. But that correspondence is not always the best choice.

For a small team, it may be better to place several contexts as modules inside one monolithic application. This reduces deployment and operational complexity while still protecting model boundaries.

Conversely, one large Bounded Context may internally be divided into several deployment units. For performance, scalability, or operational reasons, several services can exist inside the same model boundary.

Therefore the question is not “Should we create a service for each Bounded Context?”

Can this context change independently?
How strong are its data consistency requirements with other contexts?
Can a team own and operate it independently?
Can we handle network calls and deployment complexity?
Are module boundaries enough?

Service separation should be decided after answering these questions.

Module boundaries before microservices

For many teams, a more realistic starting point is a modular monolith. This means dividing Bounded Contexts into modules inside one application and controlling dependencies between modules.

subscription module
payment module
authorization module
notification module

Each module has its own model and language, and does not directly use the internal model of another module. Necessary interactions happen through explicit interfaces or events.

This structure is operationally simpler than microservices. At the same time, it allows the team to practice model boundaries. If a particular module later needs to be separated into an independent service, the boundary is already organized and separation becomes easier.

It is often safer to split models and modules first than to split services first.

Database separation should be careful

In microservices, it is often said that each service should have its own independent database. This principle is important for service autonomy. But in reality, it creates high cost.

When databases are separated, joins become difficult, transactions become distributed, and data synchronization is needed. We must create separate read models or design event-based synchronization.

Therefore DB separation should happen only after sufficiently understanding model boundaries and consistency requirements. The approach “it is a microservice, so let’s split the DB too” is dangerous.

Splitting Bounded Contexts means acknowledging different models. But deployment and storage separation are operational decisions at the next stage.

Closing

Bounded Context is a model boundary. Microservice is a deployment boundary. They are often discussed together, but they are not the same concept.

Good microservice boundaries can start from good model boundaries. But splitting services does not automatically create a good model. If services are split without understanding model boundaries, the result is a distributed monolith.

When applying DDD, first find the boundaries of language and model. Then judge whether those boundaries can become units of independent change and operation, and separate them into services only when needed.

Microservice is not the goal of DDD. The goal of DDD is to understand a complex domain and keep that understanding alive inside code and system structure. Service separation can help that goal, or it can get in the way.


Edit page
Share this post:

Previous Post
[DDD Intro #26] Explaining domain models with tests
Next Post
[DDD Intro #24] Event Sourcing is not required for DDD