Module 3: Domain-Driven Design & Bounded Contexts: Case Studies
These case studies focus on the hard part of DDD: discovering where one model stops being true. A bounded context is not a service name. It is a boundary around language, rules, ownership, and consistency.
How To Use These Case Studies
- List the domain terms and ask whether they mean the same thing everywhere.
- Separate core, supporting, and generic subdomains.
- Draw the context map before proposing services.
- Identify aggregate invariants and transaction boundaries.
- Produce the required artifact.
Case Study 1: Same Word, Different Model
Scenario: In a marketplace, "Order" means a buyer's purchase in checkout, a pick/pack task in fulfillment, a revenue event in finance, and a support case anchor in customer service. One shared orders model now has dozens of nullable fields and contradictory rules.
Source anchor: Martin Fowler's Bounded Context article explains that a single conceptual model becomes difficult across a large system, and that bounded contexts make model boundaries explicit.
Module concepts:
- bounded context
- ubiquitous language
- model boundary
- context map
- translation
Wrong Approach
"We need one canonical enterprise Order model."
That forces every context to accept fields and rules that belong somewhere else.
Better Approach
Split language by context:
Checkout:
Order = buyer intent and payment authorization
Fulfillment:
Shipment = warehouse work package
Finance:
RevenueEvent = accounting-relevant fact
Support:
CaseOrderView = read model for customer help
Integrations translate between models instead of pretending one model is universal.
Tradeoff Table
| Choice | Gain | Cost |
|---|---|---|
| canonical model | apparent consistency | model bloat and hidden disagreement |
| bounded contexts | language clarity | translation work |
| shared database table | easy reporting | context coupling |
| published language | stable integration | schema governance |
Failure Mode
One team changes status = cancelled for its workflow and breaks another team's meaning of cancellation.
Required Artifact
Draw a context map showing the four meanings of Order, their owners, and translation events.
Project / Capstone Connection
Capstone APIs should expose context language, not database table names.
Case Study 2: EventStorming Reveals The Wrong Service Boundary
Scenario: A team plans services by nouns: UserService, OrderService, PaymentService, EmailService. An EventStorming workshop shows that the real business process crosses fraud review, inventory reservation, payment authorization, fulfillment, and customer notification.
Source anchor: Alberto Brandolini's EventStorming material frames domain exploration around events, commands, policies, and people so teams can discover business flow and boundaries.
Module concepts:
- EventStorming
- domain events
- commands
- policies
- process boundaries
- service discovery
Wrong Approach
"Make one service per noun."
Nouns alone hide workflow, policy, and ownership.
Better Approach
Start from events:
Events:
CartCheckedOut
PaymentAuthorized
FraudReviewRequested
InventoryReserved
ShipmentCreated
Commands:
AuthorizePayment
ReserveInventory
CreateShipment
Policies:
if fraud score high -> request manual review
Boundaries appear where language, policy, and consistency change.
Tradeoff Table
| Choice | Gain | Cost |
|---|---|---|
| noun services | easy naming | anemic boundaries |
| event-driven discovery | exposes flow and policy | workshop facilitation needed |
| process manager | visible long-running flow | extra state machine |
| choreography | local autonomy | harder global trace |
Failure Mode
The system has services, but every feature still requires coordinated changes across all of them.
Required Artifact
Create an EventStorming slice with events, commands, actors, policies, and candidate context boundaries.
Project / Capstone Connection
Use EventStorming before drawing microservice boundaries in a capstone.
Case Study 3: Aggregate That Tries To Own The Whole World
Scenario: A subscription aggregate contains customer profile, payment methods, invoices, invoice lines, discounts, emails, and audit history. Every change loads a huge object and conflicts with unrelated changes.
Source anchor: Microsoft's DDD microservices guidance describes aggregates as consistency boundaries and warns that aggregate size affects transactional consistency and performance. See Microsoft DDD aggregate guidance.
Module concepts:
- aggregate
- invariant
- transaction boundary
- entity
- value object
- domain event
Wrong Approach
"Everything related to subscription belongs inside one aggregate."
Relationship is not ownership. Aggregates should protect invariants that must be transactionally consistent.
Better Approach
Split by invariant:
Subscription aggregate:
plan, status, renewal rules
Invoice aggregate:
invoice lines, totals, payment state
Customer aggregate:
identity and contact profile
Events:
SubscriptionRenewed
InvoiceIssued
PaymentFailed
Tradeoff Table
| Choice | Gain | Cost |
|---|---|---|
| large aggregate | simple object graph | contention and accidental invariants |
| small aggregate | focused consistency | eventual consistency between aggregates |
| domain events | decoupled follow-up work | ordering and retry rules |
| cross-aggregate transaction | immediate consistency | coupling and scalability limits |
Failure Mode
The aggregate becomes a serialized bottleneck and every team fears changing it.
Required Artifact
Write an aggregate design note: invariant, entities/value objects, commands, emitted events, and forbidden cross-aggregate updates.
Project / Capstone Connection
Capstone domain models should state aggregate invariants explicitly.
Case Study 4: Anticorruption Layer Around A Legacy Billing System
Scenario: A new subscription context integrates with a legacy billing system whose concepts are account, contract, and charge code. The new domain uses customer, subscription, and plan. Directly leaking legacy terms into new code confuses every feature.
Source anchor: Chris Richardson's microservices pattern catalog describes the Anti-Corruption Layer pattern as a translation layer that prevents a legacy model from contaminating a new model. See Anti-corruption layer pattern.
Module concepts:
- anticorruption layer
- context relationship
- translation
- legacy integration
- published language
Wrong Approach
"Just call the legacy API from the domain service and map fields inline."
Inline mapping spreads legacy language everywhere.
Better Approach
Create a translation boundary:
Subscription context:
Subscription
Plan
RenewalPolicy
Legacy billing:
Contract
ChargeCode
Account
ACL:
maps SubscriptionStarted -> CreateContract
maps ChargePosted -> InvoiceLineRecorded
Tradeoff Table
| Choice | Gain | Cost |
|---|---|---|
| direct integration | fastest first call | legacy model leaks everywhere |
| ACL | protects domain language | mapping code and operational ownership |
| conformist relationship | less translation | new context inherits old constraints |
| replace legacy first | clean model | high migration risk |
Failure Mode
The new bounded context becomes a thin wrapper over old concepts and never develops its own model.
Required Artifact
Write an ACL mapping table: new term, legacy term, transformation, error case, owner.
Project / Capstone Connection
Any capstone that integrates with third-party APIs should include an anticorruption boundary.
Case Study 5: Core Domain Starved By Generic Work
Scenario: A logistics startup spends months building authentication, invoicing PDFs, admin CRUD, and notification templates while its route-optimization engine remains primitive.
Source anchor: DDD strategic design distinguishes core, supporting, and generic subdomains so teams can focus differentiated effort where it matters most. See Context Mapper DDD strategic design concepts.
Module concepts:
- core subdomain
- supporting subdomain
- generic subdomain
- build vs buy
- strategic design
Wrong Approach
"All code in our product is equally strategic."
That spends scarce engineering attention on undifferentiated work.
Better Approach
Classify subdomains:
Core:
route optimization and carrier matching
Supporting:
shipment tracking dashboard
Generic:
authentication, invoicing PDF, email delivery
Then allocate design rigor, staffing, and build/buy decisions accordingly.
Tradeoff Table
| Choice | Gain | Cost |
|---|---|---|
| custom-build everything | full control | slow progress on core domain |
| buy generic capabilities | faster core focus | vendor constraints |
| over-invest in support domain | better local fit | opportunity cost |
| protect core domain team | strategic speed | integration work |
Failure Mode
The company has polished infrastructure around a weak differentiator.
Required Artifact
Create a subdomain classification table with build/buy/reuse decisions and rationale.
Project / Capstone Connection
Capstone scope should identify the core subdomain and avoid overbuilding generic support tools.
Source Map
| Source | Use it for |
|---|---|
| Martin Fowler: Bounded Context | model boundaries and ubiquitous language |
| EventStorming | event-first domain discovery |
| Microsoft DDD aggregate guidance | aggregate invariants and consistency boundaries |
| Microservices.io: Anti-corruption layer | protecting a new model from legacy models |
| Context Mapper context mapping | strategic design and context relationships |
Completion Standard
- At least three artifacts are completed.
- At least one context map separates language boundaries.
- At least one EventStorming slice is produced.
- At least one aggregate invariant is written.
- At least one integration has an anticorruption mapping.