Skip to main content
Create your own

Designing Bounded Contexts with DDD Strategic Patterns

Hello! Welcome to your next lesson.

In our previous modules, we've explored the foundational infrastructure of distributed systems, including DNS, load balancing, and the specific behaviors of various data stores. Now, we'll shift our focus from the physical and logical infrastructure to the architectural organization of business logic itself. This is a crucial step in designing systems that are not only scalable and resilient but also maintainable and aligned with business evolution.

This lesson introduces you to the strategic patterns of Domain-Driven Design (DDD). We will focus on the learning outcome: "Design bounded contexts for a given business domain using DDD strategic patterns."

You'll learn to decompose a complex business domain into logical, manageable parts called Bounded Contexts. This skill is fundamental for designing coherent microservices architectures and avoiding the common pitfall of creating a "distributed monolith." We will cover:

  • The core concepts of Ubiquitous Language, Subdomains, and Bounded Contexts.
  • How to identify and classify subdomains to guide strategic decisions.
  • Practical heuristics for defining the boundaries of your services.

Let's begin.

1. The Problem: The "Big Ball of Mud"

In any large-scale system, from fintech platforms to global delivery services, one of the biggest challenges is managing complexity. As a system grows, it's common for a single, unified data model to become unwieldy. Different departments or teams often have conflicting definitions for the same business concept. For example, what "Lead" means to a marketing team is very different from what it means to a sales team.

When these conflicting models are forced into a single codebase, the result is often a "God Class" or a "Big Ball of Mud"—a system that is difficult to understand, maintain, and evolve.

Domain-Driven Design provides a way to manage this complexity by explicitly defining boundaries. To see this in action, let's start with a practical demonstration of identifying and resolving this problem.

Unlocking Bounded Contexts in Domain-Driven Design – A Practical Guide

This video, from the channel Codewrinkles, provides a clear introduction to Bounded Contexts. It starts with a simple analogy and then walks through a concrete refactoring exercise that I think you'll find very illustrative.

Please watch the following segments: The 'Mouse' Analogy (03:29 - 04:56): This provides a simple, intuitive explanation of how context defines meaning. E-commerce Product 'God Class' Problem (04:56 - 09:40): Pay attention to how a single Product class accumulates properties from different business concerns, making it complex and lacking clear applicability. Refactoring into Bounded Contexts (09:40 - 18:33): This is the core of the demonstration. Observe how the single Product class is broken down into distinct models, each tailored to a specific Bounded Context (Catalog, Pricing, Inventory, Reviews).

As the video demonstrates, the core idea is to stop trying to create one model to rule them all. Instead, we acknowledge that a concept like "Product" has different attributes and behaviors depending on the context.

  • In the Catalog Context, a product is about its name, description, and images.
  • In the Inventory Context, a product is about its SKU, quantity on hand, and restock levels.
  • In the Pricing Context, a product is about its price, discounts, and tax rules.

A Bounded Context is the explicit boundary within which a specific domain model is consistent and has a well-defined meaning. Inside this boundary, we use a Ubiquitous Language—a shared, unambiguous language developed by the team (developers and domain experts) to talk about the model. The term "Product" in the Inventory context is precise and different from "Product" in the Catalog context.

2. Strategic Decomposition: Identifying Subdomains

So, how do we discover these boundaries in a real-world business domain? We start by analyzing the problem space and identifying Subdomains.

A subdomain is a distinct part of the business domain. It's about what the business does. For example, in an e-commerce company, you might have subdomains like "Shipping Logistics," "Product Catalog Management," and "User Authentication."

It's important to distinguish subdomains from bounded contexts.

Strategic DDD by Example: Bounded Contexts Mapping

This article, 'Strategic DDD by Example: Bounded Contexts Mapping,' clearly explains the difference between the problem space (subdomains) and the solution space (bounded contexts).

Please read the section 'From Subdomains to Bounded Contexts.' Focus on the distinction it makes: subdomains are about the business problem, while bounded contexts are a design decision in your software solution.

Once we identify subdomains, DDD gives us a powerful strategic tool for classifying them. This classification helps determine where to invest your development effort.

The three types of subdomains are:

  1. Core Domain: This is the heart of your business, the part that provides a competitive advantage. It's typically complex, unique to your business, and changes frequently. This is where you should focus your best talent and build custom, innovative solutions.
  2. Supporting Subdomain: These are necessary for the business to function but don't provide a competitive edge. The logic might be specific to your business, but it's not the core differentiator. For example, a custom reporting tool for the sales team. These can often be built by a separate team or even outsourced.
  3. Generic Subdomain: These are "solved problems." Every business needs them, but they are not specific to your domain. Examples include identity management, payment processing (for a non-fintech company), or sending notifications. The best strategy here is to buy an off-the-shelf solution or use an open-source product, not build it from scratch.

This classification is critical for making architectural and investment decisions. The following video explains this with excellent practical examples.

Bounded Contexts, Microservices, and Everything In Between - Vladik Khononov - KanDDDinsky 2018

In this segment from his talk at KanDDDinsky 2018, Vladik Khononov explains how to use the classification of subdomains to drive decomposition strategy.

