實(shí)際上,本文的正確標(biāo)題應(yīng)該是《如何通過DDD構(gòu)建解決快速出行問題的領(lǐng)域模型》??焖俪鲂胁攀且鉀Q的問題,汽車只是其中一種解決方案或者落地的實(shí)現(xiàn)而已。嚴(yán)格區(qū)分問題域與解決方案域是實(shí)施DDD的老大難問題了。需要死磕這個(gè)問題的讀者可以參考TW洞見的這篇文章《當(dāng)Subdomain遇見Bounded Context》,這里不展開討論。本文的目的是要展現(xiàn)一個(gè)在非IT領(lǐng)域運(yùn)用DDD構(gòu)建領(lǐng)域模型的例子。
先出要解決的業(yè)務(wù)領(lǐng)域問題:我要實(shí)現(xiàn)城市內(nèi)快速出行。
就只有一句話,沒有細(xì)節(jié)信息,感覺什么都做不了。但往往需求都是這樣的簡(jiǎn)單粗暴的(此處淚奔)。好,繼續(xù)深挖一下需求。要實(shí)現(xiàn)城市內(nèi)快速出行,最簡(jiǎn)單的要實(shí)現(xiàn)3點(diǎn):
1.? 當(dāng)我趕時(shí)間時(shí),我可以加快速度
2.? 當(dāng)我遇到障礙物時(shí),我可以減速
3.? 當(dāng)我遇到障礙物時(shí),我可以繞過
嗯,有了3個(gè)細(xì)化的需求,有點(diǎn)感覺了。這里可以引入風(fēng)靡全球的DDD落地大法-事件風(fēng)暴(Event Storm,簡(jiǎn)稱ES)。在ES的過程中,會(huì)識(shí)別出業(yè)務(wù)問題中的關(guān)鍵事件,觸發(fā)事件的命令與觸發(fā)者(角色)?;氐轿覀兊膱?chǎng)景,會(huì)是這樣:

作為例子,這里只是列舉了3個(gè)簡(jiǎn)單的事件,其余就不在列出了。但并不代表在實(shí)際建模過程中可以省略。例如這里有加快速度的需求,就一定會(huì)有減緩速度的需求;有停下的需求,就一定會(huì)有啟動(dòng)的需求。這些需求對(duì)應(yīng)的事件在實(shí)際過程中都是需要識(shí)別出來的。
好了,有了這些事件,我們可以把目光從戰(zhàn)術(shù)層面轉(zhuǎn)向戰(zhàn)略層識(shí)別子域。從事件到子域,是一個(gè)歸納與提煉的過程。通過對(duì)相關(guān)事件的歸類,劃分明確的業(yè)務(wù)領(lǐng)域與邊界,從而得到清晰的業(yè)務(wù)架構(gòu)。這個(gè)過程我認(rèn)為類似于地圖zoom out,zoom out 前能夠看到國家內(nèi)的省份,城市,zoom out后雖看不到這些細(xì)節(jié),但能夠看到所有國家的全景?;氐轿覀兊膱?chǎng)景,我們識(shí)別出2個(gè)子域:

真實(shí)的出行場(chǎng)景識(shí)別出來的子域肯定會(huì)更復(fù)雜。例如安全等子域,并且會(huì)劃分核心域,通用域,支撐域。作為例子這里就不展開了。在實(shí)戰(zhàn)過程中,需要精通業(yè)務(wù)領(lǐng)域的專家依據(jù)其豐富的業(yè)務(wù)經(jīng)驗(yàn)對(duì)事件進(jìn)行歸類與定義清晰的業(yè)務(wù)邊界。這往往是困難的,也是沒有什么章法可循的。所以為什么在DDD的建模過程中必須強(qiáng)調(diào)一定要有領(lǐng)域?qū)<以诘脑?。沒有領(lǐng)域?qū)<遥鰜淼哪P屯|(zhì)量不高,所以如果沒有領(lǐng)域?qū)<遥?領(lǐng)域建模也就可以不用做了。

有了子域,我們可以跳回戰(zhàn)術(shù)層。但這次是探索解決方案了。這一步的關(guān)鍵概念是聚合。聚合是一組業(yè)務(wù)相關(guān)性比較強(qiáng)的對(duì)象,這些對(duì)象組合起來對(duì)外提供一致的服務(wù)。聚合的特點(diǎn)是聚合內(nèi)高內(nèi)聚,聚合間低耦合。由于要對(duì)外提供服務(wù),必須有單一的訪問入口,這個(gè)入口叫做聚合根。從外部看一個(gè)聚合,只能看到它的聚合根,而看不到聚合內(nèi)部具體的對(duì)象。
從事件到聚合,是一個(gè)從發(fā)散到收斂的抽象過程。這個(gè)過程很考驗(yàn)系統(tǒng)架構(gòu)師的抽象能力?;氐轿覀兊睦樱页橄蟪鰜淼木酆鲜牵?/p>
1.? 動(dòng)力控制 - 聚合根:加速控制器
2.? 制動(dòng)控制 - 聚合根:制動(dòng)控制器
3.? 轉(zhuǎn)向控制 - 聚合根:轉(zhuǎn)向控制器

