深度解析DDD中臺和微服務設計

本文來源於 2020 年第四屆 DDD 中國峯會主題演講:《當中臺遇上 DDD,如何設計微服務》。DDD 非常強調統一語言,而 DDD、中臺與微服務產生於不同的時代,三者分別屬於不同的方法體系,而方法論的融合首要在於建立統一語言,
那 DDD、中臺和微服務的通用語言到底在哪裏?
如何用 DDD 完成中臺和微服務設計實戰?
DDD 在中臺和微服務的整體設計流程是什麼樣的?

隨着業務發展,領域模型和微服務會不斷變化和演進,如何用最小代價來適應因爲業務變化,而帶來的領域模型和微服務演進?希望你能在本文找到答案!

1

建立 DDD、中臺和微服務的統一語言

1.1

中臺回顧

我們先簡單回顧一下中臺的發展歷程,2017 年《企業 IT 架構轉型之道:阿里巴巴中臺戰略思想和架構實戰》出版後,中臺就受到業界熱捧。中臺的出現是爲了解決以往煙囪式和單體架構的重複開發、數據分散和試錯成本高的問題,也是爲了提高企業市場響應能力,解決巨型企業由於產品種類繁多、部門林立和溝通困難,而導致的商業模式創新難的問題。

但由於不同行業企業之間存在着巨大的差異,所以阿里的成功經驗並不那麼容易複製到其他企業。而且由於早期缺少案例、工具和方法論的指引,加之個別企業的翻車案例,很多企業也開始思考,如何結合企業自身特點,才能更好地完成中臺數字化轉型?近兩年來,隨着越來越多的成功案例、方法論探索和經驗的沉澱和總結,中臺慢慢進入成長和穩定期,也從爭議逐漸變爲事實。

中臺在實踐過程中被賦予了太多的涵義,比如中臺組織架構和中臺運營等內容,這些內容會由於企業不同而在落地時出現非常大的差異。今天我們主要從業務視角,來分析中臺的領域建模和微服務落地。

從企業架構角度來講,業務中臺屬於業務架構的範疇。與普通的項目不同,中臺是企業級的,所以首先要從頂層設計開始,做好抽象、標準化和能力複用設計。傳統企業在實施中臺時,其策略也會與阿里有所不同。

阿里主要集中在通用中臺建設,實現企業級能力複用,解決重複造輪子的問題。而傳統企業由於產品、業務多樣性和多渠道展業的需要,對於企業核心能力需要有更強的靈活性和多渠道複用能力。比如在保險業,意外險可以在傳統櫃檯、航運或汽運站、官網、toC 的 APP 或者融入第三方平臺以及旅遊網站進行展業銷售。所以,傳統企業除了建設通用中臺,還需要建立核心能力中臺,解決不同渠道核心能力重複建設的問題。

核心能力中臺主要面向企業核心業務領域,面向不同渠道和客戶實現核心能力複用,發揮企業核心競爭力作用。通用能力中臺則主要面向可共享的公共業務領域,通過抽象和標準化,面向所有業務板塊實現通用能力複用。

中臺是一種基於業務能力複用目的而提出的思想或理念,它的技術實現手段可以很多,企業可根據自身技術特點靈活選擇,可以採用單體架構也可以採用微服務架構。不能說採用微服務纔是中臺,而採用單體方式就不是中臺。阿里剛開始做中臺時,微服務其實也是剛提出沒多久,所以阿里早期的中臺建設應該也是採用單體架構的方式來實現的。不過,隨着雲計算和微服務等分佈式技術的成熟,微服務已經逐漸成爲中颱的最佳技術實現。

從整個企業業務域來看,通用能力中臺和核心能力中臺本質上是企業業務架構中的某一個子業務板塊,在中臺設計時需要遵循可複用、單一職責和高內聚松耦合原則,完成企業級業務領域的分解和重構。在業務板塊劃分時,可以根據屬性不同而被區分爲通用能力中臺和核心能力中臺。所以,企業業務中臺重構的本質上就是:“基於企業級能力複用目的的業務架構重構”。

