在线观看www成人影院-在线观看www日本免费网站-在线观看www视频-在线观看操-欧美18在线-欧美1级

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

2萬字帶你入門DDD

jf_ro2CN3Fa ? 來源:程序員鶴涵 ? 2023-06-15 10:10 ? 次閱讀

DDD理論

微服務和DDD的淵源

軟件架構模式的演進

fc37a67c-0b1c-11ee-962d-dac502259ad0.jpg

我們先來分析一下軟件架構模式演進的三個階段。

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

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

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

在單機和集中式架構時代,系統分析、設計和開發往往是獨立、分階段割裂進行的。

很容易導致需求、設計與代碼實現的不一致,往往到了軟件上線后,我們才發現很多功能并不是自己想要的,或者做出來的功能跟自己提出的需求偏差太大

微服務設計和拆分的困境

那進入微服務架構時代以后,微服務確實也解決了原來采用集中式架構的單體應用的很多問題,比如擴展性、彈性伸縮能力、小規模團隊的敏捷開發等等。

微服務的粒度應該多大呀?微服務到底應該如何拆分和設計呢?微服務的邊界應該在哪里?

2004年埃里克·埃文斯(Eric Evans)發表了《領域驅動設計》(Domain-Driven Design –Tackling Complexity in the Heart of Software)這本書,從此領域驅動設計(Domain Driven Design,簡稱DDD)誕生。DDD核心思想是通過領域驅動設計方法定義領域模型,從而確定業務和應用邊界,保證業務模型與代碼模型的一致性。

但DDD提出后在軟件開發領域一直都是“雷聲大,雨點小”!直到Martin Fowler提出微服務架構,DDD才真正迎來了自己的時代。

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

現在,很多大型互聯網企業已經將DDD設計方法作為微服務的主流設計方法了。DDD也開始真正火爆起來。

為什么DDD適合微服務

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

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

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

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

我們不妨來看看DDD是如何進行戰略設計的。

DDD戰略設計會建立領域模型,領域模型可以用于指導微服務的設計和拆分。

事件風暴 是建立領域模型的主要方法,它是一個從發散到收斂的過程。

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

fc52b5f2-0b1c-11ee-962d-dac502259ad0.jpg

我們可以用三步來劃定領域模型和微服務的邊界。

戰略設計主要包括三步:

通過事件風暴梳理業務過程中的要素,確定領域實體等領域對象。

根據領域實體之間的業務關聯性,將業務緊密相關的實體組合形成聚合。

根據業務和語義邊界等因素,將一個或多個聚合劃定在一個限界上下文內,形成領域模型。

戰術設計的主要工作是將領域模型中的領域對象與代碼模型中的代碼對象建立映射關系,并調整業務架構和領域模型以響應業務變化。最終,將系統架構與業務架構綁定,建立新的映射關系。

DDD與微服務的關系

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

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

總體來說:

DDD是一套完整而系統的設計方法,它能帶給你從戰略設計到戰術設計的標準設計過程,使得你的設計思路能夠更加清晰,設計過程更加規范。

DDD善于處理與領域相關的擁有高復雜度業務的產品開發,通過它可以建立一個核心而穩定的領域模型,有利于領域知識的傳遞與傳承。

DDD強調團隊與領域專家的合作,能夠幫助你的團隊建立一個溝通良好的氛圍,構建一致的架構體系。

DDD的設計思想、原則與模式有助于提高你的架構設計能力。

無論是在新項目中設計微服務,還是將系統從單體架構演進到微服務,都可以遵循DDD的架構原則。

DDD不僅適用于微服務,也適用于傳統的單體應用

關鍵概念

領域和子域Domain

我們先看一下漢語詞典中對領域的解釋:“領域是從事一種專門活動或事業的范圍 、部類或部門。”百度百科對領域的解釋:“領域具體指一種特定的范圍 或區域。”

領域就是用來確定范圍的,范圍即邊界 ,這也是DDD在設計中不斷強調邊界的原因。

既然領域是用來限定業務邊界和范圍的,那么就會有大小之分,領域越大,業務范圍就越大,反之則相反。

領域可以進一步劃分為子領域。我們把劃分出來的多個子領域稱為子域,每個子域對應一個更小的問題域或更小的業務范圍

fc755e54-0b1c-11ee-962d-dac502259ad0.jpg

我們來看一下上面這張圖。這個例子是在講如何給桃樹建立一個完整的生物學知識體系。初中生物課其實早就告訴我們研究方法了。它的研究過程是這樣的。

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

第二步:對研究對象進行細分,將桃樹細分為器官,器官又分為營養器官和生殖器官兩種。其中營養器官包括根、莖和葉,生殖器官包括花、果實和種子。桃樹的知識體系是我們已經確定要研究的問題域,對應DDD的領域。根、莖、葉、花、果實和種子等器官則是細分后的問題子域。這個過程就是DDD將領域細分為多個子域 的過程。

第三步:對器官進行細分,將器官細分為組織。比如,葉子器官可細分為保護組織、營養組織和輸導組織等。這個過程就是DDD將子域進一步細分為多個子域 的過程。

第四步:對組織進行細分,將組織細分為細胞,細胞成為我們研究的最小單元。細胞之間的細胞壁確定了單元的邊界,也確定了研究的最小邊界

第五步:細胞核、線粒體、細胞膜等物質共同構成細胞,這些物質一起協作讓細胞具有這類細胞特定的生物功能。在這里你可以把細胞理解為DDD的聚合 ,細胞內的這些物質就可以理解為聚合里面的聚合根、實體以及值對象 等,在聚合內這些實體一起協作完成特定的業務功能。這個過程類似DDD設計時,確定微服務內功能要素和邊界的過程。

核心域,通用域和支撐域

在領域不斷劃分的過程中,領域會細分為不同的子域,子域可以根據自身重要性和功能屬性劃分為三類子域,它們分別是:核心域、通用域和支撐域。

決定產品和公司核心競爭力的子域是核心域 ,它是業務成功的主要因素和公司的核心競爭力。

沒有太多個性化的訴求,同時被多個子域使用的通用功能子域是通用域

還有一種功能子域是必需的,但既不包含決定產品和公司核心競爭力的功能,也不包含通用功能的子域,它就是支撐域

這三類子域相較之下,核心域是最重要的。

通用域和支撐域如果對應到企業系統,舉例來說的話,通用域則是你需要用到的通用系統,比如認證、權限、短信等等,這類應用很容易買到,沒有企業特點限制,不需要做太多的定制化。

而支撐域則具有企業特性,但不具有通用性,例如數據代碼類的數據字典,站內信等系統。

那為什么要劃分核心域、通用域和支撐域,主要目的是什么呢?

要事為先

公司在IT系統建設過程中,由于預算和資源有限,對不同類型的子域應有不同的關注度和資源投入策略,記住好鋼要用在刀刃上。

很多公司的業務,表面看上去相似,但商業模式和戰略方向是存在很大差異的,因此公司的關注點會不一樣,在劃分核心域、通用域和支撐域時,其結果也會出現非常大的差異。

比如同樣都是電商平臺的淘寶、天貓、京東和蘇寧易購,他們的商業模式是不同的。淘寶是C2C網站,個人賣家對個人買家,而天貓、京東和蘇寧易購則是B2C網站,是公司賣家對個人買家。即便是蘇寧易購與京東都是B2C的模式,他們的商業模式也是不一樣的,蘇寧易購是典型的傳統線下賣場轉型成為電商,京東則是直營加部分平臺模式。

