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