領(lǐng)域驅(qū)動設(shè)計DDD(Domain-Driven Design)

1 背景

業(yè)務(wù)初期召烂,我們的功能大都非常簡單碱工,普通的CRUD就能滿足,此時系統(tǒng)是清晰的奏夫。隨著迭代的不斷演化怕篷,業(yè)務(wù)邏輯變得越來越復(fù)雜,我們的系統(tǒng)也越來越冗雜酗昼。模塊彼此關(guān)聯(lián)廊谓,誰都很難說清模塊的具體功能意圖是啥。修改一個功能時麻削,往往光回溯該功能需要的修改點(diǎn)就需要很長時間蒸痹,更別提修改帶來的不可預(yù)知的影響面。


傳統(tǒng)模型設(shè)計

訂單服務(wù)接口中提供了查詢呛哟、創(chuàng)建訂單相關(guān)的接口叠荠,也提供了訂單評價、支付扫责、保險的接口榛鼎。同時我們的表也是一個訂單大表,包含了非常多字段鳖孤。在我們維護(hù)代碼時者娱,牽一發(fā)而動全身,很可能只是想改下評價相關(guān)的功能淌铐,卻影響到了創(chuàng)單核心路徑肺然。雖然我們可以通過測試保證功能完備性,但當(dāng)我們在訂單領(lǐng)域有大量需求同時并行開發(fā)時腿准,改動重疊际起、惡性循環(huán)拾碌、疲于奔命修改各種問題。

2 軟件系統(tǒng)復(fù)雜性應(yīng)對

解決復(fù)雜和大規(guī)模軟件的武器可以被粗略地歸為三類:抽象街望、分治知識校翔。
分治: 把問題空間分割為規(guī)模更小且易于處理的若干子問題。分割后的問題需要足夠小灾前,以便一個人單槍匹馬就能夠解決他們防症;其次,必須考慮如何將分割后的各個部分裝配為整體哎甲。分割得越合理越易于理解蔫敲,在裝配成整體時,所需跟蹤的細(xì)節(jié)也就越少炭玫。即更容易設(shè)計各部分的協(xié)作方式奈嘿。評判什么是分治得好,即高內(nèi)聚低耦合吞加。
抽象: 使用抽象能夠精簡問題空間裙犹,而且問題越小越容易理解。舉個例子衔憨,從北京到上海出差叶圃,可以先理解為使用交通工具前往,但不需要一開始就想清楚到底是高鐵還是飛機(jī)践图,以及乘坐他們需要注意什么掺冠。
知識: 顧名思義,DDD可以認(rèn)為是知識的一種平项。
DDD提供了這樣的知識手段赫舒,讓我們知道如何抽象出限界上下文以及如何去分治。

3 與微服務(wù)架構(gòu)相得益彰

微服務(wù)架構(gòu)眾所周知闽瓢,此處不做贅述接癌。我們創(chuàng)建微服務(wù)時,需要創(chuàng)建一個高內(nèi)聚扣讼、低耦合的微服務(wù)缺猛。而DDD中的限界上下文則完美匹配微服務(wù)要求,可以將該限界上下文理解為一個微服務(wù)進(jìn)程椭符。

上述是從更直觀的角度來描述兩者的相似處荔燎。

在系統(tǒng)復(fù)雜之后,我們都需要用分治來拆解問題销钝。一般有兩種方式有咨,技術(shù)維度和業(yè)務(wù)維度。技術(shù)維度是類似MVC這樣蒸健,業(yè)務(wù)維度則是指按業(yè)務(wù)領(lǐng)域來劃分系統(tǒng)座享。

微服務(wù)架構(gòu)更強(qiáng)調(diào)從業(yè)務(wù)維度去做分治來應(yīng)對系統(tǒng)復(fù)雜度婉商,而DDD也是同樣的著重業(yè)務(wù)視角。 如果兩者在追求的目標(biāo)(業(yè)務(wù)維度)達(dá)到了上下文的統(tǒng)一渣叛,那么在具體做法上有什么聯(lián)系和不同呢丈秩?