商業模式的不同會導致核心域劃分結果的不同。有的公司核心域可能在客戶服務,有的可能在產品質量,有的可能在物流 。在公司領域細分、建立領域模型和系統建設時,我們就要結合公司戰略重點和商業模式,找到核心域了,且重點關注核心域。

通用語言

在事件風暴過程中,通過團隊交流達成共識的,能夠簡單、清晰、準確描述業務涵義和規則的語言就是通用語言。也就是說,通用語言是團隊統一的語言 ,不管你在團隊中承擔什么角色,在同一個領域的軟件生命周期里都使用統一的語言進行交流。

通用語言的價值也就很明了了,它可以解決交流障礙這個問題 ,使領域專家和開發人員能夠協同合作,從而確保業務需求的正確表達。

但是,對這個概念的理解,到這里還不夠。

通用語言包含術語和用例場景 ,并且能夠直接反映在代碼中。通用語言中的名詞可以給領域對象命名 ,如商品、訂單等,對應實體對象;而動詞則表示一個動作或事件 ,如商品已下單、訂單已付款等,對應領域事件或者命令。

通用語言貫穿DDD的整個設計過程。作為項目團隊溝通和協商形成的統一語言,基于它,你就能夠開發出可讀性更好的代碼,將業務需求準確轉化為代碼設計。

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

簡單來說,通用語言確定了項目團隊內部交流的統一語言,而這個語言所在的語義環境則是由限界上下文來限定的,以確保語義的唯一性。

限界上下文BoundedContext

我們可以將限界上下文拆解為兩個詞:限界和上下文。限界就是領域的邊界,而上下文則是語義環境 。通過領域的限界上下文,我們就可以在統一的領域邊界內用統一的語言進行交流。

綜合一下,我認為限界上下文的定義就是:用來封裝通用語言和領域對象,提供上下文環境,保證在領域之內的一些術語、業務相關對象等(通用語言)有一個確切的含義,沒有二義性。這個邊界定義了模型的適用范圍,使團隊所有成員能夠明確地知道什么應該在模型中實現,什么不應該在模型中實現。

領域專家、架構師和開發人員的主要工作就是通過事件風暴來劃分限界上下文。限界上下文確定了微服務的設計和拆分方向,是微服務設計和拆分的主要依據。如果不考慮技術異構、團隊溝通等其它外部因素,一個限界上下文理論上就可以設計為一個微服務。

實體Entity

我們先來看一下實體是什么東西?

在DDD中有這樣一類對象,它們擁有唯一標識符,且標識符在歷經各種狀態變更后仍能保持一致 。對這些對象而言,重要的不是其屬性,而是其延續性和標識,對象的延續性和標識會跨越甚至超出軟件的生命周期。我們把這樣的對象稱為實體。

1. 實體的業務形態

在DDD不同的設計過程中,實體的形態是不同的。在戰略設計時,實體是領域模型的一個重要對象。領域模型中的實體是多個屬性、操作或行為的載體。在事件風暴中,我們可以根據命令、操作或者事件,找出產生這些行為的業務實體對象,進而按照一定的業務規則將依存度高和業務關聯緊密的多個實體對象和值對象進行聚類,形成聚合。你可以這么理解,實體和值對象是組成領域模型的基礎單元。

2. 實體的代碼形態

在代碼模型中,實體的表現形式是實體類,這個類包含了實體的屬性和方法,通過這些方法實現實體自身的業務邏輯。在DDD里,這些實體類通常采用充血模型 ,與這個實體相關的所有業務邏輯都在實體類的方法中實現,跨多個實體的領域邏輯則在領域服務中實現

3. 實體的運行形態

實體以DO(領域對象)的形式存在,每個實體對象都有唯一的ID 。我們可以對一個實體對象進行多次修改,修改后的數據和原來的數據可能會大不相同。但是,由于它們擁有相同的ID,它們依然是同一個實體。比如商品是商品上下文的一個實體,通過唯一的商品ID來標識,不管這個商品的數據如何變化,商品的ID一直保持不變,它始終是同一個商品。

4. 實體的數據庫形態

與傳統數據模型設計優先不同,DDD是先構建領域模型 ,針對實際業務場景構建實體對象和行為,再將實體對象映射到數據持久化對象。

在領域模型映射到數據模型時,一個實體可能對應0個、1個或者多個數據庫持久化對象。大多數情況下實體與持久化對象是一對一 。在某些場景中,有些實體只是暫駐靜態內存的一個運行態實體,它不需要持久化。比如,基于多個價格配置數據計算后生成的折扣實體。

而在有些復雜場景下,實體與持久化對象則可能是一對多或者多對一的關系。比如,用戶user與角色role兩個持久化對象可生成權限實體,一個實體對應兩個持久化對象,這是一對多的場景。再比如,有些場景為了避免數據庫的聯表查詢,提升系統性能,會將客戶信息customer和賬戶信息account兩類數據保存到同一張數據庫表中,客戶和賬戶兩個實體可根據需要從一個持久化對象中生成,這就是多對一的場景。

值對象ValueObject

《實現領域驅動設計》一書中對值對象的定義:通過對象屬性值來識別的對象,它將多個相關屬性組合為一個概念整體。在DDD中用來描述領域的特定方面,并且是一個沒有標識符的對象,叫作值對象。

值對象描述了領域中的一件東西,這個東西是不可變的 ,它將不同的相關屬性組合成了一個概念整體。當度量和描述改變時,可以用另外一個值對象予以替換。它可以和其它值對象進行相等性比較,且不會對協作對象造成副作用。這部分在后面講“值對象的運行形態”時還會有例子。

簡單來說就是一堆不可變的屬性的集合,為了避免屬性的零碎

fc88a09a-0b1c-11ee-962d-dac502259ad0.jpg

人員實體原本包括:姓名、年齡、性別以及人員所在的省、市、縣和街道等屬性。這樣顯示地址相關的屬性就很零碎了對不對?現在,我們可以將“省、市、縣和街道等屬性”拿出來構成一個“地址屬性集合”,這個集合就是值對象了。

1. 值對象的業務形態

值對象是DDD領域模型中的一個基礎對象,它跟實體一樣都來源于事件風暴所構建的領域模型,都包含了若干個屬性,它與實體一起構成聚合。

我們不妨對照實體,來看值對象的業務形態,這樣更好理解。本質上,實體是看得到、摸得著的實實在在的業務對象,實體具有業務屬性、業務行為和業務邏輯。而值對象只是若干個屬性的集合 ,只有數據初始化操作和有限的不涉及修改數據的行為,基本不包含業務邏輯。值對象的屬性集雖然在物理上獨立出來了,但在邏輯上它仍然是實體屬性的一部分,用于描述實體的特征。

在值對象中也有部分共享的標準類型的值對象,它們有自己的限界上下文,有自己的持久化對象,可以建立共享的數據類微服務,比如數據字典。

2. 值對象的代碼形態

值對象在代碼中有這樣兩種形態。如果值對象是單一屬性,則直接定義為實體類的屬性;如果值對象是屬性集合,則把它設計為Class類 ,Class將具有整體概念的多個屬性歸集到屬性集合,這樣的值對象沒有ID,會被實體整體引用。

我們看一下下面這段代碼,person這個實體有若干個單一屬性的值對象,比如Id、name等屬性;同時它也包含多個屬性的值對象,比如地址address。

fca0e5e2-0b1c-11ee-962d-dac502259ad0.jpg

