
在領域驅動設計(Domain-Driven Design, DDD)中,我們常常將「戰略設計」與「戰術設計」並列思考。戰略設計幫助我們界定邊界、拆分業務範疇與微服務的界線;而戰術設計則進一步深入到具體的程式設計與架構實踐,讓領域模型能夠落實到程式碼之中。本文將從 Model-Driven Design 的核心理念出發,逐一介紹戰術設計中的重要構件與設計模式,並說明它們如何支撐我們打造高內聚、低耦合、具備演進性的微服務系統。
Model-Driven Design 的核心理念
戰術設計最重要的基石,是 Model-Driven Design(模型驅動設計)。這是一種以《領域模型》為核心的設計方法論,它強調軟體設計必須從業務出發,並透過不斷演進的模型,連結業務專家與技術人員,最終形成既符合業務需求、又具備技術可行性的系統。

統一語言(Ubiquitous Language)
- 領域模型的語言必須由 業務專家與技術團隊 共同創造並使用。
- 在程式碼、文件、甚至會議討論中,所有人應該使用相同的術語,避免出現語義不一致導致溝通斷層。
- 例如,在保險系統中,「核保」、「理賠」、「要保人」這些詞應該出現在程式類別名稱與測試案例中,而非只是業務文件裡的專有名詞。
統一語言其實就是團隊之間在尋求「共識」的一種過程。
模型即設計
- 模型不只是業務分析工具,更是技術設計的基礎。
- 在程式結構中,我們應該能直接看到 Entity(實體)、Value Object(值物件)、Aggregate(聚合) 等結構,這樣才能確保程式碼與業務知識保持一致。
Most developers have never seen a domain model. They've only seen data models.
在 2017 年歐洲的 DDD 年會中,Cyrille Martraire 提到大部分的開發人員並沒有看過「領域模型」,經過我自己的經驗調查看起來好像也是這樣。