1.2

DDD 如何處理高度複雜領域

DDD 解決複雜問題的過程,體現的是一種“分而治之”的思想。當我們遇到問題時,如果能力大於問題,直接用能力解決就可以了。而如果能力小於問題,那應該怎麼辦?

一般有兩種方法用來解決這類複雜問題:

第一,我們可以提高解決問題的能力,使得能力大於問題的難度,這樣問題就可以解決。

第二,採用降低問題難度的方式。將問題的難度降低到自己的能力之下,這樣能力就大於問題難度了,所以問題也可以解決。當能力有限時,我們可以拆分問題,一直拆分到能力大於問題爲止。這樣,問題也自然就解決了!

過去在業務規模不大時,我們一般採用傳統集中式架構來解決業務能力的問題,所以那時候單體應用非常流行。而隨着大量高頻海量互聯網業務場景的出現,如果將集中式架構的能力挖掘到極限,仍然不足以解決業務和應用擴展能力問題時,那麼我們就可以基於分佈式架構將原來的單體應用拆分爲多個微服務,進而上雲實現應用的彈性伸縮和業務擴展能力。所以當能力有限時,我們可以通過分解問題空間,降低問題複雜度的方式,來解決業務擴展能力的問題。

總之,DDD 和微服務都是處理高度複雜領域的設計思想!

我們來看一下複雜領域知識體系建立的一般方法。當遇到複雜問題時,我們可以按照一定規則不斷將問題空間逐級細分,採用分治策略,分別爲不同的子域求解,並建立知識體系。然後將各個子域知識體系的解合併,最終建立整個領域的知識體系。

那是否有相應的方法來指導完成問題空間的拆分?

1.3

領域分解及子域屬性定義

我們以保險領域爲例,大致瞭解一下 DDD 領域的分解過程。比如,我們可以按照保險關鍵流程環節或功能聚合,並結合領域經驗來完成保險領域細分,將複雜的保險領域拆分爲如圖所示的若干個子域。

在完成子域細分後,我們會根據子域自身的重要性和功能屬性將這些子域劃分爲三類,分別是:核心子域、通用子域和支撐子域。決定企業核心競爭力的是核心子域,核心子域一般會對應核心產品或關鍵業務環節,如承保。被多個子域複用的是通用子域,通用子域一般對應某個單一職責的功能聚合,如支付。另外,那些企業必須的,既不是企業核心競爭力,也不會被其他子域複用的子域是支撐子域。

你可能會問:爲什麼要區分這些子域的屬性呢?這是因爲當企業資源有限時,我們需要針對不同的子域制定不同的戰略資源投入策略,從而可以確保將關鍵資源投入到核心子域,以此來持續保持企業的核心競爭力。

而在將這些子域映射到中臺時,核心子域需要關注不同渠道的適配和複用能力,而通用子域則需要重點關注標準化和抽象化設計,以確保構建出的通用能力模型可以面向企業所有業務板塊實現能力複用。

在完成從領域到子域的劃分後,我們可以在子域內採用事件風暴,找出限界上下文完成領域建模。然後按照限界上下文邊界來拆分微服務,並找出微服務內聚合以及領域對象之間的依賴關係。在不同的層設計服務,進行服務組合和編排,完成微服務的分層和解耦設計。如下圖所示。

所以 DDD 問題解決的整體過程就是:從問題空間出發,逐級抽象,層層深入和細化,從業務的宏觀到技術的微觀整體考慮,最終完成領域建模和微服務落地。

1.4

從業務視角建立 DDD 與中臺的統一語言

在瞭解了中臺和 DDD 的問題域分解和建模的過程後,我們就可以從業務視角來建立 DDD 與中臺的統一語言了。

一般來說,中臺建設會站在企業高度,所以我們將問題空間定位在全企業的業務域。當我們從 DDD 的視角來進行領域分析時,我們會根據核心業務環節或者功能聚合邊界以及領域經驗等多個維度,完成從領域到子域的細分。並根據企業發展戰略來分析,以確定子域到底是通用子域還是核心子域。

