為什麼改個業務規則要改 5 個地方?DDD 如何解決

🌏 Read this article in English


你是否曾經歷過這樣的場景:產品經理說「支援新的折扣規則」,工程師開始修改 OrderService、DiscountService、PromotionService、PricingService、CustomerService…改著改著才意識到,這個簡單的需求竟然觸及了 5 個不同的模組。

這不是個別案例。這是系統設計缺陷的症狀。

領域驅動設計(Domain-Driven Design,簡稱 DDD)不是新概念,但許多工程師對它的理解停留在「複雜」和「過度設計」的刻板印象。實際上,DDD 的目的恰恰相反:透過清晰的邊界與角色定義,讓複雜系統反而變得簡單。

本文不談 DDD 的歷史或學術定義。我們從痛點出發,透過三個不同角色的視角,理解 DDD 如何一步步解決系統設計中的根本問題。


核心概念:DDD 的四大支柱

在深入故事前,先建立共同語言。DDD 的核心由四個緊密相連的概念構成:

1. 聚合根(Aggregate)- 業務規則的守門人

什麼是聚合根?

聚合根是一個領域對象,它負責確保其範圍內的所有業務規則都得以滿足。簡單說:聚合根就是一個自我保護的實體,它不允許違反業務規則的操作發生。

以訂單系統為例:Order(訂單)是聚合根。它管理著 OrderLineItem(訂單項目)、OrderDiscount(訂單折扣)等子對象。重要的是,Order 不會允許你直接修改 LineItem 的價格。所有的業務檢驗(折扣是否有效、庫存是否充足、客戶額度是否足夠)都由 Order 自己負責。

為什麼重要?

無聚合根的設計會導致業務邏輯分散: – Discount 服務驗證折扣有效性 – Customer 服務驗證客戶額度 – Inventory 服務驗證庫存 – Order 服務協調上述所有驗證

結果是:修改任何一個業務規則,都需要改多個地方。

有聚合根的設計集中化邏輯:

