近年來,「服務導向架構(SOA)」與「微服務(Microservices)」變得極為流行。人們普遍認為服務架構能帶來強大的解耦與獨立性。
但 Uncle Bob 在這章潑了一盆冷水:服務(Service)只是種物理運作機制,而非邏輯上的架構邊界。
一、服務架構的兩大迷思#
1. 解耦的幻覺 (The Decoupling Fallacy)#
- 迷思: 因服務在不同行程(Process)或伺服器上執行,透過網路通訊,所以它們彼此嚴格解耦
- 現實: 服務間往往透過共享資料(Shared Data) 產生強烈耦合
- 如果你修改了服務間傳遞的 JSON 資料欄位,或更糟的是,多個服務共享同個資料庫 Schema,那它們就完全沒有解耦
- 這種「邏輯上的耦合」遠比「物理上的分離」更重要
2. 獨立開發部署的幻覺 (The Independent Development/Deployment Fallacy)#
- 迷思: 將系統拆成小服務,就能讓團隊獨立開發、部署
- 現實: 這只有在服務邊界與架構邊界一致時才成立
- 橫切關注面(Cross-Cutting Concerns): 如果一個新功能(例如:Uber 新增「載運寵物」服務)
需同時修改 UI 服務、計費服務、司機媒合服務,那麼這些團隊就無法獨立行動。
他們須協調、同時部署,這就是所謂的「分散式單體(Distributed Monolith)」。
- 橫切關注面(Cross-Cutting Concerns): 如果一個新功能(例如:Uber 新增「載運寵物」服務)

Figure 27.1: Services for taxi aggregator system
二、物件導向的救贖:多型#
要解決上述問題,我們不能依賴「服務」這種物理邊界,而須回歸「元件」設計原則。
1. 服務內部的元件化#
我們不該把服務寫成一整塊程式碼(Monolith)。服務內部應由遵循依賴規則的元件組成。
我們可以利用 Template Method 或 Strategy 模式,創造出可擴展結構。

Figure 27.2: Object-oriented approach for cross-cutting concerns

Figure 27.3: Each service has its own internal component design
2. 符合 OCP 的擴展#
如果架構設計得當(基於 SOLID 原則),新增功能(如「載運寵物」)應只需:
- 建立新元件(Jar/Dll)
- 擴展既有抽象類別
- 將新元件加入服務的載入路徑
- 結果: 我們不需修改舊服務程式碼,而是以插件(Plugin) 的方式擴充服務

Figure 27.4: Services with internal component architectures
三、架構邊界 vs. 服務邊界#
這是本章最核心的觀念:「架構邊界不在服務間,而是貫穿服務並分解它們。」
- 錯誤觀點: 服務 A 是邊界,服務 B 是另個邊界
- 正確觀點:
- 架構邊界(如:使用案例層、實體層)可能會同時存在於服務 A 和 B 之中
- 服務只是個容器
- 為處理由橫切關注面帶來的問題,我們須將服務設計成由內部元件組成
架構是由邏輯邊界(依賴反轉、穩定的介面)定義的,而不是由物理機制(服務通訊方式)定義的。
你可選擇將元件打包成單一程式(Monolith),也可打包成多個服務(Microservices),
這只是部署選項的差異,而不應影響核心架構的設計。