🎯 什麼情境該想到我
當你「系統裡有一塊邊界不清、模型混亂、無法(或不值得)用乾淨模型去救的既有區域」的時候。你需要務實地承認它、把它圈起來,並防止它的混亂蔓延污染其他部分。
⚙️ 怎麼用(步驟 / 公式)
意圖:辨識既有系統中模型混雜、邊界模糊的區塊,明確地把它整個圈成「一個」限界上下文,接受它內部沒有乾淨模型,並築牆阻止它向外蔓延污染其他上下文。
做法要點:
- 在上下文對應上誠實標出這團混亂,把它整塊劃為一個大泥球上下文。
- 不要嘗試在裡面套用嚴謹的領域模型或通用語言——對它降低期望。
- 在它與外界之間建立防腐層,防止它的混亂概念滲進其他乾淨上下文。
- 集中精力守護外部乾淨區域;對泥球本身採維持現狀、必要時逐步收斂的策略。
★★ Evans 的用法很特別:它是一個「地圖標記」,不是一個罵人的詞
★★ 在 [[上下文對應]] 上,「大泥球」是一個正當的標記:
★ 「這一塊沒有清楚的模型邊界、概念混雜、我們不打算在裡面做 DDD」
→ ★ 它的價值是:★★ 明確劃出它的範圍,★ 並在邊界上建立防護
→ ★★ 而不是「我們要重寫它」(★ 那通常不會發生)
★★ 這是這一頁最重要的觀念轉換:
★ 大泥球不是一個「待修的 bug」,而是一個要被管理的現實。
★★ 你的目標不是消滅它,是「不讓它擴散」。
★★ 三個可觀察的特徵(用來判斷「這塊是不是大泥球」)
① ★★ 同一個名詞在同一塊程式碼裡有多種意義
★ 「用戶」有時指登入帳號、有時指付款人、有時指收件人
→ ★ 而且沒有任何型別區分它們(★★ 全部是 string userID)
② ★★ 不變式無處可尋
★ 「已出貨不可取消」這條規則在五個地方各檢查一次,★ 而其中兩個寫錯
→ ★ 判準:★★ 你能指出「這條規則的唯一守點」嗎?不能 → 大泥球
③ ★★ 任何改動的影響範圍無法預測
★ 改一個欄位 → ★ 不知道會影響什麼,只能靠 QA 全面回歸
→ ★ 這是最實際的判準:★★ 「你敢不敢改?」
★★ 邊界防護:這是唯一真正有效的策略
★ 四個具體動作(★ 按投資報酬率排序):
① ★★ 在邊界建立 [[防腐層]](★ 最重要)
★ 新的上下文絕不直接 import 大泥球的型別
→ ★★ 用 depguard 讓它變成 CI 紅燈
→ ★ 這一步的價值:★★ 大泥球的混亂「止步於此」
② ★★ 把大泥球當成一個外部系統看待
★ 它有一組(可能很醜的)API/資料表 → ★ 你只透過那組介面用它
→ ★★ 心態轉換:★ 不要試圖「理解它的模型」,★ 只要知道「怎麼跟它講話」
③ ★★ 用 [[工具-特徵測試]] 圍住你要改的那一小塊
★ 不理解它 → ★ 先寫測試記錄「它現在做什麼」
→ ★★ 這是 [[修改程式碼的藝術]] 的核心手法(見 [[工具-遺留程式碼修改流程]])
④ ★ 新功能一律放在新的上下文裡
→ ★★ 這是「不讓它擴散」最直接的手段
→ ★ 見 [[工具-服務邊界與演進式拆分]] 的絞殺者模式
★★ ①的具體做法:
# ★ depguard:新的上下文不得 import legacy
depguard:
rules:
newcontexts:
files: ["**/internal/ordering/**", "**/internal/billing/**"]
deny: [{ pkg: "myapp/internal/legacy" }]★★ 什麼時候不該碰它(★ 這是最務實的一段)
★★ 大泥球值不值得整理,看三件事:
① ★ 它「會不會改」?
★ 一年改兩次 → ★★ 不要碰。★ 整理它的成本永遠收不回來
② ★ 它「會不會擴散」?
★ 已經圍住了(有防腐層、新功能不進去)→ ★★ 讓它待著
③ ★★ 它是不是核心子領域?
★ 是 → ★ 那它遲早要處理(★★ 核心不該是大泥球)
★ 不是 → ★ 圍住它就夠了
★★ 判準:★ 「不改它會出事嗎?」
不會 → ★★ 不要碰。 ★ 這不是逃避——它是把有限的力氣放在會回本的地方。
★ 最常見的錯誤是「重寫」:★★ 重寫一個大泥球的成功率極低,
因為它的複雜度大部分來自「那些你不知道的業務規則」,
而那些規則只存在於它的程式碼裡。
★★ 如果它確實必須處理:一條可行的路徑
第 1 步 ★★ 圍住它(防腐層 + depguard + 新功能不進去)← ★ 先止血
第 2 步 ★★ 用特徵測試記錄現有行為(★ 從「最常改的那一塊」開始)
第 3 步 ★ 從邊緣切出一小塊到新的上下文(★ 絞殺者模式)
第 4 步 ★★ 讓大泥球的那一塊變成對新上下文的轉發
第 5 步 ★ 重複 3–4,★★ 而且每一步都可以停在那裡
★★ 「每一步都可以停」是這條路徑的關鍵性質:
★ 它讓「重構遺留系統」變成一個可以隨時因為優先順序改變而暫停的計畫,
而不是一個必須做完才有價值的大工程。
★ 兄弟辨析
🧪 我實際套用的紀錄
- (待填)
⚠️ 注意 / 什麼時候不適用
-
它是一種務實的「承認現實」,不是鼓勵製造爛系統;別把它當成放任亂寫的藉口。
-
不要在泥球內部投入大量心力硬做乾淨建模,投報通常很差;重點在「圈住+隔離」。
-
若這塊其實是核心領域,長期仍需規劃重寫或拆解,不能永遠只圈著。
-
★★ 大泥球在上下文對應上是一個正當的「地圖標記」,不是罵人的詞。目標不是消滅它,是「不讓它擴散」。
-
★★ 判準:「不改它會出事嗎?」不會 → 不要碰。 一年改兩次的東西,整理成本永遠收不回來。
-
★★ 重寫的成功率極低,因為它的複雜度大部分來自「那些你不知道的業務規則」,而那些規則只存在於它的程式碼裡。
-
★★ 邊界防護(防腐層 + depguard + 新功能不進去)是唯一真正有效的策略。
-
★★ 心態轉換:把它當成一個外部系統——不要試圖理解它的模型,只要知道怎麼跟它講話。
-
★★ 「每一步都可以停」是遷移路徑的關鍵性質,讓它變成可暫停的計畫而非必須做完的大工程。
-
★ 判準:你能指出「這條規則的唯一守點」嗎? 不能 → 大泥球。
-
★ 核心子領域不該是大泥球,那遲早要處理;不是核心的,圍住就夠了。
-
★ 不理解它就先寫 工具-特徵測試 記錄現有行為,不要靠閱讀推測。
🔗 相關工具
- 限界上下文 Bounded Context(把泥球整塊劃為一個上下文)
- 防腐層 Anticorruption Layer(阻止泥球污染外部的隔離牆)
- 上下文對應 Context Map(在地圖上誠實標出這團混亂)
- 領域驅動設計
- 防腐層 —— ★ 邊界防護的主要手段
- 各行其道 —— 刻意清楚的邊界
- 限界上下文 —— 大泥球就是沒有邊界的區塊
- 上下文對應 —— 標記它的地方
- 過大類別 —— 類別層級的同一現象
- 工具-特徵測試、工具-遺留程式碼修改流程 —— 處理它的手法
- 工具-服務邊界與演進式拆分 —— 絞殺者模式