DDD 分層架構:有效降低層與層之間的依賴

什麼是 DDD 分層架構?

DDD(領域驅動設計)的分層架構經歷了持續的演進。最初是經典的四層架構;隨後,四層架構得到了進一步優化,實現了各層與基礎設施層的解耦;再到後來,在領域層和應用層之間引入了上下文環境(Context)層,從而形成了五層架構(DCI,Data-Context-Interaction)

讓我們來看一下這張圖。在最早的傳統四層架構中,基礎層(Infrastructure Layer)被其他層所依賴,位於架構的核心位置。然而,按照分層架構的設計思想,領域層(Domain Layer)纔是軟件的核心,因此這種依賴關係顯然存在問題。爲了解決這一問題,我們引入了依賴倒置原則(Dependency Inversion Principle, DIP),對傳統的四層架構進行了優化,成功實現了各層對基礎層的解耦。

我們今天講的 DDD 分層架構就是優化後的四層架構。在下面這張圖中,從上到下依次是:用戶接口層、應用層、領域層和基礎層。那 DDD 各層的主要職責是什麼呢?下面我來逐一介紹一下。

1. 用戶接口層

用戶接口層的主要職責是向用戶展示信息並解釋用戶指令。這裏的 “用戶” 不僅限於人類用戶,還包括程序、自動化測試腳本以及批處理腳本等。

2. 應用層

應用層是一個相對較薄的層次,理論上不應包含具體的業務規則或邏輯,而是專注於用例和流程相關的操作。它位於領域層之上,負責協調多個聚合的服務和領域對象,完成服務的編排和組合,從而執行業務操作。此外,應用層也是微服務之間交互的通道,能夠調用其他微服務的應用服務,實現跨微服務的服務組合和編排。

需要注意的是:在設計和開發過程中,應避免將本應屬於領域層的業務邏輯錯誤地放到應用層中實現。如果應用層過於龐大,會導致領域模型失去焦點,久而久之,微服務可能會退化爲傳統的三層架構,業務邏輯變得混亂不堪。

應用服務位於應用層,其職責包括:

3. 領域層

領域層是實現企業核心業務邏輯的關鍵層次,通過各種校驗手段確保業務的正確性。它主要體現領域模型的業務能力,用於表達業務概念、業務狀態和業務規則。領域層包含聚合根、實體、值對象、領域服務等領域模型中的核心對象。

領域對象的關係說明

4. 基礎層

基礎層貫穿於所有層次,其主要職責是爲其他各層提供通用的技術支持和基礎服務。這些服務包括但不限於:

其中,數據庫持久化是基礎層最常見的功能之一。

基礎層通過依賴倒置設計,封裝基礎資源服務,實現應用層、領域層與基礎層的解耦。這種設計能夠有效降低外部資源變化對應用的影響。

DDD 分層架構最重要的原則是什麼?

DDD 分層架構有一個重要的原則:每層只能與位於其下方的層發生耦合。

根據耦合的緊密程度,架構可以分爲兩種類型:嚴格分層架構鬆散分層架構

DDD 分層架構如何推動架構演進?

  1. 微服務架構的演進

我們瞭解到領域模型中對象的層次從內到外依次爲:值對象實體聚合限界上下文

當聚合發生重組或拆分時,業務模塊和系統功能往往會隨之發生變化。因此,我們可以以聚合爲基礎單元,推動領域模型和微服務架構的演進。

具體來說:

  1. 聚合的重組或拆分
    聚合可以作爲一個整體,在不同的領域模型之間進行重組或拆分。這種調整能夠更好地適應業務需求的變化。

  2. 聚合獨立爲微服務
    在某些情況下,可以直接將一個聚合獨立爲一個微服務。這種方式能夠進一步提升系統的靈活性和可維護性。

當你發現微服務 1 中聚合 a 的功能經常被高頻訪問,以致拖累整個微服務 1 的性能時,我們可以把聚合 a 的代碼,從微服務 1 中剝離出來,獨立爲微服務 2。這樣微服務 2 就可輕鬆應對高性能場景。