3. 值對象的運行形態

實體實例化后的DO對象的業務屬性和業務行為非常豐富,但值對象實例化的對象則相對簡單和乏味。除了值對象數據初始化和整體替換的行為外,其它業務行為就很少了。

值對象嵌入到實體的話,有這樣兩種不同的數據格式,也可以說是兩種方式,分別是屬性嵌入的方式和序列化大對象的方式。

引用單一屬性的值對象或只有一條記錄的多屬性值對象的實體,可以采用屬性嵌入的方式嵌入。引用一條或多條記錄的多屬性值對象的實體,可以采用序列化大對象的方式嵌入。比如,人員實體可以有多個通訊地址,多個地址序列化后可以嵌入人員的地址屬性。值對象創建后就不允許修改了,只能用另外一個值對象來整體替換。

案例1:以屬性嵌入的方式形成的人員實體對象,地址值對象直接以屬性值嵌入人員實體中。

fcc6e738-0b1c-11ee-962d-dac502259ad0.jpg

案例2:以序列化大對象的方式形成的人員實體對象,地址值對象被序列化成大對象Json串后,嵌入人員實體中。

fcd51718-0b1c-11ee-962d-dac502259ad0.jpg

4. 值對象的數據庫形態

DDD引入值對象是希望實現從“數據建模為中心”向“領域建模為中心”轉變,減少數據庫表的數量和表與表之間復雜的依賴關系,盡可能地簡化數據庫設計,提升數據庫性能。

如何理解用值對象來簡化數據庫設計呢?

傳統的數據建模大多是根據數據庫范式設計的,每一個數據庫表對應一個實體,每一個實體的屬性值用單獨的一列來存儲,一個實體主表會對應N個實體從表。而值對象在數據庫持久化方面簡化了設計,它的數據庫設計大多采用非數據庫范式,值對象的屬性值和實體對象的屬性值保存在同一個數據庫實體表中

舉個例子,還是基于上述人員和地址那個場景,實體和數據模型設計通常有兩種解決方案:

第一是把地址值對象的所有屬性都放到人員實體表中,創建人員實體,創建人員數據表;

第二是創建人員和地址兩個實體,同時創建人員和地址兩張表。

第一個方案會破壞地址的業務涵義和概念完整性,第二個方案增加了不必要的實體和表,需要處理多個實體和表的關系,從而增加了數據庫設計的復雜性。

那到底應該怎樣設計,才能讓業務含義清楚,同時又不讓數據庫變得復雜呢?

在領域建模時,我們可以將部分對象設計為值對象,保留對象的業務涵義,同時又減少了實體的數量;在數據建模時,我們可以將值對象嵌入實體,減少實體表的數量,簡化數據庫設計。

要想發揮對象的威力,就需要優先做領域建模,弱化數據庫的作用,只把數據庫作為一個保存數據的倉庫即可 。即使違反數據庫設計原則,也不用大驚小怪,只要業務能夠順利運行,就沒什么關系。

聚合根AggregateRoot

聚合根的主要目的是為了避免由于復雜數據模型缺少統一的業務規則控制,而導致聚合、實體之間數據不一致性的問題。

如果把聚合比作組織,那聚合根就是這個組織的負責人。聚合根也稱為根實體,它不僅是實體,還是聚合的管理者。

首先它作為實體本身,擁有實體的屬性和業務行為,實現自身的業務邏輯。

其次它作為聚合的管理者,在聚合內部負責協調實體和值對象按照固定的業務規則協同完成共同的業務邏輯。

最后在聚合之間,它還是聚合對外的接口人,以聚合根ID關聯的方式接受外部任務和請求,在上下文內實現聚合之間的業務協同。也就是說,聚合之間通過聚合根ID關聯引用,如果需要訪問其它聚合的實體,就要先訪問聚合根,再導航到聚合內部實體,外部對象不能直接訪問聚合內實體。

聚合Aggregate

在DDD中,實體和值對象是很基礎的領域對象。實體一般對應業務對象,它具有業務屬性和業務行為;而值對象主要是屬性集合,對實體的狀態和特征進行描述。但實體和值對象都只是個體化的對象,它們的行為表現出來的是個體的能力。

舉個例子。社會是由一個個的個體組成的,象征著我們每一個人。隨著社會的發展,慢慢出現了社團、機構、部門等組織,我們開始從個人變成了組織的一員,大家可以協同一致的工作,朝著一個最大的目標前進,發揮出更大的力量。

領域模型內的實體和值對象就好比個體,而能讓實體和值對象協同工作的組織就是聚合,它用來確保這些領域對象在實現共同的業務邏輯時,能保證數據的一致性。

聚合就是由業務和邏輯緊密關聯的實體和值對象組合而成的 ,聚合是數據修改和持久化的基本單元,每一個聚合對應一個倉儲,實現數據的持久化。

聚合有一個聚合根和上下文邊界,這個邊界根據業務單一職責和高內聚原則,定義了聚合內部應該包含哪些實體和值對象,而聚合之間的邊界是松耦合的。按照這種方式設計出來的微服務很自然就是“高內聚、低耦合”的。

聚合在DDD分層架構里屬于領域層,領域層包含了多個聚合,共同實現核心業務邏輯。聚合內實體以充血模型實現個體業務能力,以及業務邏輯的高內聚 。跨多個實體的業務邏輯通過領域服務來實現,跨多個聚合的業務邏輯通過應用服務來實現。比如有的業務場景需要同一個聚合的A和B兩個實體來共同完成,我們就可以將這段業務邏輯用領域服務來實現;而有的業務邏輯需要聚合C和聚合D中的兩個服務共同完成,這時你就可以用應用服務來組合這兩個服務。

怎樣設計聚合?

DDD領域建模通常采用事件風暴,它通常采用用例分析、場景分析和用戶旅程 分析等方法,通過頭腦風暴列出所有可能的業務行為和事件,然后找出產生這些行為的領域對象,并梳理領域對象之間的關系,找出聚合根,找出與聚合根業務緊密關聯的實體和值對象,再將聚合根、實體和值對象組合,構建聚合。

下面我們以保險的投保業務場景為例,看一下聚合的構建過程主要都包括哪些步驟。

fcec5d4c-0b1c-11ee-962d-dac502259ad0.png

第 1 步: 采用事件風暴,根據業務行為,梳理出在投保過程中發生這些行為的所有的實體和值對象 ,比如投保單、標的、客戶、被保人等等。

第 2 步: 從眾多實體中選出適合作為對象管理者的根實體,也就是聚合根。判斷一個實體是否是聚合根,你可以結合以下場景分析:是否有獨立的生命周期?是否有全局唯一ID?是否可以創建或修改其它對象?是否有專門的模塊來管這個實體。圖中的聚合根分別是投保單和客戶實體。

第 3 步: 根據業務單一職責和高內聚原則,找出與聚合根關聯的所有緊密依賴的實體和值對象。構建出 1 個包含聚合根(唯一)、多個實體和值對象的對象集合,這個集合就是聚合。在圖中我們構建了客戶和投保這兩個聚合。

第 4 步: 在聚合內根據聚合根、實體和值對象的依賴關系,畫出對象的引用和依賴模型。這里我需要說明一下:投保人和被保人的數據,是通過關聯客戶ID從客戶聚合中獲取的,在投保聚合里它們是投保單的值對象,這些值對象的數據是客戶的冗余數據,即使未來客戶聚合的數據發生了變更,也不會影響投保單的值對象數據。從圖中我們還可以看出實體之間的引用關系,比如在投保聚合里投保單聚合根引用了報價單實體,報價單實體則引用了報價規則子實體。

