什麼是 DDD 領域驅動設計?
Domain Driven Design (DDD) 是一種以「領域邏輯」為核心的軟體開發方法論。其核心定義在於透過領域模型將複雜的業務需求轉化為清晰的軟體架構。實踐 DDD 的關鍵步驟包含:1. 通用語言 (Ubiquitous Language):確保開發者與領域專家使用一致的術語溝通;2. 有界上下文 (Bounded Context):明確定義系統功能的邊界,解決術語歧義;3. User Story 寫法:從使用者角度釐清「為什麼 (Why)」需要該功能。透過 DDD,團隊能更精準地進行微服務架構設計,確保軟體規格高度契合商業價值,並在複雜的系統中建立高品質的 Shared Mental Model。
把專案的重點放在核心領域和領域邏輯
在軟體開發上,通常會在與使用者進行訪談後,產生使用者故事和人物誌去理解和釐清核心領域以及領域邏輯。
小編在前公司曾經歷過讓行銷帶專案,行銷會認為自己為需求方,工作就是提出需求後事情就會自動完成。
工作流程: 老闆下指令 -> 行銷整理 -> 出圖實作 -> 老闆下指令
在這樣的過程中,該怎麼協助專案進行?
常見釐清需求的方式會是透過 User Journey Map 和 User Story 來進行描述
使用者旅程圖 (User Journey Map)
使用者的工作或流程通常會用使用者故事 (User Story) 來進行描述,目的是在特定的產品範圍與技術限制下去釐清相關需求。
使用者的工作、流程中的體驗大致區分為前中後三個階段:
- 使用前的預期: 預期能夠經歷或得到什麼
- 使用中的體驗: 使用的過程中是否能真的解決問題
- 使用後的體驗: 相關的社群互動、評價等等
使用者故事 (User Story)
使用者故事常見有兩種描述的句型如下:
As aActorI want toActionSo that I canOutcomeGivenActorWhenActionthenOutcome
在一句簡單的使用者故事句型中分別包含了 Actor、Action、Outcome,其中對於產品來說最重要的就是要得到使用者的 Why,確認使用者真正想要知道的是什麼。
- Actor: 誰 (Who) 在什麼情境 (Where or Which) 下使用這個產品
- Action: 做什麼 (What),需要實作的相關功能
- Outcome: 強調的是為什麼 (Why) 想看到或得到什麼,決定產品中功能開發的優先順序
以這個部落格的使用者故事當例子:
As a 部落格經營者 I want to 優化文章關鍵字 So that I can 部落格 SEO 成效提升Given 部落格經營者 When 優化文章關鍵字完成時 then 部落格 SEO 成效提升
使用者訪談
訪談的重點在凸顯痛點及用戶需求,也就是找出背後的 Why,訪談的過程則會專注在
- 定義研究範圍和問題
- 辨識出誰是使用者或是顧客
- 分析資料列出目標
- 建立使用者的任務流程
訪談的流程
- 開場介紹目的和問題
- 嘗試發現痛點:
- 留下後續紀錄
引導方式期待會是能問到使用者背後真正的原因、動機以及真正想達成的目標,舉個闖紅燈很危險的例子來說。
痛點: 闖紅燈危險
上班常遲到 -> 睡過頭 -> 沒聽到鬧鐘 -> 睡前沒設鬧鐘 -> 跟可愛女孩子聊天聊到忘記設定
該問的
- 過去經驗
- 完成任務需要完成哪些事
不該問和假設
- 價值判斷 ex 是來了解和認識不是來打分數的
- 引導性問題 ex 你討厭這個按鈕的擺放位置嗎?
- 想要什麼 ex 對方不一定知道自己想要什麼
- 假想的解決方案
領域驅動設計 (Domain Driven Design)
- 促進跨團隊的溝通、理解領域知識
- 專注在核心業務上,業務邏輯不受技術實作細節影響
- 模組化利於拆分合設計微服務
做生意的本質是商業,在各個領域中除了技術本身外最重要的就是商業邏輯。
透過將複雜的問題解構,利用領域模型 (Domain Model)、領域詞彙 (Domain Terms)、通用語言 (Ubiquitous Language) 來設計和描述系統,進而可以更快的去了解和在各部門同步使用者的流程、商業模式、系統的運行。
跨部門溝通的目標是建立 Shared Mental Model
領域 (Domain)
能將遇到的商業情境面對的問題和解法切割成問題和解決方案兩種空間
- Problem Space 依照優先權和外包程度還可以細分成三種類型
- Core Domain: 有價值不可被取代
- Supporting Subdomain: 支援性質可能還是需要實作
- Generic Subdomain: 可以直接外包或購買現成方案
- Solution Space
領域模型 (Domain Model)
定義領域模型,在商業的世界中除了實作的工程師外最重要的就是該領域的專家 (Domain Expert)。
小編過去曾在教育領域的新創服務,當時的老闆 (領域專家) 就是補教界的名師,而我們就是在領域的相討論中將系統實做出來。
接下來就會以補教業的系統為例子
- 了解系統跨足的領域 => 出題、考試、金流
- 了解使用案例 => 學生測試積點可到咖啡廳換薯條或飲料 (考試、金流領域)、老師想建立補教系統與智慧題庫協助學生學習 (建題領域)
- 透過領域詞彙去定義通用詞彙和切割子領域 => 每日測驗系統、建題系統、兌換系統 (金流領域)
有界限的語境 (Bounded Context)
當有人說出午餐想要吃一號餐,請問是肯德基的一號餐還是麥當勞的一號餐呢? 今天如果領域發生在麥當勞就會知道是大麥克餐。
所以將 “一號餐” 就需要框出範圍被隔離在有界限 (麥當勞或是肯德基) 的語境中,關鍵問題會是怎麼框出範圍?
- 同領域詞彙 -> 意義不同
- 以使用者來說,建題系統的 “使用者” 是老師、測驗系統的 “使用者” 是學生
- 同領域詞彙、意義 -> 不同使用案例
- 一號餐是大麥克還是炸雞餐、票根回收是電影票根還是餐影兌換票根
- 外部系統
參考資料: Bounded Contexts 和其應用
通用語言 (Ubiquitous Language)
當團隊有通用語言時,就不會產生溝通上的誤解,但需要注意的是要搭配 Bounded Context 才不會誤會一號餐是大麥克還是炸雞餐、票根回收是電影票根還是餐影兌換票根。
Designing with types
F# 這個語言提供了大量定義 type,透過宣告 Type 的寫法去描述複雜的領域知識也建立了通用語言。
1 | type HotelRoom = RoomNumber of int | RoomName of string |
參考資料
- https://fsharpforfunandprofit.com/posts/designing-with-types-intro/
- https://fsharpforfunandprofit.com/ddd/
- https://blog.scottlogic.com/2018/06/01/magical-domain-modelling-with-fsharp.html
Wrapping primitive types
1 | type EmailAddress = EmailAddress of string |
實際的範例
- 將所有想到的類別都列出
1 | type Contact = |
- 重構並依照相關類型進行分類
1 | type PersonalName = |
- Contact 中的聯絡方式改為選填
1 | type Contact = |
- 定義複合類型,簡化 Contact 中的聯絡方式寫法
1 |
|
- List 的類型
1 | type ContactMethod = |
參考資料
投影片可以跳到 45 頁
1 | // Bounded Context 用 module 定義 |
這段 Slideshare 簡報深入探討了如何運用 F# 類型系統進行 Domain Driven Design (DDD),詳細展示了領域模型的建立與軟體規格的精確定義,是理解 DDD 核心概念的絕佳資源。
FAQ:Domain Driven Design (DDD) 常見問題
Q1:導入 DDD 的門檻很高,小團隊也適合嗎?
A:DDD 實踐 的門檻確實存在,因為它需要開發者與領域專家的高度配合。對於小團隊,建議可以先從「戰略設計」開始,即建立 通用語言 與 有界上下文。即使不立即採用複雜的「戰術設計」(如聚合、倉庫模式),釐清業務邊界也能顯著減少未來的重構成本與溝通誤解。
Q2:如何寫出高品質的 User Story?
A:好的 User Story 寫法 關鍵在於「Action」與「Outcome」的邏輯。不要只描述「我想要一個按鈕」,而要描述「我想要透過 [Action] 來達到 [Outcome]」。這樣能幫助工程師理解需求的本質,有時甚至能提出比「加個按鈕」更優雅的技術解決方案。
Q3:DDD 領域驅動設計如何協助微服務拆分?
A:有界上下文 (Bounded Context) 是 微服務架構設計 的天然邊界。透過 DDD,我們可以識別哪些業務邏輯是強相關的(應放在同一個服務),哪些是應被隔離的(應拆分為獨立服務)。這能有效避免「分散式巨石系統 (Distributed Monolith)」的產生,讓系統更具擴充性與維護性。
喜歡這篇文章,請幫忙拍拍手喔 🤣