而當我們從中臺建設視角出發,將不同的業務板塊細分爲通用中臺和核心中臺時,從下圖中我們就可以發現,中臺一般會跟 DDD 的某一個子域對應,所以我們可以認爲:“中臺本質上就是按照 DDD 方法從企業業務領域細分出來的某個子域”。

在建立了它們的映射關係後,我們就可以統一 DDD 和中臺的通用語言了。然後就可以將 DDD 從戰略到戰術設計方法,應用到中臺的完整設計和建設過程中,完成中臺的領域分解,找出限界上下文,完成領域建模,並用微服務來完成中臺落地。

1.5

小結

我們對 DDD 與中臺和微服務的關係做一個小結,如下圖所示。

DDD 與中臺和微服務的關係是:“中臺本質是領域中的某一個子域,需要抽象並標準化,按照單一職責原則建立可複用的領域模型。而微服務則是中臺的最佳技術實現。DDD 是一種可以同時指導中臺業務建模和微服務設計的方法論,它遵循高內聚低耦合的原則,完成從業務端領域拆分、建模到應用端微服務實現的無縫落地。”

2

如何用 DDD 完成中臺和微服務設計

在建立了 DDD 與中臺和微服務的統一語言後,我們接下來討論如何用 DDD 來完成中臺和微服務設計。

2.1

DDD 核心知識體系

DDD 的知識體系非常龐大,主要包括:戰略設計和戰術設計兩個關鍵設計過程。

戰略設計從業務視角出發,完成領域到子域的分解,併爲子域定義核心子域和通用子域屬性。在子域內展開事件風暴,根據上下文語義邊界來劃分限界上下文,建立通用語言,完成領域建模。

在建立領域模型後,我們將領域模型作爲微服務設計的輸入完成戰術設計。

戰術設計從技術視角出發,側重於對領域模型的技術實現,按照領域模型完成微服務的設計和落地。在戰術設計中會有:聚合、聚合根、實體、值對象、領域服務等,我們會建立這些對象的依賴關係,並將領域模型中的領域對象以代碼對象的形式映射到微服務中,採用分層架構完成微服務設計和系統落地。

戰略設計和戰術設計兩者協同最終完成中臺和微服務設計和落地。

由於內容太多,這裏就不展開詳細介紹了,你可以參考《中臺架構與實現:基於 DDD 和微服務》,裏面有詳細的案例和代碼,也比較通俗易懂。

2.2

中臺和微服務整體設計過程

一般來說,對於比較小的領域我們可以直接從事件風暴開始,完成領域建模。而對於企業級中臺而言,由於企業領域非常龐大,不適合直接開展事件風暴。

所以,我們首先需要做好頂層設計,從劃分子域開始,確定好中臺的業務邊界,然後再開展事件風暴,再劃分限界上下文,完成領域建模,所以它是一個自上而下的設計過程。

DDD 整體設計過程主要有以下四個關鍵階段:領域分解、領域建模、微服務設計和詳細設計及技術實現,如下圖所示。

第一個階段是領域分解

本階段主要目標是基於企業業務域完成從領域到子域的分解,完成子域屬性定義,確定哪些子域是通用子域,哪些是核心子域?這個過程也是產出通用中臺和核心中臺的關鍵過程。

第二個階段是領域建模

基於第一階段產出的核心子域或通用子域,採用事件風暴工作坊等方法,劃分限界上下文,完成領域建模。這個過程我們會重點關注業務場景和問題,基本不考慮技術實現方案。在領域建模時,我們還會提取領域對象,確定限界上下文之間的服務依賴,建立領域模型內領域對象之間的依賴關係,比如誰是聚合根?誰是實體?然後根據業務內聚和對象依賴關係構建聚合。

這裏需要特別強調一下:一定要重視領域建模,因爲領域模型是微服務設計的前提和輸入,領域模型的質量會決定微服務設計的質量。

第三個階段是微服務設計

