📌 30 秒摘要(Layer 3)

面對複雜業務,最大的敵人不是技術而是領域的複雜度。DDD 主張把重心放在「領域模型」:開發者與領域專家用同一套通用語言溝通,並讓程式碼直接反映這套語言。再用限界上下文切開大系統、用實體/值物件/聚合組織模型,讓模型在各自邊界內保持一致與清晰。

🗺 心智圖(Canvas)

領域驅動設計

領域驅動設計 DDD

Eric Evans|用領域模型馴服業務複雜度

⚡ 即用工具 三張可直接上手的卡

🎯 什麼情境該想到我

分工:這張是提醒卡。怎麼在 Go 型別系統中落實通用語言、三個容易漏掉的邊界、建立它的三個具體動作 → 通用語言(型錄頁)。

當工程師與業務/PM「講的是同一件事卻用不同詞」、需求翻成程式碼常失真時。

⚙️ 怎麼用

  1. 建立一套團隊 + 領域專家共用的詞彙:一個概念一個名字,全員(含文件、對話、程式碼)都用它。
  2. 讓程式碼直接反映這套語言:類別/方法名 = 領域術語,讀 code 像讀業務。
  3. 發現詞彙模糊或衝突,就當場澄清並更新——語言的演進就是模型的演進。
  4. 詞彙若在不同脈絡意義不同 → 那是要切 工具-限界上下文 的訊號。

★ 三個自我檢查問題

  1. 業務人員說的詞,能在程式碼裡搜尋到嗎? 業務說「退貨」,程式碼裡卻叫 ReverseTransaction → 語言斷了,翻譯的地方就是 bug 的溫床。
  2. 同一個詞在程式碼裡只有一個意思嗎? Account 在帳務模組是「會計科目」、在會員模組是「登入帳號」→ 這是兩個工具-限界上下文的訊號,要分開建模,而不是做一個萬用的 Account。
  3. 程式碼裡有沒有業務聽不懂的詞? OrderManager、ProcessData、status = 3 → 這些是技術詞或魔術值,業務無法確認它們對不對。

★ 最小的實踐

  • 在 repo 裡放一份活的詞彙表(例如 CONTEXT.md 或 docs/glossary.md),每個詞寫一句定義與一個反例(「退貨 ≠ 取消訂單:取消發生在出貨前」)。
  • code review 時把「命名與詞彙表不一致」當成正式的審查意見。
  • 詞彙表要跟著討論更新;會議中出現新詞或爭議詞時,當場記下來。

🧪 我實際套用的紀錄

  • 2026-07-14:(待填)

⚠️ 注意

  • 通用語言要「活」在日常溝通與程式碼裡,不是一份放著長灰塵的詞彙表。

🔗 相關工具

  • Skills For Real Engineers —— 通用語言的 agent 版:把行話寫進 CONTEXT.md,除了溝通一致,還讓 agent 少花 token 思考、更好導航 codebase
  • 工具-限界上下文 —— 配套概念,通用語言只在一個上下文內成立,跨上下文同詞可以不同義
  • 工具-有意義的命名 —— 落到程式碼那一步,通用語言的詞要原封不動出現在型別與方法名上

🎯 什麼情境該想到我

當系統/模型越長越大越糊,或發現「同一個名詞在不同部門意義不同」時。

⚙️ 怎麼用

  1. 劃出邊界:在某個邊界內,一套模型與 工具-通用語言 保持一致、無歧義。
  2. 一個詞在不同上下文意義不同 → 就該分成不同上下文(例:「商品」在銷售 vs 物流意義不同)。
  3. 用 Context Map 描述上下文之間的關係(上下游、防腐層 ACL、共享核心…)。
  4. 邊界也是團隊、部署(含微服務拆分)的自然切點。

★ 核心洞察:同一個詞,在不同上下文是不同的東西

「訂單 Order」
  銷售上下文:客戶、商品、金額、折扣          ← 關心「賣了什麼」
  倉儲上下文:SKU、數量、重量、儲位            ← 關心「拿什麼出貨」
  財務上下文:應收金額、稅、發票號碼、帳期      ← 關心「錢怎麼算」

❌ 建一個「統一的 Order 模型」滿足三方
   → ★ 30 個欄位,每一方只用 10 個,但每次改動都要三方一起 review
   → 這就是「統一模型」必然的下場

★ 限界上下文的主張是反直覺的:不要追求統一模型,而是承認「同一個名詞有多個模型」,並明確劃出邊界。
邊界內:術語一致、模型統一(這就是 工具-通用語言)。
邊界外:透過明確的轉換來往,不共用模型。

