Strategic design is the part of DDD that decides how to divide a large domain into manageable and coherent pieces. In the previous lesson we learned how to classify subdomains; now we are going to draw the concrete boundaries of the model within the software through the most important concept in all of DDD: the Bounded Context. Alongside it we will study the Ubiquitous Language, the shared vocabulary that keeps business and development aligned. This lesson matters because it is where DDD connects directly with architecture: the boundaries we draw here will determine, for example, the frontiers of our microservices. Getting these boundaries wrong is one of the most expensive causes of failure in distributed systems.

Contents

  1. The problem: the same term, different meanings
  2. Ubiquitous Language
  3. Bounded Context
  4. Relationship between Bounded Contexts and microservices
  5. Integrated example in an insurance company

  1. The problem: the same term, different meanings

In any medium-sized organization, the same words mean different things depending on the department. Consider the word "Customer" in an insurance company:

  • For the Sales area, a Customer is a lead with contact details and a history of sales interactions.
  • For the Underwriting area, a Customer is a risk profile with age, occupation, and prior claims history.
  • For the Billing area, a Customer is an account with a direct debit setup, receipts, and debts.

If we try to create a single giant Customer class that serves everyone, we get a huge object, full of fields that only some use, with contradictory rules, and that no one can modify without fear of breaking another area. This is the classic "single model for the entire company," and it always fails in complex domains.

DDD proposes the opposite: accept that meaning depends on the context and draw explicit boundaries.

  1. Ubiquitous Language

The Ubiquitous Language is a common, rigorous vocabulary shared between developers and domain experts, used everywhere: in conversations, in documentation, and—crucially—in the code.

Principles:

  • Each term has a single, precise meaning within its context.
  • If the business says "underwrite a policy," the code has an underwrite() method, not create() or save().
  • The language evolves: when a nuance is discovered, the spoken language and the code are updated at the same time.

Let's see the difference it makes in the code:

// WITHOUT Ubiquitous Language: generic technical names
public class PolicyManager {
    public void process(PolicyData data) { /* ... */ }
    public void update(Long id, int status) { /* ... */ }
}

Problems with the previous fragment:

  • PolicyManager, process, and update say nothing about the business. What does it process? What does it update?
  • The state is represented with an int: no one knows what status = 2 means.
  • A domain expert could not read this code or validate that it does the right thing.
// WITH Ubiquitous Language: the code speaks the language of the business
public class Policy {
    public void underwrite(Subscriber subscriber) { /* ... */ }
    public void rejectForExcessiveRisk(RejectionReason reason) { /* ... */ }
    public void renew() { /* ... */ }
}

Here:

  • The names underwrite, rejectForExcessiveRisk, and renew are exactly the verbs the business uses.
  • The Subscriber and RejectionReason types are domain concepts, not loose primitive data.
  • A domain expert can read and understand what the class does, which allows modeling errors to be detected in conversation, without running anything.

The Ubiquitous Language is the bridge that eliminates the constant translation between "what the business says" and "what the programmer writes."

  1. Bounded Context

A Bounded Context is an explicit boundary within which a domain model and its Ubiquitous Language have a single, consistent meaning. Outside that boundary, the same terms may mean something different, and that is fine.

Each Bounded Context has:

  • Its own domain model.
  • Its own Ubiquitous Language (the word "Customer" can be modeled differently in each one).
  • Its own business rules and, usually, its own database.

Returning to the "Customer" example:

Bounded Context How it models the "Customer" Relevant attributes
Sales Lead / Prospect Contact details, funnel stage, assigned salesperson
Underwriting Insured / Risk Profile Age, occupation, claims history
Billing CustomerAccount Payment method, receipts, outstanding balance

The radical idea is: there is no single "Customer". There are three distinct models, each optimal for its context, that share a referenced identity (a common identifier) but not the same structure. How those contexts communicate is something we will see in lesson 06-04 (Context Mapping).

graph LR
    subgraph BC_Ventas[Bounded Context: Sales]
        L[Lead]
    end
    subgraph BC_Suscripcion[Bounded Context: Underwriting]
        A[Insured]
    end
    subgraph BC_Facturacion[Bounded Context: Billing]
        C[CustomerAccount]
    end
    L -. same real customer .-> A
    A -. same real customer .-> C

About this Mermaid diagram (graph LR, left to right):

  • Each subgraph represents a Bounded Context with its explicit boundary.
  • Within each context lives a different model of the "customer": Lead, Insured, CustomerAccount.
  • The dotted arrows (-.->) indicate that they refer to the same real person, but do not share the same code model: they are connected by identity, not by structure.

  1. Relationship between Bounded Contexts and microservices

There is a natural—but not mandatory—correspondence between Bounded Contexts and microservices:

Concept Bounded Context (DDD) Microservice (architecture)
Nature Logical boundary of a model Physical unit of deployment
Defines Consistent meaning of terms Independent process, API, own DB
Relationship Is a good candidate for a microservice Ideally, aligns its boundary with a BC

