Adventures in Domain-Driven Stories
Let's say your team is building a brand new software system, let's assume it's a typical business application for support of organizational processes, and a decision has been handed down from above to use a microservice-based architecture.
Straightaway, important questions jump out — and none of them are about technology:
- What services will the system comprise?
- How many services will there be?
- What will they be called?
- What business problem will each service attempt to solve?
- What precisely goes into each service — what entities, rules, and responsibilities belong where?
That is to say: just how exactly will you break down your system?
This uncertainty exists regardless of architectural style. Whether you build a system made up of microservices, a modular monolith, or something else, you still need to divide the system into smaller units.
This is the point at which teams typically start drawing boxes and arrows. They name services based on a mix of intuition, past experience, or organizational structure. Entities are placed into services based on what "feels right." Little time is spent validating these decisions because teams are expected to get coding as soon as possible — sometimes from day one. (To see why this approach is problematic, read my article DDD vs DDD)
When microservices are partitioned incorrectly, problems show up quickly. Services need to communicate constantly because the behavior and data that belong together have been split apart. Entities in one service become tightly coupled to entities in another, and before long frequent synchronous calls are needed just to perform basic business operations.

As the system grows, these calls multiply. Latency increases. Problems become harder to debug. To manage distributed consistency, teams introduce patterns such as sagas — not because they truly need them, but because the system design forces them to.
Sagas are often a symptom, not a solution
In many systems, sagas are introduced to compensate for services that were divided along the wrong boundaries in the first place.
At this point, the architecture has all the disadvantages of distribution — network calls, partial failures, operational complexity — without the benefits of independence. Any changes still require coordination. Deployments still need careful sequencing. Teams are afraid to touch the system.
In such cases, a well-structured monolith would be a better architectural choice than these poorly partitioned microservices.
This is not an argument against microservices. It is an argument against guessing boundaries. Without a structured way to decide what belongs together and what does not, microservices can become a mess. So the real challenge is learning how to discover the right boundaries.
The importance of boundaries
When boundaries are poorly defined, the effects are both immediate and long-lasting.
◉ The business rules are scattered across multiple components. ◉ Data ownership has become unclear. ◉ The teams have to constantly coordinate changes because responsibilities overlap.
Over time, the system has become harder to understand and work with — not because it is large, but because it lacks clear separation along the correct lines.
In contrast, well-defined boundaries create the opposite effect. They localize complexity. Changes stay within a fixed area. Teams can work independently because responsibilities are clear and well-defined.
Importantly, boundaries are not about minimizing communication. They are about making communication intentional. A good boundary does not eliminate collaboration between parts of the system — it makes that collaboration explicit, stable, and easier to manage.
Yet boundaries are often defined based on convenience rather than meaning. Systems are split by technical layers, CRUD operations, organizational charts, causing the above-mentioned problems with poorly divided services. As a remedy, for boundaries to be effective, they must be rooted in the domain. They should align with the actual business capabilities, language, and rules. Only then can a boundary serve as a true unit of change rather than a source of friction.
So how can we discover boundaries in a systematic way?
To answer that, first, we need to understand what makes a boundary strong enough to stand on its own. That leads us to the concept of architectural quanta.
What are architectural quanta?
An architectural quantum is an independently deployable unit with high functional cohesion. It represents a set of behaviors, rules, and data that belong so naturally together that they can evolve, change, and be deployed as a single unit.
The concept of Architectural Quanta is first introduced in the book Building Evolutionary Architectures by Neal Ford, Rebecca Parsons and Patrick Kua.
The emphasis here is not on deployment alone. Independence is only meaningful when it is supported by strong cohesion. A component that can technically be deployed on its own, but requires constant coordination with other components to function correctly, is not truly independent.
What matters is that everything inside the quantum changes for the same reasons. Business rules evolve together. Data belongs to the same conceptual model. Decisions made inside the boundary do not leak assumptions to the outside.
When a system is composed of well-defined architectural quanta, change becomes local. Teams can reason about a component in isolation. Failures are contained. The system becomes easier to evolve, not because it is simpler, but because its complexity is properly partitioned.
This also provides a useful lens for evaluating existing architectures. If a so-called microservice requires constant synchronous calls to other services, shares data models, or takes part in long-running distributed transactions just to perform basic operations, it is likely not an architectural quantum. It may be a deployment unit, but it is not an autonomous one.
So now we're ready to answer the important question: how do we identify these cohesive, independent units in the first place?
We need to stop thinking of boundaries as an artificially imposed structure. Rather, we discover boundaries by understanding the context of the business processes that the software will support. These processes and related entities are bounded by their context. These Bounded Contexts are central to Domain-Driven Design.
Bounded Contexts: The story of Domain-Driven Design
To better understand bounded contexts, we need to step back and take a closer look at some of the problems Domain-Driven Design (DDD) was created to solve.
The term Domain-Driven Design was first coined by Eric Evans in the influential "blue book", Domain-Driven Design: Tackling Complexity in the Heart of Software
As software systems grow, they inevitably absorb more and more business complexity. New rules are added, exceptions accumulate, and different parts of the organization evolve at different speeds. Over time, teams are using the same terms across the system — but the meaning of those terms differs according to who you talk to.
In Sales, an "order" represents a customer's intent to buy. To Billing, an "order" represents an obligation to be paid. Down in Shipping, an "order" means a physical package to be delivered.

Attempting to model these different meanings as a single concept leads to confusion. The model becomes bloated, full of conditional logic, and difficult to change. Every modification risks breaking behavior somewhere else.
A bounded context defines a clear boundary within which a particular domain model is valid and consistent. Inside that boundary, language is precise, assumptions are shared, and business rules are coherent. Outside the boundary, those assumptions no longer apply and must be translated explicitly.
Bounded contexts are not about splitting codebases or databases. They are about protecting meaning. They allow teams to model different parts of the business accurately without forcing false consistency across the entire system.
This has profound architectural implications. When a bounded context is clearly defined, it naturally forms a unit with high internal cohesion. The concepts inside the boundary change together because they represent a single, coherent view of the domain.
In other words, a bounded context is a design-time definition of an architectural quantum. It identifies what belongs together before any decisions are made about implementation, about microservices, modules or any other technical artefact. It gives architects an organized way to decide where boundaries should exist, based on business understanding rather than technical convenience.
How bounded contexts, architectural quanta, and microservices all tie together
Domain-Driven Design provides the process and tools to discover bounded contexts. In turn, bounded contexts define cohesive units of meaning. And those units, when implemented, become architectural quanta.

Domain-Driven Design provides a disciplined process for addressing this challenge. By staying in the problem space, collaborating closely with domain experts, and applying techniques such as EventStorming and Context Mapping, DDD helps teams uncover the natural boundaries in the domain. These boundaries become bounded contexts — clear borders within which meaning is consistent and models are cohesive.
It's outside of the scope of this article to teach you DDD, you can learn more about Domain Driven Design at DDD-Academy or DDD-machine or read my article Domain Driven Design, an elevator pitch. The diagram below summarizes the DDD process:

In a nutshell, the core problem is not whether to use microservices, a modular monolith, or another architectural style. The real challenge is deciding where to draw boundaries in a way that reflects how the business actually works.
By allowing time to be spent on the discovery phase and taking a DDD approach, the team of domain experts and developers will collaboratively develop a shared understanding of the domain and the business problem. This understanding will empower them to discover the right boundaries by grouping entities and pieces of functionality that truly belong together, forming bounded contexts. The bounded context, when correctly implemented, naturally forms an architectural quantum: a cohesive, autonomous unit that can evolve independently!