Domain-Driven Design DDD 領域驅動開發筆記
【核心知識】
DDD 是一種軟體開發方法論,透過深入理解業務領域知識,將複雜的業務邏輯轉化為清晰的程式碼結構,讓技術實作與業務需求緊密對齊。
【三維解析】
原理層:核心運作機制
DDD 的核心理念是「讓程式碼說業務的語言」,主要透過以下機制運作:
- 通用語言 (Ubiquitous Language):開發團隊與領域專家共同建立一套統一的術語系統,消除溝通鴻溝
- 限界上下文 (Bounded Context):將大型系統切分成多個獨立的業務邊界,每個邊界內有自己的模型與規則
- 分層架構:
- 領域層 (Domain Layer):核心業務邏輯
- 應用層 (Application Layer):協調領域物件完成業務流程
- 基礎設施層 (Infrastructure Layer):技術實作細節
- 介面層 (Interface Layer):與外部互動
實踐層:具體應用方法
核心建模元素:
實體 (Entity)
├─ 有唯一識別碼 (ID)
└─ 例:User、Order
值物件 (Value Object)
├─ 無識別碼,由屬性值定義
└─ 例:Address、Money
聚合 (Aggregate)
├─ 一組相關物件的集合
├─ 有聚合根 (Aggregate Root) 統一管理
└─ 例:訂單聚合 = Order + OrderItems
領域服務 (Domain Service)
├─ 不屬於單一實體的業務邏輯
└─ 例:轉帳服務需要兩個帳戶協作
領域事件 (Domain Event)
├─ 記錄業務中發生的重要事實
└─ 例:OrderPlaced、PaymentCompleted
實際案例:電商訂單系統
// 值物件:金額
class Money {
constructor(
private amount: number,
private currency: string
) {}
add(other: Money): Money {
if (this.currency !== other.currency) {
throw new Error('幣別不同無法相加');
}
return new Money(this.amount + other.amount, this.currency);
}
}
// 實體:訂單項目
class OrderItem {
constructor(
public id: string,
public productId: string,
public quantity: number,
public price: Money
) {}
}
// 聚合根:訂單
class Order {
private items: OrderItem[] = [];
constructor(public id: string) {}
addItem(item: OrderItem): void {
// 業務規則:同一商品不重複添加
if (this.items.find(i => i.productId === item.productId)) {
throw new Error('商品已存在');
}
this.items.push(item);
}
calculateTotal(): Money {
return this.items.reduce(
(total, item) => total.add(item.price),
new Money(0, 'TWD')
);
}
}
關聯層:相關領域延伸
- 微服務架構:DDD 的限界上下文是微服務劃分的理論基礎
- 事件驅動架構 (EDA):領域事件可作為系統間的解耦機制
- CQRS (命令查詢職責分離):常與 DDD 搭配,分離讀寫模型
- 事件溯源 (Event Sourcing):透過領域事件重建系統狀態
- 整潔架構 (Clean Architecture):與 DDD 分層理念相呼應
【深度問答】
Q1:當業務邏輯很簡單時,為什麼不能直接用 CRUD 而要採用 DDD?
→ DDD 適合「複雜且核心」的業務領域。如果只是簡單的增刪改查,使用 DDD 反而會過度設計,增加不必要的複雜度。判斷標準:業務規則是否頻繁變動?是否有複雜的業務約束?
Q2:為什麼不能讓多個聚合直接互相修改對方的資料?
→ 這會破壞聚合的「一致性邊界」。正確做法是透過領域事件或應用服務協調,確保每個聚合內部的資料一致性由聚合根負責。
Q3:通用語言只是改個變數名稱嗎?為什麼這麼重要?
→ 不只是命名!通用語言要貫穿需求討論、文件、程式碼、測試。當 PM 說「取消訂單」,工程師的 method 也叫 cancelOrder(),這能大幅降低認知負擔與溝通成本。
【可視化建議】
- 限界上下文地圖 (Context Map):用方塊圖展示不同子系統的邊界與關係
- 聚合結構圖:樹狀圖呈現聚合根與內部實體、值物件的關係
- 事件風暴 (Event Storming) 時間軸:橫向時間軸標示領域事件流程
- 分層架構圖:同心圓或分層矩形展示依賴方向(由外向內)
【進階路徑】
- 戰術設計深化
關鍵字:Aggregate Design、Repository Pattern、Factory Pattern、Specification Pattern - 戰略設計探索
關鍵字:Context Mapping、Anti-Corruption Layer、Shared Kernel、Customer-Supplier - 實戰整合架構
關鍵字:CQRS + Event Sourcing、Hexagonal Architecture、Event-Driven Microservices
【知識分類標籤】
#type/framework
#tech/backend/architecture
#depth/understanding
#usage/problem-solving
【心智圖】
id: ddd-mindmap
name: DDD 領域驅動設計心智圖
type: mermaid
content: |-
flowchart LR
DDD[Domain-Driven Design]
DDD --> Strategy[戰略設計]
DDD --> Tactical[戰術設計]
DDD --> Philosophy[核心理念]
Philosophy --> UL[通用語言]
Philosophy --> BC[限界上下文]
Strategy --> ContextMap[上下文映射]
Strategy --> Subdomain[子領域劃分]
Subdomain --> Core[核心域]
Subdomain --> Supporting[支撐域]
Subdomain --> Generic[通用域]
Tactical --> Entity[實體]
Tactical --> VO[值物件]
Tactical --> Aggregate[聚合]
Tactical --> Service[領域服務]
Tactical --> Event[領域事件]
Tactical --> Repository[倉儲]
Aggregate --> AggRoot[聚合根]
DDD --> Related[相關架構]
Related --> Microservices[微服務]
Related --> CQRS[CQRS]
Related --> EventSourcing[事件溯源]
Related --> CleanArch[整潔架構]
💡 給你的建議
根據你的特質(Ideation + Strategic + Learner),DDD 非常適合你:
- 創意發揮:設計限界上下文與建模需要大量創造性思維
- 策略思考:戰略設計層面需要全局觀與系統性規劃
- 持續學習:DDD 是個深坑,有大量延伸知識可探索
行動建議:
- 先從一個真實專案的「單一聚合」開始練習(例如訂單或購物車)
- 嘗試用「事件風暴」工作坊方式,與團隊一起梳理業務流程
- 閱讀 Eric Evans 的《Domain-Driven Design》藍皮書,或 Vaughn Vernon 的《實作領域驅動設計》紅皮書