The good practice is: a microservice should contain one or more complete Bounded Contexts, never split a Bounded Context across several microservices. If you split a context, you distribute its model and its rules across different services, which generates extremely strong coupling and constant communication.

Bounded Contexts offer the decomposition criterion that microservice teams often miss. Without DDD, many split services by technical entities ("user service," "order service") and end up with a distributed monolith.

Example of how a Bounded Context translates into the configuration of an independent microservice:

# deployment of the microservice that implements the Underwriting Bounded Context
apiVersion: apps/v1
kind: Deployment
metadata:
  name: underwriting-service        # one BC = one deployable service
spec:
  replicas: 2
  template:
    spec:
      containers:
        - name: underwriting
          image: registry.fiatc/underwriting:1.4.0
          env:
            - name: DB_URL
              value: jdbc:postgresql://db-underwriting:5432/underwriting  # own DB

Comments on this Kubernetes YAML:

  • name: underwriting-service makes it clear that the service corresponds to a single Bounded Context (Underwriting).
  • image references the container image of that context, versioned independently.
  • The DB_URL variable points to db-underwriting: a dedicated, exclusive database for the context. Other contexts do not access it directly; that preserves the boundary.

  1. Integrated example in an insurance company

Let's put it all together. An insurance company could organize its system into these Bounded Contexts:

graph TD
    V[Sales] --> S[Underwriting]
    S --> P[Policy Management]
    P --> SI[Claims Management]
    P --> F[Billing]
    SI --> F

Reading the diagram:

  • Sales captures interested parties; when one accepts, they move to Underwriting.
  • Underwriting assesses the risk and, if it approves, Policy Management creates the policy.
  • Claims Management and Billing depend on the active policy.

Each of these contexts has its own Ubiquitous Language: in Sales they speak of "Lead" and "opportunity"; in Claims, of "claim report," "loss adjuster," and "indemnity." Forcing a single vocabulary across all of them would be a mistake.

Common Mistakes and Tips

  • The single corporate model. Trying to make a single Customer or Product class serve the entire company. Result: an unmanageable object. Accept the multiplicity of models.
  • Bounded Contexts that are too small. If every entity is its own context, you will have hundreds of tiny services talking to each other nonstop. The context must be cohesive, not atomic.
  • Confusing logical boundary with physical boundary. A Bounded Context is a logical concept of DDD; a microservice is a deployment decision. You can start with several contexts within the same monolith (a modular monolith) and separate them into services only when needed.
  • Not keeping the Ubiquitous Language alive. If the business changes a term and the code does not, the bridge breaks. Refactor the names when the language changes.
  • Tip: organize your Java packages by Bounded Context (com.fiatc.underwriting, com.fiatc.claims), not by technical layer (controllers, services). The package should shout the domain.

Exercises

Exercise 1. Choose the term "Product" in an online store and describe how you would model it differently in at least two Bounded Contexts (for example, Catalog and Inventory).

Exercise 2. Rewrite the following method signature applying the Ubiquitous Language of the claims domain: void update(Long id, int type, String text).

Exercise 3. A team has divided its system into "database-service," "logic-service," and "frontend-service." Explain why this division does not correspond to Bounded Contexts and propose an alternative.

Solutions

Solution 1. In the Catalog context, a Product is marketing content: name, description, photos, sale price, categories. In the Inventory context, the same product is a StockItem: SKU, available units, warehouse location, reorder point. They share the product identifier, but their attributes and rules are different.

Solution 2. A possible rewrite: void registerClaimReport(ClaimId id, ClaimType type, DamageDescription description). The names reflect the business concepts and the types replace the generic primitives.

Solution 3. That division is technical, by layers, not by domain: each "service" needs the others to do anything, which produces total coupling and constant communication (a distributed monolith). An alternative based on Bounded Contexts would be to divide by business capabilities—for example, "Underwriting," "Policies," "Claims"—where each service contains its own logic, data, and interface for its part of the domain.

Conclusion

We have seen that strategic design is about drawing boundaries: the Ubiquitous Language ensures that business and code speak the same language, and the Bounded Context delimits the scope within which that language and its model are consistent. We have verified that the same real-world concept ("Customer," "Product") is modeled differently in each context, and that these contexts are the best candidates for defining the boundaries of microservices, avoiding the dreaded distributed monolith.

In the next lesson, "Tactical Design: Entities, Aggregates, and Repositories", we will descend from the strategic map to the implementation detail: we will see with Java code how to build the rich model within a Bounded Context using the tactical patterns of DDD.

Application Architecture Course

Module 1: Fundamentals of Application Architecture

Module 2: Design Principles and Tactics

Module 3: Architectural Styles and Patterns

Module 4: Distributed Architectures and Microservices

Module 5: Event-Driven Architectures and Messaging

Module 6: Domain-Driven Design (DDD)

Module 7: Data and Persistence

Module 8: Cloud Architecture and Deployment

Module 9: Quality, Security and Observability

Module 10: Evolution, Governance and Case Studies

© Copyright 2026. All rights reserved