★ 怎麼找出邊界(四個實用訊號)

訊號說明
★ 語言的斷裂同一個詞在兩群人口中意思不同 → 那裡就是邊界
★ 一起改變的東西用 git log 看哪些檔案總是一起被改(見 工具-影響分析)
★ 組織結構不同團隊負責的部分天然會形成邊界(工具-康威定律)
交易一致性的需求★ 必須在同一個交易裡的東西,不該跨上下文

★ 最後一條特別重要:如果你發現「切開之後需要分散式事務」,
那八成是切錯了(見 工具-分散式事務的取捨)。

★ 上下文之間的七種關係(上下文對應 Context Map)

關係意思何時
★ 防腐層 ACL我方寫一層翻譯,把對方的模型轉成我的★ 對方模型很糟或會變時的標準做法
開放主機服務 OHS我提供一個公開的、穩定的協定給所有下游下游很多時
發布語言 PL用一個大家同意的中介格式(Protobuf schema、事件定義)配合 OHS
客戶-供應商下游能影響上游的排程同公司內
追隨者下游完全接受上游的模型,不做轉換★ 上游穩定且模型合用時(省事,但耦合)
共享核心兩個上下文共用一小塊模型與程式碼⚠️ 要非常小心,見下
各行其道完全不整合沒有整合需求時

★ 共享核心是最危險的一個:

共用的那一塊同時屬於兩個團隊,改它要兩邊同意。
它會慢慢長大,最後變成一個誰都不敢改的巨石。
→ 預設用防腐層;只在「共用的部分極小且極穩定」時才考慮共享核心。

★ 邊界 ≠ 微服務

限界上下文  = ★ 邏輯邊界(模型與語言的邊界)
微服務      = ★ 部署邊界(可獨立部署的單元)

★ 一個限界上下文「可以」是一個微服務,但不必是。
在單體裡用模組/套件劃出限界上下文,是完全正確且通常更務實的做法
——你拿到了模型的清晰,卻不用付分散式系統的代價。

★ 先在單體內劃清邊界,等邊界被驗證穩定了,再考慮拆成服務(見 工具-服務邊界與演進式拆分)。

★ 實際長什麼樣(Go)

internal/
  sales/          ← ★ 限界上下文
    order.go        type Order struct { CustomerID, Items, Discount ... }
  warehouse/      ← ★ 另一個限界上下文
    order.go        type Order struct { SKUs, Weight, Location ... }   ★ 同名不同型別,這是對的
    acl.go          ★ 防腐層:把 sales 的事件翻譯成 warehouse 的模型
  billing/
    invoice.go

★ 關鍵:warehouse 不 import sales 的型別,只透過事件或 ACL 取得它需要的資訊。
這可以用架構測試自動驗證(見 工具-好萊塢原則與依賴反轉)。

🧪 我實際套用的紀錄

  • 2026-07-14:(待填)

⚠️ 注意 / 什麼時候不適用

  • ★ 小系統不需要。整個團隊五個人、一個產品、術語一致 → 一個上下文就好。
    限界上下文解決的是「不同群人對同一個詞有不同理解」的問題——沒有這個問題就不需要它。
  • ★ 一開始就切邊界通常會切錯。你還不夠了解領域。
    → 先寫成一個模組化的單體,讓邊界在實作中浮現(見 工具-服務架構的演進與拆分)。
  • ★ 「重複」是刻意的,不是疏失。兩個上下文各有一個 Order,這不是違反 DRY——
    它們是不同的概念碰巧同名(見 工具-DRY原則 對「知識的重複 vs 程式碼的重複」的區分)。
    硬要合併才是錯的。
  • 邊界要有人守。沒有 review 紀律或架構測試,import 會慢慢穿透邊界,最後回到泥球。
  • 上下文對應要畫出來並維護。它是團隊之間的契約,不是一張畫完就丟的圖。
  • 不要為了「以後好拆微服務」而過度切割。切太細會讓每個改動都要跨好幾個上下文。

🔗 相關工具

🎯 什麼情境該想到我

分工:這張是三選一的快速判準。三個建構區塊各自的完整展開——判準、Go 的實作方式、常見錯誤、兄弟辨析 → 實體、值物件(DDD)、聚合。

當你在設計領域模型的結構,猶豫「這東西該有身分嗎、一致性邊界該畫在哪」時。

