耦合是什麼#
「耦合(coupling)」常被當成爛設計的代名詞,於是工程師的直覺就是「全部解耦」——拆分類別、模組、服務或整個系統,期望換來獨立演進的自由。但這真的是對的方向嗎?
從詞源來看,coupling 源自拉丁文 copulare(co-「一起」+ apere-「繫緊」),意思就是「繫在一起」、「連結」。

Figure 1.1: 「coupling」一詞的詞源
看到「coupled」就把它替換成「connected」。「兩個服務是耦合的」等於「兩個服務是連結的」。
耦合無所不在:齒輪與彈簧連結成鐘錶、引擎與輪軸連結成車輛、器官連結成生物、粒子連結成宇宙萬物,連天體之間都因引力而保持耦合。
耦合的強度(Magnitude)#
耦合的強度反映「相連元件之間的相互依賴程度」:連結越強,維護所需的成本越高。即便所謂「鬆耦合」,元件之間仍然彼此影響,無法完全獨立。
在軟體設計中,耦合強度越高,元件越常需要「一起被修改」。造成這種「一起改」的根源有兩個:共享生命週期(shared lifecycle) 與 共享知識(shared knowledge)。
共享生命週期#
最直接的耦合就是把元件綁在同一個生命週期裡。例如同一個 Payments 與 Authorization 模組:
- 共置於 monolith 中:必須一起測試、一起部署、一起維護,生命週期耦合度高
- 抽出成兩個獨立服務(如
Billing與Identity & Access):各自可以獨立開發與部署,生命週期耦合度降低

Figure 1.2: 將模組共置於同一封裝邊界會增加生命週期耦合
除了封裝邊界(encapsulation boundary)之外,還有許多結構性與組織性因素會耦合元件的生命週期,這些會在 Chapter 8(距離)中深入討論。
共享知識#
要協同工作,耦合元件必然得共享某些知識。共享越多,連動修改越多。書中以 CustomersService 模組依賴 repository 為例:
MySQLRepository:名稱直接洩漏「使用 MySQL」這個實作細節,要換成記憶體版本就得改CustomersService- 依賴
IRepository介面(暴露BeginTransaction、ExecuteSQL):封裝了「具體是 MySQL」這件事,但仍洩漏「屬於關聯式資料庫」這個事實,換成 key-value 資料庫照樣要改 - 依賴
IRepository介面(暴露Save、Query):連「關聯式資料庫」都封裝起來,可換的範圍大幅擴張

Figure 1.3: 不同設計共享的知識量不同
共享知識可以是隱性的(implicit)。元件可能對作業系統版本、特定硬體做出未明說的假設,這些都是潛在的耦合點。
知識的流向(Flow of Knowledge)#
為了討論方便,作者建立一套貫穿全書的詞彙,描述知識在元件間的流動方向。
考慮 Distribution 元件依賴 CRM 元件的情境:
Distribution必須了解CRM的整合介面、功能與運作細節- 也就是說,知識的流向跟依賴方向相反:依賴指向
CRM,但知識從CRM流向Distribution
書中以「上游/下游」描述這個流動:
- 上游元件(upstream):提供功能給其他元件使用,介面對外暴露其知識
- 下游元件(downstream):消費上游元件提供的功能,必須吸收上游介面所共享的知識
在上述例子中,CRM 是上游、Distribution 是下游(或者說 Distribution 是 CRM 的消費者)。

Figure 1.4: 知識在耦合元件之間的流向
系統的構成#
要理解耦合在系統中的角色,得先定義「系統」。Donella H. Meadows 在 Thinking in Systems: A Primer 中的經典定義是:
系統是一組互相連結的元素,被組織起來以達成某個目的。
這個定義點出系統的三個核心構成:元件(components)、連結(interconnections) 與 目的(purpose)。
軟體本身就是「由系統組成的系統」:
- 巨觀層級:服務、應用、排程作業、資料庫等元件耦合起來,達成業務功能
- 中觀層級:每個服務都是系統,由實作功能的類別組成
- 微觀層級:類別本身也是系統,由方法與變數組成;甚至一個方法都可以視為由語句組成的系統

Figure 1.5: 典型軟體系統的組成元件
軟體系統這種層層巢套的「層級結構」是貫穿全書的母題,最終會在 Chapter 12「軟體設計的碎形幾何」中收束。
系統三要素的相互依賴#
齒輪只有放對位置才能讓鐘錶運作。系統的三個要素彼此緊密相連:

Figure 1.6: 鐘錶的組成元件
- 目的決定需要哪些元件、需要怎樣的互動
- 元件介面決定哪些整合方式可行,元件功能決定系統能否達成目的
- 互動透過協調元件,讓系統真正完成目的
改動三要素的任何一個,必然牽動其他至少一個。改變系統的目的,就得修改元件,而元件改變又會引發互動方式的變化。

Figure 1.7: 系統的核心要素彼此互相依賴
這也帶出系統設計的另一個關鍵概念——邊界(boundaries)。引用 Ruth Malan 的話:
System design is inherently about boundaries (what’s in, what’s out, what spans, what moves between) and about tradeoffs.
元件的邊界定義了:
- 哪些知識屬於這個元件、哪些不屬於
- 哪些功能由它實作、哪些責任交給其他元件
- 元件之間如何互動,哪些知識能跨越邊界
為什麼不能完全解耦#
「完全解耦」是個迷思。如果兩個元件需要協同工作,它們就一定要共享知識——互動本身就需要知識共享。沒有互動就沒有耦合,沒有耦合就無法達成系統的目的。
軟體工程師常把焦點放在「拆盒子」——把業務領域分解成服務、模組、物件。但盒子之間的「線」至少同樣重要。設計什麼知識能跨邊界、如何跨邊界、影響為何,才是設計的真正核心。
必要與意外的耦合#
耦合是把系統黏在一起的膠水,但盲目引入依賴並不會產生好設計。耦合分為兩類:
- 必要的耦合(essential coupling):來自系統目的本身,是不可避免的
- 意外的耦合(accidental coupling):來自不當設計,可以被消除
模組化設計的工作就是「消除意外耦合,謹慎管理必要的相互依賴」。
機械工程中的耦合(補充)#
機械製造中也有類似概念。製造的接合零件不可能完全精確無誤差,因此設計時會給連接點預留容差(tolerance):
- 容差過大 → 連接不可靠
- 容差過小 → 無法吸收製造誤差

Figure 1.8: 透過耦合接點設計連接的兩個零件
軟體設計中的耦合也是同樣道理:「剛剛好」最重要。
重點整理#
評估程式碼時,常問自己這兩個問題:
- 元件需要知道其他元件的什麼,才能協同工作?這些共享知識若改變,影響範圍有多大?
- 哪些元件僅僅因為跟易變元件「同生命週期」才被連帶測試與部署?
本章的核心訊息:耦合不該被當成「壞設計」的同義詞,而是設計工具。真正讓系統失控、讓程式碼陷入泥沼的力量另有其名——複雜度(complexity),這是下一章的主題。