大白話說清楚DDD是什么

DDD是與技術無關的,從純業務的角度分析業務模型和業務流程,面向純業務進行建模,這個和傳統的面向數據庫建模是有很大區別的。

一、 傳統開發模式 VS DDD開發模式的區別
傳統開發模式:基于傳統三層框架(Controller+Service+Dao)+SSM+面向數據庫建模。
DDD開發模式:基于DDD分層框架(interface+application+domain+infrace)+SSM+面向業務建模。

面向數據庫建模的缺點:代碼完全丟棄了業務語義,代碼和業務流程、業務模型是不匹配的,導致了我們是按照數據庫思維寫出來的代碼(數據庫表的CURD),導致代碼可維護性極差,哪怕是自己寫的代碼,過幾個月在來看,可能都看不懂業務流程是啥,如果是別人來接手更加看不懂,需要花更多時間來梳理代碼邏輯確定業務流程。

傳統開發模式采用貧血模型,實體(entity)只保留了屬性、setter和getter方法,沒有其它任何具有業務邏輯的方法或者行為。

面向DDD建模開發的優點:代碼保留了業務語義,代碼能夠準確的還原業務流程和模型,面向數據庫表的CRUD、ES、redis、MQ等邏輯完全隱藏在業務流程里面,代碼可讀性好、可維護性好,產品經理等非技術人員也能通過代碼和注釋讀懂業務流程

DDD開發模式采用了充血模型,實體保留了屬性、setter和getter方法之外,還具有業務邏輯的方法或者行為,這個業務邏輯不依賴外部業務(第三方平臺接口)

二、DDD的一些概念
子域、有界上下文、聚合、實體、值對象、倉儲、領域服務、六邊形架構、清潔架構、CQRS、DDD分層模型。

三、DDD落地方法論
DDD落地分為三個步驟,戰略設計、戰術設計、代碼落地(DDD三層框架、開源框架例如阿里的cola)

3.1 戰略設計主要包含有界上下文劃分、映射、子域類型確定、通用語言確定
3.1.1 有界上下文:業務邊界劃分,確定哪些是我們負責的,哪些不是我們負責的
有界上下文通過事件風暴會議進行劃分,在做ddd項目的時候,可能是對手頭上已有的項目進行DDD建模和重構,對于項目的業務流程、邏輯是比較了解的,那么就可以自己和幾個負責開發項目的同事一起進行風暴會議,必須根據自己對業務的理解,把技術相關的東西全部剝離(數據庫設計、es、redis、mq),純粹站在業務的角度去進行風暴會議,梳理出業務相關的流程,如果是新項目,那么開發、產品、跨團隊、用戶、客戶、運營,很多人最好都召集在一起,進行頭腦風暴,大家一起對這個業務領域的所有事件進行梳理。

事件風暴會議分為5個步驟:
(1)召集一個會議,程序員、用戶、產品經理、管理者、其他人,開始一塊兒進行頭腦風暴,一塊兒來梳理和說出來,履約相關的所有的事件,事件(動詞、動作),有多少事件就說多少事件,但凡是跟履約這個事情相關的事件,都可以說出來。

(2)把所有梳理出來的履約相關的事件,按照時間線進行排列,按照時間發生的先后順序,做一個排列。

(3)梳理出來履約相關的所有的用戶界面和命令,針對上面的所有事件的發生,是否有系統用戶界面,有用戶參與進來發出一個指令、命令(在系統界面里,點擊按鈕、提交表單、發起操作),驅動了履約各個事件的執行。

(4)把用戶界面、命令、事件,按照時間線,先后順序,交互邏輯,全部串聯起來,一環一環的。

(5)在上面的那個大串聯的邏輯里,找出來履約有界上下文,哪些事情應該是屬于履約要解決的問題,哪些事情明顯是屬于別的有界上下文,是屬于別人要去做的事情

3.1.2 映射:不同的有界上下文之間如何進行交互,例如接口調用或者MQ,有以下幾種交互類型:
? separate way:完全沒關系。

? customer-supplier:u-d,可以商量,如果你有一些變化,我有一些需求,大家可以商量一下的,所以這種關系,常見于一個大的項目組內的不同的小項目組之間的依賴關系。

大廠,有幾塊大的業務,新零售、O2O、B端、云計算、電商,大的事業部里,技術團隊,假設有500個人,劃分為了n個大的團隊,每個團隊有幾十個人,每個團隊幾十個人內部又分為了幾個小組,每個組10個人,10來個人。

對于幾十個人的團隊,做一個大的項目,有幾個小組,每個小組負責維護一個系統,系統之間有依賴的關系,我要調用你 的接口,你是上游,我是下游,我們的關系和距離,組織結構是比較近的,所以這個時候往往就是我有一些接口的需求,我們是可以很好的進行一個商量的。