第 5 步: 多個聚合根據業務語義和上下文一起劃分到同一個限界上下文內。

這就是一個聚合誕生的完整過程了。

聚合的一些設計原則

《實現領域驅動設計》一書中對聚合設計原則的描述

1. 在一致性邊界內建模真正的不變條件。 聚合用來封裝真正的不變性,而不是簡單地將對象組合在一起。聚合內有一套不變的業務規則,各實體和值對象按照統一的業務規則運行,實現對象數據的一致性,邊界之外的任何東西都與該聚合無關,這就是聚合能實現業務高內聚的原因。

2. 設計小聚合。 如果聚合設計得過大,聚合會因為包含過多的實體,導致實體之間的管理過于復雜,高頻操作時會出現并發沖突或者數據庫鎖,最終導致系統可用性變差。而小聚合設計則可以降低由于業務過大導致聚合重構的可能性,讓領域模型更能適應業務的變化。

3. 通過唯一標識引用其它聚合。 聚合之間是通過關聯外部聚合根ID的方式引用,而不是直接對象引用的方式。外部聚合的對象放在聚合邊界內管理,容易導致聚合的邊界不清晰,也會增加聚合之間的耦合度。

4. 在邊界之外使用最終一致性。 聚合內數據強一致性,而聚合之間數據最終一致性。在一次事務中,最多只能更改一個聚合的狀態。如果一次業務操作涉及多個聚合狀態的更改,應采用領域事件的方式異步修改相關的聚合,實現聚合之間的解耦。

5. 通過應用層實現跨聚合的服務調用。 為實現微服務內聚合之間的解耦,以及未來以聚合為單位的微服務組合和拆分,應避免跨聚合的領域服務調用和跨聚合的數據庫表關聯。

原則需要消化吸收后靈活運用到自己的系統中才能產生威力

領域事件

領域事件是領域模型中非常重要的一部分,用來表示領域中發生的事件。一個領域事件將導致進一步的業務操作,在實現業務解耦的同時,還有助于形成完整的業務閉環。

舉例來說的話

領域事件可以是業務流程的一個步驟,比如投保業務繳費完成后,觸發投保單轉保單的動作;

也可能是定時批處理過程中發生的事件,比如批處理生成季繳保費通知單,觸發發送繳費郵件通知操作;

或者一個事件發生后觸發的后續動作,比如密碼連續輸錯三次,觸發鎖定賬戶的動作。

那如何識別領域事件呢?

很簡單,和剛才講的定義是強關聯的。在做用戶旅程或者場景分析時,我們要捕捉業務、需求人員或領域專家口中的關鍵詞:“如果發生……,則……”“當做完……的時候,請通知……”“發生……時,則……”等。在這些場景中,如果發生某種事件后,會觸發進一步的操作,那么這個事件很可能就是領域事件

領域事件總體架構

領域事件的執行需要一系列的組件和技術來支撐。

領域事件處理包括:事件構建和發布、事件數據持久化、事件總線、消息中間件、事件接收和處理等。下面我們逐一講一下。

fd1f1174-0b1c-11ee-962d-dac502259ad0.jpg

1. 事件構建和發布

事件基本屬性至少包括:事件唯一標識、發生時間、事件類型和事件源 ,其中事件唯一標識應該是全局唯一的,以便事件能夠無歧義地在多個限界上下文中傳遞。事件基本屬性主要記錄事件自身以及事件發生背景的數據。

另外事件中還有一項更重要,那就是業務屬性,用于記錄事件發生那一刻的業務數據,這些數據會隨事件傳輸到訂閱方,以開展下一步的業務操作。

事件基本屬性和業務屬性一起構成事件實體,事件實體依賴聚合根。領域事件發生后,事件中的業務數據不再修改,因此業務數據可以以序列化值對象的形式保存,這種存儲格式在消息中間件中也比較容易解析和獲取。

為了保證事件結構的統一,我們還會創建事件基類 DomainEvent(參考下圖),子類可以擴充屬性和方法。由于事件沒有太多的業務行為,實現方法一般比較簡單。

fd37bb7a-0b1c-11ee-962d-dac502259ad0.jpg

事件發布之前需要先構建事件實體并持久化。事件發布的方式有很多種,你可以通過應用服務或者領域服務發布到事件總線或者消息中間件,也可以從事件表中利用定時程序或數據庫日志捕獲技術獲取增量事件數據,發布到消息中間件。

2. 事件數據持久化

事件數據持久化可用于系統之間的數據對賬,或者實現發布方和訂閱方事件數據的審計。當遇到消息中間件、訂閱方系統宕機或者網絡中斷,在問題解決后仍可繼續后續業務流轉,保證數據的一致性。

事件數據持久化有兩種方案,在實施過程中你可以根據自己的業務場景進行選擇。

持久化到本地業務數據庫的事件表中,利用本地事務保證業務和事件數據的一致性。

持久化到共享的事件數據庫中。這里需要注意的是:業務數據庫和事件數據庫不在一個數據庫中,它們的數據持久化操作會跨數據庫,因此需要分布式事務機制來保證業務和事件數據的強一致性,結果就是會對系統性能造成一定的影響。

3. 事件總線(EventBus)

事件總線是實現微服務內聚合之間領域事件的重要組件,它提供事件分發和接收等服務。事件總線是進程內模型,它會在微服務內聚合之間遍歷訂閱者列表,采取同步或異步的模式傳遞數據。事件分發流程大致如下:

如果是微服務內的訂閱者(其它聚合),則直接分發到指定訂閱者;

如果是微服務外的訂閱者,將事件數據保存到事件庫(表)并異步發送到消息中間件;

如果同時存在微服務內和外訂閱者,則先分發到內部訂閱者,將事件消息保存到事件庫(表),再異步發送到消息中間件。

4. 消息中間件

跨微服務的領域事件大多會用到消息中間件,實現跨微服務的事件發布和訂閱。消息中間件的產品非常成熟,市場上可選的技術也非常多,比如Kafka,RabbitMQ等。

5. 事件接收和處理

微服務訂閱方在應用層采用監聽機制,接收消息隊列中的事件數據,完成事件數據的持久化后,就可以開始進一步的業務處理。領域事件處理可在領域服務中實現。

領域事件運行機制案例

承保業務流程的繳費通知單事件,來給你解釋一下領域事件的運行機制。這個領域事件發生在投保和收款微服務之間。發生的領域事件是:繳費通知單已生成。下一步的業務操作是:繳費。

fd5b22f4-0b1c-11ee-962d-dac502259ad0.jpg

事件起點:出單員生成投保單,核保通過后,發起生成繳費通知單的操作。

1.投保微服務應用服務,調用聚合中的領域服務createPaymentNotice和createPaymentNoticeEvent,分別創建繳費通知單、繳費通知單事件。其中繳費通知單事件類PaymentNoticeEvent繼承基類DomainEvent。

2.利用倉儲服務持久化繳費通知單相關的業務和事件數據。為了避免分布式事務,這些業務和事件數據都持久化到本地投保微服務數據庫中。

3.通過數據庫日志捕獲技術或者定時程序,從數據庫事件表中獲取事件增量數據,發布到消息中間件。這里說明:事件發布也可以通過應用服務或者領域服務完成發布。

4.收款微服務在應用層從消息中間件訂閱繳費通知單事件消息主題,監聽并獲取事件數據后,應用服務調用領域層的領域服務將事件數據持久化到本地數據庫中。

