部分邊界 (Partial Boundaries)#
建立完整的架構邊界(Full Architectural Boundaries)是昂貴的。 它需要雙向的多型介面(Reciprocal Polymorphism)、獨立的輸入/輸出資料結構(Input/Output Data Structures),以及繁瑣的依賴管理(版本控制、獨立編譯、獨立部署)。
這是一個典型的兩難:
- YAGNI (You Aren’t Gonna Need It): 如果現在不需要,過早建立完整邊界是過度設計(Over-engineering)。
- 未來擴展: 如果完全沒有邊界,未來需要時再拆分會極其困難。
折衷方案就是**「部分邊界(Partial Boundaries)」**。架構師可以透過以下三種方式來保留未來的可能性,同時降低當下的成本。
一、三種部分邊界策略#
1. 省略最後一步 (Skip the Last Step)#
這是最常見的作法。
- 作法: 完成建立完整邊界所需的所有程式碼工作(定義介面、分離資料結構、依賴反轉),除了最後一步:分開部署。
- 結構: 將所有東西放在同一個元件(Same Component / Same .jar)中。
- 優點: 結構已經分好了,未來要拆分只需把類別移到新的 jar 檔即可。省去了版本追蹤與多重編譯的麻煩。
- 缺點(隨著時間): 因為缺乏編譯器的強制力(都在同個 jar 裡),開發者很容易因為貪圖方便而寫出越過邊界的依賴。久而久之,分離度會減弱,邊界會模糊。
2. 單維邊界 (One-Dimensional Boundary)#
使用標準的 Strategy 模式。
- 作法: 使用一個簡單的
Service介面,讓 Client 依賴它,而 ServiceImpl 實作它。 - 簡化: 省略了完整邊界中所需的「雙向介面」,只保留單向依賴。
- 缺點(反向通道): 因為結構簡單,很容易形成「反向通道(Backchannel)」。
- 例如:
ServiceImpl開始依賴Client傳遞特定的參數,這導致兩者產生隱性的耦合。
- 例如:
[Image of Strategy Pattern Diagram]
3. 外觀模式 (Facade Pattern)#
這是更簡化的作法,甚至連依賴反轉(DIP)都省略了。
- 作法: 定義一個
Facade類別,它列出了所有服務的方法。Client 只呼叫 Facade,Facade 再將請求轉發給後後的 Service 類別。 - 優點: 隱藏了系統的複雜性。
- 缺點(傳遞依賴):
- 這是違反 DIP 的。Client 雖然只看到 Facade,但實際上它傳遞依賴(Transitive Dependency) 了 Facade 背後的所有類別。
- 如果 Service 修改了原始碼,Client 可能也需要重新編譯。
二、架構師的職責:監控退化#
所有的部分邊界都有一個共同的風險:退化(Degradation)。 因為它們都不是「完整」的邊界,隨著時間推移,分離性都會逐漸降低。
- 判斷: 架構師必須判斷哪裡需要邊界,以及要實作「完全」還是「部分」邊界。
- 監控: 如果選擇了部分邊界,架構師必須時刻關注其狀態。一旦發現依賴關係開始混亂(反向通道出現、邊界被侵蝕),就必須決定是否將其升級為完整邊界。
總結: 部分邊界是一種「買保險」的策略。 它允許你在不支付全額成本(獨立部署)的情況下,獲得大部分的架構優勢(解耦)。但你必須有紀律地維護它,否則它終將崩壞。