4+2 分層架構 - Ricardo

banq發表於2022-09-13

應用於軟體架構的關注點分離,這個4+2 分層架構提案是對clean Architecture的改進,僅公開了領域業務規則最相關的概念以及介面 API與注入實現的使用。

介紹
許多原則推動了軟體開發,而關注點分離可能是最基本的,許多其他原則都源自於它。函式派生自它。類、物件和方法都派生自它。模組化和分層架構源自它。
在類的微觀維度中,關注點分離意味著一些“最佳實踐”,例如:不要在同一方法中混合抽象級別;不要在同一個方法和類中混合職責。
更進一步,關注點分離推動了模組化,告訴我們將業務規則和領域模型與資料訪問和使用者介面分開。告訴我們在庫中分離相關和可重用的程式碼。
關注點分離也是我們的目標,即使用允許模組可插入和可測試的介面/實現策略來管理低耦合的依賴關係。中央模組介面定義API,而提供者模組實現這些API,使兩個模組都可獨立測試。
在本文中,我將重新審視分層架構,並提出一個精緻的檢視,只展示最重要的概念。

分層架構和依賴注入
當應用於軟體架構時,這一原則是許多分層架構的基礎,這些架構從模型檢視控制器 (MVC) 演變為模型檢視展示器 (MVP)、六邊形架構、洋蔥架構⁴和清潔架構⁵等。
最初的Clean Architecture提案由 Robert Martin (Uncle Bob) ⁵在 2012 年提出,它使用 Ivar Jacobson ²、Steve Freeman 等人的軟體工程概念描繪了層。Bob Martin 指出,所有這些先前的架構都有相同的目標:關注點分離以產生以下系統:

  • 獨立於框架
  • 可測試
  • 獨立於 UI
  • 獨立於資料庫
  • 獨立於外部機構

4+2 分層架構 - Ricardo

上圖羅伯特馬丁論文的原始影像

但是在這些架構提案中存在一個概念上的挑戰,即內層對外層“一無所知” 。這實際上是正確分層的靜態依賴要求:層應該只依賴於內層型別。這是“必須遵守”的規則!
另一方面,在執行時內層確實依賴於外層提供的實現。例如,域用例確實依賴於來自外部持久層的資料儲存庫實現。
這個挑戰透過依賴倒置原則或更具體地透過依賴注入機制“解決” ,其中內部類被注入其依賴的外部實現。更籠統地說,我們可以說:“在執行時,內部層配置有眾所周知的介面的未知實現”。
1978 年,Trygve Reenskaug 在 Xerox PARC ¹為 Smalltalk 設計 MVC 架構時,首先使用了這種使用注入實現的控制反轉機制。然後它被廣泛用於 Smalltalk-80 語言和環境。
唐納德·華萊士 (Donald Wallace) 在 1980 年也在施樂 PARC 為 Mesa 專案開發元件時,稱其為好萊塢定律的應用——“不要打電話給我們,我們會打電話給你”。
大約在 1994 年,Bob 叔叔使用了Dependency Inversion Principle的表達方式,並在 2004 年 Martin Fowler 創造了Dependency Injection 一詞。

重新審視清潔Clean架構
這種分層概念隨著技術和經驗的發展而成熟,總是朝著元件之間的更少耦合方向發展,有效地變得更加可測試、靈活和適應性強。
我想重新審視清潔架構並提出一個分層檢視,它揭示了我稱之為4+2 分層架構中最重要的概念,它包含:
4個主要層次:

  • 領域層(業務規則)
  • 資料層(永續性)
  • 服務層(外部服務)
  • 表示層(UI)

2 個附件層:
  • 核心層(共享庫)
  • 依賴注入層(依賴倒置)

4+2 分層架構 - Ricardo

上圖4+2分層架構

這與以前的分層架構並沒有背離,而是一次回顧,一方面提出了更通用的層定義(未提及 Web、控制器和其他框架或技術解決方案),另一方面明確定義了核心領域概念,即介面/實現的使用和依賴注入的必要性。

讓我們詳細看看這些層:

領域層
包含獨立於基礎設施和表示的核心概念和規則。它表示為應用程式建模的狀態和行為。它包含以下概念:

  • 實體
  • 業務邏輯(用例、驗證器、異常)
  • 資料儲存庫介面
  • 服務介面

該層不靜態依賴於外部定義(型別),但在執行時它可能依賴於滿足其內部介面定義的注入實現(依賴倒置原則)。
這種低耦合結構使該中央層無法抵禦外部變化,從而建立了一個高度可測試且獨立的元件。