在實(shí)戰(zhàn)的過程中,過程會(huì)更復(fù)雜,涉及的概念會(huì)更多。例如實(shí)體,值對(duì)象,領(lǐng)域服務(wù),聚合根的識(shí)別等。這些展開的話都會(huì)是一篇文章。
需要注意的一點(diǎn)是,我這里識(shí)別的聚合已經(jīng)是解決方案的聚合,但實(shí)操過程中,有人會(huì)在這一步之前識(shí)別業(yè)務(wù)實(shí)體作為問題域的具體對(duì)象,然后再從業(yè)務(wù)實(shí)體識(shí)別出解決方案的聚合。很難說哪一種更好。先識(shí)別業(yè)務(wù)實(shí)體再識(shí)別聚合可能會(huì)更流暢,但也會(huì)因此引入更多的概念,讓對(duì)DDD不熟悉的人容易產(chǎn)生混淆的感覺。
到了這一步,我們?cè)趩栴}域的戰(zhàn)略層面有邊界清晰的業(yè)務(wù)架構(gòu),在解決方案域的戰(zhàn)術(shù)層面有能組合起來對(duì)外提供服務(wù)的聚合,是時(shí)候探索解決方案域的戰(zhàn)略設(shè)計(jì)了。這一步我的慣常做法是把戰(zhàn)術(shù)層面的聚合放回戰(zhàn)略層面的子域,看能不能解決子域的業(yè)務(wù)問題,如果能解決,就形成戰(zhàn)略層面的解決方案,即所謂的限界上下文。這個(gè)名字非常拗口,但這個(gè)名字卻很好的表明了它的特性:限界表明它是邊界劃分清晰的,職責(zé)是明確的,上下文表明它是有一定的語境的。這往往是最難理解的一點(diǎn)。一個(gè)簡(jiǎn)單的例子就是對(duì)于“女兒”的解讀?!芭畠骸痹诓煌募彝ド舷挛睦锼傅娜耸遣灰粯拥?。在我的家庭上下文里面,“女兒”是指我的女兒,但是在我岳母的家庭上下文里面,“女兒”指的就是我妻子。所以如果一個(gè)子域里面只有一個(gè)聚合,那往往就會(huì)以這個(gè)聚合形成一個(gè)限界上下文;但如果一個(gè)子域里面存在多于一個(gè)聚合,并且不同的聚合里面存在一個(gè)名字一樣的對(duì)象,為了區(qū)分二義性,就要考慮是否需要拆開不同的上下文?;氐轿覀兊睦?,限界上下文長(zhǎng)這樣:
1.? 動(dòng)力控制上下文(同屬于速度控制子域)
2.? 制動(dòng)控制上下文(同屬于速度控制子域)
3.? 轉(zhuǎn)向控制上下文

這里速度控制子域還是維持動(dòng)力與制動(dòng)兩個(gè)上下文,更多的考慮點(diǎn)還是職責(zé)區(qū)分。
到這一步,快速出行工具的的領(lǐng)域模型構(gòu)建基本已經(jīng)完成了。再往后走就是實(shí)現(xiàn)域的事情,也就沒有DDD什么事了。到這里,才會(huì)涉及具體的技術(shù)實(shí)現(xiàn),技術(shù)對(duì)復(fù)雜的業(yè)務(wù)架構(gòu)的影響被DDD構(gòu)建的領(lǐng)域架構(gòu)完美隔離。從領(lǐng)域模型到具體實(shí)現(xiàn)的轉(zhuǎn)化,就輪到技術(shù)架構(gòu)師出場(chǎng)了。 技術(shù)架構(gòu)師基于系統(tǒng)架構(gòu)開展具體的技術(shù)架構(gòu)設(shè)計(jì)時(shí),更多的是需要考慮現(xiàn)實(shí)的限制因素。例如,在古代,科學(xué)不像現(xiàn)在這么發(fā)達(dá),出行工具以馬車的形式出現(xiàn),加速控制器被設(shè)計(jì)為馬鞭,制動(dòng)控制器被設(shè)計(jì)為馬韁繩,轉(zhuǎn)向控制就靠馬本身;在現(xiàn)代,出行工具變成了汽車,加速控制器是加速踏板,制動(dòng)控制器是制動(dòng)踏板,轉(zhuǎn)向控制是方向盤。但是,無論出行工具怎么進(jìn)化,無論是地鐵,汽車,還是電動(dòng)車,自行車,其通用系統(tǒng)架構(gòu)與領(lǐng)域模型其實(shí)并沒有發(fā)生非常大的改變。究其原因是人們?cè)诔鲂袝r(shí)的具體需求沒有發(fā)生實(shí)質(zhì)性變化,無非都是加速,減速,轉(zhuǎn)向。變化的其實(shí)是具體的技術(shù)架構(gòu)。


