DDD學習筆記 - 基礎篇(Ⅰ)

最近在自學DDD(領域驅動設計),打算將學習筆記以博客的形式記錄下來。

---------------------------------------------------------------------------------------------------------------------------

領域驅動設計DDD

 

開篇詞

作爲中颱,需要將通用的可複用的業務能力沉澱到中臺業務模型,實現企業級能力複用。

早在2003年就誕生的DDD,怎麼來指導遲到近20年才大熱的微服務設計呢?

 

1.搞清楚DDD的核心設計思想,DDD、微服務和中臺的關係:

中臺本質是業務模型,微服務是業務模型的系統落地方案,DDD是一種設計思想,它可以同時指導中臺業務建模和微服務設計,他們之間是鐵三角關係

DDD強調領域模型和微服務設計的一體性,現有領域模型然後纔有微服務。

 

2.戰略設計。建立領域模型、劃分爲服務邊界。關鍵

 

3.戰術設計。從領域模型轉向微服務設計和落地。

 

術語多且陌生。

DDD必知必會十大概念、微服務架構分層、代碼模型設計、DDD戰略設計、事件風暴、領域建模、企業級中臺業務建模。走一遍DDD戰略設計和戰術設計的全流程,DDD在領域模型和微服務設計過程中的技術要點。深化微服務設計原則、建立演進式微服務架構。

 

基礎篇:領域、子域、核心域、通用域、支撐域、限界上下文、實體、值對象、聚合、聚合根。

 

進階篇:領域事件、DDD分層架構、常見的微服務架構模型、中臺設計思想

  • 如何通過領域事件實現微服務解耦
  • 怎樣進行微服務分層設計
  • 如何實現層與層之間的服務協作
  • 領域模型和微服務分層的作用和價值
  • 中臺設計的核心思想,如何實現前中後臺的協同和融合,如何利用DDD進行中臺設計

 

實戰篇:中臺和領域建模的實戰、微服務設計實戰

 

-------------------------------------------------------------------------------------------------------------------------------------------------------------------------

 

 

01 | 領域驅動設計:微服務設計爲什麼要選擇DDD?

課程鏈接:https://time.geekbang.org/column/article/149943

微服務設計過程中往往會面臨邊界如何劃定的問題,微服務到底應該拆多小?

 

軟件架構模式的演進:

大體來說經歷了單機、集中式、到分佈式微服務架構三個階段。

 

單機架構:採用面向過程的設計方法。系統包括UI層和數據庫兩層,採用C/S架構模式,整個系統圍繞數據庫驅動設計和開發,總是從設計數據庫和字段開始。

集中式架構:採用面向對象的設計方法,包括業務接入層、邏輯層和數據庫層,是經典的三層架構,也有的採用傳統的SOA架構。這種架構容易是系統變得臃腫,可擴展性和彈性伸縮性差。

分佈式微服務架構:隨着微服務架構理念的提出,集中式架構正式向微服務架構演進。可以很好的實現應用之間的解耦,解決單體應用擴展性和彈性伸縮能力不足的問題。

 

在單機和集中式架構時代,系統分析、設計和開發往往是獨立、分階段割裂進行的。提出需求、需求分析、系統設計、代碼實現的流程很長,經手的人很多,容易導致信息丟失,容易導致需求、設計和代碼實現的不一致。

在單機和集中式架構這兩種模式下,軟件無法快速響應需求和業務的迅速變化。

 

微服務設計和拆分的困境:

微服務的粒度應該多大?應該如何拆分和設計?邊界應該在哪裏?

很久以來都沒有一套系統的理論和方法可以指導微服務的拆分,甚至包括微服務架構模式的提出者Martin Fowler也沒有告訴我們應該如何拆分微服務。有很多項目因爲前期微服務拆分過度,導致項目複雜度過高,無法上線和維護。

微服務拆分困境產生的根本原因就是不知道業務或者微服務的邊界到底在哪裏。確定了業務邊界和應用邊界,這個困境也就迎刃而解了。

 

領域驅動設計和微服務的前世今生。

2004年Eric Evans發表《領域驅動設計》一書,從此DDD誕生。

DDD核心思想是通過領域驅動設計方法定義領域模型,從而確定業務和應用邊界,保證業務模型與代碼模型的一致性。

直到Martin Fowler提出微服務架構,DDD才真正迎來了自己的時代。

