轉(zhuǎn)自終端研發(fā)部某大佬的文章,發(fā)現(xiàn)這個解釋的非常通俗清楚放椰,所以作為存檔留存一份,用于產(chǎn)品設(shè)計的相關(guān)參考愉粤。
最近大家都在聊DDD砾医,有一些傳統(tǒng)的公司也在使用DDD開發(fā)模式,最近在做一些微服務(wù)相關(guān)的設(shè)計衣厘,內(nèi)容包括服務(wù)的劃分如蚜,Restful API的設(shè)計等。其中比較棘手的就是Service的職責(zé)劃分:如何抽象具有統(tǒng)一業(yè)務(wù)范疇的Model影暴,使其模塊化错邦,又如何高度提煉并組合多模塊,使得業(yè)務(wù)可獨立服務(wù)化型宙。為了找尋答案撬呢,看了不少書籍和博客,在DDD中找到了一些思路妆兑,個人覺得受益匪淺魂拦,或許也可以受用于大家,特分享于此箭跳。
什么是DDD
軟件開發(fā)不是一蹴而就的事情晨另,我們不可能在不了解產(chǎn)品(或行業(yè)領(lǐng)域)的前提下進(jìn)行軟件開發(fā),在開發(fā)前谱姓,通常需要進(jìn)行大量的業(yè)務(wù)知識梳理,而后到達(dá)軟件設(shè)計的層面刨晴,最后才是開發(fā)屉来。而在業(yè)務(wù)知識梳理的過程中路翻,我們必然會形成某個領(lǐng)域知識,根據(jù)領(lǐng)域知識來一步步驅(qū)動軟件設(shè)計茄靠,就是領(lǐng)域驅(qū)動設(shè)計的基本概念茂契。
聽起來這和傳統(tǒng)意義的軟件開發(fā)沒啥區(qū)別,只是換了點新鮮的名詞而已慨绳,其實不然掉冶。
軟件開發(fā) VS DDD
一般軟件設(shè)計或者說軟件開發(fā)分兩種:瀑布式,敏捷式脐雪。
前者一般是項目經(jīng)理經(jīng)過大量的業(yè)務(wù)分析后厌小,會基于現(xiàn)有需求整理出一個基本模型,再將結(jié)果傳遞給開發(fā)人員战秋,這就是開發(fā)人員的需求文檔璧亚,他們只需要照此開發(fā)便是。這種模式下脂信,是很難頻繁的從用戶那里得到反饋癣蟋,因此在前期分析時就已經(jīng)默認(rèn)了這個業(yè)務(wù)模型是正確的,那么結(jié)果可想而之狰闪,數(shù)月甚至數(shù)年后交付的時候疯搅,必然和客戶的預(yù)期差距較大。
后者在此基礎(chǔ)上進(jìn)行了改進(jìn)埋泵,它也需要大量的分析幔欧,范圍會設(shè)計到更精細(xì)的業(yè)務(wù)模塊,它是小步迭代秋泄,周期性交付琐馆,那么獲取客戶的反饋也就比較頻繁和及時『阈颍可敏捷也不能夠?qū)I(yè)務(wù)中的方方面面都考慮到瘦麸,并且敏捷是擁抱變化的,大量的需求或者業(yè)務(wù)模型變更必將帶來不小的維護(hù)成本歧胁,同時滋饲,對人(Developer)的要求也必然會更高。
DDD則不同:它像是更小粒度的迭代設(shè)計喊巍,它的最小單元是領(lǐng)域模型(Domain Model)屠缭,所謂領(lǐng)域模型就是能夠精確反映領(lǐng)域中某一知識元素的載體,這種知識的獲取需要通過與領(lǐng)域?qū)<?Domain Expert)進(jìn)行頻繁的溝通才能將專業(yè)知識轉(zhuǎn)化為領(lǐng)域模型崭参。領(lǐng)域模型無關(guān)技術(shù)呵曹,具有高度的業(yè)務(wù)抽象性,它能夠精確的描述領(lǐng)域中的知識體系;同時它也是獨立的奄喂,我們還需要學(xué)會如何讓它具有表達(dá)性铐殃,讓模型彼此之間建立關(guān)系,形成完整的領(lǐng)域架構(gòu)跨新。通常我們可以用象形圖或一種通用的語言(Ubiquitous Language)去描述它們之間的關(guān)系富腊。在此之上,我們就可以進(jìn)行領(lǐng)域中的代碼設(shè)計(Domain Code Design)域帐。如果將軟件設(shè)計比做是造一座房子赘被,那么領(lǐng)域代碼設(shè)計就好比是貼壁紙。前者已經(jīng)將房子的藍(lán)圖框架規(guī)劃好肖揣,而后者只是一個小部分的設(shè)計:如果墻紙貼錯了民假,我們可以重來,可如果房子結(jié)構(gòu)設(shè)計錯了许饿,那可就悲劇了阳欲。
建立領(lǐng)域知識(Build Domain Model)
說了這么多領(lǐng)域模型的概念,到底什么是領(lǐng)域模型呢陋率?以飛機(jī)航行為例子:
現(xiàn)要為航空公司開發(fā)一款能夠為飛機(jī)提供導(dǎo)航球化,保證無路線沖突監(jiān)控軟件。那我們應(yīng)該從哪里開始下手呢瓦糟?根據(jù)DDD的思路筒愚,我們第一步是建立領(lǐng)域知識:作為平時管理和維護(hù)機(jī)場飛行秩序的工作人員來說,他們自然就是這個領(lǐng)域的專家菩浙,我們第一個目標(biāo)就是與他們溝通巢掺,也許我們并不能從中獲取所有想要的知識,但至少可以篩選出主要的內(nèi)容和元素劲蜻。你可能會聽到諸如起飛陆淀,著陸,飛行沖突先嬉,延誤等領(lǐng)域名詞轧苫,讓們從一個簡單的例子開始(就算是錯誤的也沒關(guān)系):
起點->飛機(jī)->終點
這個模型很直接,但有點過于簡單疫蔓,因為我們無法看出飛機(jī)在空中做了什么含懊,也無法得知飛機(jī)怎么從起點到的終點,剛才我們似乎提到無路線沖突衅胀,那么如此似乎會好些:
飛機(jī)->路線->起點/終點
既然點構(gòu)成線岔乔,那何不:
飛機(jī)->路線->points(含起點,終點)
這個過程滚躯,是我們不斷建立領(lǐng)域知識的過程雏门,其中的重點就是尋找領(lǐng)域?qū)<翌l繁溝通嘿歌,從中提煉必要領(lǐng)域元素。
盡管看起來還是很簡單剿配,但我們已經(jīng)開始一步步的在建立領(lǐng)域?qū)ο蠛皖I(lǐng)域模型了搅幅。
通用語言(Ubiquitous Language)
上面的例子的確看起來簡單阅束,但過程并非容易:我們(開發(fā)人員)和領(lǐng)域?qū)<以跍贤ǖ倪^程中是存在天然屏障的:我們滿腦子都是類呼胚,方法,設(shè)計模式息裸,算法蝇更,繼承,封裝呼盆,多態(tài)年扩,如何面向?qū)ο蟮鹊龋贿@些領(lǐng)域?qū)<沂遣欢姆闷裕麄冎恢里w機(jī)故障厨幻,經(jīng)緯度,航班路線等專業(yè)術(shù)語腿时。
所以况脆,在建立領(lǐng)域知識的時候,我們(開發(fā)人員和領(lǐng)域?qū)<遥┍仨氁粨Q知識批糟,知識的范圍范圍涉及領(lǐng)域模型的各個元素格了,如果一方對模型的描述令對方感到困惑,那么應(yīng)該立刻換一種描述方式徽鼎,直到雙方都能夠接受并且理解為止盛末。在這一過程中,就需要建立一種通用語言否淤,作為開發(fā)人員和領(lǐng)域?qū)<业臏贤蛄骸?/p>
可如何形成這種通用語言呢悄但?其實答案并不唯一,確切的說也沒有什么標(biāo)準(zhǔn)答案石抡。
a)UML
利用UML可以清晰的表現(xiàn)類檐嚣,并且展示它們之間的關(guān)系。但是一旦聚合關(guān)系復(fù)雜汁雷,UML葉子節(jié)點將會變的十分龐大净嘀,可能就沒有那么直觀易懂了。最重要的是侠讯,它無法精確的描述類的行為挖藏。為了彌補(bǔ)這種缺陷,可以為具體的行為部分補(bǔ)充必要說明(可以是標(biāo)簽或者文檔)厢漩,但這往往又很耗時膜眠,而且更新維護(hù)起來十分不便。
b)偽代碼
極限編程是推薦這么做的,這個辦法對程序猿來說固然好宵膨,可立刻就要將現(xiàn)有模型映射到代碼層面架谎,這對人的要求也是不低,并不容易實現(xiàn)辟躏。
還有一篇關(guān)于DDD寫的不錯的一篇文大家可以去參考一下:
終端研發(fā)部:什么是DDD(領(lǐng)域驅(qū)動設(shè)計)谷扣? 這是我見過最容易理解的一篇關(guān)于DDD 的文章了547 贊同 · 65 評論文章
軟件架構(gòu)模式發(fā)展到現(xiàn)在可以主要經(jīng)歷了三個階段:
1、UI+DataBase的兩層架構(gòu)捎琐、
2会涎、UI+Service+DataBase的多層SOA架構(gòu)、
3瑞凑、分布式微服務(wù)架構(gòu)
一末秃、傳統(tǒng)架構(gòu)的缺點
在前兩種架構(gòu)中,系統(tǒng)分析籽御、設(shè)計和開發(fā)往往是獨立练慕、分階段割裂進(jìn)行的。
1技掏、兩層架構(gòu)是面向數(shù)據(jù)庫的架構(gòu)铃将,根本沒有靈活性。
2零截、微服務(wù)盛行的今天麸塞,多層SOA架構(gòu)已經(jīng)完全不能滿足微服務(wù)架構(gòu)應(yīng)用的需求,它存在這么一些問題
臃腫的servcie
三層分層后文件的隨意組裝方式
技術(shù)導(dǎo)向分層涧衙,導(dǎo)致業(yè)務(wù)分離哪工,不能快速定位。
比如弧哎,在系統(tǒng)建設(shè)過程中雁比,我們經(jīng)常會看到這樣的情形:A 負(fù)責(zé)提出需求,B 負(fù)責(zé)需求分析撤嫩,C 負(fù)責(zé)系統(tǒng)設(shè)計偎捎,D 負(fù)責(zé)代碼實現(xiàn),這樣的流程很長序攘,經(jīng)手的人也很多茴她,很容易導(dǎo)致信息丟失。最后程奠,就很容易導(dǎo)致需求丈牢、設(shè)計與代碼實現(xiàn)的不一致,往往到了軟件上線后瞄沙,我們才發(fā)現(xiàn)很多功能并不是自己想要的己沛,或者做出來的功能跟自己提出的需求偏差太大慌核。
在這兩種模式下,軟件無法快速響應(yīng)需求和業(yè)務(wù)的迅速變化申尼,最終錯失發(fā)展良機(jī)垮卓。此時,分布式微服務(wù)的出現(xiàn)就有點恰逢其時的意思了师幕。
二粟按、DDD領(lǐng)域驅(qū)動
雖說分布式微服務(wù)有這么好的優(yōu)點,但也不是適合所有的系統(tǒng)们衙,而且也會有許多問題钾怔。
微服務(wù)的粒度應(yīng)該多大呀?微服務(wù)到底應(yīng)該如何拆分和設(shè)計呢蒙挑?微服務(wù)的邊界應(yīng)該在哪里?這些都是微服務(wù)設(shè)計要解決的問題愚臀,但是很久以來都沒有一套系統(tǒng)的理論和方法可以指導(dǎo)微服務(wù)的拆分忆蚀,綜合來看,我認(rèn)為微服務(wù)拆分困境產(chǎn)生的根本原因就是不知道業(yè)務(wù)或者微服務(wù)的邊界到底在什么地方姑裂。換句話說馋袜,確定了業(yè)務(wù)邊界和應(yīng)用邊界,這個困境也就迎刃而解了舶斧。
DDD 核心思想是通過領(lǐng)域驅(qū)動設(shè)計方法定義領(lǐng)域模型欣鳖,從而確定業(yè)務(wù)和應(yīng)用邊界,保證業(yè)務(wù)模型與代碼模型的一致性茴厉。
領(lǐng)域驅(qū)動設(shè)計是一種以業(yè)務(wù)為導(dǎo)向的軟件設(shè)計方法和思路泽台。我們在開發(fā)前,通常需要進(jìn)行大量的業(yè)務(wù)知識梳理矾缓,而后到達(dá)軟件設(shè)計的層面怀酷,最后才是開發(fā)。而在業(yè)務(wù)知識梳理的過程中嗜闻,我們必然會形成某個領(lǐng)域知識蜕依,根據(jù)領(lǐng)域知識來一步步驅(qū)動軟件設(shè)計,就是領(lǐng)域驅(qū)動設(shè)計的基本概念琉雳。而領(lǐng)域驅(qū)動設(shè)計的核心就在于建立正確的領(lǐng)域驅(qū)動模型样眠。
1、DDD 包括戰(zhàn)略設(shè)計和戰(zhàn)術(shù)設(shè)計兩部分翠肘。
a檐束、戰(zhàn)略設(shè)計主要從業(yè)務(wù)視角出發(fā),建立業(yè)務(wù)領(lǐng)域模型锯茄,劃分領(lǐng)域邊界厢塘,建立通用語言的限界上下文茶没,限界上下文可以作為微服務(wù)設(shè)計的參考邊界。
b晚碾、戰(zhàn)術(shù)設(shè)計則從技術(shù)視角出發(fā)抓半,側(cè)重于領(lǐng)域模型的技術(shù)實現(xiàn),完成軟件開發(fā)和落地格嘁,包括:聚合根笛求、實體、值對象糕簿、領(lǐng)域服務(wù)探入、應(yīng)用服務(wù)和資源庫等代碼邏輯的設(shè)計和實現(xiàn)。
很多 DDD 初學(xué)者懂诗,學(xué)習(xí) DDD 的主要目的蜂嗽,可能是為了開發(fā)微服務(wù),因此更看重 DDD 的戰(zhàn)術(shù)設(shè)計實現(xiàn)殃恒。殊不知 DDD 是一種從領(lǐng)域建模到微服務(wù)落地的全方位的解決方案植旧。
戰(zhàn)略設(shè)計時構(gòu)建的領(lǐng)域模型,是微服務(wù)設(shè)計和開發(fā)的輸入离唐,它確定了微服務(wù)的邊界病附、聚合、代碼對象以及服務(wù)等關(guān)鍵領(lǐng)域?qū)ο蠛蕖nI(lǐng)域模型邊界劃分得清不清晰完沪,領(lǐng)域?qū)ο蠖x得明不明確,會決定微服務(wù)的設(shè)計和開發(fā)質(zhì)量嵌戈。沒有領(lǐng)域模型的輸入覆积,基于 DDD 的微服務(wù)的設(shè)計和開發(fā)將無從談起。因此我們不僅要重視戰(zhàn)術(shù)設(shè)計咕别,更要重視戰(zhàn)略設(shè)計技健。
2、DDD的優(yōu)勢
接觸到需求第一步就是考慮領(lǐng)域模型惰拱,而不是將其切割成數(shù)據(jù)和行為雌贱,然后數(shù)據(jù)用數(shù)據(jù)庫實現(xiàn),行為使用服務(wù)實現(xiàn)偿短,最后造成需求的首肢分離欣孤。DDD讓你首先考慮的是業(yè)務(wù)語言,而不是數(shù)據(jù)昔逗。重點不同導(dǎo)致編程世界觀不同降传。
DDD可以更加領(lǐng)域模型界限上下文邊界快速拆分微服務(wù),實現(xiàn)系統(tǒng)架構(gòu)適應(yīng)業(yè)務(wù)的快速變化勾怒,例如:系統(tǒng)的用戶量并發(fā)量增長得很快婆排,單體應(yīng)用很快就支持不了声旺,如果我們一開始就采用DDD領(lǐng)域驅(qū)動設(shè)計,那我們就能很快的把服務(wù)拆分成多個微服務(wù)段只,以適應(yīng)快速增長的用戶量腮猖。
DDD 是一套完整而系統(tǒng)的設(shè)計方法,它能帶給你從戰(zhàn)略設(shè)計到戰(zhàn)術(shù)設(shè)計的標(biāo)準(zhǔn)設(shè)計過程赞枕,使得你的設(shè)計思路能夠更加清晰澈缺,設(shè)計過程更加規(guī)范。
使用DDD可以降低服務(wù)的耦合性炕婶,讓系統(tǒng)設(shè)計更加規(guī)范姐赡,即使是剛加入團(tuán)隊的新人也可以根據(jù)業(yè)務(wù)快速找到對應(yīng)的代碼模塊,降低維護(hù)成本柠掂。
DDD 善于處理與領(lǐng)域相關(guān)的擁有高復(fù)雜度業(yè)務(wù)的產(chǎn)品開發(fā)项滑,通過它可以建立一個核心而穩(wěn)定的領(lǐng)域模型,有利于領(lǐng)域知識的傳遞與傳承陪踩。
DDD 強(qiáng)調(diào)團(tuán)隊與領(lǐng)域?qū)<业暮献髡让牵軌驇椭愕膱F(tuán)隊建立一個溝通良好的氛圍,構(gòu)建一致的架構(gòu)體系肩狂。
DDD 的設(shè)計思想、原則與模式有助于提高你的架構(gòu)設(shè)計能力姥饰。
無論是在新項目中設(shè)計微服務(wù)傻谁,還是將系統(tǒng)從單體架構(gòu)演進(jìn)到微服務(wù),都可以遵循 DDD 的架構(gòu)原則列粪。
3审磁、DDD設(shè)計原則
要領(lǐng)域驅(qū)動設(shè)計,而不是數(shù)據(jù)驅(qū)動設(shè)計岂座,也不是界面驅(qū)動設(shè)計态蒂。
要邊界清晰的微服務(wù),而不是泥球小單體费什。
要職能清晰的分層钾恢,而不是什么都放的大籮筐。
要做自己能 hold 住的微服務(wù)鸳址,而不是過度拆分的微服務(wù)瘩蚪。
4、微服務(wù)拆分需要考慮哪些因素稿黍?
理論上一個限界上下文內(nèi)的領(lǐng)域模型可以被設(shè)計為微服務(wù)疹瘦,但是由于領(lǐng)域建模主要從業(yè)務(wù)視角出發(fā),沒有考慮非業(yè)務(wù)因素巡球,比如需求變更頻率言沐、高性能邓嘹、安全、團(tuán)隊以及技術(shù)異構(gòu)等因素险胰,而這些非業(yè)務(wù)因素對于領(lǐng)域模型的系統(tǒng)落地也會起到?jīng)Q定性作用汹押,因此在微服務(wù)拆分時我們需要重點考慮它們。我列出了以下主要因素供你參考鸯乃。
4.1鲸阻、基于領(lǐng)域模型
基于領(lǐng)域模型進(jìn)行拆分,圍繞業(yè)務(wù)領(lǐng)域按職責(zé)單一性缨睡、功能完整性拆分鸟悴。
4.2、基于業(yè)務(wù)需求變化頻率
識別領(lǐng)域模型中的業(yè)務(wù)需求變動頻繁的功能奖年,考慮業(yè)務(wù)變更頻率與相關(guān)度细诸,將業(yè)務(wù)需求變動較高和功能相對穩(wěn)定的業(yè)務(wù)進(jìn)行分離。這是因為需求的經(jīng)常性變動必然會導(dǎo)致代碼的頻繁修改和版本發(fā)布陋守,這種分離可以有效降低頻繁變動的敏態(tài)業(yè)務(wù)對穩(wěn)態(tài)業(yè)務(wù)的影響震贵。
4.3、基于應(yīng)用性能
識別領(lǐng)域模型中性能壓力較大的功能水评。因為性能要求高的功能可能會拖累其它功能猩系,在資源要求上也會有區(qū)別,為了避免對整體性能和資源的影響中燥,我們可以把在性能方面有較高要求的功能拆分出去寇甸。
4.4、基于組織架構(gòu)和團(tuán)隊規(guī)模
除非有意識地優(yōu)化組織架構(gòu)疗涉,否則微服務(wù)的拆分應(yīng)盡量避免帶來團(tuán)隊和組織架構(gòu)的調(diào)整拿霉,避免由于功能的重新劃分,而增加大量且不必要的團(tuán)隊之間的溝通成本咱扣。拆分后的微服務(wù)項目團(tuán)隊規(guī)模保持在 10~12 人左右為宜绽淘。
4.5、基于安全邊界
有特殊安全要求的功能闹伪,應(yīng)從領(lǐng)域模型中拆分獨立沪铭,避免相互影響。
4.6祭往、基于技術(shù)異構(gòu)
領(lǐng)域模型中有些功能雖然在同一個業(yè)務(wù)域內(nèi)伦意,但在技術(shù)實現(xiàn)時可能會存在較大的差異,也就是說領(lǐng)域模型內(nèi)部不同的功能存在技術(shù)異構(gòu)的問題硼补。由于業(yè)務(wù)場景或者技術(shù)條件的限制驮肉,有的可能用.NET,有的則是 Java已骇,有的甚至大數(shù)據(jù)架構(gòu)离钝。對于這些存在技術(shù)異構(gòu)的功能票编,可以考慮按照技術(shù)邊界進(jìn)行拆分。
5卵渴、其他
效率問題
雖然DDD有這么多明顯的優(yōu)勢慧域,但也不是所有的系統(tǒng)都適合采用DDD領(lǐng)域驅(qū)動設(shè)計。
如上圖是兩層架構(gòu)浪读、多層SOA架構(gòu)與DDD隨著業(yè)務(wù)復(fù)雜度的增加在開發(fā)成本上的比較昔榴,可以看到剛開始DDD的成本是最高的,所以碘橘,如果是簡單的系統(tǒng)互订,后續(xù)業(yè)務(wù)不會有太大變化,那么久不適合用DDD痘拆,合適才是最好的仰禽。
對設(shè)計和開發(fā)人員的要求相對較高
DDD 戰(zhàn)術(shù)設(shè)計對設(shè)計和開發(fā)人員的要求相對較高,實現(xiàn)起來相對復(fù)雜纺蛆。不同企業(yè)的研發(fā)管理能力和個人開發(fā)水平可能會存在差異吐葵。尤其對于傳統(tǒng)企業(yè)而言,在戰(zhàn)術(shù)設(shè)計落地的過程中桥氏,可能會存在一定挑戰(zhàn)和困難温峭,我建議你和你的公司如果有這方面的想法,就一定要謹(jǐn)慎評估自己的能力字支,選擇最合適的方法落地 DDD诚镰。
參考
https://blog.csdn.net/w1lgy/article/details/109562193?https://juejin.cn/post/6917125801460629518?httpss://http://www.reibang.com/p/b6ec06d6b594
補(bǔ)充:
關(guān)于都在聊DDD, 哪里超越了MVC:?https://zhuanlan.zhihu.com/p/423892114
以上這些東西如果在學(xué)習(xí)了DDD之后再去學(xué)習(xí)會對DDD有更深入的了解,但我覺得DDD相對比較基礎(chǔ)祥款,如果我們在已經(jīng)了解了DDD的基礎(chǔ)之上再去學(xué)習(xí)這些東西會更加有效和容易掌握。
我是架構(gòu)師小于哥?
?月杉,偶爾出來聊聊天刃跛,寫寫代碼,經(jīng)常分享開發(fā)經(jīng)驗與技術(shù)技巧哦
https://zhuanlan.zhihu.com/p/361427612