回到IT領(lǐng)域,當(dāng)系統(tǒng)架構(gòu)確定后,系統(tǒng)的實(shí)現(xiàn)究竟是以現(xiàn)在火熱的微服務(wù)架構(gòu)來實(shí)現(xiàn)還是沿用傳統(tǒng)的單體架構(gòu)來實(shí)現(xiàn),并不是DDD所要回答的問題。技術(shù)架構(gòu)師必須基于現(xiàn)實(shí)因素來綜合考慮具體落地的實(shí)現(xiàn)方式。例如微服務(wù)架構(gòu)最大的好處就是松耦合帶來的高響應(yīng)力,就像上面提到的馬車,馬車與馬之間是松耦合的,馬累趴下了可以立刻換馬;單體架構(gòu)的好處是不存在跨網(wǎng)絡(luò)調(diào)用,性能往往比微服務(wù)好,就像現(xiàn)在的汽車(好吧,我承認(rèn)我在黑微服務(wù))。但是不論是微服務(wù)還是單體,基于DDD構(gòu)建的領(lǐng)域模型都給最后的落地從架構(gòu)上提供了很好的保障。

討論到這里,可能會(huì)有人問按照這種方法出來的模型跟我自己拍腦袋想的也差不多呀。然而事實(shí)就是這樣,我們能拍出來一個(gè)八九不離十的模型是因?yàn)槲覀儗?duì)各種出行工具已經(jīng)非常熟悉了,以至于可以認(rèn)為我們其實(shí)都是一定程度上的領(lǐng)域?qū)<?。類似的問題我們?cè)趲涂蛻魧?shí)施DDD的過程中也經(jīng)常被問到。尤其是對(duì)于遺留系統(tǒng)改造或者是系統(tǒng)平遷,最后出來的模型往往與客戶腦子里面的模型差不多,然后他們就會(huì)問:“這和我們現(xiàn)在的差不多呀,也沒什么特別大的區(qū)別呢?!保@個(gè)時(shí)候我一般會(huì)這樣回答:“這個(gè)是肯定的呢,如果你們現(xiàn)有系統(tǒng)架構(gòu)與業(yè)務(wù)領(lǐng)域相去甚遠(yuǎn),你覺得你的系統(tǒng)能存活到現(xiàn)在嗎?”
回到我們的問題:我要實(shí)現(xiàn)城市內(nèi)快速出行。話說回來,其實(shí)這個(gè)問題的最快解決方法難道不是直接買一輛汽車嗎?還花什么心思自己構(gòu)建一輛呢?這個(gè)我承認(rèn)。對(duì)我們來說,市內(nèi)快速出行只是一個(gè)通用域的問題,直接花錢買一輛汽車就行。所以我們的建模過程就會(huì)快速收斂成以下這樣:

嗯,不錯(cuò)。遇到非核心域快速收斂。Fail fast,才是DDD的精髓所在。
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
相關(guān)閱讀更多精彩內(nèi)容
- 10月有幸參加ThoughtWorks組織的《領(lǐng)域驅(qū)動(dòng)的微服務(wù)架構(gòu)設(shè)計(jì)實(shí)戰(zhàn)工作坊》培訓(xùn)課程,盡管課程時(shí)間只有短短一...
- 本文是以最簡(jiǎn)單的方式去敘述DDD的概念。DDD 與 微服務(wù) 是緊密相關(guān)的, 所以必須是先了解 DDD 的方式才比較...
- 引言 在討論DDD分層架構(gòu)的模式之前,我們先一起回顧一下DDD和分層架構(gòu)的相關(guān)知識(shí)。 DDD DDD(Domain...
- 家訪 是什么力量,能讓一群陌生人迅速團(tuán)結(jié)在一起?答曰:家訪。 一個(gè)百人微信群,不用發(fā)紅包大家就踴躍發(fā)言,這是什么群...
- 面對(duì)困難時(shí)的由于退縮,面對(duì)挫折時(shí)的恐懼慌張,面對(duì)失敗后的彷徨失措……現(xiàn)在的我是否太脆弱了?思緒一拉開,難免將心...