Doamin Model 是一群「名詞」的連結!
持續反饋與演進
- 領域模型不是一次設計完成的靜態產物,而是一個 動態演進的成果。
- 在與業務專家的持續對話中,模型會被不斷修正、細化,才能保持與現實需求的同步。
分層架構
- 戰術設計通常與 Layered Architecture(分層架構) 搭配,將領域模型封裝於「Domain Layer」,並與 Application、Infrastructure、Presentation 解耦。
- 這種方式能避免基礎設施的變動(例如資料庫或第三方 API)直接影響領域模型。
戰術設計的核心組件
Entity(實體)
Entity 是戰術設計中最直觀的建構。它的核心特徵是 具備唯一識別(Identity),並且隨著時間演進,內部狀態可能會發生變化。
- 特性:
具有唯一識別(如會員 ID、身分證字號)。
內部屬性可變,但其身份不變。
- 案例:
在電商系統中,訂單(Order)是一個實體。即使訂單狀態從「待付款」變成「已出貨」,它的訂單編號依然不變。
實體設計的挑戰:過度依賴資料庫 ID,而忽略了業務層面的識別。DDD 強調的是 業務身份,而非技術層面的自增主鍵。 (放下 DB 立地成 ....)
Value Oject (值物件)
Value Object 是用來表達一個概念的值或特性,沒有唯一身份,而是由其屬性決定。
- 特性:
無唯一識別。
不可變更(Immutable)。
行為與數據緊密結合。
- 案例:
「金額(Money)」是典型的值物件,通常包含金額數字與幣別,並附帶運算行為(如加總、比較)。
「地址(Address)」也是值物件,它本身沒有 ID,唯一性取決於街道、城市、郵遞區號等欄位。
反模式提醒:如果值物件僅剩下資料而沒有行為,就會淪為所謂的「貧血模型」。這會破壞 DDD 的核心精神。 (我們經常看到人們寫一個類別,然後只有 Getter and Setter 沒有核心業務邏輯)
Aggregate(聚合)
Aggregate 是一種更高層次的建構,用來管理相關實體和值物件的整體。
- 核心理念:
聚合內部的所有操作,必須保持 一致性邊界。
聚合根(Aggregate Root)負責統一對外的存取,外部不得直接操作聚合內部的子實體。
- 案例:
在銀行領域中,「帳戶(Account)」可以是一個聚合,其內部可能包含交易紀錄、餘額計算等子實體。所有交易都必須透過「帳戶」這個聚合根完成,確保一致性。
- 與微服務的關係:
一個聚合常常是 微服務劃分的最小單位。
當系統切割微服務時,Aggregate 提供了一個天然的邊界。
Service(領域服務)
Service 負責封裝那些不屬於任何單一實體或值物件的業務邏輯。
- 特性:
無狀態。
專注於協調多個實體或值物件的邏輯。
- 案例:
「轉帳服務(TransferService)」負責將金額從帳戶 A 轉移到帳戶 B。這個邏輯不自然屬於單一帳戶,因此需要透過 Service 來實現。
最佳實踐:Service 不應該淪為「大雜燴」,而應保持高內聚,僅承擔必要的協調角色。
Factory(工廠)
Factory 模式負責複雜物件的創建,將初始化邏輯與業務使用分離。
- 價值:
封裝複雜建構過程。
確保建立物件時遵循領域規則。
- 案例:
在建立「保單(Policy)」時,可能需要根據多個輸入(要保人資訊、險種設定、附加條款)來決定最終的保單對象。這種情況下,Factory 能避免建構過程過度散落在應用層中。
Repository(儲存庫)
Repository 是領域層與資料持久化之間的抽象橋樑。
- 特性:
對領域層提供集合操作介面。
隱藏底層資料存取細節(SQL、NoSQL)。
- 案例:
OrderRepository 可以提供 findById(orderId) 或 save(order) 這樣的方法,而不讓領域層關心這背後是透過 SQL 還是 API 存取。
好處:讓領域模型專注於業務邏輯,而非資料存取。
Domain Events(領域事件)
-
特性:
過去式命名(如 OrderShipped、PaymentCompleted)。
具備業務意義。
-
案例:
當訂單完成付款後,系統會觸發 PaymentCompleted 事件,其他子系統(例如物流或通知系統)可以訂閱並執行後續處理。
-
價值:
領域事件能夠 解耦 Bounded Context 之間的通訊。
在微服務架構中,領域事件更能支撐獨立部署與高擴展性。
Layered Architecture(分層架構)
典型的 DDD 分層架構包含:
- Presentation Layer(表現層):處理使用者介面與請求輸入。
- Application Layer(應用層):協調業務流程,但不包含業務規則。
- Domain Layer(領域層):核心業務邏輯所在。
- Infrastructure Layer(基礎設施層):資料庫、訊息中介軟體等技術細節。
價值:透過分層,我們能讓領域邏輯與外部技術細節解耦,提升系統的可維護性。
戰術設計與微服務的關聯
戰略設計幫助我們劃分 Bounded Context,而戰術設計則是將這些界線具體落實到程式碼中。二者的關聯可以歸納為:
• 戰略設計決定邊界:哪些功能屬於哪個服務。
• 戰術設計落實細節:如何在該服務內部以 Entity、Value Object、Aggregate 等方式實現。
• 領域事件:成為不同微服務之間的溝通橋樑。
這也是為什麼 DDD 成為微服務設計的主要方法論之一。
實務建議與常見反模式
- 避免貧血模型:
若實體或值物件只有資料欄位而沒有行為,就失去了 DDD 的意義。
- 避免過度設計:
戰術設計的模式不是每個專案都要用到全部,要依據業務複雜度與需求裁剪。
- 保持語言一致:
程式碼命名必須對應到統一語言,否則容易回到傳統「技術導向」的設計。
結語
戰術設計是 DDD 的落地實踐,透過 Entity、Value Object、Aggregate、Service、Factory、Repository、Domain Events 與分層架構,我們能將抽象的業務需求轉化為具體的程式結構。更重要的是,這些模式讓系統具備高內聚、低耦合、持續演進的能力,支撐微服務的長期發展。
在今天快速變動的數位環境中,業務需求不斷演進。唯有透過 DDD 戰術設計,我們才能打造真正與業務緊密貼合的軟體,並且在技術上保持彈性與可持續性。這正是 DDD 能在微服務浪潮中成為核心方法論的原因。