Bounded Contexts: The Foundation of DDD
Bounded Contexts are the most important concept in Domain-Driven Design. They define explicit boundaries within which a domain model applies. Without clear boundaries, you get the "Big Ball of Mud" - a tangled mess where everything depends on everything.
TL;DR
| Concept | Definition |
|---|---|
| Bounded Context | A boundary within which a particular domain model is defined and applicable |
| Why it matters | Prevents model pollution, enables team autonomy, clarifies ownership |
| Key insight | The same word can mean different things in different contexts |
The Problem: Ambiguous Models
Consider a simple word: "Customer"
In a typical enterprise, "Customer" means different things to different teams:
What goes wrong:
- Sales adds
LeadScore,SalesRep,Pipeline - Support adds
TicketHistory,SatisfactionScore,PreferredChannel - Billing adds
PaymentMethod,CreditLimit,InvoiceAddress - Shipping adds
ShippingPreference,DeliveryInstructions
Result: A God Object with 500+ fields that everyone depends on and no one owns.
The Solution: Explicit Boundaries
Each context has its own Customer model with only the attributes it needs.
What Defines a Bounded Context?
1. Linguistic Boundary
The same term means different things:
| Term | Sales Context | Shipping Context |
|---|---|---|
| Order | A potential sale with negotiation | A shipment request with tracking |
| Product | SKU with pricing tiers | Physical item with dimensions/weight |
| Customer | Lead with revenue potential | Delivery recipient with address |
2. Model Boundary
Different models for the same concept:
// Sales Context
interface Customer {
id: CustomerId;
name: string;
leadScore: number;
assignedRep: SalesRepId;
opportunities: Opportunity[];
}
// Shipping Context
interface Customer {
id: CustomerId;
name: string;
defaultAddress: Address;
deliveryPreferences: DeliveryPrefs;
// No leadScore - doesn't exist here
}
3. Team Boundary
Often aligns with team ownership:
┌─────────────────────────────────────────────────────────┐
│ Bounded Context ≈ Team Boundary (Conway's Law) │
├─────────────────────────────────────────────────────────┤
│ Sales Context → Sales Engineering Team │
│ Billing Context → Payments Team │
│ Shipping Context → Logistics Team │
│ Support Context → Customer Success Team │
└─────────────────────────────────────────────────────────┘
4. Technical Boundary
Can be (but doesn't have to be) a deployment boundary:
| Boundary Type | Example |
|---|---|
| Separate service | Microservice per context |
| Module in monolith | Namespace/package separation |
| Schema | Separate database schemas |
| None | Logical boundary only (early stage) |
Context Boundaries in Code
Bad: Shared Entity Across Contexts
// ❌ One Product class used everywhere
public class Product
{
public Guid Id { get; set; }
public string Name { get; set; }
public string Description { get; set; } // Catalog
public decimal Price { get; set; } // Pricing
public int StockLevel { get; set; } // Inventory
public decimal Weight { get; set; } // Shipping
public string TaxCode { get; set; } // Billing
// 50 more fields...
}
Good: Context-Specific Models
// ✅ Catalog Context
namespace Catalog
{
public class Product
{
public ProductId Id { get; }
public string Name { get; }
public string Description { get; }
public List<CategoryId> Categories { get; }
}
}
// ✅ Inventory Context
namespace Inventory
{
public class StockItem
{
public ProductId ProductId { get; } // Reference, not full entity
public int QuantityOnHand { get; }
public int ReorderPoint { get; }
}
}
// ✅ Pricing Context
namespace Pricing
{
public class PricedProduct
{
public ProductId ProductId { get; }
public Money BasePrice { get; }
public List<PricingRule> Rules { get; }
}
}
Common Mistakes
Mistake 1: Database-Driven Boundaries
❌ "We have a Products table, so we have a Products context"
✅ "We have different teams with different needs for product data"
Mistake 2: Technical-Only Boundaries
❌ "Frontend context, Backend context, Database context"
✅ Boundaries based on business capabilities
Mistake 3: Too Granular
❌ One context per entity (Customer context, Order context, Product context)
✅ Contexts around cohesive business capabilities
Bounded Context Checklist
Before defining a bounded context, verify:
- Clear language - Terms have unambiguous meaning within the boundary
- Cohesive model - Entities and rules belong together
- Single team - One team can own and evolve it
- Minimal dependencies - Limited integration points with other contexts
- Clear interfaces - Well-defined contracts at boundaries
- Appropriate size - Not too big (God context) or too small (nano contexts)
Quick Reference Card
┌─────────────────────────────────────────────────────────┐
│ BOUNDED CONTEXT QUICK REFERENCE │
├─────────────────────────────────────────────────────────┤
│ Definition: │
│ Explicit boundary where a domain model applies │
│ │
│ Identifies by: │
│ • Linguistic boundaries (same word, different meaning)│
│ • Team ownership │
│ • Change patterns │
│ • Consistency requirements │
│ │
│ Size guidance: │
│ • One team can own it │
│ • 5-10 aggregates typical │
│ • Can deploy independently │
│ │
│ Anti-patterns: │
│ • God context (everything in one) │
│ • Nano contexts (one per entity) │
│ • Technical boundaries (frontend/backend) │
└─────────────────────────────────────────────────────────┘
Next Steps
- Ubiquitous Language - The shared vocabulary within a context
- Context Mapping - How contexts relate to each other
- Event Storming - Technique for discovering contexts