? publish-subscribe:p-s,有一方發布一個事件,另外一方監聽事件以及處理這個事件,這種關系就叫做ddd里面的ps映射關系,這種關系,說句實話,在企業開發里,非常的常見,一般來說,就是對于你一個有界上下文,如果你要跟別的有界上下文進行交互,你可以選擇發布一個事件出去,你作為一個有界上下文,你還可以自己發布事件,自己去監聽和處理這個事件。


image.png

? anti corruption layer:acl(防腐層),不是一個孤立、單獨使用的映射關系,一般是跟其他的映射關系,一起進行使用,CS關系,PS關系,CS關系來舉個例子,supplier給我接口返回的東西,本來這個東西大家約定好了里面有8個字段,但是現在雖然還是8個字段,可是里面有的字段的名稱變化了(其實本質沒變化,可是名稱變化了),或者是字段的類型變化了,或者是字段的值,可選的值變化了,字段可選的值:true、false,加了一種unknown,對于我來說,是不是說直接修改我的代碼呢?一般來說可以加一個防腐層,acl層,一般來說會把你返回過來的東西,做一個適配和轉化,把他轉為我內部的一個我自己固定的一個對象,我固定的對象,他的字段的名稱、類型、值,都是不變的,如果你那里返回的東西有變化,此時我可以在我的防腐層的代碼里,做一個轉化,把他轉換位我固定的不變的東西就可以了,防止外部返回結果有變化引起本地代碼調整,只要轉換邏輯調整一下就可以了。
? conformist:u(upstream上游)-d(downstream下游),完全沒法商量,
不同的大的部門之間,系統之間要進行調用,電商部門有500個技術,劃分為了10個技術部門,每個技術部門是50個人,有的部門50個人專門做訂單,有的部門50個人專門做商品,有的部門50個人專門做營銷,假設你的訂單劃分為了多個技術小組,多個技術小組之間維護的系統互相依賴,cs,還好商量。

但是如果說要是跨了部門了以后,商品中心,有50個人,對外提供的給別人調用的接口,可能都是固定死的,一般來說你不太能去跟他們商量,新增一個接口,這種商量可能是極為極為難的,你要用,就直接用就可以了,遵奉他們的調用模式,沒法商量,平臺技術部,專門提供一些 基礎性的系統和接口出來,人家是為全公司服務的,他一般是收集大家的普適性的需求,按照自己的計劃迭代和升級的。


image.png

? open host service+published language:OHS+PL
對于第三方支付平臺,第三方物流平臺,saas云平臺(提供出來API接口),open host service,開放主機服務,開放平臺接口,他們會定義一套自己的通信協議和數據格式,通信協議都是HTTP協議,數據格式一般來說都是他們定義好結構的JSON格式的數據。

? 子域類型:確定有界上下文所屬子域類型,劃分出核心子域、支持子域、通用子域。
? 核心子域:對于一個電商領域而言,用于完成用戶購物是個核心需求,所需要具備的一些核心的子域,就是屬于核心子域,商品子域、訂單子域、支付子域、履約子域、會員子域、營銷子域。

? 支持子域:負責支持核心子域,他的作用,明顯的是用于支持別的核心子域的功能實現的,屬于支持性的子域,倉儲子域、物流子域 、財務子域、報表子域、平臺技術子域, 履約子域在履約的過程中,需要倉儲和物流的支持,財務子域,支持我們的一些業務運作,報表子域支持公司對業務進行分析和決策,平臺技術子域支持各個業務服務 。

? 通用子域:不用自己公司來開發了,都是外購的軟件,或者是第三方的通用的平臺和系統,第三方支付平臺,第三方物流平臺,通用子域。

? 通用語言:當前有界上下文邊界范圍內要制定一套統一的命名規范。
? 為什么需要這套通用語言,假設履約有界上下文,里面的技術團隊有20個人,劃分了幾個小組,5個人一個小組,一個是4個小組,每個小組都負責了一個履約系統里的一個微服務,假設對自己負責的服務涉及到的代碼,命名規則和規范都有一套自己的理解的話,那么在這個有界上下文會表現的很亂,叫什么的都有,但都表示同一個意思,所以每個有界上下文里面,對所有的名詞和動詞,業務操作、業務事件、業務語義,都用統一的一套規則和規范去做。

3.2 戰術設計包含實體、值對象、聚合、倉儲、領域服務、業務組件、領域事件、命令和查詢 。
? 實體 -> 我們之前在項目代碼里搞的那種domain類,Order(他是有一個唯一標識,OrderId,他里面的很多數據是可以變化的),我們的上下文里,對于一些核心的數據,一般來說都會設計一些類出來,如果他有唯一標識、而且他的數據是允許變化的,此時在ddd戰術設計里,他被稱之為:實體,Entity,這樣的一個概念,就是一個Class類,有唯一標識,類里面的數據允許變化,例如訂單狀態

