目錄
概覽:三個 *DD 不是同一層的東西
名字都叫「X-Driven」,但它們回答的問題不同、作用層次不同,這是最常被誤解的地方:
| 方法論 | 全名 | 驅動的是 | 關注層次 |
|---|---|---|---|
| TDD | Test-Driven Development | 用「測試」驅動寫程式 | 程式碼 / 實作 |
| BDD | Behavior-Driven Development | 用「行為描述」驅動開發 | 需求 / 溝通 |
| DDD | Domain-Driven Design | 用「業務領域」驅動設計 | 架構 / 模型 |
DDD:怎麼「設計」軟體(領域模型、邊界、架構) ← 戰略/架構層
BDD:怎麼「描述需求與行為」(讓三方溝通一致) ← 需求/協作層
TDD:怎麼「寫程式」(測試先行、紅綠重構) ← 實作/程式碼層
三者不互斥,可同時使用:用 DDD 設計領域模型、用 BDD 釐清行為、用 TDD 實作細節。
TDD:測試驅動開發
TDD(Test-Driven Development) 的核心:先寫測試,再寫實作。測試定義「程式該做什麼」,實作只為通過測試而存在。
紅-綠-重構循環(Red-Green-Refactor)
🔴 Red :先寫一個會失敗的測試(功能還不存在)
🟢 Green :寫最少的程式碼讓測試通過(不求漂亮)
🔵 Refactor:在測試保護下重構,改善設計,保持測試綠燈
↺ 重複
範例(虛擬碼)
# 1. Red:先寫測試
test "add(2, 3) 應回傳 5":
assert add(2, 3) == 5 # add 還不存在 → 失敗
# 2. Green:最小實作
def add(a, b):
return a + b # 測試通過
# 3. Refactor:在測試保護下整理程式碼
Kent Beck 的三條規則
- 在寫出失敗測試前,不寫任何產品程式碼
- 只寫剛好能失敗的測試(編譯失敗也算失敗)
- 只寫剛好能讓當前失敗測試通過的產品程式碼
優缺點
| 優點 | 缺點 / 限制 |
|---|---|
| 測試覆蓋率高、迴歸有保障 | 前期較慢、學習曲線 |
| 逼出可測試、低耦合的設計 | 不適合需求探索期 / 拋棄式原型 |
| 重構有信心、文件即測試 | 測試本身也要維護 |
| 快速回饋、縮短除錯時間 | UI / 整合 / 難測元件不易套用 |
TDD 是實作層的紀律,產出的測試多為單元測試(unit test)。
BDD:行為驅動開發
BDD(Behavior-Driven Development) 是 TDD 的延伸與「外移」:把焦點從「測試程式單元」提升到「描述系統行為」,並用自然語言讓業務、開發、測試三方對需求達成共識。
Given-When-Then 結構
行為以「情境」描述,常用 Gherkin 語法:
Feature: 購物車結帳
Scenario: 套用折扣碼
Given 購物車有一件 1000 元的商品
When 我套用折扣碼 "SAVE10"
Then 應付金額應為 900 元
- Given:前置條件(情境)
- When:觸發的動作 / 事件
- Then:預期的結果
工具
這些情境可被工具解析、對應到測試步驟並自動執行:
- Cucumber(多語言)、SpecFlow(.NET)、Behave(Python)、JBehave(Java)
BDD vs TDD
| 面向 | TDD | BDD |
|---|---|---|
| 焦點 | 程式單元正確 | 系統行為符合需求 |
| 語言 | 程式語言 / 測試框架 | 自然語言(Gherkin) |
| 讀者 | 開發者 | 開發 + 測試 + 業務 |
| 問題 | 「這段程式對不對」 | 「我們是否做對的東西」 |
BDD 不是取代 TDD,而是在更外層補上「需求溝通」。很多團隊「外層 BDD 描述行為、內層 TDD 實作細節」。
DDD:領域驅動設計
DDD(Domain-Driven Design) 由 Eric Evans 提出,核心:讓軟體模型忠實反映業務領域,把複雜度管理在領域本身。它是設計 / 架構方法,與 TDD/BDD 的層次不同。
戰略設計(Strategic Design)— 巨觀
| 概念 | 說明 |
|---|---|
| 通用語言(Ubiquitous Language) | 業務與開發共用同一套術語,反映在程式碼中 |
| 限界上下文(Bounded Context) | 把大系統切成有明確邊界的子領域,各自有獨立模型 |
| 上下文映射(Context Map) | 描述各 Bounded Context 之間的關係與整合方式 |
| 核心域 / 支撐域 / 通用域 | 區分業務的核心價值與周邊,集中資源在核心域 |
戰術設計(Tactical Design)— 微觀
領域模型的建構元件:
| 元件 | 說明 |
|---|---|
| Entity(實體) | 有唯一識別、生命週期的物件(如 訂單 Order) |
| Value Object(值物件) | 無識別、以值相等、不可變(如 金額 Money、地址) |
| Aggregate(聚合) | 一組相關物件的一致性邊界,由 Aggregate Root 統一存取 |
| Repository(儲存庫) | 封裝聚合的取存,隔離持久化細節 |
| Domain Service(領域服務) | 不屬於單一實體的領域邏輯 |
| Domain Event(領域事件) | 領域中發生的有意義事件,用於解耦 |
| Factory(工廠) | 封裝複雜聚合的建立邏輯 |
範例(聚合概念)
Order(聚合根 Aggregate Root)
├─ OrderItem(實體,只能透過 Order 操作)
├─ Money(值物件,不可變)
└─ 不變條件:訂單總額 = 所有明細金額加總
→ 外部不能直接改 OrderItem,必須經由 Order 維持一致性
適用與成本
- 適合:業務複雜、規則多變、長期演進的核心系統
- 不適合:簡單 CRUD、業務邏輯薄的應用(會過度設計)
- 成本:學習曲線陡、需要與領域專家密切協作
DDD 常與微服務搭配:Bounded Context 是切分微服務邊界的自然依據。
三者比較與關係
需求/溝通 設計/架構 實作/程式碼
BDD DDD TDD
「做對的東西嗎?」 「如何建模領域?」 「程式對不對?」
Given-When-Then Bounded Context Red-Green-Refactor
自然語言情境 Entity/Aggregate 測試先行
│ │ │
└─────── 可同時使用、互補,非互斥 ───────────┘
| 維度 | TDD | BDD | DDD |
|---|---|---|---|
| 類型 | 開發實踐 | 開發實踐 / 協作 | 設計方法論 |
| 解決問題 | 程式正確性 | 需求一致性 | 複雜度管理 |
| 主要產物 | 單元測試 | 行為規格(可執行) | 領域模型 / 架構 |
| 核心關係人 | 開發者 | 開發 + 業務 + 測試 | 開發 + 領域專家 |
| 是否需要測試 | 是(核心) | 是(行為層) | 否(與測試正交) |
關鍵認知:DDD 回答「軟體怎麼設計」,TDD/BDD 回答「怎麼把它正確做出來並驗證」。三者解決不同問題,搭配使用最常見。
其他開發方法論
除了這三個,*Driven 家族與相關方法論還有不少:
*DD 家族
| 縮寫 | 全名 | 核心 |
|---|---|---|
| ATDD | Acceptance Test-Driven Development | 以「驗收測試」驅動,與 BDD 高度重疊,更強調驗收標準 |
| FDD | Feature-Driven Development | 以「功能清單」為單位迭代開發 |
| MDD | Model-Driven Development | 以模型(UML 等)為核心,部分程式由模型生成 |
| EDD | Event-Driven Development | 以事件流為核心的架構風格(與 event-driven architecture 相關) |
| TypeDD | Type-Driven Development | 以型別系統引導設計(Haskell / Idris 等強型別語言) |
| CDD | Contract-Driven / Component-Driven | 以介面契約 / 元件為驅動單位 |
ATDD 與 BDD 常被混用:兩者都以「期望行為 / 驗收條件」先行,差別主要在用語與側重(ATDD 偏驗收標準,BDD 偏行為描述與三方溝通)。
相關工程實踐 / 流程
- XP(eXtreme Programming,極限編程):TDD、配對編程、持續整合等實踐的集合
- Scrum / Kanban:敏捷專案管理框架(流程層,非編碼方法論)
- CI/CD:持續整合 / 持續交付(自動化流程)
- DevOps:開發與維運整合的文化與實踐
設計原則(不是方法論,但常一起談)
- SOLID:物件導向五大原則
- DRY / KISS / YAGNI:避免重複 / 保持簡單 / 不過度設計
- Clean Architecture / Hexagonal(六角架構):與 DDD 常搭配的分層架構
怎麼選 / 怎麼搭配
沒有「選一個」這回事
它們大多是互補的。常見的組合:
DDD(設計領域模型、切 Bounded Context)
└─ BDD(用 Given-When-Then 描述每個行為 / 驗收條件)
└─ TDD(實作時測試先行,紅綠重構)
└─ CI/CD(自動跑測試、自動部署)
依情境取捨
| 情境 | 建議 |
|---|---|
| 簡單 CRUD、邏輯薄 | 不必上 DDD;TDD 視團隊習慣 |
| 業務複雜、長期演進 | DDD 管理複雜度,搭 TDD/BDD |
| 需求模糊、跨部門溝通成本高 | BDD 拉齊三方理解 |
| 重視品質、頻繁重構 | TDD 提供安全網 |
| 探索性原型 / 拋棄式程式 | 先別套 TDD,避免拖慢探索 |
常見問題
問題 1:TDD、BDD、DDD 要三選一嗎?
不用。它們作用在不同層次(實作 / 需求 / 設計),可同時使用、互相補強。
問題 2:BDD 是不是只是「換句話說的 TDD」?
不是。BDD 把焦點從「測程式單元」提升到「描述系統行為」,用自然語言讓業務也看得懂,重點在需求一致性與溝通,而不只是測試。
問題 3:DDD 為什麼跟 TDD/BDD 不太一樣?
因為 DDD 是設計 / 架構方法論(怎麼建模領域、切邊界),而 TDD/BDD 是開發實踐(怎麼把它正確做出來)。DDD 不規定你怎麼測試。
問題 4:小專案需要 DDD 嗎?
通常不需要。業務邏輯薄的 CRUD 套 DDD 會過度設計。DDD 的價值在於管理複雜業務,簡單系統用不到那層抽象。
問題 5:ATDD 和 BDD 差在哪?
高度重疊,都以期望行為 / 驗收條件先行。差別主要在側重:ATDD 強調「驗收標準」,BDD 強調「行為描述與三方共同語言」,實務上常被當成同一回事。
總結
核心要點
- 三個 *DD 不同層次:TDD(實作)、BDD(需求溝通)、DDD(設計架構),不互斥
- TDD:先寫測試 → 紅綠重構,逼出可測試的低耦合設計
- BDD:Given-When-Then 自然語言描述行為,拉齊業務 / 開發 / 測試三方
- DDD:用通用語言與限界上下文建模複雜業務,戰略 + 戰術設計
- 還有 ATDD / FDD / MDD / EDD / TypeDD 等家族,以及 XP、SOLID 等實踐與原則
- 實務常疊加使用:DDD 設計 → BDD 描述 → TDD 實作 → CI/CD 自動化
快速參考
| 方法論 | 一句話 | 招牌 |
|---|---|---|
| TDD | 測試先行 | 紅-綠-重構 |
| BDD | 行為先行 | Given-When-Then |
| DDD | 領域先行 | Bounded Context / Aggregate |
| ATDD | 驗收先行 | 驗收測試 |
| FDD | 功能先行 | 功能清單迭代 |
建立日期:2026-06-18