Order.applyDiscount(code) { // Order 內部檢驗所有規則 // 如果規則改變,只改 Order 類 }

聚合根的邊界與保護

graph LR
    User["🧑 外部調用者"]

    subgraph Agg ["📦 Order Aggregate"]
        Root["Order Aggregate Root"]
        Child1["LineItem Entity 1"]
        Child2["LineItem Entity 2"]
        Val["OrderDiscount Value Object"]
        Rules["✅ 驗證規則<br/>• 庫存檢查<br/>• 折扣合法性<br/>• 價格有效性<br/>• 客戶額度"]
    end

    User -->|只能調用<br/>applyDiscount 方法| Agg

    Root --> Child1
    Root --> Child2
    Root --> Val
    Root --> Rules

    BadWay["❌ 不允許<br/>直接修改<br/>LineItem.price"]
    User -.->|禁止| BadWay

    style Agg fill:#f3e5f5
    style Root fill:#9c27b0,color:#fff
    style Rules fill:#ce93d8
    style BadWay fill:#ffcdd2

2. 通用語言(Ubiquitous Language)- 跨角色溝通

什麼是通用語言?

開發者、產品經理、業務分析師用同一套詞彙討論系統。不是「我們的 Order Service」,而是「訂單聚合根」。不是「user table」,而是「客戶」。

這聽起來簡單,但威力巨大。當所有人都用「訂單無法在已支付後修改」而不是「post_status = 2 時不允許更新」時,理解變得即時且準確。

3. 限界上下文(Bounded Context)- 明確的邊界

什麼是限界上下文?

複雜系統往往跨越多個業務領域。購物車系統與訂單系統看似接近,但它們對「客戶」有不同的理解:

  • 購物車 BC:客戶 = ID + 購物偏好 + 瀏覽歷史
  • 訂單 BC:客戶 = ID + 收貨地址 + 支付方式

如果你試圖用同一個 Customer 對象服務兩個系統,結果就是:修改收貨地址時,購物車系統不需要但也被迫存儲了它。

DDD 的解決方案:每個限界上下文有自己的 Customer 定義。它們透過事件通信,而不是共享資料庫。

多個 Bounded Context 的獨立設計

graph LR
    subgraph Cart["🛒 Shopping Cart BC<br/>購物車上下文"]
        C["Customer"]
        C1["- CustomerID<br/>- 瀏覽歷史<br/>- 購物偏好"]
        C --> C1
    end

    subgraph Order["📦 Order BC<br/>訂單上下文"]
        O["Customer"]
        O1["- CustomerID<br/>- 收貨地址<br/>- 支付方式<br/>- 信用額度"]
        O --> O1
    end

    subgraph Payment["💳 Payment BC<br/>支付上下文"]
        P["Customer"]
        P1["- CustomerID<br/>- 銀行卡<br/>- 風險評分"]
        P --> P1
    end

    EventBus["📡 Event Bus<br/>鬆耦合通信"]

    Cart -->|公佈事件<br/>CartCreated| EventBus
    Order -->|公佈事件<br/>OrderPlaced| EventBus
    Payment -->|公佈事件<br/>PaymentSucceeded| EventBus

    EventBus -->|訂閱| Cart
    EventBus -->|訂閱| Order
    EventBus -->|訂閱| Payment

    style C fill:#c8e6c9
    style O fill:#f3e5f5
    style P fill:#fff3e0

4. 領域事件(Domain Event)- 異步解耦

什麼是領域事件?

當訂單被支付時,系統不應該直接調用「扣減庫存」、「發送發票」、「更新推薦引擎」。而是發佈一個事件:「訂單已支付」。

各個系統各自訂閱這個事件: – 庫存系統:聽到「訂單已支付」→ 扣減庫存 – 計費系統:聽到「訂單已支付」→ 生成發票 – 推薦系統:聽到「訂單已支付」→ 更新推薦模型

好處: 新增功能時無需修改訂單核心邏輯。只需訂閱事件即可。


三個角色的故事

故事 1:後端工程師的困境與救贖

人物: 李明,在線電商平台的後端工程師,2 年經驗

第一幕:陷阱

2024 年 Q1,公司決定支援「VIP 折扣」功能。李明接到這個任務,開始思考:

訂單處理流程: 1. 使用者下單 → 調用 OrderService.createOrder() 2. OrderService 檢驗庫存 → 調用 InventoryService.checkStock() 3. OrderService 計算總價 → 調用 PricingService.calculatePrice() 4. OrderService 應用折扣 → 調用 DiscountService.applyDiscount() 5. OrderService 檢驗客戶額度 → 調用 CustomerService.validateCredit()

新需求:VIP 客戶的折扣規則不同。李明的做法:

// 無 DDD 的做法

public class OrderService {

public Order createOrder(String customerId, List<Item> items) {

// 驗證庫存

inventoryService.checkStock(items);
// 計算價格

Money basePrice = pricingService.calculatePrice(items);
// 應用折扣

Money discountedPrice = discountService.applyDiscount(

  basePrice, customerId, getCurrentPromoCode()

);
// VIP 特殊折扣(新增)

if (customerService.isVIP(customerId)) {

  discountedPrice = discountedPrice.multiply(0.9);

  // 額外 10% 折扣

}
// 驗證客戶額度

customerService.validateCredit(customerId, discountedPrice);
// 儲存訂單

return orderRepository.save(new Order(...));

}

}

看起來合理。但 3 個月後,折扣規則變複雜了:

  • VIP 客戶在促銷期間折扣加倍
  • 新客戶首次購買有額外折扣
  • 組合商品有特殊折扣
  • 某些商品分類有上限折扣

OrderService 變成 500 行的怪物,每次改折扣規則都要小心翼翼地修改多個地方。而且,修改時容易破壞其他邏輯。

視覺化對比:無 DDD vs 有 DDD

graph TD
    A["需求:支持 VIP 折扣翻倍"]

    A --> B["修改 OrderService"]
    A --> C["修改 DiscountService"]
    A --> D["修改 PricingService"]
    A --> E["修改 CustomerService"]
    A --> F["修改 InventoryService"]

    B --> B1["調整訂單計算邏輯"]
    C --> C1["添加 VIP 折扣規則"]
    D --> D1["修改價格計算"]
    E --> E1["修改客戶驗證"]
    F --> F1["庫存檢驗邏輯"]

    B1 --> G["❌ 問題:"]
    C1 --> G
    D1 --> G
    E1 --> G
    F1 --> G

    G --> H["• 改一處壞一處<br/>• 難以測試所有組合<br/>• 每次修改都害怕<br/>• 新需求來臨再改..."]

    style A fill:#ffebee
    style G fill:#ffcdd2
    style H fill:#ff9800,color:#fff

第二幕:覺醒

李明參加了一個 DDD 工作坊。他開始重新思考:為什麼 Order 不能自己管理折扣邏輯?

引入 DDD 後的設計:

// DDD 的做法

public class Order {

private OrderId orderId;

private CustomerId customerId;

private List<LineItem> lineItems;

private OrderDiscount discount;

private OrderStatus status;

private List<DomainEvent> events = new ArrayList<>(); // 聚合根負責業務規則

public static Order create(CustomerId customerId, List<Item> items) {

Order order = new Order(OrderId.generate(), customerId);

// Order 自己驗證庫存(委託給 Domain Service)

order.validateItems(items);

// Order 添加訂單項目

for (Item item : items) {

  order.addLineItem(item);

}

return order;

} // 應用折扣 - 由 Order 自己決定

public void applyDiscount(DiscountCode code, Customer customer) {

// 驗證折扣有效性

if (!code.isValid()) {

  throw new InvalidDiscountException();

}

// 驗證客戶是否有權使用此折扣

if (customer.isVIP()) {

  // VIP 折扣規則

  this.discount = OrderDiscount.createVIPDiscount(code);

} else if (customer.isNewCustomer()) {

  // 新客戶折扣規則

  this.discount = OrderDiscount.createNewCustomerDiscount(code);

} else {

  // 普通折扣規則

  this.discount = OrderDiscount.create(code);

}

// 檢驗折扣後的價格是否在允許範圍

if (this.getTotalPrice().isNegative()) {

  throw new InvalidDiscountAmountException();

}

} // 下單 - 由 Order 確保一致性

public void place() {

// 最終檢驗:所有業務規則都滿足

if (lineItems.isEmpty()) {

  throw new EmptyOrderException();

}

if (!this.status.equals(OrderStatus.DRAFT)) {

  throw new InvalidOrderStatusException();

}

this.status = OrderStatus.PLACED;

// 發佈事件

this.events.add(new OrderPlacedEvent(

  this.orderId, this.customerId, this.getTotalPrice()

));

} // 獲取訂單總價(包含折扣)

public Money getTotalPrice() {

Money basePrice = lineItems.stream()

  .map(LineItem::getPrice)

  .reduce(Money.ZERO, Money::add);

if (discount != null) {

  return basePrice.minus(discount.getAmount());

}

return basePrice;

}

}

有 DDD:Order 聚合根自主管理

graph TD
    A["需求:支持 VIP 折扣翻倍"]

    A --> B["修改 Order.applyDiscount()"]

    B --> C["Order 聚合根自身驗證<br/>VIP 折扣規則"]

    C --> D["✅ 問題解決:"]

    D --> E["• 只改一個地方<br/>• Order 內部完整測試<br/>• 其他服務完全不受影響<br/>• 修改安全可控"]

    style A fill:#c8e6c9
    style B fill:#81c784,color:#fff
    style D fill:#4caf50,color:#fff
    style E fill:#a5d6a7

現在,修改折扣規則只需改 Order 類。新增 VIP 折扣?改 Order。新增組合商品折扣?改 Order。其他服務完全不受影響。

而且,Order 對象本身就是文件。新人看著 Order 類就能理解「訂單是如何工作的」。


故事 2:產品經理的協作變化

人物: 王經理,電商產品負責人

無 DDD 時的對話

王經理:「我們需要支援 VIP 客戶的特殊折扣。」

李明(工程師):「好的。這會影響 OrderService、DiscountService、PricingService、CustomerService。需要 2-3 週。」

王經理:「但這只是個折扣啊,為什麼要改 4 個 Service?」

李明:「因為折扣邏輯分散在多個地方…」

王經理:最後什麼都不懂,只能相信李明的估時。而且,修改變得很危險——改 OrderService 時可能無意中破壞了 DiscountService 的邏輯。

有 DDD 時的對話

王經理:「我們需要支援 VIP 客戶的特殊折扣。」

李明:「好的。這個邏輯完全在 Order 聚合根內,只需改 Order 類。5 個工作天。」

王經理:「為什麼只要改一個地方?」

李明:「因為我們用 DDD 設計了系統。Order 聚合根責任就是管理訂單的所有業務規則,包括折扣。修改只會影響 Order,不會波及其他服務。」

王經理:立即相信,而且能理解邊界。

另一個例子:新客戶首次購買有額外折扣

王經理:「新客戶首次購買要額外優惠 15%。」

李明:「需要改 Order 的 applyDiscount() 方法,加一個 Customer.isNewCustomer() 的判斷。3 天。」

王經理:「萬一改壞了怎麼辦?」

李明:「Order 類有完整的單元測試。所有折扣組合都有測試用例。改壞了測試會失敗,發佈前會被攔住。」

王經理:看到 Order 的測試:

@Test void 新客戶首次購買應該獲得額外折扣() { Order order = Order.create(customerId, items); Customer newCustomer = new Customer(customerId, CustomerType.NEW);
order.applyDiscount(promoCode, newCustomer);
// 驗證折扣是否正確應用 assertEquals(expectedDiscountAmount, order.getDiscount().getAmount()); }
@Test void VIP客戶應該獲得最高折扣() { Order order = Order.create(customerId, items); Customer vipCustomer = new Customer(customerId, CustomerType.VIP);
order.applyDiscount(promoCode, vipCustomer);
assertEquals(expectedVIPDiscountAmount, order.getDiscount().getAmount()); }

王經理的信心瞬間提升。他看到了業務邏輯的完整定義和完整的測試覆蓋。

需求評估的複雜度對比

graph TD
    Req["「支持新客戶首購 15% 折扣」"]

    subgraph NoDD ["❌ 無 DDD"]
        N1["評估影響:"]
        N2["需改 OrderService?"]
        N3["需改 CustomerService?"]
        N4["需改 DiscountService?"]
        N5["需改 PricingService?"]
        N6["...還要改別的嗎?"]

        N1 --> N2 --> N3 --> N4 --> N5 --> N6

        Result1["😕 王經理:為什麼<br/>這麼複雜?"]
        N6 --> Result1
    end

    subgraph DD ["✅ 有 DDD"]
        D1["評估影響:"]
        D2["Order 聚合根內<br/>applyDiscount() 方法"]
        D3["檢查客戶類型<br/>newCustomer?"]
        D4["應用 15% 折扣規則"]

        D1 --> D2 --> D3 --> D4

        Result2["😊 王經理:明白了!<br/>就改 Order 一個地方"]
        D4 --> Result2
    end

    Req --> NoDD
    Req --> DD

    style Result1 fill:#ffcdd2,color:#c62828
    style Result2 fill:#c8e6c9,color:#2e7d32

故事 3:系統架構師的拆分之痛

人物: 張架構師,負責系統從單體向微服務的遷移

無 DDD 時的微服務化困境

公司決定拆分微服務。張架構師的計畫:

  • 購物車微服務(購物車邏輯)
  • 訂單微服務(訂單邏輯)
  • 支付微服務(支付邏輯)
  • 推薦微服務(推薦邏輯)

問題:四個微服務都需要用 Customer 對象。但 Customer 的定義是什麼?

購物車需要:使用者 ID、購物車項目、購物偏好 訂單需要:使用者 ID、收貨地址、支付方式 支付需要:使用者 ID、信用卡資訊、風控額度 推薦需要:使用者 ID、瀏覽歷史、購買歷史

如果四個服務都共享一個 Customer 對象,任何改動都會引發連鎖反應:

  • 購物車加了「購物偏好」欄位
  • 訂單服務也被迫更新 Customer schema
  • 支付服務也被迫更新 Customer schema

改著改著,Customer 變成了包含所有欄位的怪物,每個服務都用不到 80% 的欄位,卻要為它們付出維護成本。

有 DDD 時的微服務化

張架構師改變了思路:定義限界上下文。

購物車 BC (Bounded Context):
  - Cart(購物車聚合根)
    - CartItem
    - CustomerReference (只含 ID)
  - CartPreference(購物偏好)

訂單 BC:

  • Order(訂單聚合根)
    • OrderLineItem
    • ShippingAddress
    • BillingInfo
    • CustomerReference (只含 ID)

支付 BC:

  • Payment(支付聚合根)
    • PaymentMethod
    • RiskScore
    • CustomerReference (只含 ID)

推薦 BC:

  • RecommendationProfile(推薦配置聚合根)
    • BrowsingHistory
    • PurchaseHistory
    • CustomerReference (只含 ID)

每個 BC 有自己的 Customer 概念。它們不共享資料庫,而是透過事件通信:

購物車 BC 發佈事件: – “CartCreated” → 推薦 BC 訂閱,更新瀏覽歷史

訂單 BC 發佈事件: – “OrderPlaced” → 庫存 BC 訂閱,扣減庫存 – “OrderPlaced” → 計費 BC 訂閱,生成發票 – “OrderPlaced” → 推薦 BC 訂閱,更新推薦模型

支付 BC 發佈事件: – “PaymentSucceeded” → 訂單 BC 訂閱,更新訂單狀態 – “PaymentFailed” → 訂單 BC 訂閱,標記支付失敗

結果:

  1. 每個微服務獨立演變:購物車想加新欄位?只改購物車 BC,其他服務不受影響。

  2. 通信清晰:透過事件而不是 API 呼叫,系統更鬆散耦合。

  3. 故障隔離:推薦服務掛了,不會影響訂單流程。

  4. 擴展簡單:想加新功能(如積分系統)?加一個新 BC,訂閱相關事件即可,無需改現有代碼。

從單體到微服務的演進

graph TD
    A["問題:如何分離成<br/>多個微服務?"]

    subgraph BadWay ["❌ 錯誤做法:共享 Customer 模型"]
        B1["所有服務共用<br/>一個 Customer 表"]
        B2["購物車加欄位<br/>↓ 所有服務更新"]
        B3["訂單加欄位<br/>↓ 所有服務更新"]
        B4["...每個服務都<br/>只用 20% 的欄位<br/>卻維護 100% 的複雜度"]

        B1 --> B2 --> B3 --> B4
    end

    subgraph GoodWay ["✅ DDD 做法:分離 Bounded Context"]
        G1["購物車 BC 擁有<br/>自己的 Customer"]
        G2["訂單 BC 擁有<br/>自己的 Customer"]
        G3["支付 BC 擁有<br/>自己的 Customer"]

        G1 -.->|Event| EventBus["📡<br/>Event<br/>Bus"]
        G2 -.->|Event| EventBus
        G3 -.->|Event| EventBus

        EventBus -.->|Subscribe| G1
        EventBus -.->|Subscribe| G2
        EventBus -.->|Subscribe| G3
    end

    A --> BadWay
    A --> GoodWay

    BadWay --> Result1["😞 單體地獄<br/>改不了"]
    GoodWay --> Result2["😊 微服務天堂<br/>獨立演進"]

    style BadWay fill:#ffebee
    style GoodWay fill:#e8f5e9
    style Result1 fill:#ff5252,color:#fff
    style Result2 fill:#4caf50,color:#fff

常見誤區

誤區 1:DDD = 微服務

錯誤: DDD 需要微服務,或者用了微服務就是在用 DDD。

真相: DDD 是設計思想,可用於單體應用或微服務。一個良好設計的單體應用完全可以用 DDD。反之,拆成微服務但沒用 DDD 反而會增加複雜度。

實例: 只有 Order 和 Customer 兩個主要業務的小公司,用單體 + DDD 比微服務更簡單。

誤區 2:DDD = 複雜框架

錯誤: DDD 需要特殊框架和工具。

真相: DDD 是純粹的設計思想。Order、LineItem、DiscountCode 都是普通的 Java 類。框架是輔助,不是 DDD 本身。

誤區 3:所有項目都要用 DDD

錯誤: DDD 是銀彈,所有項目都該用。

真相: DDD 的收益來自於複雜的業務邏輯。如果你的系統業務規則簡單(如 CRUD API),DDD 反而是過度設計。

評估清單:你的項目適合 DDD 嗎?

  • 業務邏輯複雜(超過 50 個業務規則或用例)→ 適合
  • 多個團隊並行開發 → 適合
  • 業務規則頻繁變化 → 適合
  • 只是簡單的 CRUD API → 不適合
  • 無人長期維護 → 不適合

誤區 4:DDD = 過度設計

錯誤: DDD 會讓系統變複雜。

真相: DDD 的目標是簡化複雜系統。是的,引入 DDD 需要更多初始思考,但它是為了減少未來的複雜度和維護成本。

對比:

無 DDD:100 行簡單 Service → 6 個月後變成 2000 行怪物 有 DDD:200 行設計 + 結構 → 6 個月後仍然清晰,修改容易


實踐指導:如何開始

第一步:識別限界上下文(不要寫代碼)

用 30 分鐘,與業務人員一起列出:

  1. 所有的業務角色:客戶、客服、倉管、財務… 2. 所有的主要流程:下單、支付、退貨、推薦… 3. 概念在不同流程中的變化:「客戶」在下單流程中是什麼?在推薦流程中是什麼?

例如: – 訂單 BC:客戶 = 收貨地址 + 支付方式 – 推薦 BC:客戶 = 瀏覽歷史 + 購買偏好

第二步:定義通用語言

寫一個簡短的詞彙表,確保開發者、PM、業務都用同一套術語。例如:

訂單 (Order): 客戶購買商品的記錄,包含商品、數量、折扣、支付方式

折扣碼 (DiscountCode): 特定條件下可應用於訂單的優惠

聚合根 (Aggregate Root): 邊界內所有業務規則的守護者

第三步:設計核心聚合根

從最複雜的業務流程開始。以訂單系統為例,Order 是聚合根,它包含:

  • OrderLineItem(子對象)
  • OrderDiscount(子對象)
  • 所有業務規則檢驗

第四步:寫測試,然後寫代碼

@Test void 訂單應該驗證折扣碼有效性() { Order order = Order.create(customerId, items); InvalidDiscountCode code = new InvalidDiscountCode();
assertThrows(InvalidDiscountException.class, () -> order.applyDiscount(code, customer) ); }
@Test void VIP客戶應該獲得額外折扣() { Order order = Order.create(customerId, items); DiscountCode code = new DiscountCode("VIP2024"); Customer vipCustomer = new Customer(customerId, CustomerType.VIP);
order.applyDiscount(code, vipCustomer);
Money expectedDiscount = basePrice.multiply(0.2); // 20% 折扣 assertEquals(expectedDiscount, order.getDiscount().getAmount()); }

測試寫好了,業務邏輯就明確了。然後實現 Order 類來通過測試。


完整工作流程示範

訂單處理的 DDD 流程

sequenceDiagram
    actor User as 用戶
    participant OrderBC as Order BC<br/>聚合根
    participant InventoryBC as Inventory BC
    participant BillingBC as Billing BC
    participant RecommendBC as Recommend BC

    User->>OrderBC: 下單<br/>Order.create()
    activate OrderBC

    OrderBC->>OrderBC: ✅ 檢驗庫存<br/>✅ 檢驗折扣<br/>✅ 檢驗額度

    OrderBC->>OrderBC: 發佈事件<br/>OrderPlaced
    deactivate OrderBC

    Note over OrderBC: Order 作為完整的<br/>業務規則守護者<br/>所有驗證在此完成

    OrderBC->>InventoryBC: OrderPlaced 事件
    OrderBC->>BillingBC: OrderPlaced 事件
    OrderBC->>RecommendBC: OrderPlaced 事件

    par 並行異步處理
        activate InventoryBC
        InventoryBC->>InventoryBC: 監聽 OrderPlaced<br/>異步扣減庫存
        InventoryBC-->>User: 庫存已扣
        deactivate InventoryBC
    and
        activate BillingBC
        BillingBC->>BillingBC: 監聽 OrderPlaced<br/>異步生成發票
        BillingBC-->>User: 發票已生成
        deactivate BillingBC
    and
        activate RecommendBC
        RecommendBC->>RecommendBC: 監聽 OrderPlaced<br/>異步更新推薦模型
        RecommendBC-->>User: 推薦已更新
        deactivate RecommendBC
    end

DDD 的核心價值

graph LR
    subgraph Before ["無 DDD<br/>散落的邏輯"]
        B1["Service A"]
        B2["Service B"]
        B3["Service C"]
        B4["Service D"]
        B5["Service E"]

        B_logic["❌ 業務規則<br/>散落在各處"]

        B1 --- B2
        B2 --- B3
        B3 --- B4
        B4 --- B5
    end

    subgraph After ["有 DDD<br/>聚集的規則"]
        A1["Aggregate Root<br/>🏛️"]
        A_logic["✅ 業務規則<br/>集中管理"]

        A2["其他服務"]
    end

    Before -->|引入 DDD| After

    style B_logic fill:#ff5252,color:#fff
    style A_logic fill:#4caf50,color:#fff

總結

DDD 不是銀彈,但對於複雜業務系統,它是正確的藥。它的核心承諾是:透過清晰的邊界與角色,讓複雜系統變得簡單。

關鍵收穫:

  1. 聚合根集中化業務邏輯:修改時不會波及系統各處 2. 限界上下文明確邊界:不同業務領域有獨立的概念定義 3. 領域事件實現解耦:新功能無需修改核心邏輯 4. 通用語言統一溝通:開發者、PM、業務用同一套詞彙

下一步,選擇你最複雜的業務流程,嘗試用 DDD 重新設計它。你會發現,原本糾纏的邏輯變得清晰,修改變得安全。

Leave a Comment