5.收款微服務調用領域層的領域服務PayPremium,完成繳費。

6.事件結束。

事件風暴

事件風暴需要準備些什么

1. 事件風暴的參與者

除了領域專家(對業務極其了解的人),事件風暴的其他參與者可以是DDD專家、架構師、產品經理、項目經理、開發人員和測試人員等項目團隊成員。

領域建模是統一團隊語言的過程,因此項目團隊應盡早地參與到領域建模中,這樣才能高效建立起團隊的通用語言。到了微服務建設時,領域模型也更容易和系統架構保持一致。

2. 事件風暴要準備的材料

在這個過程中,我們要用不同顏色的貼紙區分領域行為。如下圖,

用藍色表示命令

用綠色表示實體

橙色表示領域事件

黃色表示補充信息(補充信息主要用來說明注意事項,比如外部依賴等。)

fd90d7c8-0b1c-11ee-962d-dac502259ad0.jpg

3. 事件風暴的場地

事件風暴的發明者曾經建議要準備八米長的墻,這樣設計就不會受到空間的限制了。當然,這個不是必要條件,看各自的現實條件吧,不要讓思維受限就好。

或者是一個多人在線協作的白板。

4. 事件風暴分析的關注點

在領域建模的過程中,我們需要重點關注這類業務的語言和行為。比如某些業務動作或行為(事件)是否會觸發下一個業務動作,這個動作(事件)的輸入和輸出是什么?是誰(實體)發出的什么動作(命令),觸發了這個動作(事件)…我們可以從這些暗藏的詞匯中,分析出領域模型中的事件、命令和實體等領域對象。

如何用事件風暴構建領域模型

領域建模的過程主要包括產品愿景、業務場景分析、領域建模和微服務拆分與設計這幾個重要階段。下面以用戶中臺為例,介紹一下如何用事件風暴構建領域模型。

1. 產品愿景

產品愿景的主要目的是對產品頂層價值的設計,使產品目標用戶、核心價值、差異化競爭點等信息達成一致,避免產品偏離方向。

產品愿景的參與角色:領域專家、業務需求方、產品經理、項目經理和開發經理。

在建模之前,項目團隊要思考這樣兩點:

用戶中臺到底能夠做什么?

它的業務范圍、目標用戶、核心價值和愿景,與其它同類產品的差異和優勢在哪里?

這個過程也是明確用戶中臺建設方向和統一團隊思想的過程。參與者要對每一個點(下圖最左側列的內容)發表意見,用水筆寫在貼紙上,貼在黃色貼紙的位置。這個過程會讓參與者充分發表意見,最后會將發散的意見統一為通用語言。如果你的團隊的產品愿景和目標已經很清晰了,那這個步驟你可以忽略。

2. 業務場景分析

場景分析是從用戶視角出發的,根據業務流程或用戶旅程,采用用例和場景分析 ,探索領域中的典型場景,找出領域事件、實體和命令等領域對象,支撐領域建模。事件風暴參與者要盡可能地遍歷所有業務細節,充分發表意見,不要遺漏業務要點。

場景分析的參與角色:領域專家、產品經理、需求分析人員、架構師、項目經理、開發經理和測試經理。

用戶中臺有這樣三個典型的業務場景:

第一個是系統和崗位設置,設置系統中崗位的菜單權限;

第二個是用戶權限配置,為用戶建立賬戶和密碼,設置用戶崗位;

第三個是用戶登錄系統和權限校驗,生成用戶登錄和操作日志。

我們可以按照業務流程,一步一步搜尋用戶業務流程中的關鍵領域事件,比如崗位已創建,用戶已創建等事件。再找出什么行為會引起這些領域事件,這些行為可能是一個或若干個命令組合在一起產生的,比如創建用戶時,第一個命令是從公司HR系統中獲取用戶信息,第二個命令是根據HR的員工信息在用戶中臺創建用戶,創建完用戶后就會產生用戶已創建的領域事件。當然這個領域事件可能會觸發下一步的操作,比如發布到郵件系統通知用戶已創建,但也可能到此就結束了,你需要根據具體情況來分析是否還有下一步的操作。

fda2442c-0b1c-11ee-962d-dac502259ad0.jpg

3. 領域建模

領域建模時,我們會根據場景分析過程中產生的領域對象,比如命令、事件等之間關系,找出產生命令的實體,分析實體之間的依賴關系組成聚合,為聚合劃定限界上下文,建立領域模型以及模型之間的依賴。領域模型利用限界上下文向上可以指導微服務設計,通過聚合向下可以指導聚合根、實體和值對象的設計。

領域建模的參與角色:領域專家、產品經理、需求分析人員、架構師、項目經理、開發經理和測試經理。

具體可以分為這樣三步。

第一步:從命令和事件中提取產生這些行為的實體。用綠色貼紙表示實體。通過分析用戶中臺的命令和事件等行為數據,提取了產生這些行為的用戶、賬戶、認證票據、系統、菜單、崗位和用戶日志七個實體。

fdca69de-0b1c-11ee-962d-dac502259ad0.jpg

第二步:根據聚合根的管理性質從七個實體中找出聚合根,比如,用戶管理用戶相關實體以及值對象,系統可以管理與系統相關的菜單等實體等,可以找出用戶和系統等聚合根。然后根據業務依賴和業務內聚原則,將聚合根以及它關聯的實體和值對象組合為聚合,比如系統和菜單實體可以組合為“系統功能”聚合。按照上述方法,用戶中臺就有了系統功能、崗位、用戶信息、用戶日志、賬戶和認證票據六個聚合。

第三步:劃定限界上下文,根據上下文語義將聚合歸類。根據用戶域的上下文語境,用戶基本信息和用戶日志信息這兩個聚合共同構成用戶信息域,分別管理用戶基本信息、用戶登錄和操作日志。認證票據和賬戶這兩個聚合共同構成認證域,分別實現不同方式的登錄和認證。系統功能和崗位這兩個聚合共同構成權限域,分別實現系統和菜單管理以及系統的崗位配置。根據業務邊界,我們可以將用戶中臺劃分為三個限界上下文:用戶信息、認證和權限。

fde4bfd2-0b1c-11ee-962d-dac502259ad0.jpg

到這里我們就完成了用戶中臺領域模型的構建了。那由于領域建模的過程中產生的領域對象實在太多了,我們可以借助表格來記錄。

fe005490-0b1c-11ee-962d-dac502259ad0.jpg

4. 微服務拆分與設計

我們在基礎篇講過,原則上一個領域模型就可以設計為一個微服務,但由于領域建模時只考慮了業務因素,沒有考慮微服務落地時的技術、團隊以及運行環境等非業務因素,因此在微服務拆分與設計時,我們不能簡單地將領域模型作為拆分微服務的唯一標準,它只能作為微服務拆分的一個重要依據。

一般來說一個限界上下文拆分成一個微服務

微服務的設計還需要考慮服務的粒度、分層、邊界劃分、依賴關系和集成關系。除了考慮業務職責單一外,我們還需要考慮將敏態與穩態業務的分離、非功能性需求(如彈性伸縮要求、安全性等要求)、團隊組織和溝通效率、軟件包大小以及技術異構等非業務因素。

微服務設計建議參與的角色:領域專家、產品經理、需求分析人員、架構師、項目經理、開發經理和測試經理。