將第二階段產出的領域模型作爲微服務設計的輸入,完成微服務拆分,基於分層架構等技術來完成微服務設計。這個階段我們會確定微服務之間的上下文服務依賴,進一步細化聚合、實體、值對象依賴關係以及服務的分層和組合關係,完成微服務代碼的目錄結構設計,建立領域模型與應用代碼模型的映射關係。

第四個階段是微服務詳細設計和技術實現

在第三階段設計的基礎上,繼續細化並完成微服務詳細設計和落地技術實現,這一階段要重點關注微服務落地過程中的所有實現細節,比如:API 設計和服務規約,數據模型設計,測試和集成以及部署和運維等相關內容。

2.3

領域建模過程

領域建模一般採用事件風暴工作坊方法。我們來了解一下領域建模的幾個關鍵步驟。

  1. 團隊成員和領域專家聚集在一個開放的區域,藉助牆、白板和貼紙等工具,採用頭腦風暴形式,根據業務場景或用戶旅程分析,列出所有領域事件,對每一個事件標註出導致該事件的命令,爲每一個事件標註出命令的發起方。

  2. 從命令和領域事件中提取產生這些業務行爲的對象,即實體或值對象。根據命令來提取服務或實體的方法。這個過程我們可以採用名詞和動詞分析法,比如根據名詞提取實體,根據動詞提取命令來設計實體的方法或者服務。

  3. 根據領域對象之間的依賴關係,構建聚合。首先,從衆多實體中根據聚合根的特點找出聚合根,比如:是否有獨立的生命週期?是否有全局唯一 ID?是否可以創建或修改其他對象?是否有專門的模塊來管理這個實體?然後,根據業務內聚的原則,找出與聚合根關聯的所有實體和值對象,構建出“高內聚,低耦合”的聚合。

  4. 劃分限界上下文,構建領域模型,將多個聚合歸類到同一個上下文語義環境,劃定限界上下文邊界,建立上下文映射,完成領域模型的構建。

以上就是領域建模的大致過程。領域建模過程是項目團隊成員統一語言和建立通用語言的關鍵過程,所以建議團隊成員應儘早參與。

2.4

分層架構及領域模型的核心價值

在完成領域建模後,我們下一步就可以根據領域模型開始微服務設計了。微服務一般會基於分層架構來設計,現在比較流行的分層架構有:DDD 四層架構、六邊形架構和洋蔥架構。

三種分層架構的核心思想就是將領域模型放在應用的最核心位置,然後通過分層建立外層依賴內層的松耦合依賴關係,從而隔離外部環境的“變”與領域模型的“不變”。

我們在領域模型設計時,一般太不關注前端用例或者界面類需求。領域模型內實體和服務大多是一些相對穩定的原子業務邏輯。但是,前端頁面或流程以及技術組件總是在不斷的變化,比如大量新技術組件的出現會導致基礎設施層技術組件的頻繁更新和升級,界面要素和流程會隨外部需求和業務場景的需要而頻繁做出調整等。這些外部變化會對領域模型的核心邏輯產生比較大的影響。

我們一起來看看如何通過分層來隔離外部變化對領域模型的影響?

分層架構大多是通過前端或後端適配,逐層控制外部變化向領域層傳導,從而降低外部變化對領域模型的影響。比如在前端應用中可以消化掉頁面邏輯和頁面流程類需求;在用戶接口層可以完成前端應用接口和數據適配,避免將接口和數據適配類需求傳導到應用層;在應用層通過服務組合和編排,可以避免用例或服務組合類需求向領域層傳導;在基礎設施層通過依賴倒置設計,可以隔離技術組件變化對領域邏輯的影響。

這樣由外向裏逐層消化和隔離外部變化對領域模型的影響,從而可以最大限度保持領域模型原子性和長期穩定。一個穩定的領域模型可以給我們帶來非常多的好處。

首先,領域模型的構建過程是項目團隊通用語言建立的過程,領域模型就是團隊的通用語言,它會貫穿項目的所有過程。

