# 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
By clicking below, you agree to our
terms of service
.
Sign in via Facebook
Sign in via Twitter
Sign in via GitHub
Sign in via Dropbox
Sign in with Wallet
Wallet (
)
Connect another wallet
New to HackMD?
Sign up