Java架構(gòu)設(shè)計(jì)之六步拆解 DDD
引言
相信通過前面幾篇文章的介紹,大家對(duì)于 DDD 的相關(guān)理論以及實(shí)踐的套路有了一定的理解,但是理解 DDD 理論和實(shí)踐手段是一回事,能不能把這些理論知識(shí)實(shí)際應(yīng)用到我們實(shí)際工作中又是另外一回事,因此本文通過實(shí)際的業(yè)務(wù)分析把之前文章中涉及的理論和手段全部帶著大家走一遍,我想通過這種方式,讓大家實(shí)際的感受下 DDD 落地過程中會(huì)遇到哪些問題以及我們應(yīng)該怎樣去解決這些問題。
項(xiàng)目需求信息
這里還是大家比較熟悉的電商場(chǎng)景來進(jìn)行說明,我想這樣大家比較好理解一點(diǎn)。在前段時(shí)間雙十一,大家被各種購物優(yōu)惠券的套路整的眼花繚亂,仿佛數(shù)學(xué)不好,都不配拿到最優(yōu)惠的價(jià)格了。大家都在吐槽,就不能少點(diǎn)套路,買東西直接給我 5 折不就天下太平了嗎?我想造成這種現(xiàn)象的原因大概就是中國(guó)電商行業(yè)的內(nèi)卷吧,只有通過各種營(yíng)銷活動(dòng)的堆積,才能讓大家話更多的時(shí)間去瀏覽更過的商品,才能獲得更好的留客以及交易。好了,跑題了,這些我們先不去關(guān)心。那我們今天就用這個(gè)折磨人的優(yōu)惠券的流程作為設(shè)計(jì)實(shí)例來說明整個(gè) DDD 的落地過程吧。優(yōu)惠券的關(guān)鍵業(yè)務(wù)流程如下:
(1)當(dāng)需要進(jìn)行大促活動(dòng)的時(shí)候,運(yùn)營(yíng)同學(xué)需要選定對(duì)應(yīng)的商品,創(chuàng)建創(chuàng)建優(yōu)惠券。
(2)運(yùn)營(yíng)同學(xué)需要?jiǎng)?chuàng)建營(yíng)銷活動(dòng),制定對(duì)應(yīng)的營(yíng)銷活動(dòng)規(guī)則,比如什么滿減啊,跨店減啊類似這種折磨人腦細(xì)胞的規(guī)則,然后關(guān)聯(lián)相應(yīng)的優(yōu)惠券,最后提交活動(dòng)審批。審批通過后,進(jìn)行營(yíng)銷活動(dòng)發(fā)布。
(3)提交活動(dòng)審批后,審批進(jìn)行營(yíng)銷活動(dòng)審批。
(4)用戶在營(yíng)銷頁面領(lǐng)取優(yōu)惠券之后,下單購買商品之后,在付款的時(shí)候根據(jù)對(duì)應(yīng)的優(yōu)惠券進(jìn)行付費(fèi)金額計(jì)算并完成支付。
DDD 落地實(shí)踐
項(xiàng)目背景信息我們大致了解之后,那么我們就要著手開始通過DDD來進(jìn)行領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)的過程了。其實(shí)我們學(xué)習(xí) DDD 理論以及方法不是最終的目的,而通過它實(shí)現(xiàn)實(shí)際的業(yè)務(wù)復(fù)雜度治理以及優(yōu)化微服務(wù)設(shè)計(jì)才是真正的目的。
戰(zhàn)略設(shè)計(jì)
在戰(zhàn)略設(shè)計(jì)階段,我們最主要的過程大致包括了業(yè)務(wù)場(chǎng)景分析、領(lǐng)域建模、劃分邊界上下文三個(gè)階段。實(shí)際上戰(zhàn)略設(shè)計(jì)是 DDD 過程中的核心步驟。
1、業(yè)務(wù)分析
在這個(gè)階段我們所有做的就是進(jìn)行全面的業(yè)務(wù)梳理,吧業(yè)務(wù)中涉及到的所有細(xì)節(jié)都梳理出來,為后續(xù)進(jìn)行領(lǐng)域建模分析提供足夠的、全面的業(yè)務(wù)輸入。經(jīng)常使用到的業(yè)務(wù)場(chǎng)景分析方法主要包括用例分析法、事件風(fēng)暴法以及四色建模法。這里我們使用事件風(fēng)暴進(jìn)行業(yè)務(wù)場(chǎng)景的分析以及梳理。
(1)事前準(zhǔn)備
在進(jìn)行事件風(fēng)暴之前我們需要進(jìn)行一些準(zhǔn)備,主要包括貼紙、筆以及討論的會(huì)議室,會(huì)議室中最好不要有椅子,目的是想讓大家都能夠站立在一起、全神貫注的去進(jìn)行業(yè)務(wù)討論。
(2)邀請(qǐng)參會(huì)的人
會(huì)議的參與方主要包括業(yè)務(wù)、用戶、PD、研發(fā)、測(cè)試、架構(gòu)師等。
(3)業(yè)務(wù)討論
首先確定我們今天需要討論的業(yè)務(wù)是什么,目標(biāo)是什么。像前文所說的那樣,本次討論的業(yè)務(wù)就是營(yíng)銷活動(dòng)的優(yōu)惠券業(yè)務(wù),目標(biāo)就是完成優(yōu)惠券的業(yè)務(wù)梳理,確保沒有業(yè)務(wù)方面的理解 gap,在團(tuán)隊(duì)中達(dá)成業(yè)務(wù)理解的的一致性。在這個(gè)過程中我們需要通過提問的方式來驅(qū)動(dòng)交流。
a、分析業(yè)務(wù)中的事件,搞清楚事件發(fā)生的前因后果,什么意思呢?就是什么動(dòng)作會(huì)導(dǎo)致當(dāng)前時(shí)間的發(fā)生,當(dāng)前這個(gè)事件發(fā)生后又會(huì)導(dǎo)致怎樣的后果。這些我們都需要梳理清楚。還有一點(diǎn)需要注意, 我不但要關(guān)注正常的業(yè)務(wù)流程還要關(guān)注異常的業(yè)務(wù)流程。
b、尋找業(yè)務(wù)邏輯和業(yè)務(wù)規(guī)則,比如我們?cè)谔峤换顒?dòng)前,需要確定這些優(yōu)惠券適用哪些人、領(lǐng)取方式是怎樣的以及生效事件是怎樣的等等,這些都是我們?cè)趫?zhí)行操作之前需要確定的業(yè)務(wù)規(guī)則。
如下圖所示,我們將優(yōu)惠券的業(yè)務(wù)流程進(jìn)行了梳理,分別從操作人、事件、命令的方式來描述整個(gè)優(yōu)惠券業(yè)務(wù)流轉(zhuǎn)的過程。
注:在進(jìn)行事件風(fēng)暴過程中,所有的參與人都要全身投入整個(gè)過程,放下手機(jī)以及電腦,一起參與整個(gè)業(yè)務(wù)梳理過程,只有這樣,事件風(fēng)暴才可能有比較好的效果。
2、領(lǐng)域建模
在前面的事件風(fēng)暴業(yè)務(wù)梳理中,我們已經(jīng)把優(yōu)惠券業(yè)務(wù)涉及到的參與者、動(dòng)作以及事件等都進(jìn)行了全面的梳理。那么接下來我們就要在此基礎(chǔ)之上進(jìn)行領(lǐng)域建模,這是整個(gè) DDD 的核心。
(1)領(lǐng)域?qū)ο蠓治?/h4>
如上面所示的事件風(fēng)暴小黑板中的內(nèi)容,我們需要在這些梳理出來的內(nèi)容中找到對(duì)應(yīng)的實(shí)體、值對(duì)象以及圍繞這些的領(lǐng)域事件以及命令操作。根據(jù)分析,我們總整個(gè)業(yè)務(wù)過程中提取了優(yōu)惠券、營(yíng)銷活動(dòng)、活動(dòng)審批單、活動(dòng)規(guī)則、審批意見等實(shí)體以及值對(duì)象以及和這些領(lǐng)域?qū)ο笙嚓P(guān)的命令操作。
(2)構(gòu)建業(yè)務(wù)聚合
完成領(lǐng)域?qū)ο蠓治鲋螅覀冃枰獦?gòu)建業(yè)務(wù)聚合。想要構(gòu)建聚合,那么首先就要在實(shí)體中找到聚合根。我們先來回顧下聚合根的特點(diǎn),聚合根一定是實(shí)體,那么它具有全局唯一的標(biāo)識(shí),另外它是具備生命周期的同時(shí)需要專門的模塊來進(jìn)行管理。根據(jù)這樣的標(biāo)準(zhǔn),在領(lǐng)域?qū)ο笾形覀儼l(fā)現(xiàn)優(yōu)惠券、營(yíng)銷活動(dòng)以及活動(dòng)審批單是具備聚合根特征的,而營(yíng)銷規(guī)則、營(yíng)銷內(nèi)容等是和營(yíng)銷活動(dòng)緊密相關(guān)的,因此他們構(gòu)成營(yíng)銷活動(dòng)聚合關(guān)系。優(yōu)惠券規(guī)則、優(yōu)惠券類型等是和優(yōu)惠券聚合根緊密相連的,所以他們構(gòu)成優(yōu)惠券聚合關(guān)系。同理活動(dòng)審批單也會(huì)構(gòu)成聚合關(guān)系。最終我們形成如下的聚合關(guān)系。
3、劃分邊界上下文
在上述步驟中,我們獲得了整個(gè)業(yè)務(wù)流程中的所有聚合后,我們需要更具業(yè)務(wù)語義上下文將具體的聚合劃分到對(duì)應(yīng)的上下文中,因此我們可以把優(yōu)惠券的業(yè)務(wù)分為優(yōu)惠券、營(yíng)銷活動(dòng)以及審批三個(gè)限界上下文。
戰(zhàn)術(shù)設(shè)計(jì)
在戰(zhàn)略設(shè)計(jì)階段,我們通過事件風(fēng)暴法對(duì)整體的業(yè)務(wù)進(jìn)行了全部的梳理,同時(shí)構(gòu)建了領(lǐng)域模型以及劃分了邊界下文。那么接下來我們就要將領(lǐng)域模型映射到工程結(jié)構(gòu)以及代碼中實(shí)現(xiàn)最終的實(shí)現(xiàn)落地。另外在這個(gè)階段實(shí)際還有很多細(xì)節(jié)需要明確,那優(yōu)惠券來說,它包含哪些屬性,需要哪些領(lǐng)域服務(wù),哪些需要設(shè)計(jì)為實(shí)體,哪些需要設(shè)計(jì)為值對(duì)象,這些都是需要在戰(zhàn)術(shù)設(shè)計(jì)階段明確下來。
1、微服務(wù)拆分
我們根據(jù)已經(jīng)劃分的邊界上下文,我們可以拆分為優(yōu)惠券服務(wù)、營(yíng)銷活動(dòng)服務(wù)以及審批中心三個(gè)微服務(wù),至于用戶支付使用這塊,還是由原先已存在支付服務(wù)來完成,只是在付款核算的時(shí)候需要使用到優(yōu)惠券進(jìn)行最后的金額計(jì)算。
2、領(lǐng)域分層
在領(lǐng)域分層方面,我們還是按照之前文章中所說的分層結(jié)構(gòu)來進(jìn)行,即 interfaces 層、biz 層、domain 層以及 instructure 層。每層代表的含義之前的文章中已經(jīng)進(jìn)行了詳細(xì)的說明,大家可以翻看前面文章中的介紹,這里不再進(jìn)行贅述了。
我們以優(yōu)惠券為例,實(shí)際聚合中對(duì)象還需要進(jìn)行進(jìn)一步的細(xì)化。對(duì)于優(yōu)惠券來說它實(shí)際上還有如下所示的值對(duì)象以及實(shí)體來組成實(shí)際的優(yōu)惠券。同時(shí)在優(yōu)惠券我們的梳理的領(lǐng)域服務(wù)還包括創(chuàng)建優(yōu)惠券、查詢優(yōu)惠券以及修改優(yōu)惠券狀態(tài),這些動(dòng)作實(shí)際都應(yīng)該在領(lǐng)域?qū)油ㄟ^領(lǐng)域服務(wù)的形式完成落地。而對(duì)應(yīng)的 biz 層就相當(dāng)于業(yè)務(wù)的編排組合,也就是實(shí)際的業(yè)務(wù)流程的串聯(lián)。
3、代碼結(jié)構(gòu)
當(dāng)我們把領(lǐng)域?qū)ο筮M(jìn)行進(jìn)一步的細(xì)化之后,同時(shí)把對(duì)應(yīng)的領(lǐng)域服務(wù)敲定之后,我們可以把這些分析后的內(nèi)容映射成工程分層后的代碼了。如下圖所示,即為優(yōu)惠券的 domain 層的代碼映射。
當(dāng)然到這里并不意味著結(jié)束,其實(shí)在后續(xù)還有很多工作要做,比如詳細(xì)設(shè)計(jì)、編寫代碼以及功能測(cè)試,特別實(shí)在詳細(xì)設(shè)計(jì)階段,我們還要涉及很多的細(xì)節(jié)問題的敲定,比如數(shù)據(jù)庫表的設(shè)計(jì)、比如使用什么 MQ,用不用緩存,怎么保證緩存和數(shù)據(jù)庫的數(shù)據(jù)一致性問題,分布式服務(wù)有沒有分布式事務(wù)的問題,應(yīng)該怎么解決?有沒有服務(wù)冪等問題,應(yīng)該怎么解決?這些都是需要在詳細(xì)設(shè)計(jì)階段進(jìn)行確定的。因此 DDD 就像是框架,通過它把業(yè)務(wù)映射成為領(lǐng)域?qū)ο笠约邦I(lǐng)域服務(wù)和領(lǐng)域事件,再把這些領(lǐng)域相關(guān)內(nèi)容再讀映射為實(shí)際的代碼。使得我們的服務(wù)更加的邏輯清晰以及擴(kuò)展性更強(qiáng),但是分布式的技術(shù)實(shí)現(xiàn)細(xì)節(jié),我們還是需要有對(duì)應(yīng)的解決方案來進(jìn)行解決。
總結(jié)
本文以電商行業(yè)的營(yíng)銷活動(dòng)中的優(yōu)惠券的發(fā)放和使用作為實(shí)際案例來闡述 DDD 領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)落地實(shí)踐的過程,通過整個(gè)過程的梳理,為大家提煉了整個(gè)設(shè)計(jì)過程的精要,相信大家可以按照這樣的思路在實(shí)際的工作中再結(jié)合各自的業(yè)務(wù)特征應(yīng)該可以真正完成整個(gè) DDD 的實(shí)踐。萬事開頭難,相信只要大家能夠親自去參與或者主導(dǎo)一個(gè) DDD 的落地實(shí)踐過程,那么對(duì)于理解 DDD 這套架構(gòu)設(shè)計(jì)方法論又會(huì)進(jìn)入一個(gè)新的臺(tái)階。在后面的文章中再和大家聊聊落地 DDD 過程中可能會(huì)遇到的一些問題以及軟件復(fù)雜度治理的問題。
真正的大師永遠(yuǎn)懷著一顆學(xué)徒的心 ————————————————
到此這篇關(guān)于Java架構(gòu)設(shè)計(jì)之六步拆解 DDD的文章就介紹到這了,更多相關(guān)Java 拆解 DDD內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
迅速學(xué)會(huì)@ConfigurationProperties的使用操作
這篇文章主要介紹了迅速學(xué)會(huì)@ConfigurationProperties的使用,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-10-10Java中&&與?表達(dá)式結(jié)合時(shí)出現(xiàn)的坑
這篇文章主要給大家介紹了關(guān)于Java中&&與?表達(dá)式結(jié)合時(shí)出現(xiàn)的坑的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-02-02學(xué)會(huì)IDEA REST Client后就可以丟掉postman了
這篇文章主要介紹了學(xué)會(huì)IDEA REST Client后就可以丟掉postman了,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-12-12淺析java中 Spring MVC 攔截器作用及其實(shí)現(xiàn)
本篇文章主要介紹了java中SpringMVC 攔截器的使用及其實(shí)例,需要的朋友可以參考2017-04-04使用springboot開發(fā)的第一個(gè)web入門程序的實(shí)現(xiàn)
這篇文章主要介紹了使用springboot開發(fā)的第一個(gè)web入門程序的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-04-04SpringBoot如何獲取當(dāng)前操作用戶的id/信息
在一般性的基設(shè)需求中,有需要獲取當(dāng)前用戶操作記錄的情況,也就是說我們需要記錄當(dāng)前用戶的信息,如:id、昵稱、賬號(hào)等信息,這篇文章主要介紹了SpringBoot獲取當(dāng)前操作用戶的id/信息,需要的朋友可以參考下2023-10-10Springboot Autowried及Resouce使用對(duì)比解析
這篇文章主要介紹了Springboot Autowried及Resouce使用對(duì)比解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-06-06