其次,領域模型的業務邏輯大多是可複用的原子邏輯,不易受外部變化的影響。將這些核心邏輯沉澱到領域層,讓核心邏輯更聚焦,核心代碼更內聚。然後在應用層通過應用服務對領域層服務完成組合和編排,可以大量複用領域層的核心業務邏輯代碼,從而提升代碼複用率。

第三,領域模型的核心代碼可交由專門的資深開發人員維護,從而提升代碼質量,也能夠保證應用關鍵核心業務邏輯的長期穩定運行。

第四,領域模型內聚合邊界清晰,可方便微服務以聚合爲單位的功能和代碼的拆分和重組,讓微服務具有更強的演進能力。

2.5

DDD 分層架構與微服務設計

不同分層架構模型,在微服務開發和落地時其代碼實現方式就會存在差異,所以建議結合自身技術特點,從上述三種分層架構模型中來選擇合適自己的分層架構模型來完成微服務落地。這裏,我們選擇了經典的 DDD 四層分層架構。

先來簡單介紹一下 DDD 分層架構。

DDD 分層架構共包含四層,分別是用戶接口層、應用層、領域層和基礎設施層。

領域層在分層架構最核心的位置,主要實現領域模型的最核心領域邏輯。領域層包括若干個聚合,每個聚合內有一個聚合根、若干實體和值對象。在微服務設計和開發時,要重點關注聚合之間對象和服務的解耦設計。一般來說聚合之間只通過聚合根 ID 關聯,應儘量避免不同聚合領域對象或服務以及數據實體之間產生依賴,以便微服務在架構演進時可以相對輕鬆地完成聚合的拆分和重組。

爲了避免聚合之間產生服務依賴,聚合之間的數據交互一般採用異步化的領域事件驅動方式。另外,你也可以將聚合之間的服務調用上升到應用層,在應用服務中完成不同聚合之間的服務組合和調用。

領域層之上是應用層,它連接用戶接口層和領域層,通過應用服務協調領域層多個聚合完成服務的組合和編排,形成粗粒度的組合服務。由於這一層基本不實現領域邏輯,所以它很薄。

再往上一層就是用戶接口層。微服務架構通常採用前後端分離設計,一個微服務可能會面對多個不同類型的前端應用。而前端應用由於技術或業務場景差異,對 API 的技術實現或數據可能會存在差異。在用戶接口層我們可以根據前端需求封裝應用層的應用服務,面向不同前端應用提供接口和數據適配。

基礎設施層爲其他各層提供通用技術和基礎服務。通過依賴倒置設計,封裝基礎資源服務實現邏輯,實現各層與基礎設施層的解耦,降低外部資源和技術組件升級變化對核心業務邏輯的影響。

根據 DDD 分層架構,我們就可以設計微服務代碼的目錄結構了,如下圖所示。

與 DDD 分層架構對應,微服務會有四個一級目錄分別對應:用戶接口層、應用層、領域層和基礎設施層。另外,每一個聚合在領域層代碼目錄下也有完全隔離的二級目錄,用於存放聚合代碼。在聚合代碼目錄設計時,我們需要提前做好聚合代碼的隔離,以便在微服務演進時可以相對輕鬆地完成聚合代碼的拆分和重組。

在完成微服務代碼目錄後,我們就可以建立領域對象與代碼對象的映射關係了,這個過程也就建立了領域模型到系統模型的映射關係。

在領域建模時,我們會分析領域中的事件、命令等,這時會產生大量的領域對象,爲了方便建立團隊的通用語言,我們會將這些領域對象記錄到表格中。下面這個表格就是一個領域模型聚合內的所有領域對象。

在微服務設計時,我們會根據領域對象同步設計領域對象對應的代碼對象,並在表格中記錄它們的映射關係。在微服務代碼落地時,我們就可以在對應的代碼目錄結構中完成代碼對象的開發。這樣就建立了領域模型與系統模型的映射關係。

如果領域模型中的某些領域對象發生了變化,我們就可以根據對象之間的這種映射關係,很容易地找到領域對象對應的代碼對象的位置,同步調整系統模型,實現從領域模型變化到系統模型變化的有效聯動。