用戶中臺微服務設計如果不考慮非業務因素,我們完全可以按照領域模型與微服務一對一的關系來設計,將用戶中臺設計為:用戶、認證和權限三個微服務。但如果用戶日志數據量巨大,大到需要采用大數據技術來實現,這時用戶信息聚合與用戶日志聚合就會有技術異構。雖然在領域建模時,我們將他們放在一個了領域模型內,但如果考慮技術異構,這兩個聚合就不適合放到同一個微服務里了。我們可以以聚合作為拆分單位,將用戶基本信息管理和用戶日志管理拆分為兩個技術異構的微服務,分別用不同的技術來實現它們。

分層架構

DDD分層架構

DDD的分層架構在不斷發展。最早是傳統的四層架構;后來四層架構有了進一步的優化,實現了各層對基礎層的解耦;再后來領域層和應用層之間增加了上下文環境(Context)層,五層架構(DCI)就此形成了。

fe0f64c6-0b1c-11ee-962d-dac502259ad0.jpg

我們看一下上面這張圖,在最早的傳統四層架構中,基礎層是被其它層依賴的,它位于最核心的位置,那按照分層架構的思想,它應該就是核心,但實際上領域層才是軟件的核心,所以這種依賴是有問題的。后來我們采用了依賴倒置(Dependency inversion principle,DIP)的設計,優化了傳統的四層架構,實現了各層對基礎層的解耦。

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

fe3868f8-0b1c-11ee-962d-dac502259ad0.png

1.用戶接口層

用戶接口層負責向用戶顯示信息和解釋用戶指令。這里的用戶可能是:用戶、程序、自動化測試和批處理腳本等等。

2.應用層

應用層是很薄的一層,理論上不應該有業務規則或邏輯,主要面向用例和流程相關的操作。但應用層又位于領域層之上,因為領域層包含多個聚合,所以它可以協調多個聚合的服務和領域對象完成服務編排和組合,協作完成業務操作。

此外,應用層也是微服務之間交互的通道,它可以調用其它微服務的應用服務,完成微服務之間的服務組合和編排。

這里我要提醒你一下:在設計和開發時,不要將本該放在領域層的業務邏輯放到應用層中實現。因為龐大的應用層會使領域模型失焦,時間一長你的微服務就會演化為傳統的三層架構,業務邏輯會變得混亂。

另外,應用服務是在應用層的,它負責服務的組合、編排和轉發,負責處理業務用例的執行順序以及結果的拼裝,以粗粒度的服務通過API網關向前端發布。還有,應用服務還可以進行安全認證、權限校驗、事務控制、發送或訂閱領域事件等。

3.領域層

領域層的作用是實現企業核心業務邏輯 ,通過各種校驗手段保證業務的正確性。領域層主要體現領域模型的業務能力,它用來表達業務概念、業務狀態和業務規則。

領域層包含聚合根、實體、值對象、領域服務 等領域模型中的領域對象。

這里我要特別解釋一下其中幾個領域對象的關系,以便你在設計領域層的時候能更加清楚。

首先,領域模型的業務邏輯主要是由實體和領域服務來實現的,其中實體會采用充血模型來實現所有與之相關的業務功能。

其次,你要知道,實體和領域服務在實現業務邏輯上不是同級的,當領域中的某些功能,單一實體(或者值對象)不能實現時,領域服務就會出馬,它可以組合聚合內的多個實體(或者值對象),實現復雜的業務邏輯。

4.基礎層

基礎層是貫穿所有層的,它的作用就是為其它各層提供通用的技術和基礎服務,包括第三方工具、驅動、消息中間件、網關、文件、緩存以及數據庫 等。比較常見的功能還是提供數據庫持久化。

基礎層包含基礎服務,它采用依賴倒置設計,封裝基礎資源服務,實現應用層、領域層與基礎層的解耦,降低外部資源變化對應用的影響。

比如說,在傳統架構設計中,由于上層應用對數據庫的強耦合,很多公司在架構演進中最擔憂的可能就是換數據庫了,因為一旦更換數據庫,就可能需要重寫大部分的代碼,這對應用來說是致命的。那采用依賴倒置的設計以后,應用層就可以通過解耦來保持獨立的核心業務邏輯。當數據庫變更時,我們只需要更換數據庫基礎服務就可以了,這樣就將資源變更對應用的影響降到了最低。

DDD分層架構最重要的原則

在《實現領域驅動設計》一書中,DDD分層架構有一個重要的原則:每層只能與位于其下方的層發生耦合

而架構根據耦合的緊密程度又可以分為兩種:嚴格分層架構和松散分層架構。優化后的DDD分層架構模型就屬于嚴格分層架構,任何層只能對位于其直接下方的層產生依賴。而傳統的DDD分層架構則屬于松散分層架構,它允許某層與其任意下方的層發生依賴。

建議采用嚴格分層架構。

在嚴格分層架構中,領域服務只能被應用服務調用,而應用服務只能被用戶接口層調用,服務是逐層對外封裝或組合的,依賴關系清晰。而在松散分層架構中,領域服務可以同時被應用層或用戶接口層調用,服務的依賴關系比較復雜且難管理,甚至容易使核心業務邏輯外泄。

試想下,如果領域層中的某個服務發生了重大變更,那該如何通知所有調用方同步調整和升級呢?但在嚴格分層架構中,你只需要逐層通知上層服務就可以了。

代碼架構

整潔架構

整潔架構又名“洋蔥架構 ”。為什么叫它洋蔥架構?看看下面這張圖你就明白了。整潔架構的層就像洋蔥片一樣,它體現了分層的設計思想。

在整潔架構里,同心圓代表應用軟件的不同部分,從里到外依次是領域模型、領域服務、應用服務和最外圍的容易變化的內容,比如用戶界面和基礎設施。

整潔架構最主要的原則是依賴原則,它定義了各層的依賴關系,越往里依賴越低,代碼級別越高,越是核心能力。外圓代碼依賴只能指向內圓,內圓不需要知道外圓的任何情況。

fe48985e-0b1c-11ee-962d-dac502259ad0.png

在洋蔥架構中,各層的職能是這樣劃分的:

領域模型實現領域內核心業務邏輯,它封裝了企業級的業務規則。領域模型的主體是實體,一個實體可以是一個帶方法的對象,也可以是一個數據結構和方法集合。

領域服務實現涉及多個實體的復雜業務邏輯。

應用服務實現與用戶操作相關的服務組合與編排,它包含了應用特有的業務流程規則,封裝和實現了系統所有用例。

最外層主要提供適配的能力,適配能力分為主動適配和被動適配。主動適配主要實現外部用戶、網頁、批處理和自動化測試等對內層業務邏輯訪問適配。被動適配主要是實現核心業務邏輯對基礎資源訪問的適配,比如數據庫、緩存、文件系統和消息中間件等。

紅圈內的領域模型、領域服務和應用服務一起組成軟件核心業務能力。

六邊形架構

六邊形架構又名“端口適配器架構” 。追溯微服務架構的淵源,一般都會涉及到六邊形架構。

六邊形架構的核心理念是:應用是通過端口與外部進行交互的 。我想這也是微服務架構下API網關盛行的主要原因吧。

也就是說,在下圖的六邊形架構中,紅圈內的核心業務邏輯(應用程序和領域模型)與外部資源(包括APP、Web應用以及數據庫資源等)完全隔離,僅通過適配器進行交互。它解決了業務邏輯與用戶界面的代碼交錯問題,很好地實現了前后端分離。六邊形架構各層的依賴關系與整潔架構一樣,都是由外向內依賴。