在業務發展到一定程度以後,你會發現微服務 3 的領域模型有了變化,聚合 d 會更適合放到微服務 1 的領域模型中。這時你就可以將聚合 d 的代碼整體搬遷到微服務 1 中。如果你在設計時已經定義好了聚合之間的代碼邊界,這個過程不會太複雜,也不會花太多時間。

最後我們發現,在經歷模型和架構演進後,微服務 1 已經從最初包含聚合 a、b、c,演進爲包含聚合 b、c、d 的新領域模型和微服務了。

  1. 微服務內服務的演進

在微服務內部,實體的方法被領域服務組合和封裝,領域服務又被應用服務組合和封裝。在服務逐層組合和封裝的過程中,你會發現這樣一個有趣的現象。

讓我們來看一下這張圖。在服務設計時,你可能無法完全預測哪些下層服務會被多少個上層服務組合調用。因此,領域層通常只提供一些原子服務,例如領域服務 a、b、c。

然而,隨着系統功能的增強和外部接入的增多,應用服務會不斷豐富。某一天,你可能會發現領域服務 b 和 c 被多個應用服務頻繁調用,且它們的執行順序基本一致。這時,你可以考慮將 b 和 c 合併,並將應用服務中 b 和 c 的功能下沉到領域層,演變爲一個新的領域服務(b+c)。

這種演進方式不僅減少了服務的數量,還降低了上層服務組合和編排的複雜度。

三層架構如何演進到 DDD 分層架構?

通過前面的講解,相信你已經對 DDD 分層架構的優勢有了清晰的認識。我們可以總結出以下兩個最重要的優點:

  1. 層間松耦合
    DDD 分層架構通過解耦各層之間的依賴關係,使得我們可以專注於本層的設計,而無需過多關注其他層。這種設計不僅降低了層與層之間的耦合度,還避免了因某一層的改動而影響其他層的情況。

  2. 結構清晰,易於升級和維護
    分層架構使程序結構更加清晰,升級和維護變得更加容易。當我們需要修改某一層的代碼時,只要該層的接口參數保持不變,其他層通常無需進行任何改動。即使某一層的接口發生變化,也只會影響其直接相鄰的上層,修改工作量較小且風險可控,不會引發意外的系統問題。

那我們該怎樣轉向 DDD 分層架構呢?不妨看看下面這個過程。

傳統企業應用大多是單體架構,而單體架構則大多是三層架構。三層架構解決了程序內代碼間調用複雜、代碼職責不清的問題,但這種分層是邏輯概念,在物理上它是中心化的集中式架構,並不適合分佈式微服務架構。

DDD 分層架構中的要素其實和三層架構類似,只是在 DDD 分層架構中,這些要素被重新歸類,重新劃分了層,確定了層與層之間的交互規則和職責邊界。

讓我們來看一下這張圖,分析從三層架構向 DDD 分層架構演進的過程。

1. 演進的核心區域

從三層架構向 DDD 分層架構的演進,主要集中在業務邏輯層數據訪問層

2. 用戶接口層的變化

DDD 分層架構在用戶接口層引入了 DTO(數據傳輸對象),爲前端提供了更多的可用數據,並提升了展示的靈活性。

3. 業務邏輯層的優化

DDD 分層架構對三層架構的業務邏輯層進行了更清晰的劃分,解決了三層架構中核心業務邏輯混亂、代碼改動相互影響大的問題。具體來說:

4. 數據訪問層的改進

在數據訪問層和基礎層之間,DDD 分層架構引入了倉儲(Repository)設計模式,取代了三層架構中的 DAO 方式。倉儲模式通過依賴倒置原則,實現了各層對基礎資源的解耦。倉儲分爲兩部分:

此外,三層架構中通用的第三方工具包、驅動、Common、Utility、Config 等公共資源類,在 DDD 分層架構中被統一放到了基礎層

5. 演進的意義

傳統三層架構向 DDD 分層架構的演進,體現了領域驅動設計思想的逐步成熟和應用。這種演進不僅優化了架構的分層設計,還提升了系統的靈活性、可維護性和可擴展性。

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/o33Z_AsNgltXLP84afUunQ