Please watch the section 'Heuristic 3: Decomposing by Business Subdomains' (22:15 - 28:38). Pay close attention to how he advises treating Core, Supporting, and Generic subdomains differently in terms of service boundaries and implementation choices (build vs. buy, abstracting third-party systems).

Your experience with payment platforms is a perfect illustration of this concept. For Yandex's core services, the payment infrastructure you built was likely a core or at least a critical supporting subdomain. For a small e-commerce startup, payment processing would be a generic subdomain, best handled by integrating a service like Stripe or Adyen.

3. A Pragmatic Approach to Defining Boundaries

With the concepts of Bounded Contexts and Subdomains in mind, we can establish a practical, heuristic-driven approach to decomposition.

The primary driver for defining a bounded context is to resolve ambiguity in the ubiquitous language. If two groups of stakeholders use the same word to mean different things, you have found a boundary.

Bounded Contexts, Microservices, and Everything In Between - Vladik Khononov - KanDDDinsky 2018

Let's return to Vladik Khononov's talk for two more powerful heuristics that provide a pragmatic guide to decomposition.

Please watch the following clips: Bounded Contexts as a Decomposition Strategy (04:02 - 06:01): This section introduces the 'lead' example, which is a classic case of conflicting models that necessitates a bounded context. Heuristic 1: Always Decompose to Bounded Context (19:34 - 20:29): This reinforces the idea that the first, non-negotiable decomposition is along the lines of linguistic boundaries. Heuristic 2: Do Not Decompose Bounded Context Further Without Good Reason (20:18 - 22:15): This is a crucial counterpoint to the microservice hype. It argues that a monolith within a bounded context is perfectly valid and often preferable, as it avoids the complexities of distributed systems until necessary.

This leads to a key insight: a bounded context is the boundary of your largest valid monolith. Decomposing within a bounded context into smaller microservices is a tactical decision driven by non-functional requirements like scalability, team autonomy, or technology stack diversity. But the first and most important decomposition is strategic: separating the bounded contexts themselves.

Once you have multiple bounded contexts, they will inevitably need to communicate. This introduces the "integration challenge." If not managed carefully, you can end up with a "distributed monolith," where services are physically separate but logically so tightly coupled that you lose all the benefits of a distributed architecture.

Managing these relationships is the domain of Context Mapping.

Strategic DDD by Example: Bounded Contexts Mapping

Let's revisit the 'Strategic DDD by Example' article to briefly introduce the concept of Context Mapping.

Please read the sections 'The Integration Challenge,' 'Strategy First, Technology Second,' and the introduction to 'Context Mapping Patterns.' You don't need to memorize all the patterns, but focus on understanding the concepts of Upstream and Downstream contexts and the purpose of patterns like the Anti-Corruption Layer (ACL).

An Anti-Corruption Layer (ACL) is a particularly important pattern. It's a defensive layer in a downstream context that translates data from an upstream context's model into its own. This isolates the downstream model, protecting it from changes in the upstream system and preventing its ubiquitous language from being "corrupted" by foreign concepts.

4. Design Exercise

Let's apply these concepts to a domain you are familiar with. Consider a simplified version of a ride-hailing and food delivery service.

The business involves several key areas:

  • Rider Management: User profiles, payment methods, trip history.
  • Driver Management: Driver profiles, vehicle information, earnings, performance ratings.
  • Dispatching: Matching riders with drivers in real-time, calculating ETAs, route optimization.
  • Billing & Payments: Calculating fares, processing payments, handling refunds and disputes.
  • Support: Handling customer and driver issues.
  • Marketing: Promotions, loyalty programs, user acquisition campaigns.

Your task:

  1. Identify at least four potential subdomains from the description above.
  2. For each subdomain, classify it as Core, Supporting, or Generic. Justify your classification.
  3. Pick one concept, such as "Trip" or "User," and describe how its meaning and model might differ across at least two different bounded contexts that you would design.

Take about 5-10 minutes to think through this and outline your answer. There's no single correct answer; the goal is to practice the strategic thinking process.


Conclusion

In this lesson, we've taken a significant step up the architectural stack, moving from implementing components to strategically organizing the business domain itself.

Key Takeaways:

  • Bounded Contexts are the cornerstone of strategic DDD. They provide explicit boundaries within which a domain model and its Ubiquitous Language are consistent.
  • The primary driver for identifying a bounded context is resolving linguistic ambiguities—when different parts of the business use the same term for different concepts.
  • Analyzing the business domain in terms of Subdomains (Core, Supporting, and Generic) is a powerful tool for guiding architectural strategy, investment, and build-vs-buy decisions.
  • Decomposition should start at the bounded context level. Further decomposition into smaller services is a tactical choice driven by non-functional requirements, and a "monolith" within a well-defined context is a valid and often desirable architecture.
  • Once contexts are defined, their interactions must be managed strategically using Context Mapping patterns to avoid creating a distributed monolith.

Preview of the Next Lesson

Identifying bounded contexts is the first strategic step. The next question is: how do we model the concepts inside a bounded context? In our next lesson, we will explore Aggregates, the tactical DDD pattern used to define consistency boundaries around our domain objects. This is fundamental to ensuring data integrity and managing transactions within a service.

Can't find a good explanation? Sign up and we'll make it for you

Sign up