# What is Domain Driven Design (DDD)? ==破題== > Domain Driven Design 是一種以「業務領域」為核心的軟體設計方法。 它透過與業務相關者建立「共通語言 (Ubiquitous Language)」,並在程式中建立貼合業務邏輯的領域模型,使系統可維護、可演進且不易走樣。 --- ### 為什麼我們需要這個概念? 軟體的核心是為使用者解決業務需求, 隨著服務越來越多樣化、流程越來越複雜,系統不再只是資料庫的 CRUD,而是需要處理: - 一連串業務規則 - 多種角色行為 - 不變條件(Invariants) - 日益變動的需求 這些複雜性如果直接寫成 CRUD 風格的程式碼,系統很容易僵化、難以維護,也難以讓人從程式碼理解業務。 因此 Eric Evans 提出了 Domain-Driven Design(DDD),希望程式開發能夠更貼近業務邏輯,而不是只停留在資料表 CRUD。 下面用一段程式碼簡單演示差異: > Service 後的實作不是重點,這裡就不展示該怎麼實作 ``` // 沒有 ddd 概念的建立訂單(純 CRUD) var order = new OrderEntity { CustomerId = 1, Total = 500, CreatedAt = DateTime.UtcNow }; var repo = new OrderRepo(); repo.Create(order); ``` ``` // ddd 概念的建立訂單 (強調業務語意) var orderRepo = new OrderRepo(); var orderService = new OrderService(orderRepo); var orderId = orderService.CreateOrder( customerId: 1, total: 500, createdAt: DateTime.UtcNow); ``` 上面兩段程式碼背後做的事情可能都只是 CRUD, 但語意完全不同: > 上面只是「新增一筆資料」 > 下面是執行「建立訂單」這個業務行為 DDD 的目的不是讓程式碼變複雜,而是: - 讓程式碼表達真正的業務邏輯 - 把規則封裝在領域模型中(不是散落在 Controller、Repository) - 保護系統的業務邏輯(不變條件不會亂被破壞) - 適應未來業務變化(加入新規則,不必大改架構) - 讓開發團隊與業務人員使用同一語言 這能讓系統達到一種狀態: >程式即設計,設計即程式(The code is the model)。 --- ### 什麼是 DDD? > Domain 就是 「為解決某個問題所需的全部知識集合」,包含問題本身、專業術語、業務規則與可行解法。 > ==DDD 就是以這個 Domain 為核心的軟體開發設計== 實作上 DDD 分為兩個層面 - 策略性 (Strategic): 與領域專家合作,將 Domain 劃分為各個 Subdomains,並明確界定 Bounded Contexts,把團隊的注意力放在能產生最大價值的 Core Subdomains 上 - 戰術性 (Tactical): 利用一系列的設計模式 (Aggregate, Entity, Repository ...etc) 實踐 Strategic Design 定義好的各個 Subdomain 白話來說,DDD 不只把方法命名的更語意化,更把 「業務邏輯、規則、共通語言」注入到 Model 中,使程式碼能直接表達業務 --- ### 用共通語言 (Ubiquitous Language) 溝通 在 DDD 中,團隊必須建立一套「所有人都使用的語言」,包含業務、PM、工程師、QA、甚至程式碼本身。 這套語言用來描述: - 業務流程 - 規則 - 模型 - 行為 - 邏輯 這麼做的目的,不只是減少溝通成本,而是: >讓整個團隊在討論與開發時,都能指向同一個概念,沒有誤解與模糊地帶。 例如:「取消訂單」對技術人員可能以為只是把狀態改為 Cancelled; 但對業務來說,可能包含退款、回補庫存、通知顧客、更新發票等流程。 若沒有共通語言,系統最終會反映工程師「以為」的業務,而不是「真正」的業務。  (Source: [fx777: 關於 Domain-Driven Design 以及他的魅力](https://ithelp.ithome.com.tw/m/articles/10216645)) --- ### 配合業務邏輯,封裝 Method 看到這裡,讀者可能會以為: >簡單來說,DDD 就是把方法封裝好嘛? 這句話有一半對,但遠不只如此。 DDD 的封裝不是一般的 OOP 封裝,而是: 只針對真正的業務行為進行封裝,並在 Model 中維護該行為的規則、不變條件與限制。 例如: - Order.Cancel() 不是改一個欄位 - Order.Pay() 不只是「把 IsPaid 設為 true」 - Cart.AddItem() 要檢查庫存、檢查是否重複加入、計算金額等 這種封裝讓: 1. 程式模型與業務邏輯緊密綁在一起 2. 方法會隨著業務演進而演進 3. 方法名稱自然反映業務語意,不需要為命名苦惱 也就是說: DDD 將業務語言、規則、流程直接放進程式碼,使模型本身就能表達業務。 --- ### 優缺點 優點: 1. 統一專業術語(Ubiquitous Language) 讓跨角色(業務、PM、工程師)溝通一致,減少誤解。 2. 保護業務邏輯(封裝不變條件) 業務規則集中在 Model 中,不會被 Controller / Repository 分散污染。 3. 高度模組化,可測試性強 Aggregate、Value Object 都能獨立測試,維護成本降低。 4. 更容易拆分成 microservice 因為 bounded context 原本就界定了系統邊界,天然適合作為 microservice 切割基礎。 缺點: 1. 較難快速建立產品,前期需要大量討論 Domain 2. 要導入溝通文化、學習成本高 3. 沒有領域專家會很難開頭 若缺乏業務知識,Model 難以正確形成,也會讓 DDD 成為形式主義 4. 過度使用會成為負擔 如果 Domain 不複雜,硬套 DDD 會增加不必要的成本 #### 參考資料 [Jimmy Coding: 白话讲解领域驱动设计domain driven design (DDD)](https://www.bilibili.com/video/BV11u411176h/?spm_id_from=333.337.search-card.all.click&vd_source=8f375110dafd4e9c975e5276d51c4840) [fx777: 關於 Domain-Driven Design 以及他的魅力](https://ithelp.ithome.com.tw/m/articles/10216645)
×
Sign in
Email
Password
Forgot password
or
Sign in via Google
Sign in via Facebook
Sign in via X(Twitter)
Sign in via GitHub
Sign in via Dropbox
Sign in with Wallet
Wallet (
)
Connect another wallet
Continue with a different method
New to HackMD?
Sign up
By signing in, you agree to our
terms of service
.