可以利用DDD設計方法來建立領域模型,劃分領域邊界,再根據這些領域邊界從業務視角劃分微服務邊界。按照DDD方法設計出的微服務的業務和應用邊界都非常合理,可以很好的實現微服務內部和外部的“高內聚、低耦合”。

 

DDD是一種處理高度複雜領域的設計思想,它試圖分離技術實現的複雜性,並圍繞業務概念構建領域模型來控制業務的複雜性,以解決軟件難以理解,難以演進的問題。DDD不是架構,而是一種架構設計方法論,它通過劃分邊界將複雜業務領域簡單化,幫我們設計出清晰的領域和應用邊界,可以很容易實現架構演進。

 

DDD包括戰略設計和戰術設計兩部分:

戰略設計主要從業務視角出發,建立業務領域模型,劃分領域邊界,建立通用語言的限界上下文,限界上下文可以作爲微服務設計的參考邊界。

戰術設計主要從技術視角出發,側重於領域模型的技術實現,完成軟件開發和落地。包括聚合根、實體、值對象、領域服務、應用服務和資源庫等代碼邏輯的設計和實現。

 

DDD如何進行戰略設計:

DDD戰略設計(事件風暴) == 》建立領域模型 == 》指導微服務的設計和拆分。

事件風暴是建立領域模型的主要方法,是一個從發散到收斂的過程。通常採用用例分析、場景分析、用戶旅程分析,儘可能全面不遺漏地分解業務領域,並梳理領域對象之間的關係,這是一個發散的過程。事件風暴過程會產生很多的實體、命令、事件等領域對象,將這些領域對象從不同維度進行聚類,形成聚合、限界上下文等邊界,建立領域模型,這是一個收斂的過程。

劃定領域模型和微服務的邊界,分爲三個步驟:

第一步:在事件風暴中梳理業務過程中的用戶操作、時間以及外部依賴關係等,根據這些要素梳理出領域實體等領域對象。

第二步:根據領域實體之間的業務關聯性,將業務緊密相關的實體進行組合形成聚合,同時確定聚合中的聚合根、值對象和實體。在這個圖裏,聚合之間的邊界是第一層邊界,他們在同一個微服務實例中運行,這個邊界是邏輯邊界,所以用虛線表示。

第三步:根據業務及語義邊界等因素,將一個或者多個聚合劃定在一個限界上下文內,形成領域模型。在這個圖裏,限界上下文之間的邊界是第二層邊界,這一層邊界可能就是未來微服務的邊界,不同限界上下文內的領域邏輯被隔離在不同的微服務實例中運行,物理上相互隔離,所以是物理邊界,用實線表示。

有了這兩層邊界,微服務的設計就不難了。

至此,建立了領域模型,劃定了業務領域的邊界,建立了通用語言和限界上下文,確定了領域模型中各個領域對象的關係。業務端領域模型和設計基本就完成了,同時也確定了應用端的微服務邊界。

在從業務模型向服務落地的過程中,也就是戰略設計向戰術設計的實施過程中,會將領域模型中的領域對象與代碼模型中的代碼對象建立映射關係,將業務架構和系統架構進行綁定。當爲了響應業務變化調整業務架構和領域模型時,系統架構也會同時發生調整,同步建立新的映射關係。

 

DDD與微服務的關係:

DDD是一種架構設計方法,微服務是一種架構風格,從本質上講都是爲了追求高響應力,都強調從業務出發。

DDD主要關注:從業務領域視角劃分領域邊界,構建通用語言進行高效溝通,通過業務抽象,建立領域模型,維持業務和代碼的邏輯一致性。

微服務主要關注:運行時的進程間通信、容錯和故障隔離,實現去中心化數據管理和去中心化服務治理,關注微服務的獨立開發、測試、構建和部署。

 

總結:

DDD戰略設計 => 建立領域模型 => 劃定領域邊界 => 劃定微服務拆分邊界

DDD不僅可以用於微服務設計,還可以很好的應用於企業中臺的設計。

DDD戰術設計對設計和開發人員的要求相對較高,實現起來相對複雜。

 

 

-------------------------------------------------------------------------------------------------------------------------------------------------------------------

 

02 | 領域、子域、核心域、通用域和支撐域:傻傻分不清?

課程鏈接:https://time.geekbang.org/column/article/149945