fe66739c-0b1c-11ee-962d-dac502259ad0.png

六邊形架構將系統分為內六邊形和外六邊形兩層,這兩層的職能劃分如下:

紅圈內的六邊形實現應用的核心業務邏輯;

外六邊形完成外部應用、驅動和基礎資源等的交互和訪問,對前端應用以API主動適配的方式提供服務,對基礎資源以依賴倒置被動適配的方式實現資源訪問。

六邊形架構的一個端口可能對應多個外部系統,不同的外部系統也可能會使用不同的適配器,由適配器負責協議轉換。這就使得應用程序能夠以一致的方式被用戶、程序、自動化測試和批處理腳本使用。

三種模型對比

雖然DDD分層架構、整潔架構、六邊形架構的架構模型表現形式不一樣,但你不要被它們的表象所迷惑,這三種架構模型的設計思想正是微服務架構高內聚低耦合原則的完美體現,而它們身上閃耀的正是以領域模型為中心的設計思想。

fe8bd2fe-0b1c-11ee-962d-dac502259ad0.png

我們看下上面這張圖,結合圖示對這三種架構模型做一個分析。

請你重點關注圖中的紅色線框,它們是非常重要的分界線,這三種架構里面都有,它的作用就是將核心業務邏輯與外部應用、基礎資源進行隔離。

紅色框內部主要實現核心業務邏輯,但核心業務邏輯也是有差異的,有的業務邏輯屬于領域模型的能力,有的則屬于面向用戶的用例和流程編排能力。按照這種功能的差異,我們在這三種架構中劃分了應用層和領域層,來承擔不同的業務邏輯。

領域層實現面向領域模型,實現領域模型的核心業務邏輯,屬于原子模型,它需要保持領域模型和業務邏輯的穩定,對外提供穩定的細粒度的領域服務,所以它處于架構的核心位置。

應用層實現面向用戶操作相關的用例和流程,對外提供粗粒度的API服務。它就像一個齒輪一樣進行前臺應用和領域層的適配,接收前臺需求,隨時做出響應和調整,盡量避免將前臺需求傳導到領域層。應用層作為配速齒輪則位于前臺應用和領域層之間。

COLA4.0

GitHub:https://github.com/alibaba/COLA 作者博客:https://blog.csdn.net/significantfrank/article/details/110934799

生成器:https://start.aliyun.com/bootstrap.html

fea732c4-0b1c-11ee-962d-dac502259ad0.png

基于 Spring Boot + MyBatis Plus + Vue & Element 實現的后臺管理系統 + 用戶小程序,支持 RBAC 動態權限、多租戶、數據權限、工作流、三方登錄、支付、短信、商城等功能

項目地址:https://github.com/YunaiV/ruoyi-vue-pro

視頻教程:https://doc.iocoder.cn/video/

DDD實戰

feb9e162-0b1c-11ee-962d-dac502259ad0.png

模塊劃分如下

fed0aaa0-0b1c-11ee-962d-dac502259ad0.png

本次我們重點完成

賬戶模塊

廣告管理模塊

廣告下發模塊

戰略設計

戰略設計階段:此階段主要是依賴于事件風暴(可理解為基于事件流程的頭腦風暴),來呈現出產品的發展方向以及核心流程和場景,并文檔化。

1.產品要解決的問題,以及從用戶角度歸納出典型業務場景,落實文檔 -----> 產品愿景、場景分析

2.找出上一步總結出的關鍵名詞,作為各個場景的實體 -----> 領域建模:找出領域對象

3.根據上一步總結出實體,總結出之間的關系(聚合根、值對象、普通實體),劃分出聚合 -----> 領域建模:定義聚合

4.以上一步歸納出的聚合為單位,根據業務場景將聚合分組,得到限界上下文(也就是所屬的領域) ----->領域建模:定義界限上下文

在第 1 步落實文檔后,后面的 2,3,4 領域建模階段都要不斷的參照第 1 步總結出的業務流程場景來進行拆解與合并;產品愿景、場景分析 兩個階段是從宏觀到微觀的過程,而 領域建模階段是從微觀到宏觀的過程,也就是自底向上的思想。整體就像是總分、分總的過程。

產品愿景

產品愿景是對產品頂層價值設計,對產品目標用戶、核心價值、差異化競爭點等信息達成一致,避免產品偏離方向。

服務用戶

想投廣告的人。廣告主以及代理商的優化師

提供能力

給廣告主提供豐富的廣告資源,實現廣告的管理和投放。廣告投放效果,以及效率

提高交互效率。提供open-api,可以讓客戶通過程序化的方式管理廣告。

定位

業界先進的一站式效果投放平臺。提供RTA,DPA,OCPX等專業能力

優勢

依托于手機廠商提供的數據能力,給廣告主提供更好的投放效果。

場景分析

fee0a892-0b1c-11ee-962d-dac502259ad0.png

領域建模

領域建模是通過對業務和問題域進行分析,建立領域模型。

向上通過限界上下文指導微服務邊界設計,向下通過聚合指導實體對象設計。

領域建模是一個收斂的過程,分三步:

第一步找出領域實體和值對象等領域對象;

第二步找出聚合根,根據實體、值對象與聚合根的依賴關系,建立聚合;

第三步根據業務及語義邊界等因素,定義限界上下文。

第一步:找出實體和值對象等領域對象

根據場景分析,分析并找出發起或產生這些命令或領域事件的實體和值對象,將與實體或值對象有關的命令和事件聚集到實體。

fef84f88-0b1c-11ee-962d-dac502259ad0.png

第二步:定義聚合

定義聚合前,先找出聚合根。然后找出與聚合根緊密依賴的實體和值對象。我們發現審批意見、審批規則和請假單緊密關聯,組織關系和人員緊密關聯。

ff2fd71e-0b1c-11ee-962d-dac502259ad0.png

第三步:定義限界上下文

把整個定義為廣告管理限界上下文

通用語言

廣告業務:

中文 英文
廣告計劃 AdCampaign
廣告組 AdGroup
廣告定向 AdTargeting
廣告創意 AdCreative
廣告素材 AdAsset
操作日志 OperationLog
賬號 Account

微服務拆分

理論上一個限界上下文就可以設計為一個微服務,但還需要綜合考慮多種外部因素,比如:職責單一性、敏態與穩態業務分離、非功能性需求(如彈性伸縮、版本發布頻率和安全等要求)、軟件包大小、團隊溝通效率和技術異構等非業務要素。

可以微服務的拆分粒度大一些,但是聚合和限界上下文一定要邊界清晰,后續隨著某些功能逐漸變大再去拆分也會比較容易

戰術設計

有了戰略設計階段的結果,反而戰術設計階段相對清晰一些。

1.按照 DDD 四層模型建包,咱們這里使用COLA生成的包結構

2.確定聚合中的對象關系,定義哪些是實體,哪些是值對象,具體字段都有什么。

3.通過戰略設計階段文檔中的命令、事件來編排充血模型的領域對象,構建應用服務與領域服務

詳細設計

技術選型跟上面的關系不大。可以使用COLA4.0分層框架。

使用SpringCloud技術棧,以及根據業務建模選擇中間件。





審核編輯:劉清

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 數據庫
    +關注

    關注

    7

    文章

    3839

    瀏覽量

    64543
  • 驅動設計
    +關注

    關注

    1

    文章

    111

    瀏覽量

    15294

原文標題:2萬字帶你入門DDD