我們將架構(gòu)設(shè)計活動精簡為以下三個層面:
業(yè)務(wù)架構(gòu)——根據(jù)業(yè)務(wù)需求設(shè)計業(yè)務(wù)模塊及其關(guān)系
系統(tǒng)架構(gòu)——設(shè)計系統(tǒng)和子系統(tǒng)的模塊
技術(shù)架構(gòu)——決定采用的技術(shù)及框架

DDD的核心訴求就是將業(yè)務(wù)架構(gòu)映射到系統(tǒng)架構(gòu)上,在響應(yīng)業(yè)務(wù)變化調(diào)整業(yè)務(wù)架構(gòu)時淳衙,也隨之變化系統(tǒng)架構(gòu)蘑秽。而微服務(wù)追求業(yè)務(wù)層面的復(fù)用,設(shè)計出來的系統(tǒng)架構(gòu)和業(yè)務(wù)一致箫攀;在技術(shù)架構(gòu)上則系統(tǒng)模塊之間充分解耦肠牲,可以自由地選擇合適的技術(shù)架構(gòu),去中心化地治理技術(shù)和數(shù)據(jù)匠童。

領(lǐng)域模型設(shè)計

4 業(yè)務(wù)拆分領(lǐng)域模型

1埂材、 根據(jù)需求劃分出初步的領(lǐng)域和限界上下文塑顺,以及上下文之間的關(guān)系汤求;
2、 進(jìn)一步分析每個上下文內(nèi)部严拒,識別出哪些是實(shí)體扬绪,哪些是值對象;
3 裤唠、對實(shí)體挤牛、值對象進(jìn)行關(guān)聯(lián)和聚合,劃分出聚合的范疇和聚合根种蘸;
4 墓赴、為聚合根設(shè)計倉儲,并思考實(shí)體或值對象的創(chuàng)建方式航瞭;
5 诫硕、在工程中實(shí)踐領(lǐng)域模型,并在實(shí)踐中檢驗(yàn)?zāi)P偷暮侠硇钥睿雇颇P椭胁蛔愕牡胤讲⒅貥?gòu)章办。

5 名詞介紹

限界上下文
一個由顯示邊界限定的特定職責(zé)。領(lǐng)域模型便存在于這個邊界之內(nèi)滨彻。在邊界內(nèi)藕届,每一個模型概念,包括它的屬性和操作亭饵,都具有特殊的含義休偶。
用來封裝通用語言和領(lǐng)域?qū)ο螅峁┥舷挛沫h(huán)境辜羊,保證在領(lǐng)域之內(nèi)的一些術(shù)語踏兜、業(yè)務(wù)相關(guān)對象等(通用語言)有一個確切的含義懂算,沒有二義性。這個邊界定義了模型的適用范圍庇麦,使團(tuán)隊所有成員能夠明確地知道什么應(yīng)該在模型中實(shí)現(xiàn)计技,什么不應(yīng)該在模型中實(shí)現(xiàn)。

限界上下文劃分

我們的實(shí)踐是山橄,考慮產(chǎn)品所講的通用語言垮媒,從中提取一些術(shù)語稱之為概念對象,尋找對象之間的聯(lián)系航棱;或者從需求里提取一些動詞睡雇,觀察動詞和對象之間的關(guān)系;我們將緊耦合的各自圈在一起饮醇,觀察他們內(nèi)在的聯(lián)系它抱,從而形成對應(yīng)的界限上下文。形成之后朴艰,我們可以嘗試用語言來描述下界限上下文的職責(zé)观蓄,看它是否清晰、準(zhǔn)確祠墅、簡潔和完整侮穿。簡言之,限界上下文應(yīng)該從需求出發(fā)毁嗦,按領(lǐng)域劃分亲茅。

限界上下文之間的映射關(guān)系