3

領域模型和微服務的演進

在完成領域建模和微服務設計後,你可能會問花了這麼大精力設計出的領域模型是否合理?這個問題可能只有在真正的生產實踐中才能找到答案!

當領域模型應用到真實的業務場景後,如果發現領域模型設計不合理,我們就需要根據實際情況不斷完成領域模型和微服務的迭代演進,讓它們真正能夠滿足業務的需要。另外,因爲企業業務的發展和變化,往往也會導致領域模型變化和微服務架構演進。

領域模型不是一成不變的,所以不要期望一勞永逸的構建出一個恆久不變的領域模型。但我們可以通過提前設計,在變化發生時,依然可以用一種相對輕鬆的方式,完成領域模型和微服務的演進。

那麼,如何以最小的代價來完成領域模型和微服務演進?我們下面根據具體情況來分析。

企業業務的變化對領域模型和微服務架構演進的影響,一般會有兩種類型:

  1. 應用之間功能模塊級的變化。這類變化通常會影響到微服務之間的功能模塊的拆分或重組,所以影響就會比較大。

  2. 應用內方法或者服務級的變化。這類變化對微服務的影響一般都比較小,我們修改實體方法或服務,就可以相對容易地解決。

3.1

功能模塊級的演進

對於第一種情況,如果我們在微服務設計時仍然採用傳統三層架構模式,這樣設計出來的微服務的內部功能和代碼的耦合度依然很高,我們得到的實際上是一個一個分佈式小單體。

當業務發生變化,我們需要對這些小單體進行功能拆分或重組時,就會存在非常大的困難。在進行功能和代碼拆分時,由於耦合度過高會有大量的代碼重構工作,這也會給生產運營帶來非常大的不確定性風險。

我們再來看看採用 DDD 分層架構設計出來的微服務是什麼樣子的?

我們知道,微服務的邊界來源於限界上下文。在限界上下文內會有多個聚合。一個聚合會有若干個領域對象。聚合是領域模型的最小業務單元,它本質上就是一個小的功能模塊。由於聚合功能的高內聚,而且可以自包含地獨立運行,所以除了按照限界上下文邊界拆分的微服務之外,聚合也是領域模型內可進一步獨立爲微服務部署的最小單元。

不過,在現有分佈式架構下,以限界上下文邊界來拆分微服務就足以滿足業務需要了,我們沒必要將微服務拆分得過細(除非對聚合相關的功能有極致的性能要求),這樣會運維和集成能力會提出過高的要求。而在 serverless 架構下,當採用基於更細粒度的函數式編程時,會不會以聚合爲單位來拆分函數代碼單元就不得而知了,這也可以作爲我們研究的一個方向。

按照 DDD 方法設計出來的微服務會有兩個清晰的邊界:

第一層是微服務內松耦合的聚合邊界,這是一個邏輯邊界,它讓微服務具有了基於聚合進行二次拆分和功能模塊重組的能力;

第二層是限界上下文的邊界,在微服務落地時,就變成了微服務之間的物理邊界。

當我們在領域模型中確定了這兩個邊界以後,就可以基於這兩個邊界來定義微服務的代碼模型,完成代碼開發。在進行聚合代碼開發時,我們應該重點關注聚合之間的對象和服務解耦設計,做好聚合之間的代碼隔離,在領域層儘量避免聚合之間產生各種形式的依賴。這樣,當領域模型發生聚合級功能變化時,就可以隨時在微服務之間完成聚合代碼重組。因爲領域模型內部和外部都有清晰的邊界,所以當發生功能模塊級變化時,微服務就可以快速平穩的完成功能和代碼重組,完成架構演進。

而如果採用 DDD 設計,我們只要定義好了聚合這個邏輯邊界,做好了架構的分層,其實也不一定要拆分出太多的微服務,即使採用分層架構將所有聚合放在一個單體中也未嘗不可。有了聚合這層邊界和聚合之間的解耦設計,未來需要將單體應用拆分或重組出新應用時,也不是一件難事。這個過程不會花太多的時間,也不需要改動太多的代碼。