DDD的知識體系提出了很多的名詞:領域、子域、核心域、通用域、支撐域、限界上下文、聚合、聚合根、實體、對象值等等,都是關鍵概念。雖然在微服務設計和開發過程中不一定都用得上,但可以幫助理解DDD的核心設計思想和理念。在IT戰略設計、業務建模和微服務設計中都是可以借鑑的。

 

如何理解領域和子域:

詞典中的解釋:“領域是從事一種專門活動或事業的範圍、部類和部門。”、“領域具體指一種的特定的範圍或區域”。

領域就是用來確定範圍的,範圍即邊界。

 

DDD會按照一定的規則將業務領域進行細分,當細分到一定的成都後,會將問題範圍限定在特定的邊界內,在這個邊界內建立領域模型,進而用代碼實現該領域模型,解決響應的業務問題。DDD的領域就是這個邊界內要解決的業務問題域。

領域越大,業務範圍就越大。

領域可以進一步劃分爲子領域,叫做子域,每個子域對應一個更小的問題域或更小的業務範圍。

 

DDD的研究方法和自然科學的研究方法類似。將問題一步一步細分,逐個深入研究,當所有子域完成研究時,就建立了全部領域的完整知識體系。

第一步:確定研究對象,即研究領域,一棵桃樹。

第二步:對研究對象細分爲器官,器官又分爲營養器官和生殖器官。不同的器官再分。桃樹的知識體系是要研究的問題域,對應DDD的領域。根、莖、葉、花、果實、種子等器官則是細分後的子域。這就是DDD將領域細分爲多個子域的過程。

第三步:對器官進行細分爲組織。葉子惡意細分爲保護組織、營養組織和輸導組織。這是DDD將子域進一步細分爲多個子域。

第四步:對組織細分爲細胞。細胞是最小的研究單元。細胞壁確定了單元的邊界,即研究的最小邊界。

 

在這裏可以把細胞理解爲DDD的聚合,細胞內的細胞核、小立體、細胞膜等可以理解爲聚合裏面的聚合根、實體以及值對象等,在聚合內這些實體一起寫作完成特定的業務功能。這個功能類似DDD設計時,確定微服務內功能要素和邊界的過程。

 

每一個細分的領域都會有一個知識體系,也就是DDD的領域模型。在所有子域的研究完成後,就建立了全域的知識體系,也就建立了全域的領域模型。

領域建模和微服務建設的過程和方法基本類似,其核心思想就是將問題域逐步分解,降低業務理解和系統實現的複雜度。

 

如何理解核心域、通用域、支撐域:

子域可以根據自身重要性和功能屬性劃分爲三類:核心域、通用域、支撐域。

決定產品和公司核心競爭力的子域是核心域。沒有太多個性化訴求,同時被多個子域使用的通用功能子域是通用域。還有一種功能子域是必需的,但既不是公司核心,也不含通用功能的子域,就是支撐域

核心域是最重要的。通用域例如認證、權限等,支撐域具有企業特性,但不具有通用性。

 

爲什麼要劃分核心域、通用域、支撐域?

什麼是桃樹的核心域?長在公園裏,花是核心域;長在果園裏,果實是核心域。不同場景下核心域不同。有時爲了保證果實的營養,還會裁剪掉莖和葉(通用域和支撐域)。對不同的子域應有不同的關注度和資源投入策略,好鋼用在刀刃上。

 

淘寶是C2C,個人賣家對個人買家,天貓、京東和蘇寧是B2C,企業賣家對個人買家。蘇寧是典型的傳統線下轉電商、京東則是直營加部分平臺。商業模式不同會導致核心域劃分結果不同。

 

總結:

領域的核心思想是將問題逐級細化,降低理解和實現的複雜度。逐步縮小微服務需要解決的問題域,構建合適的領域模型,領域模型映射成系統就是微服務。

 

----------------------------------------------------------------------------------------------------------------------------------

 

03 | 限界上下文:定義領域邊界的利器

課程鏈接:https://time.geekbang.org/column/article/149950

DDD領域建模和系統建設過程中,領域專家、產品經理、項目經理、架構師、開發經理和測試經理都會參與。爲了理解和交流的障礙,DDD中出現了“通用語言”和“限界上下文”兩個重要概念。

通用語言定義上下文含義,限界上下文定義領域邊界。

兩個問題:

1爲什麼要提出限界上下文的概念?(除了解決交流障礙)

2限界上下文在微服務設計中的作用和意義

 

什麼是通用語言:

先說通用語言:在事件風暴過程中,通過團隊交流達成共識的,能夠簡單、清晰、準確描述業務含義和規則的語言就是通用語言