文章出處:【微信號:芋道源碼,微信公眾號:芋道源碼】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    萬字長文,看懂激光基礎知識!

    深入介紹激光基礎知識,幫助您輕松理解激光領域的關鍵概念和原理。
    的頭像 發表于 12-20 09:49 ?204次閱讀
    <b class='flag-5'>萬字</b>長文,看懂激光基礎知識!

    在DVEVM上通過ddd運行Demo

    電子發燒友網站提供《在DVEVM上通過ddd運行Demo.pdf》資料免費下載
    發表于 10-15 10:05 ?0次下載
    在DVEVM上通過<b class='flag-5'>ddd</b>運行Demo

    TVP5146M2 VBI快速入門

    電子發燒友網站提供《TVP5146M2 VBI快速入門.pdf》資料免費下載
    發表于 09-30 11:10 ?0次下載
    TVP5146M<b class='flag-5'>2</b> VBI快速<b class='flag-5'>入門</b>

    DDD學習與感悟——向屎山沖鋒

    軟件系統是通過軟件開發來解決某一個業務領域或問題單元而產生的一個交付物。而通過軟件設計可以幫助我們開發出更加健壯的軟件系統。因此,軟件設計是從業務領域到軟件開發之間的橋梁。而DDD是軟件設計中的其中
    的頭像 發表于 09-24 13:31 ?248次閱讀
    <b class='flag-5'>DDD</b>學習與感悟——向屎山沖鋒

    第三篇-V1.5 TB6612電機pwm控制STM32智能小車 STM32F103C8T6單片機

    通過合理的硬件設計和詳細的視頻筆記介紹,硬件使用STM32F103主控資料多方便學習,通過3萬字筆記、12多個小時視頻、20多章節代碼手把手教會你如何開發和調試。
    的頭像 發表于 08-12 18:29 ?1696次閱讀
    第三篇-V1.5 TB6612電機pwm控制STM32智能小車 STM32F103C8T6單片機

    第一篇:V1.5-STM32f103c8t6智能小車筆記 標準庫開發 6612電機驅動新手入門項目

    這是全網最詳細、性價比最高的STM32實戰項目入門教程,通過合理的硬件設計和詳細的視頻筆記介紹,硬件使用STM32F103主控資料多方便學習,通過3萬字筆記、12多個小時視頻、20多章節代碼手把手教會你如何開發和調試。讓你更快掌握嵌入式系統開發。
    的頭像 發表于 08-12 18:25 ?1713次閱讀
    第一篇:V1.5-STM32f103c8t6智能小車筆記 標準庫開發 6612電機驅動新手<b class='flag-5'>入門</b>項目

    1.3萬字!詳解半導體先進封裝行業,現狀及發展趨勢!

    。 典型封裝技術包括:1)倒片封裝(Flip-Chip):芯片倒置,舍棄金屬引線,利用凸塊連接;2)扇入型/扇出型封裝(Fan-In/Fan-Out):在晶圓上進行整體封裝,成本更低,關鍵工藝為重新布線(RDL);3)2.5D/3D封裝:2.5D封裝中芯片位于硅中介層上,3D封裝舍
    的頭像 發表于 07-03 08:44 ?2059次閱讀
    1.3<b class='flag-5'>萬字</b>!詳解半導體先進封裝行業,現狀及發展趨勢!

    萬字長文淺談系統穩定性建設

    流程:需求階段,研發階段,測試階段,上線階段,運維階段;整個流程中的所有參與人員:產品,研發,測試,運維人員都應關注系統的穩定性。業務的發展及系統建設過程中,穩定性就是那個1,其他的是1后面的0,沒有穩定性,就好比將
    的頭像 發表于 07-02 10:31 ?407次閱讀
    <b class='flag-5'>萬字</b>長文淺談系統穩定性建設

    這個調試工具咋賣39.9?分析了原理后,我悟了

    ——功能(第2章),電路設計實現原理(3-5章),組裝步驟(第6章),軟件說明(第7章)展開手把手教學。助你快速入門并學透嵌入式產品的基礎設計理念。前方萬字干貨預警!建
    的頭像 發表于 06-21 08:04 ?180次閱讀
    這個調試工具咋賣39.9?分析了原理后,我悟了

    商湯大模型開“卷”長文本,支持100萬字處理

    知情者透露,此次升級的日日新大模型還具備跨平臺操作特性,在Web和App端都可以使用。App端更是新增了粵語口語語音對話功能,進一步提升了模型對粵語及香港本土文化的理解。
    的頭像 發表于 05-29 11:43 ?428次閱讀

    MiniMax推出“海螺AI”,支持超長文本處理

    近日,大模型公司MiniMax宣布,其全新產品“海螺AI”已正式上架。這款強大的AI工具支持高達200ktokens的上下文長度,能夠在1秒內處理近3萬字的文本。
    的頭像 發表于 05-17 09:30 ?780次閱讀

    AI初創企業推MoE混合專家模型架構新品abab 6.5

    losoev 6.5s:與 losoev 6.5 共享相同的訓練技術和數據,但效率更高,同樣支持 200k tokens 的上下文長度,且能夠在 1 秒鐘內處理近 3 萬字的文本。
    的頭像 發表于 04-17 15:06 ?532次閱讀

    阿里通義千問重磅升級,免費開放1000萬字長文檔處理功能

    近日,阿里巴巴旗下的人工智能應用通義千問迎來重磅升級,宣布向所有人免費開放1000萬字的長文檔處理功能,這一創新舉措使得通義千問成為全球文檔處理容量第一的AI應用。
    的頭像 發表于 03-26 11:09 ?827次閱讀

    馬斯克狀告OpenAI,OpenAI回應馬斯克訴訟

    馬斯克在長達46頁、1.4萬字的訴訟文件中,控訴OpenAI背離了其初衷——即致力于開發開源人工通用智能(AGI)并服務全人類。
    的頭像 發表于 03-04 15:33 ?952次閱讀

    Purple Pi 帶你7天入門OpenHarmony

    大家好!我是一名剛入門OpenHarmony的小白,很高興能夠和大家一起學習OpenHarmony,在本系列文章里,我將分享使用PurplePiOH從零開始學習開源鴻蒙的整個流程,并提供每一步需要
    的頭像 發表于 02-19 13:20 ?511次閱讀
    Purple Pi <b class='flag-5'>帶你</b>7天<b class='flag-5'>入門</b>OpenHarmony
    主站蜘蛛池模板: 亚色成人| 综合久久婷婷| avtt天堂网永久资源| 一区二区三区在线播放| 色橹橹| 国产特黄一级片| 欧美精品成人久久网站| 天堂电影在线| 业余性自由色xxxx视频| 久久国产99| 欧美一区视频| 亚洲第一页国产| 69hdxxxx日本| sesese在线播放| 亚洲精品91大神在线观看| 国产成人1024精品免费| 久久精品操| 久久久美女视频| 日本加勒比高清一本大道| 午夜视频在线观看免费视频| 最新激情网站| 6月婷婷| 欧美天天| 久久啊| 4444kk在线看片| 伊人www| 五月婷六月婷婷| 特级全黄大片| 涩涩涩丁香色婷五月网视色| 四虎网址最新| 日本高清午夜色wwwσ| 拍拍拍美女黄色1000视频| 欧美日本综合| www.亚洲成在线| 夜夜骑日日操| 天天视频国产免费入口| 色极影院| 91免费网站在线看入口黄| 亚洲色图25p| 色视频久久| 六九视频在线观看|