合作關(guān)系(Partnership):兩個上下文緊密合作的關(guān)系,一榮俱榮狗准,一損俱損克锣。
共享內(nèi)核(Shared Kernel):兩個上下文依賴部分共享的模型。
客戶方-供應(yīng)方開發(fā)(Customer-Supplier Development):上下文之間有組織的上下游依賴腔长。
遵奉者(Conformist):下游上下文只能盲目依賴上游上下文袭祟。
防腐層(Anticorruption Layer 簡稱:ACL):一個上下文通過一些適配和轉(zhuǎn)換與另一個上下文交互。
開放主機(jī)服務(wù)(Open Host Service 簡稱:OHS):定義一種協(xié)議來讓其他上下文來對本上下文進(jìn)行訪問饼酿。
發(fā)布語言(Published Language 簡稱:PL):通常與OHS一起使用榕酒,用于定義開放主機(jī)的協(xié)議。
大泥球(Big Ball of Mud):混雜在一起的上下文關(guān)系故俐,邊界不清晰想鹰。
另謀他路(SeparateWay):兩個完全沒有任何聯(lián)系的上下文。

通過上下文映射關(guān)系药版,我們明確的限制了限界上下文的耦合性辑舷,即在抽獎平臺中,無論是上下文內(nèi)部交互(合作關(guān)系)還是與外部上下文交互(防腐層)槽片,耦合度都限定在數(shù)據(jù)耦合(Data Coupling)的層級何缓。

實(shí)體
當(dāng)一個對象由其標(biāo)識(而不是屬性)區(qū)分時肢础,這種對象稱為實(shí)體(Entity)。

值對象

特性 : 沒有唯一標(biāo)識 不變性

在值對象中碌廓,不關(guān)心標(biāo)識传轰,只要我們能確定值對象的屬性值都一樣,我們就可以說這兩個值對象是相同的谷婆。
比如說兩個學(xué)生的家庭地址(省市縣街道門牌號)是一樣的慨蛙,我們就可以認(rèn)為是同一個地址,這就是相等性比較纪挎。
如果學(xué)生在修改地址的時候期贫,無論修改的省或者市或者縣,我們不關(guān)心改了多少异袄,而是 將整個值對象覆蓋通砍,它具有不變性、相等性和可替換性烤蜕。

聚合根
Aggregate(聚合)是一組相關(guān)對象的集合封孙,作為一個整體被外界訪問,聚合根(Aggregate Root)是這個聚合的根節(jié)點(diǎn)玖绿。
聚合是一個非常重要的概念敛瓷,核心領(lǐng)域往往都需要用聚合來表達(dá)。
聚合由根實(shí)體斑匪,值對象和實(shí)體組成。
如何創(chuàng)建好的聚合?
邊界內(nèi)的內(nèi)容具有一致性:在一個事務(wù)中只修改一個聚合實(shí)例锋勺。如果你發(fā)現(xiàn)邊界內(nèi)很難接受強(qiáng)一致蚀瘸,不管是出于性能或產(chǎn)品需求的考慮,應(yīng)該考慮剝離出獨(dú)立的聚合庶橱,采用最終一致的方式贮勃。
設(shè)計小聚合:大部分的聚合都可以只包含根實(shí)體,而無需包含其他實(shí)體苏章。即使一定要包含寂嘉,可以考慮將其創(chuàng)建為值對象。
通過唯一標(biāo)識來引用其他聚合或?qū)嶓w:當(dāng)存在對象之間的關(guān)聯(lián)時枫绅,建議引用其唯一標(biāo)識而非引用其整體對象泉孩。如果是外部上下文中的實(shí)體,引用其唯一標(biāo)識或?qū)⑿枰膶傩詷?gòu)造值對象并淋。 如果聚合創(chuàng)建復(fù)雜寓搬,推薦使用工廠方法來屏蔽內(nèi)部復(fù)雜的創(chuàng)建邏輯。