⚙️ 怎麼用(三個建構區塊)

  1. Entity(實體):有唯一身分、生命週期中即使屬性變了仍是「同一個」(如:一個訂單)。
  2. Value Object(值物件):沒有身分,只看值是否相等、不可變(如:金額、地址)。優先用值物件,簡單又安全。
  3. Aggregate(聚合):一組相關物件的一致性邊界,有一個 Aggregate Root 當唯一入口;外部只能透過 root 改動內部,交易一次只改一個聚合。

★ 30 秒判斷流程

這個東西需要被「追蹤」嗎?(屬性全變了,它還是「同一個」嗎?)
├─ 否 → 值物件(金額、地址、日期區間、座標)
│       → 不可變、用值比較、自帶驗證
└─ 是 → 實體(訂單、使用者、帳戶)
        → 它和哪些東西必須「同時」保持一致?
            ├─ 有一條規則同時涉及它和其他物件 → 把它們放在同一個聚合,選一個當根
            └─ 沒有 → 它自己就是一個聚合(最常見的情況)

★ 最常見的三個誤判

誤判症狀改法
所有東西都做成實體到處是 ID 欄位、Address 也有自己的資料表和 ID問「它被單獨追蹤嗎?」——地址通常不是
聚合畫太大一個 Customer 聚合包含所有訂單;每次下單都要鎖整個客戶從真正的不變式反推邊界;訂單自己是一個聚合,用客戶 ID 參照
在一個交易裡改兩個聚合下單同時扣庫存,兩個聚合在同一個交易裡一個交易只改一個聚合;其他用領域事件達成最終一致

「從不變式反推邊界」的完整方法、跨聚合一致性三種做法的代價 → 聚合。

🧪 我實際套用的紀錄

  • 2026-07-14:(待填)

⚠️ 注意

🔗 相關工具

  • 工具-限界上下文 —— 上位邊界,聚合畫在上下文之內,先有上下文才知道聚合該多大
  • 工具-通用語言 —— 命名來源,實體與值物件的名字要跟業務講的詞一致,否則模型會慢慢失真

🧱 建構元件 Building Blocks(9)

[[實體|實體 Entity]] ・ [[值物件(DDD)|值物件 Value Object]] [[聚合|聚合 Aggregate]] ・ [[儲存庫(DDD)|儲存庫 Repository]] [[工廠|工廠 Factory]] ・ [[領域服務|領域服務 Domain Service]] [[領域事件|領域事件 Domain Event]] ・ [[模組|模組 Module]] [[規格|規格 Specification]]

🗺 戰略設計 Strategic Design(6)

[[通用語言|通用語言 Ubiquitous Language]] [[限界上下文|限界上下文 Bounded Context]] [[上下文對應|上下文對應 Context Map]] [[核心子領域|核心子領域 Core Domain]] [[支撐子領域|支撐子領域 Supporting Subdomain]] [[通用子領域|通用子領域 Generic Subdomain]]

🔗 上下文對應模式 Context Map Patterns(9)

[[合作關係|合作關係 Partnership]] ・ [[共享核心|共享核心 Shared Kernel]] [[客戶-供應商|客戶-供應商 Customer-Supplier]] ・ [[追隨者|追隨者 Conformist]] [[防腐層|防腐層 Anticorruption Layer]] [[開放主機服務|開放主機服務 Open Host Service]] [[發布語言|發布語言 Published Language]] [[各行其道|各行其道 Separate Ways]] ・ [[大泥球|大泥球 Big Ball of Mud]]

Link to original

🧰 這本書給我的工具(即用快速工具)

📖 完整型錄(詳解在 reference/)

🧱 建構元件 Building Blocks

🗺 戰略設計 Strategic Design

🔗 上下文對應模式 Context Map Patterns

✨ 關鍵重點(Layer 1–2)

  • 模型驅動設計:程式碼與領域模型緊密對應,模型即設計。
  • 通用語言(Ubiquitous Language):團隊與專家共用同一套詞彙,貫穿討論與程式碼。
  • 限界上下文(Bounded Context):明確劃定某模型有效的邊界;跨界用 Context Map 對應。
  • 建構區塊:Entity(有身分)、Value Object(無身分只看值)、Aggregate(一致性邊界)、Repository、Factory、Service。
  • 精煉:區分核心領域與支撐子域,把心力投在核心。

💬 金句原文(Layer 0)

  • 「模型與設計的核心互相塑造。」
  • 「複雜性應對之道,在於一個好的領域模型。」

🔗 相關