這是一種思想,不是一個工具。更多內(nèi)容前往 IT-BLOG
一、領域驅(qū)動設計(DDD:Domain-Driven Design)
Eric Evans
于2004
年提出的一種軟件設計方法和理論。在應用架構的設計中,領域驅(qū)動設計DDD
占據(jù)著非常重要的位置,可以說DDD
是應用架構設計的核心。DDD
是一套綜合軟件系統(tǒng)分析和設計的面向?qū)ο蠼7椒ā?/p>
過去系統(tǒng)分析和系統(tǒng)設計都是分離的,正如“系統(tǒng)分析師” 和“系統(tǒng)設計師” 兩種職稱考試一樣,這樣割裂的結果導致,需求分析的結果無法直接進行設計編程,而能夠進行編程運行的代碼卻扭曲需求,導致客戶運行軟件后才發(fā)現(xiàn)很多功能不是自己想要的,而且軟件不能快速跟隨需求變化。
DDD則打破了這種隔閡,提出了領域模型概念,統(tǒng)一了分析和設計編程,使得軟件能夠更靈活快速跟隨需求變化。
二、DDD與數(shù)據(jù)驅(qū)動設計的區(qū)別
DDD
給我們帶來的是設計模式的改變。DDD
的設計模式與傳統(tǒng)的面向數(shù)據(jù)驅(qū)動的開發(fā)模式有明顯的區(qū)別。
【1】數(shù)據(jù)驅(qū)動設計從數(shù)據(jù)出發(fā),先梳理E-R
圖(實體-聯(lián)系圖),設計數(shù)據(jù)庫表結構,編寫DAO
,然后實現(xiàn)業(yè)務邏輯。數(shù)據(jù)驅(qū)動設計主要采用貧血模型[數(shù)據(jù)對象除了簡單setter/getter
方法外,沒有任何業(yè)務方法],業(yè)務邏輯散落在大量的方法中,當系統(tǒng)越來越復雜時,開發(fā)和維護成本很高。
【2】DDD
從領域出發(fā),主要采用充血模型,分析領域內(nèi)模型及它們之間的關系,并進行領域建模,設計核心業(yè)務邏輯,進而實現(xiàn)技術細節(jié)。通過DDD
,定義領域模型,從而確定業(yè)務和應用的邊界,保證業(yè)務與代碼的一致性。
DDD
最大的好處是:接觸到需求第一步就是考慮領域模型,而不是將其切割成數(shù)據(jù)和行為,然后數(shù)據(jù)用數(shù)據(jù)庫實現(xiàn),行為使用服務實現(xiàn),最后造成需求的首肢分離。DDD
讓你首先考慮的是業(yè)務語言,而不是數(shù)據(jù)。重點不同導致編程世界觀不同。領域模型和數(shù)據(jù)模型是解耦的,有時也不是一一對應的,因此在應用DDD
進行設計時,一定要擺脫數(shù)據(jù)模型優(yōu)先的束縛,不要讓領域模型被數(shù)據(jù)模型“綁架”,設計出合理的領域模型是首要任務。
DDD
是解決復雜中大型軟件的一套行之有效方式,在國外已經(jīng)成為主流。DDD
認為很多原因造成軟件的復雜性,我們不可能避免這些復雜性,能做的是對復雜的問題進行控制。而一個好的領域模型是控制復雜問題的關鍵。領域模型的價值在于提供一種通用的語言,使得領域?qū)<?、產(chǎn)品經(jīng)理和軟件技術人員聯(lián)系在一起,溝通無歧義。
三、DDD與微服務的關系
微服務提倡將應用劃分成更細粒度的服務,服務之間互相協(xié)調(diào)、互相配合,為用戶提供最終價值,是技術層面的分布式技術架構模式,是技術實現(xiàn)和部署的范疇。
DDD
根據(jù)限界上下文設計出的領域模型和領域服務,通過微服務進行落地,并結合微服務及其他分布式技術(如DevOps
、CI/CD
、秒殺、全鏈路壓測等),加速系統(tǒng)的落地。一個域服務可由一個微服務來實現(xiàn),也可根據(jù)DDD
領域分析拆分為多個微服務,對外集合成統(tǒng)一的域服務。
四、DDD常用的分析方法
DDD概念參考鏈接
DDD
常用的分析方法主要有用例分析法、四色建模法、事件風暴法、領域故事講述、用例法、戰(zhàn)術設計、戰(zhàn)略設計、洋蔥框架、六邊形架構、分層架構、CQRS
和COLA
等。
用例分析法
在比較傳統(tǒng)的需求調(diào)研過程中結合領域模型的設計思路進行,核心是通過業(yè)務需求、場景流程等梳理用例,進而規(guī)劃領域模型。
用例分析的前提是業(yè)務架構的需求輸入,其中核心是業(yè)務能力與業(yè)務流程。
比如電商領域的訂單尋源、庫存鎖定、商品價格計算、優(yōu)惠券核銷等業(yè)務能力,以及訂單處理、分單和拆單、逆向退款等業(yè)務流程。
編寫用例時要避免使用技術術語,應該使用最終用戶或者領域?qū)<铱梢岳斫獾恼Z言,進而我們可以基于用例分析法,根據(jù)語義來整理用例,然后整理領域模型,大概步驟如下。
收集用例: 從業(yè)務能力、業(yè)務流程、業(yè)務需求描述中進行提取,收集相應的名詞、動詞、形容詞,以及對應的業(yè)務場景。
提取實體: 從名詞中定位出主要實體,如商品、SKU、品類等。
提取屬性: 從形容詞中添加實體屬性,如顏色、價格等。
添加關聯(lián): 從動詞或形容詞中添加實體和實體之間的關聯(lián),如商品“包含”SKU,賣家“開設”“多家”店鋪等。
完善模型: 識別出初步模型,驗證并迭代模型,同時補充用例驗證模型、業(yè)務流程驗證模型。
舉個關于電商的例子:假設有這樣的需求描述:“會員使用代金券兌換了很多促銷的商品?!?br> 我們先從名詞“會員”“代金券”“商品”中提取實體,并從形容詞“促銷的”提取商品的屬性,進而將動詞“使用”“兌換”識別成關聯(lián),同時結合行業(yè)知識得知,代金券屬于優(yōu)惠券的一種,最終得出領域模型。
四色建模法
四色建模法在實踐中也比較常用,其包括以下幾個核心概念。
時間記錄(Moment-Interval): 具有可追溯性的記錄運營或管理數(shù)據(jù)的時刻或時段對象(如用粉紅色表示)。
人、地、物(Party-Place-Thing Archetype,PPT): 代表參與到流程中的參與方、地點、物(如用綠色表示)。
角色(Role): 在時間記錄與PPT對象(通常是參與方)之間參與的角色(如用黃色表示)。
描述(Description): 對PPT對象的一種補充描述(如用藍色表示)。
簡單地說,四色建模法關注的是,某個人(Party)的角色(PartyRole)在某個地點(Place)的角色(PlaceRole)用某個東西(Thing)的角色(ThingRole)做了某件事情(Moment-Interval)。
下面以一個課程報名繳費的例子對四色建模法進行說明:
報名人可以為學生進行報名,產(chǎn)生對應的報名登記記錄和課程表,進而繳費人進行繳費,產(chǎn)生繳費記錄。
在這個過程中,“人”有學生和課程,對應的“角色”是報名人和繳費人,完成的“時間記錄”是報名登記記錄、課程表及繳費記錄,再加上一些補充描述。
事件風暴法
事件風暴又稱事件建模,與頭腦風暴類似,可以快速分析復雜的業(yè)務領域,完成領域建模的目標。事件風暴是事件驅(qū)動設計的典型代表,是一種快速、輕量且未得到充分認可的群體建模技術,它對于加速開發(fā)團隊非常適用。
事件風暴法關注以下元素:
事件: 發(fā)生了什么事情,產(chǎn)生了什么結果(如用橘黃色表示)。
屬性: 事件的輸入、輸出,是對時間的細化描述。
命令: 某個動作的發(fā)起者,可能是人、外部事件、定時器等(如用藍色表示)。
領域: 領域的聚合、內(nèi)聚、低耦合,聚合內(nèi)部保證數(shù)據(jù)的一致性(如用黃色表示)。
簡單理解就是誰在何時基于什么(輸入)做了什么(命令),產(chǎn)生了什么(輸出),影響了什么(事件),最后聚合成了什么(領域)。
事件風暴催化并加速整個建模過程,強調(diào)正確的人(業(yè)務人員、領域?qū)<?、技術人員、架構師、測試人員等關鍵角色都要參與其中)、開放空間(有足夠的空間可以將事件流可視化,讓人們可以交互討論)、即時貼(至少三種顏色),關聯(lián)的人充分討論,集體決策,從價值角度來審視業(yè)務流程的合理性。領域事件容易促使業(yè)務人員和非業(yè)務人員達成共識。
下面通過一個電商的例子說明事件風暴的主要過程:
【1】基于業(yè)務流程和業(yè)務流程的輸入,對事件進行頭腦風暴,主要識別應用層面的主要狀態(tài)結果。比如識別出“商品已創(chuàng)建”,“庫存已扣減”,“訂單已支付”等。
【2】識別命令,即什么人做什么事,可以識別出運營人員可以添加商品和編輯庫存,用戶可以創(chuàng)建訂單,并伴隨著對應的事件。
【3】進行聚合,即將相關的實體聚合在一起,可以看到商品、庫存、訂單三個領域初步識別,并與相關的命令和事件結合在一起。
【4】對這些領域進行邊界劃分,識別出對應的限界上下文。
五、DDD分層架構
DDD
在具體落地實施的過程中,強調(diào)四層分層結構,將核心概念進行有效的整合,各層的職能定義如下。
展示層(Facade Layer): 負責與不同用戶和應用之間的交互協(xié)議和數(shù)據(jù)格式的轉(zhuǎn)換,因此它又叫用戶接口層。
應用層(Application Layer): 應用層是很薄的一層,負責展示層與領域?qū)又g的協(xié)調(diào),它是與其他系統(tǒng)的應用層進行交互的必要渠道,負責對領域?qū)咏M件進行簡單封裝,例如事務、調(diào)用應用程序的任務。應用層要盡量簡單,其服務及方法一般以用例為對應關系,通常一個用例對應到一個應用層的服務方法,方法中不包含業(yè)務規(guī)則或者知識,不保留業(yè)務對象的狀態(tài),只保留應用任務的進度狀態(tài),更注重業(yè)務能力或者業(yè)務流程的相關展示。主要通過調(diào)用領域?qū)雍突A設施層來完成協(xié)調(diào)。
領域?qū)樱―omain Layer): 領域?qū)邮?code>DDD的核心,包含一些核心概念,如領域?qū)嶓w、值對象、領域服務、聚合,以及它們之間的關系。它主要負責表達業(yè)務概念、業(yè)務狀態(tài)信息及業(yè)務規(guī)則,具體表現(xiàn)形式是領域模型。DDD
提倡充血模型,即盡量將業(yè)務邏輯歸屬到領域?qū)ο笊稀?br>基礎設施層(Infrastructure Layer): 基礎設施層向其他層提供通用的技術能力,為應用層傳遞消息(如API網(wǎng)關等),為領域?qū)犹峁┏志没瘷C制(如數(shù)據(jù)庫資源、中間件交互等),屏蔽技術底座能力(如底層服務的健康度檢查、配置參數(shù)等)及其他通用的工具類服務。
除了比較經(jīng)典的四層分層架構,DDD
還有一種松散分層架構,即端口適配器架構。
端口適配器架構通過劃分內(nèi)部和外部,系統(tǒng)由內(nèi)而外圍繞領域模型展開。領域部分位于最內(nèi)層,應用程序包含領域模型和業(yè)務邏輯,對于外部而言,通過各種適配器進行上下文集成,包括數(shù)據(jù)持久化、第三方數(shù)據(jù)集成,同時基于依賴注入和Mock
機制,適配器完成便捷的替換和模擬。
不論哪種分層架構,都遵循以下幾個通用的DDD
分層原則:
無環(huán)依賴原則: 組件的依賴關系中沒有環(huán)路,如果出現(xiàn),則需要打破循環(huán)依賴。
穩(wěn)定依賴原則: 被依賴者應該比依賴者更穩(wěn)定,同時組件的抽象程度應該與其穩(wěn)定程度保持一致。一個穩(wěn)定的組件應該是抽象的,這樣便于擴展。
依賴倒置原則: 高層次的模塊不應該依賴低層次的模塊,它們都應該依賴抽象。抽象不應該依賴具體,具體應該依賴抽象。
六、實戰(zhàn)
以渠道中心(一個微服務)作為例子來做領域模型設計,核心就是設計2個圖,一個是戰(zhàn)略設計圖(宏觀) ,一個是戰(zhàn)術設計圖(細節(jié))。
領域戰(zhàn)略設計圖
戰(zhàn)略設計圖是從一個限界上下文的角度出發(fā)去分析業(yè)務場景。主要是宏觀上的核心域、子域、實體關系圖。demo
如下圖:
領域戰(zhàn)術設計圖
戰(zhàn)術設計圖是從一個限界上下文的角度出發(fā)去分析業(yè)務場景。細化到核心業(yè)務字段、領域?qū)嶓w、值對象、領域服務、領域事件等等?;旧线@個圖畫完,代碼已經(jīng)知道怎么寫了。demo
如下圖:
技術實現(xiàn)
整體項目框架分層圖如下所示:
4層典型DDD
分層結構:
【1】展現(xiàn)層: controller
層,無業(yè)務邏輯。
【2】應用服務層: 此層可以包含查詢邏輯,但核心業(yè)務邏輯必須下沉到領域?qū)印?br> 【3】領域服務層: 業(yè)務在這里組裝。倉儲(資源庫)接口在此層定義。
【4】基礎設施層: 倉儲(資源庫)實現(xiàn)層+PO持久化層。
服務調(diào)用問題
域內(nèi)調(diào)用: 領域內(nèi)調(diào)用,隨便調(diào)用,絲般順滑。至于實現(xiàn),可以由一個核心域的倉儲實現(xiàn)層(第四層)去實現(xiàn)多個Repository接口。(比如這里A是核心域的實體名,B是支撐域、通用域等)
跨域調(diào)用: 使用領域事件eventbus
來做解耦,考慮是否有可能合并為一個領域。跨上下文(肯定跨域):ACL
層->Adapter
適配器層->feign
調(diào)用
包結構
包結構如下:
展開包結構如下:
展現(xiàn)層: Controller
僅做接口的入口定義和編排轉(zhuǎn)發(fā),不做任何的業(yè)務處理。
應用服務層: application
負責接口參數(shù)DTO的簡單校驗,以及DTO
和實體值對象的數(shù)據(jù)轉(zhuǎn)換,對于簡單的業(yè)務,也可以在應用層加載實體直接執(zhí)行實體行為方法。
領域?qū)?/strong>
模型: 根據(jù)領域模型分析領域內(nèi)各實體、聚合、聚合根、值對象等,這些對象在*.domain.model
定義,實體內(nèi)的行為方法只負責維護實體自身的生命周期和狀態(tài)。
行為: 領域內(nèi)各實體、聚合、聚合根等,會有相應的行為,在*.domain.model
包下定義行為方法。
領域服務: 領域提供的接口服務,需要定義在*.domain.service
包下,業(yè)務相關的前置業(yè)務判斷、多個實體或值對象的行為邏輯處理等,都在領域服務中實現(xiàn),需要注意的是并不是每個實體都有一個對應的領域服務,但是依賴多個實體的行為方法,最好根據(jù)這個業(yè)務模塊是建立一個領域服務。
倉儲: 領域服務或上層應用服務需要使用到的基礎設施層,包括DB
、Feign
調(diào)用等,定義在*.domain.repository
下,在*.infrastructure.repository
下實現(xiàn)。
適配層: 在acl
包下的feign
定義依賴外部的接口,并在acl
的adapter
包編寫轉(zhuǎn)換,由倉儲層操作實體時調(diào)用。文章來源:http://www.zghlxwxcb.cn/news/detail-761968.html
持久層: 與常用DAO
定義一致,由倉儲層操作實體時調(diào)用。文章來源地址http://www.zghlxwxcb.cn/news/detail-761968.html
到了這里,關于DDD[領域驅(qū)動模型]的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!