資料層
包含永續性基礎設施實現和介面卡。它可能包含:

  • 資料模型
  • 模型/實體對映器
  • 資料儲存庫實現(永續性)

再一次,關注點分離提出了一個可測試和可插拔的模組,可以滿足內部領域層介面的要求。
有時這一層可能會有替代實現,例如支援不同的資料庫。每個實現都可以獨立測試。所選擇的替代方案將由依賴注入機制選擇。
替代實現並不總是那麼簡單,因為特定的解決方案可能會影響內層 API 中的定義。這違背了內層獨立性的提議,但我們可能不得不處理它。例如,一些永續性框架使用非同步呼叫,而另一些是同步的,這樣的改變很可能需要在整個應用程式中重新定義。但是由於我們組織得很好,我們的影響點也很明確,通常在介面和用例級別。

服務層
這是一個可選層,用於對資料永續性之外的外部依賴項進行建模,例如對 Web 服務、遠端裝置、硬體等的訪問。
當應用程式不依賴外部服務時,該層將被省略,成為3+2 分層架構變體。

表示層
這是呈現資訊並與使用者互動的層。它僅取決於內層定義的型別,主要取決於Domain Use Cases、Entities和Exceptions。正是介面和實現注入的“魔力”使得這一層可以在執行時使用資料和服務層提供的程式碼。
這個層的內部組織非常依賴於框架,這裡的主要概念是沒有其他層依賴於這一層,並且可以實現多個表示替代方案並獨立執行。例如,同一個應用程式可能會提供一個 Web UI、一個移動 UI 和一個桌面 UI,它們都使用相同的域用例。

核心層
這個附屬層也是可選的,它是一個模組,用於組織不屬於域層但必須廣泛用於應用程式的公共介面和實用程式類和函式。

依賴注入層
這是最外層;它將包含依賴注入機制。根據語言和庫的不同,這可能只是配置檔案(XML、JSON 等)。在其他平臺上,該層可能包含 DI 程式碼以程式設計方式配置內部層。
作為最外層,它將具有檢視所有應用程式程式碼的不良能力。一些語言確實提供了控制內部層可見性的方法,允許每個層只公開所需的API和實現(原則“讓正確的事情變得容易,讓錯誤的事情變得困難”)。

層間關係
我們已經提到內層不應該依賴於外層的型別,並且在執行時內層可以配置有眾所周知的介面的外部實現。
在這裡,關注點分離提醒我們,我們應該使用促進層獨立性的機制來最小化一層相對於其他層的知識。Gilad Bracha 的新話語言³使用巢狀類,因此巢狀了沒有全域性範圍的名稱空間,是模組化和依賴項提供的漂亮實現。
在基於類或物件的語言中,透過為每個層實現層管理器物件來應用關注點分離會很有趣,該物件將顯式公開其層依賴關係並在注入所需實現時配置其模組。我還為這個4+2 分層架構的Flutter實現製作了一個補充文件和影片教程,它將這個原理與 AppLayer 物件應用於層間互動;結構化實現可作為公共 github 模板專案⁶

更大的應用
在大型領域中,我們的4+2 分層架構命題將解決領域宇宙的特定背景。關注點分離表明應該將大型應用程式劃分為有凝聚力的互連模組。然後將使用4+2 分層架構方法單獨開發每個模組。

測試
測試是基礎,並已成為許多軟體開發實踐(敏捷、測試驅動、持續整合)的標準。應用程式架構是允許和促進有效可測試性的關鍵元件。
人們普遍希望在我們的測試中獲得最大的程式碼覆蓋率,但這通常是一把雙刃劍——大量的測試會導致重構程式碼的大量工作;大量的測試通常會驅動大量的複製/貼上開發(無意識測試)。
我們首先需要對使用者故事進行良好的測試覆蓋,探索業務規則和邊界案例,通常針對模擬實現或配置的依賴項(眾所周知的行為)。
其次,我們需要測試實現 API(黑盒測試)。再次,使用邊界情況和眾所周知的依賴關係。
這種分層架構確實透過強制大多數層間互動確實依賴於用例(業務規則)和實現 API來提高可測試性。

結論
分層架構是將關注點分離應用於應用程式結構的結果。這個4+2 分層架構提案是對Clean Architecture的改進,僅公開了領域業務規則最相關的概念以及介面 API與注入實現的使用。

案例原始碼
 

相關文章