打破架構邊界:三種簡單卻高效的實現方法!
構建完整的架構邊界的成本是很高的。需要為系統設計雙向多態的邊界接口、輸入和輸出數據結構以及所有必要的依賴管理,以便將兩個部分隔離為可獨立編譯和部署的組件。這涉及大量的工作和后期維護。
許多情況下,一個好的架構師可能會認為設置這樣的邊界的開支太高,但仍然希望為以后可能需要的邊界留下位置。
這種預判性設計常常被敏捷社區中的許多人指責為違反 YAGNI(你不會需要它)原則。然而,架構師可能會看到問題并想到:“是啊,但是我可能會需要’在這種情況下,他們可能會實現一個不完全邊界。
一、跳到最后一步
構造不完全邊界的一種方法是將系統分割成一系列可以獨立編譯和部署的組件,之后再把它們組合成一個組件。換言之,將相應的接口和輸入/輸出數據結構都設置好,并且一切都已準備妥當,但我們仍選擇將這些組件編譯和部署為單個組件。
顯然,這種不完全邊界需要與完全邊界同樣數量的代碼和設計工作。但是它不需要管理多個組件。沒有版本號跟蹤或發布管理負擔。這一差異不容忽視。這是 FitNesse 的早期策略。FitNesse 的網絡服務器組件被設計為可與 FitNesse的 wiki 和測試部分分離。這樣,我們就可以使用該網絡組件創建其他基于 Web 的應用程序。同時,我們不希望用戶下載兩個組件。請記住,我們的一個設計目標是“下載并運行”。我們的意圖是用戶下載一個jar 文件并執行它,而不必尋找其他 jar 文件,解決版本兼容性等問題。
FitNesse 的經歷也揭示了這種方式的其中一個危害。隨著時間的推移,人們逐漸認識到不再需要單獨的 Web 組件,Web 組件和 wiki 組件之間的分離開始變得脆弱。依賴關系開始朝著錯誤的方向交叉?,F在,重新分離它們可能會是一項煩瑣的任務。
二、單向邊界
完全成熟的架構邊界使用雙向邊界接口來保持雙向隔離。維護這種雙向的隔離性,通常不會是一次性的工作,需要我們持續投入資源。
圖 24.1 顯示了一個更簡單的結構,用于暫時保留以后擴展為完全邊界的位置它展示了傳統的策略模式。serviceBoundary(服務邊界)接口由客戶端使用并由 serviceImpl(服務具體實現)類實現。
上述設計顯然為未來的架構邊界打下了基礎。為了將 Client(客戶端)與ServiceImpl隔離開來,必須進行必要的依賴反轉。同時,我們清楚看到分離可能會相當迅速地降級,如圖示中的惡意虛線所示。由于沒有雙向接口,除了依賴開發人員和架構師的勤勉和自律,沒有任何事物可以防止這種反向通道的出現。
三、外觀
一個更簡單的邊界是外觀模式,如圖24.2所示。在這種情況下,不需要使用依賴反轉。該邊界僅由 Facade(外觀)類定義,該類將所有服務列為方法,并將服務調用部署到客戶端不應訪問的類中。
請注意,客戶端對所有這些服務類都具有傳遞性依賴。在靜態語言中,對其中一個服務類源代碼的更改將強制客戶端重新編譯。此外,你可以想象使用此結構創建反向通道是多么容易。
我們已經看到了部分實現不完全邊界的三種簡單方法。當然,還有很多其他方法。這三種策略僅作為示例提供。
這些方法中的每一種都有其自己的成本和收益。在特定的情況下,每種方法都是適宜的,作為一個最終完全邊界的替代方案。如果該邊界從未實現,則每種方法都可能會受到損害。