領域模型和微服務功能模塊級的架構演進,一般會基於聚合這個最小的業務功能單元。我們可以根據業務發展和變化,將聚合獨立爲微服務,也可以在不同的領域模型和微服務之間完成聚合的功能重組,從而完成領域模型和微服務架構演進。

我們來看一下下面這個例子,看看它們到底是以什麼樣的方式來完成微服務架構演進的。在最早的原始模型中有兩個微服務,其中每個微服務有三個聚合。

當應用上線一段時間後,隨着業務發展,我們突然發現微服務 1 內聚合 a 的功能變成了海量高頻業務。這時聚合 a 就會拖累整個微服務 1,並且因爲聚合 a 面臨性能瓶頸,在微服務 1 進行彈性擴縮時,也會造成資源浪費。這時,我們就可以將聚合 a 從微服務 1 中整體拆分,獨立爲一個新微服務 3。這樣,微服務 3 就擁有了獨立的資源和運行環境,在資源配置方面也可以更加有針對性的投入到微服務 3 了,可以隨時滿足高頻訪問的性能要求了。

或者在運行一段時間後,我們發現在領域建模時錯誤地將聚合 d 放到了微服務 2 裏,或者隨着業務發展聚合 d 更適合放在微服務 1 裏。由於領域模型的不合適,可能會導致微服務之間出現頻繁調用,進而導致微服務之間出現緊耦合關係。這時,我們就可以對領域模型做出調整,將聚合 d 從微服務 2 整體遷移到微服務 1 裏。

由於我們在微服務設計時,已經做好了聚合之間的解耦,同時聚合代碼也在目錄結構上進行了隔離。所以,有了聚合這個邏輯邊界,我們就不需要花太多的時間,也不需太多的代碼調整,就可以相對輕鬆地完成領域模型和微服務的演進。

經過兩輪領域模型演進,我們發現最早的兩個微服務最終演進成爲三個微服務,同時聚合 a 已經獨立拆分爲新的微服務,聚合 d 也在不同微服務之間完成了重組。由於我們在微服務設計時,已經提前做好了聚合之間的解耦設計,聚合間的代碼也進行了目錄隔離。所以當業務出現變化時,我們依然可以非常輕鬆地完成領域模型和微服務的同步演進。

3.2

服務級的演進

我們再來看一下微服務內的服務演進。

領域層的服務大多是原子服務,我們在進行服務設計時並不會考慮太多的前端用例需求,我們也無法預測到它會被多少個前端應用調用,會組合成什麼樣的應用服務。

而隨着前端應用接入越來越多,這時你會發現有些領域服務在應用層被頻繁的組合和編排,如上圖所示領域服務 b 和領域服務 c。這時,你就需要注意了,我們可以進行服務演進了。

我們可以將同一個聚合中,那些被頻繁組合和編排的多個領域服務(領域服務 b 和領域服務 c)的邏輯,封裝成一個新的領域服務(領域服務 b+c)。當新接入前端應用時,它們就不需要在應用層組合和編排領域服務 b 和領域服務 c 了,而是直接調用領域服務 b+c。這樣,既減少了領域層服務的數量,同時減輕了應用服務組合和編排的複雜度。

最後你會發現,隨着這種類型的服務演進,領域模型會越來越精煉,同時微服務也越來越能適應外部需求變化了。

4

總結

DDD 博大精深,其實還有很多內容。比如,在中臺建設時:微前端設計、領域事件驅動模型以及單元化的設計思想等內容,無法在這裏一一展開。

你可以參考《中臺架構與設計:基於 DDD 和微服務》,裏面有非常詳細的介紹。

DDD 很好,但也不是萬能的“銀彈” !

只有將中臺和 DDD 視作一種設計思想和方法,吸收它的精髓,與時俱進。並結合企業文化和團隊技術特點,有所取捨,靈活運用纔是王道!

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