? 值對象 -> ValueObject,OrderId(建模成一個獨立的類),對于一個訂單,他的唯一的標識,OrderId而言,里面可能包含和封裝了訂單再數據庫里的唯一的主鍵以及我們分配給他的一個訂單編號,這些東西,是絕對不會變化的,而且OrderId自己就沒有必要再有一個自己的唯一標識,他代表的就是一份不會變化的數據,ddd戰術設計里稱之為值對象,就是一個class類,沒有唯一標識,類里面的數據在運行過程中不會變化,例如訂單id和訂單編號
? 聚合 -> 把有強關系的一些實體+值對象放在一塊,這些實體所謂的強關系是指創建的時候一起創建,更新的時候一起更新,刪除的時候一起刪除,聚合里的這些實體必須放在一個事務里,要么一起成功,要么一起失敗,聚合還有一些貼合業務語義的業務行為,聚合最外層的實體就叫做聚合根,聚合是要進行充血模型設計,也就是要有一些核心符合業務語義的業務邏輯行為(不依賴第三方的服務)
? 領域服務 -> 有一些業務行為是沒辦法放在聚合里的,針對跨越多個聚合執行的業務行為,就沒辦法放在一個聚合里面來做,只能是放在領域服務里面來做, 他的業務行為都是委托給多個聚合來做

? 業務組件 -> 貼合業務語義的class(類),例如訂單狀態機、從第三方平臺提供的api獲取數據的行為,都可以設計成業務組件類

? 領域事件 -> 某個有界上下文執行的一些動作和操作會驅動其他有界上下文某個方面業務流程的執行,例如訂單上下文會發起訂單支付事件會驅動履約流程的執行,這就是領域時間

? 命令(查詢) -> 人驅動發起的命令,一些核心的業務動作和操作,應該是人發起的,例如web系統網頁界面、手機APP界面,通過UI界面發起的動作和操作,在DDD里面就叫做命令(command),如果是更新數據一類的動作叫命令COMMAND,如果是查詢一類的動作叫查詢QUERY

? 倉儲 -> 負責與持久層進行交互,聚合和實體數據都是通過倉儲來進行持久化和讀取,類似于DAO

3.3 DDD代碼落地
DDD在代碼落地時候借鑒了六邊形架構和CQRS,所以DDD分層架構即四層架構,分別是:
接口層(用戶層)adapter-> 最外層跟用戶界面、其他上下文進行交互的一層,例如通過界面交互的controller層\通過接口調用進行交互的api層\通過MQ進行交互的listener層。

應用服務層application -> 進行業務流程編排,基于倉儲、聚合、領域服務、業務組件執行各種各樣的動作,完成業務流程中整個業務鏈路里的各個環節。

領域服務層domain -> 基于倉儲、聚合、領域服務、業務組件完成多個聚合操作,實際處理業務細節的地方(面向數據庫的CRUD、面向REDIS\MQ\ES的CRUD、業務邏輯處理)。

基礎設施層infrastracture -> 負責與具體的基礎設施交互的地方(跟DB\REDIS\ES\MQ進行交互),repository依賴反轉。

四、DDD是否成功的驗證
驗證你的ddd做的對不對,成功與否,關鍵點在于,上面那套東西配合起來,能夠實現一個效果就是,用代碼,還原出來一套完整的業務語義、業務流程、業務模型 -> 這套還原出來的代碼,我有一個驗收的標準,這套代碼,主流程,如果找PM產品經理來走讀代碼,讓他結合英文單詞的含義,來讀代碼,結合你的一些注釋,是否可以直接通過英文單詞的含義,把他理解的業務語義和流程能夠理解出來才算ddd成功了,ddd成功的一個關鍵的點,在于說,你的代碼做出來,基本貼合業務語義和流程,拋棄掉技術細節不說,底層的crud,sql,緩存,nosql,mq,es,搜索,數據庫連接池,單純是業務代碼主流程,能把業務語義還原出來,ddd就成功了。

五、系統和服務的區別,領域和子域的區別
? 領域是個大的概念,一個領域包含多個子域(子域一般對應一個系統,也可能是一個服務)。
? 系統是一個大的概念,一個系統包含多個服務
一個系統包含多個服務,商品系統包含商品后臺管理服務、商品供需服務、商品B端基礎服務、商品C端查詢服務、商品質檢報告服務、商品定時計算服務、商品生命周期服務、商品價格服務。

六、DDD借鑒了六邊形架構和CQRS
把ddd思想跟六邊形架構的思想、CQRS思想結合起來使用。
CQRS主要是更新和查詢是分離成兩套系統,六邊形架構主要是提供api與外部系統進行交互,提供 spi與外部基礎設施進行交互,提供領域模型層 ,提供應用服務層
DDD分層架構借鑒了六邊形架構和CQRS。

簡單的業務,純粹就是界面里的一些增刪改查,表單的提交,數據更新,沒什么太復雜的業務的不要用DDD,DDD是用來解決復雜業務的

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,117評論 6 537
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,860評論 3 423
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,128評論 0 381
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,291評論 1 315
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,025評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,421評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,477評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,642評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,177評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,970評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,157評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,717評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,410評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,821評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,053評論 1 289
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,896評論 3 395
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,157評論 2 375

推薦閱讀更多精彩內容