Introduction
Domain-Driven Design (DDD) is more than just a method of writing code — it's thinking that decomposes complex systems into parts that make business sense. DDD is the foundation that decides how to divide Microservices and how to divide Micro Frontend. If divided incorrectly, you will have a "distributed monolith" — worse than the original monolith.

1. Why is DDD needed?
1.1 The problem of technical decomposition
Dividing the system into technical layers (UI layer, Business layer, Data layer) is the most common mistake:
❌ Technical Decomposition (SAI):
├── frontend-service
├── backend-service
├── database-service
└── notification-service
✅ Domain Decomposition (ĐÚNG):
├── user-management (UI + API + DB cho User)
├── product-catalog (UI + API + DB cho Product)
├── order-processing (UI + API + DB cho Order)
└── payment (UI + API + DB cho Payment)
1.2 What does DDD solve?
- Ubiquitous Language: The whole team (dev, PM, business) speaks the same "language"
- Bounded Context: Define clear boundaries between domains
- Reduce coupling: Each bounded context is an independent unit
- Align business & tech: Architecture reflects business structure
2. Strategic DDD — Look at the big picture
2.1 Ubiquitous Language
Each Bounded Context has its own language. Same word "Product" but different meaning in each context:
┌───────────────────┐ ┌──────────────────┐ ┌──────────────────┐
│ Product Catalog │ │ Order Context │ │ Shipping Context│
│ │ │ │ │ │
│ Product: │ │ OrderItem: │ │ Parcel: │
│ - name, desc │ │ - productId │ │ - weight │
│ - price, images │ │ - quantity │ │ - dimensions │
│ - categories │ │ - unitPrice │ │ - tracking │
│ - reviews │ │ - discount │ │ - destination │
└───────────────────┘ └──────────────────┘ └──────────────────┘
Cùng "Product" nhưng mỗi context cần thông tin khác nhau!
2.2 Bounded Context
Bounded Context is the logical boundary within which a consistent domain model is applied.
Principles:
- Each Bounded Context = 1 Microservice (or a small group)
- Each Bounded Context = 1 Micro Frontend (or part of UI)
- Between contexts: communicate via API or Events (no shared database!)
2.3 Context Mapping
Bounded Contexts do not exist independently — they have relationships with each other:
Context Map:
┌──────────────┐ ┌──────────────┐
│ Product │◄─────────│ Order │
│ Catalog │ Upstream │ Processing │
│ (Supplier) │──────────►│ (Consumer) │
└──────────────┘ └──────┬───────┘
│
┌──────┴───────┐
│ Payment │
│ Gateway │
└──────────────┘
Relationship patterns:
| Pattern | Description | When to use |
|---|---|---|
| Customer-Supplier | Upstream provides, Downstream consumes | Explicit dependency relationships |
| Shared Kernel | Share part of the model | The two contexts are closely related |
| Anti-Corruption Layer | Layer transition between two models | Legacy system integration |
| Published Language | Standard API/Schema for communication | Many consumers need to use |
3. Tactical DDD — Design details
3.1 Aggregates
Aggregate is a group of entities treated as a unit of consistency. All changes go through Aggregate Root.
Order Aggregate:
┌─────────────────────────────────┐
│ Order (Aggregate Root) │
│ ├── OrderItem │
│ ├── OrderItem │
│ └── ShippingAddress │
│ │
│ Invariants: │
│ - Total = sum(items.price) │
│ - Status transitions are valid │
│ - At least 1 item required │
└─────────────────────────────────┘
3.2 Domain Events
Domain Events describes events that occurred in the domain:
// Domain Events
interface OrderPlaced {
orderId: string;
customerId: string;
items: OrderItem[];
totalAmount: number;
placedAt: Date;
}
interface PaymentConfirmed {
paymentId: string;
orderId: string;
amount: number;
confirmedAt: Date;
}
// Event flow
OrderPlaced → PaymentService listens → PaymentConfirmed → ShippingService listens
4. Event Storming — Domain Discovery
4.1 What is Event Storming?
Event Storming is a workshop where developers + domain experts explore domains together by pasting sticky notes:
Timeline: ─────────────────────────────────────────────►
🟧 Domain Event 🟦 Command 🟨 Policy/Rule
"Order Placed" "Place Order" "If payment fails,
cancel order"
🟪 Aggregate 🟩 External System 🔴 Hot Spot
"Order" "Payment Gateway" "Race condition
when checking stock"
4.2 From Event Storming to Bounded Context
After the workshop, group related events → define Bounded Context → map to Microservices + Micro Frontends.
Event Storming Results → Bounded Contexts:
├── Product Context: ProductCreated, ProductUpdated, CategoryChanged
├── Cart Context: ItemAddedToCart, CartAbandoned, CouponApplied
├── Order Context: OrderPlaced, OrderConfirmed, OrderShipped
├── Payment Context: PaymentInitiated, PaymentConfirmed, RefundIssued
└── User Context: UserRegistered, ProfileUpdated, AddressAdded
Mapping:
├── Product Context → Product Microservice + Product MFE
├── Cart Context → Cart Microservice + Cart MFE
├── Order Context → Order Microservice + Checkout MFE
├── Payment Context → Payment Microservice (no separate MFE)
└── User Context → User Microservice + Account MFE
5. Apply DDD to Micro Frontend
5.1 Bounded Context → Micro Frontend
Each Bounded Context not only maps into 1 Microservice but also maps into 1 Micro Frontend:
Bounded Context: Product Catalog
├── Backend: Product Microservice
│ ├── REST API / GraphQL
│ ├── PostgreSQL database
│ └── Search index (Elasticsearch)
│
├── Frontend: Product Micro Frontend
│ ├── Product listing page
│ ├── Product detail page
│ ├── Search & filter UI
│ └── Product reviews
│
└── Team: Product Team (full-stack ownership)
5.2 Team Topology according to DDD
┌──────────────────────────────────────────┐
│ Organization │
├──────────┬──────────┬────────┬───────────┤
│ Team │ Team │ Team │ Team │
│ Product │ Cart │ Order │ Platform │
├──────────┼──────────┼────────┼───────────┤
│ MFE: │ MFE: │ MFE: │ Shell App │
│ Product │ Cart │ Order │ Design Sys│
│ pages │ sidebar │ pages │ Auth │
├──────────┼──────────┼────────┼───────────┤
│ µS: │ µS: │ µS: │ API GW │
│ Product │ Cart │ Order │ Infra │
│ API │ API │ API │ │
├──────────┼──────────┼────────┼───────────┤
│ DB: │ DB: │ DB: │ Shared │
│ Postgres │ Redis │ Postgres│ Services │
└──────────┴──────────┴────────┴───────────┘
Summary
- DDD is the thinking foundation for properly decomposing systems
- Bounded Context defines the boundary → maps to Microservices + Micro Frontends
- Event Storming helps explore domains with business experts
- Context Mapping defines the relationship between contexts
- Dividing by domain (not by technical layer) is the golden rule
Next article: Lesson 3: Full-Stack overview architecture — Microservices + Micro Frontend + BFF