。通用語言是團隊統一的語言,可以解決交流障礙的問題。

通用語言包含屬於和用例場景,且能夠直接反映在代碼中。其中的名詞可以給領域對象命名,如商品、訂單等,對應實體對象;動詞則表示一個動作或事件,如下單、付款等,對應領域事件。其貫穿DDD的整個設計過程。

上圖描述了從事件風暴建立通用語言到領域對象設計和代碼落地的完成過程:

1.事件風暴的過程中,領域專家、設計、開發一起建立領域模型,建模過程中會形成通用的業務屬於和用戶故事。這是團隊同意語言的過程。

2.通過用戶故事分析會形成一個個領域對象,並對應領域模型的業務對象,每一個業務對象和領域對象是一一映射的

3.微服務代碼模型來源於領域模型,每個代碼模型的代碼和領域對象一一對應。

 

設計過程中可以用一些表格,來記錄事件風暴和微服務設計過程中產生的領域對象及其屬性。比如領域對象在DDD分層架構中的位置、屬性、依賴關係以及與代碼模型對象的映射關係等。

DDD分析和設計的每一個環節都保證限界上下文內術語的統一,在代碼模型設計的時候就要建立領域對象和代碼對象的一一映射,保證業務模型和代碼模型的一致,實現業務語言與代碼語言的統一

 

什麼是限界上下文:

通用語言有它的上下文環境。“限界上下文”用來確定通用語言所在的領域邊界。

限界、和上下文。限界就是領域的邊界,上下文則是語義環境。

限界上下文的定義:用來封裝通用語言和領域對象,提供上下文環境,保證在領域內的一些術語、業務相關對象等(通用語言)有一個確切的含義,沒有二義性。這個邊界定義了模型的適用範圍。

 

進一步理解限界上下文:

舉個例子:

孩子問媽媽:今天應該穿幾件衣服?媽媽說:能穿幾件穿幾件。

到底穿多還是穿少。

如果可以知道這句話的語義環境,炎炎夏日或寒冬臘月,那就能理解了。所以語言離不開它的語義環境。

而業務的通用語言就有它的業務邊界,不大可能用一個簡單的術語沒有歧義的描述一個複雜的業務領域。限界上下文就是用來細分領域,定義通用語言所在的邊界。

 

用一個保險領域的例子來說明:保險業務又投保單、保單、批單、賠案等專業術語,分別對應保險的不同業務流程:

  1. 客戶投保時,記錄投保信息,系統對應有投保單bean;
  2. 繳費完成後,投保單轉爲保單,系統對應有保單bean,保單bean與投保單bean關聯;
  3. 如需要修改保單信息,保單變爲批單,系統對應有批單bean,批單bean與保單bean關聯;
  4. 如果發生理賠,生成賠案,系統對應有賠案bean,賠案bean與保單bean或批單備案關聯。

投保單、保單、批單、賠案等,雖然都有保單有關,但不能將保單這個術語作用在保險全業務領域,因爲術語有它的邊界。

正如電商領域的商品,在銷售階段是商品,在運輸階段則變成了貨物。同樣的東西,因爲業務領域不同,賦予了這些術語不同的涵義和指責邊界,這個邊界可能就會成爲未來微服務設計的邊界。領域邊界就是通過限界上下文來定義的。

 

限界上下文和微服務的關係:

車險承保的流程包含了投保、繳費、出單等流程,如果出險還會有報案、查勘、定損、理算等。

用一個簡單的保險模型來說明下屆上下文和微服務的關係:

首先,保險領域被拆分爲投保、支付、保單管理、理賠四個子域。

子域還可以根據需要進一步拆分爲子子域,到一定程度後,有些子子域的領域邊界可能就變成限界上下文的邊界了。子域可能包含多個限界上下文,如理賠包含報案、查看、定損等(限界上下文和理賠的子子域領域邊界重合),也有可能子域本身的邊界就是限界上下文邊界,如投保子域。

理論上限界上下文就是微服務的邊界。將限界上下文內的領域模型映射到微服務,就完成了從問題域到軟件的解決方案。

限界上下文是微服務拆分的主要依據,如果不考慮其他外部因素,領域模型中一個限界上下文就是可以設計爲一個微服務。

當然,這只是理論,微服務的拆分有很多限制因素,設計中不宜過度拆分。

 

 

 

 

 

 

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章