領(lǐng)域服務(wù)
一些重要的領(lǐng)域行為或操作县耽,可以歸類為領(lǐng)域服務(wù)句喷。它既不是實(shí)體镣典,也不是值對象的范疇。
領(lǐng)域中的服務(wù)表示一個無狀態(tài)的操作唾琼,它用于實(shí)現(xiàn)特定于某個領(lǐng)域的任務(wù)兄春。這里我們要搞清楚什么樣的操作需要實(shí)體,值對象锡溯,什么樣的操作需要采用領(lǐng)域服務(wù)神郊。
另外,領(lǐng)域服務(wù)不是應(yīng)用服務(wù)趾唱,在應(yīng)用服務(wù)中我們不需要處理業(yè)務(wù)邏輯涌乳,業(yè)務(wù)邏輯都落在領(lǐng)域服務(wù)中。
領(lǐng)域服務(wù)發(fā)現(xiàn):
執(zhí)行一個顯著的業(yè)務(wù)操作過程
對領(lǐng)域?qū)ο筮M(jìn)行轉(zhuǎn)換
以多個領(lǐng)域?qū)ο笞鳛檩斎脒M(jìn)行計算甜癞,產(chǎn)生一個值對象夕晓。
過度使用領(lǐng)域服務(wù)將會產(chǎn)生一個貧血模型,例如數(shù)據(jù)建模時悠咱,我們的實(shí)體常用只含有g(shù)et/set方法蒸辆,所有的業(yè)務(wù)邏輯都包含在了service。這樣導(dǎo)致service變成了一個大泥球析既。注意區(qū)分領(lǐng)域服務(wù)與實(shí)體躬贡,值對象行為。

領(lǐng)域事件
領(lǐng)域事件是對領(lǐng)域內(nèi)發(fā)生的活動進(jìn)行的建模眼坏。
領(lǐng)域事件通常是用來與其他聚合解耦的拂玻,采用觀察者模式,一個聚合訂閱另外一個聚合的事件宰译。

實(shí)例 抽獎DDD


image.png
image.png

注意: U 代表上游 D 代表下游

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末檐蚜,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子沿侈,更是在濱河造成了極大的恐慌闯第,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,376評論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件缀拭,死亡現(xiàn)場離奇詭異咳短,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)蛛淋,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,126評論 2 385
  • 文/潘曉璐 我一進(jìn)店門咙好,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人铣鹏,你說我怎么就攤上這事敷扫。” “怎么了?”我有些...
    開封第一講書人閱讀 156,966評論 0 347
  • 文/不壞的土叔 我叫張陵葵第,是天一觀的道長绘迁。 經(jīng)常有香客問我,道長卒密,這世上最難降的妖魔是什么缀台? 我笑而不...
    開封第一講書人閱讀 56,432評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮哮奇,結(jié)果婚禮上膛腐,老公的妹妹穿的比我還像新娘。我一直安慰自己鼎俘,他們只是感情好哲身,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,519評論 6 385
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著贸伐,像睡著了一般勘天。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上捉邢,一...
    開封第一講書人閱讀 49,792評論 1 290
  • 那天脯丝,我揣著相機(jī)與錄音,去河邊找鬼伏伐。 笑死宠进,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的藐翎。 我是一名探鬼主播材蹬,決...
    沈念sama閱讀 38,933評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼阱高!你這毒婦竟也來了赚导?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,701評論 0 266
  • 序言:老撾萬榮一對情侶失蹤赤惊,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后凰锡,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體未舟,經(jīng)...
    沈念sama閱讀 44,143評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,488評論 2 327
  • 正文 我和宋清朗相戀三年掂为,在試婚紗的時候發(fā)現(xiàn)自己被綠了裕膀。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,626評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡勇哗,死狀恐怖昼扛,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤抄谐,帶...
    沈念sama閱讀 34,292評論 4 329
  • 正文 年R本政府宣布渺鹦,位于F島的核電站,受9級特大地震影響蛹含,放射性物質(zhì)發(fā)生泄漏毅厚。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,896評論 3 313
  • 文/蒙蒙 一浦箱、第九天 我趴在偏房一處隱蔽的房頂上張望吸耿。 院中可真熱鬧,春花似錦酷窥、人聲如沸咽安。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,742評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽妆棒。三九已至,卻和暖如春拳氢,著一層夾襖步出監(jiān)牢的瞬間募逞,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評論 1 265
  • 我被黑心中介騙來泰國打工馋评, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留什湘,地道東北人。 一個月前我還...
    沈念sama閱讀 46,324評論 2 360
  • 正文 我出身青樓放坏,卻偏偏與公主長得像孩哑,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子蜕青,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,494評論 2 348

推薦閱讀更多精彩內(nèi)容