從零教你領(lǐng)域模型在實(shí)際項(xiàng)目中的落地

最近學(xué)習(xí)了領(lǐng)域模型炸卑,雖然對(duì)領(lǐng)域模型中的每個(gè)概念都有大致的一個(gè)了解亡蓉,但是總是在腦海里面模棱兩可,看了極客?歐老師的DDD模型講解理論太多瞳浦,導(dǎo)致自己總是摸不著門(mén)路担映,不知道從何下手,怎么打破平時(shí)我們習(xí)慣性的E-R圖建模思維叫潦,故在美團(tuán)DDD實(shí)踐的基礎(chǔ)上在嘗試一下自己模擬一下業(yè)務(wù)場(chǎng)景從頭到尾的搭建一個(gè)DDD領(lǐng)域模型的業(yè)務(wù)場(chǎng)景蝇完。美團(tuán)DDD實(shí)戰(zhàn)項(xiàng)目鏈接:https://tech.meituan.com/2017/12/22/ddd-in-practice.html

文章就不從領(lǐng)域模型的概念開(kāi)始說(shuō)起了,在下面實(shí)際的項(xiàng)目里面會(huì)加入自己對(duì)于各個(gè)領(lǐng)域模塊的理解诅挑,如果有什么不對(duì)的地方希望可以得到大家的糾正四敞。

開(kāi)場(chǎng)白:

至少30年以前泛源,一些軟件設(shè)計(jì)人員就已經(jīng)意識(shí)到領(lǐng)域建模和設(shè)計(jì)的重要性拔妥,并形成一種思潮,Eric Evans將其定義為領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)(Domain-Driven Design达箍,簡(jiǎn)稱DDD)没龙。在互聯(lián)網(wǎng)開(kāi)發(fā)“小步快跑,迭代試錯(cuò)”的大環(huán)境下缎玫,DDD似乎是一種比較“古老而緩慢”的思想硬纤。然而,由于互聯(lián)網(wǎng)公司也逐漸深入實(shí)體經(jīng)濟(jì)赃磨,業(yè)務(wù)日益復(fù)雜筝家,我們?cè)陂_(kāi)發(fā)中也越來(lái)越多地遇到傳統(tǒng)行業(yè)軟件開(kāi)發(fā)中所面臨的問(wèn)題。在《復(fù)雜軟件設(shè)計(jì)之道》里面作者說(shuō)到了技術(shù)負(fù)債一詞邻辉,我在一家千萬(wàn)級(jí)別的電商公司上班溪王,聽(tīng)到這個(gè)詞的時(shí)候立馬就產(chǎn)生了共鳴腮鞍,公司前期處于發(fā)展階段,開(kāi)發(fā)人員為了能將產(chǎn)品快速上市莹菱,導(dǎo)致各種業(yè)務(wù)雜亂無(wú)章移国,平時(shí)改一個(gè)很簡(jiǎn)單的功能點(diǎn),改了一個(gè)地方道伟,另外一個(gè)業(yè)務(wù)也用到了(老員工也不熟悉業(yè)務(wù)迹缀,代碼毫無(wú)關(guān)聯(lián)的地方),導(dǎo)致上線總是出現(xiàn)一些這沒(méi)生效蜜徽,那沒(méi)反應(yīng)的問(wèn)題祝懂。等等

場(chǎng)景需求:

? ??抽獎(jiǎng)平臺(tái)

?? ?1.抽獎(jiǎng)活動(dòng)有活動(dòng)限制,例如用戶的抽獎(jiǎng)次數(shù)限制拘鞋,抽獎(jiǎng)的開(kāi)始和結(jié)束的時(shí)間嫂易,抽獎(jiǎng)人來(lái)源的抽獎(jiǎng)機(jī)會(huì)類型(例如分享xx才能抽獎(jiǎng)),等掐禁;

?? ?2.一個(gè)抽獎(jiǎng)活動(dòng)包含多個(gè)獎(jiǎng)品怜械,可以針對(duì)一個(gè)或多個(gè)用戶群體,獎(jiǎng)品可以指定人群(標(biāo)簽傅事,會(huì)員級(jí)別)發(fā)放缕允;

?? ?3.獎(jiǎng)品有自身的獎(jiǎng)品配置,例如庫(kù)存量蹭越,被抽中的概率等障本,最多被一個(gè)用戶抽中的次數(shù)等等;

?? ?4.用戶群體有多種區(qū)別方式响鹃,如按照用戶所在城市區(qū)分驾霜,按照新老客區(qū)分,會(huì)員等級(jí)买置,活躍度等粪糙;

?? ?5.活動(dòng)具有風(fēng)控配置,能夠限制用戶參與抽獎(jiǎng)的頻率忿项。

大家先是思考下如果按照我們平時(shí)的開(kāi)發(fā)習(xí)慣肯定就是先把數(shù)據(jù)結(jié)構(gòu)建好(E-R),然之后開(kāi)始用curd進(jìn)行過(guò)程式代碼的編寫(xiě)蓉冈。

1、建立活動(dòng)表(t_activity),活動(dòng)規(guī)則表(a_activity_condition),活動(dòng)獎(jiǎng)品表(t_activity_prize)等

2轩触、生成對(duì)應(yīng)的mapp寞酿,dao等

3、建立一個(gè)lotteryService脱柱,里面存放了大量的mapper伐弹,各種if邏輯.


基于數(shù)據(jù)結(jié)構(gòu)的開(kāi)發(fā)模式

這種業(yè)務(wù)模型簡(jiǎn)單的時(shí)候還好,等業(yè)務(wù)復(fù)雜起來(lái)的話榨为,會(huì)出現(xiàn)大量的業(yè)務(wù)邏輯存放在service里面惨好,業(yè)務(wù)邊界不明確椅邓,可能其中的某個(gè)方法某個(gè)判斷也存放在其他的service里面,導(dǎo)致改某個(gè)片段的代碼昧狮,其他的service也影響到了景馁,或者說(shuō)改ServiceA中的某段代碼,ServiceB也影響到了逗鸣。

? ? 平時(shí)我們開(kāi)發(fā)維護(hù)的時(shí)候產(chǎn)品說(shuō)加一個(gè)xx需求合住,我們每次都需要想這樣子改動(dòng)會(huì)不會(huì)影響到其他地方,最后的出的結(jié)果就是撒璧,不確定會(huì)不會(huì)影響透葛,或者直接和產(chǎn)品說(shuō):做不了等。導(dǎo)致產(chǎn)品為了兼顧開(kāi)發(fā)的難度導(dǎo)致調(diào)整了需求卿樱,本來(lái)應(yīng)該是讓技術(shù)去適應(yīng)市場(chǎng)的僚害,現(xiàn)在卻倒轉(zhuǎn)過(guò)來(lái),導(dǎo)致做出來(lái)的東西不符合原本的想法繁调。


DDD領(lǐng)域模型的核心思想就是“高內(nèi)聚萨蚕,低耦合”,或者面向?qū)ο蟮脑O(shè)計(jì)說(shuō)的“”蹄胰,我們平時(shí)開(kāi)發(fā)總是將業(yè)務(wù)邏輯和底層的模塊(如mapper,redis的工具代碼岳遥,es的工具代碼)耦合起來(lái),例如上面中的獎(jiǎng)品裕寨,先出現(xiàn)redis,沒(méi)有數(shù)據(jù)就查詢mysql浩蓉,我們一般寫(xiě)成


這方法一般是放在上面的 ?lotteryService里面,各位想下這本身是一個(gè)抽獎(jiǎng)應(yīng)用層宾袜,獲取獎(jiǎng)品本身的邏輯為什么會(huì)出現(xiàn)在這里捻艳,或者說(shuō)抽獎(jiǎng)邏輯為什么需要知道從redis取還是mysql拿呢?如果改成es庆猫?或者是其他的nosql认轨,這樣是不是要去修改lotteryService這個(gè)類,但是這個(gè)本身就不屬于抽獎(jiǎng)邏輯的阅悍,為什么最后需要去修改這個(gè)類呢好渠?這就是面向?qū)ο笳f(shuō)的昨稼,封閉原則节视。職責(zé)單一性。

接下來(lái)開(kāi)始使用DDD領(lǐng)域模型去拆解這個(gè)抽獎(jiǎng)業(yè)務(wù)

?戰(zhàn)略設(shè)計(jì)

? ? ? ? ? ?戰(zhàn)略設(shè)計(jì)是根據(jù)用戶旅程分析假栓,找出領(lǐng)域?qū)ο蠛途酆细靶校瑢?duì)實(shí)體和值對(duì)象進(jìn)行聚類組成聚合,劃分限界上下文匾荆,建立領(lǐng)域模型的過(guò)程拌蜘。戰(zhàn)略設(shè)計(jì)采用的方法是事件風(fēng)暴杆烁,包括:產(chǎn)品愿景、場(chǎng)景分析简卧、領(lǐng)域建模和微服務(wù)拆分等幾個(gè)主要過(guò)程兔魂。戰(zhàn)略設(shè)計(jì)階段建議參與人員:領(lǐng)域?qū)<摇I(yè)務(wù)需求方举娩、產(chǎn)品經(jīng)理析校、架構(gòu)師、項(xiàng)目經(jīng)理铜涉、開(kāi)發(fā)經(jīng)理和測(cè)試經(jīng)理智玻。

? ? ? ? ? ? 是不是很難懂?別急下面我們一步一步來(lái)芙代。我們可以把抽獎(jiǎng)拆解成C端和M端吊奢,M端就是我們常說(shuō)的管理后臺(tái),設(shè)計(jì)抽獎(jiǎng)活動(dòng)的相關(guān)配置纹烹。接下來(lái)講解的是C端


根據(jù)需求描述我們不難想到核心子域是抽獎(jiǎng)子域页滚。我們想下抽獎(jiǎng)的邏輯,可以分為1)抽獎(jiǎng)前判斷用戶是否滿足抽獎(jiǎng)條件铺呵;2)獲取獎(jiǎng)品池中的獎(jiǎng)品逻谦,根據(jù)概率抽獎(jiǎng),得出中獎(jiǎng)的獎(jiǎng)品? 3)得到的獎(jiǎng)品進(jìn)行判斷用戶是否瞞住得到獎(jiǎng)品的資格陪蜻;4)根據(jù)類型發(fā)放獎(jiǎng)品邦马。

可以得出,這個(gè)業(yè)務(wù)可以分成抽獎(jiǎng)前宴卖,抽獎(jiǎng)后兩個(gè)領(lǐng)域滋将。


2、戰(zhàn)術(shù)設(shè)計(jì)

針對(duì)抽獎(jiǎng)的子域部分症昏,我們可以得出如下的集合根和實(shí)體


UserInfoFacade:防腐層的含義可以理解為適配器随闽,由于UserInfo這個(gè)信息是在另外的微服務(wù)里面,我們需要通過(guò)http去獲取相對(duì)于的信息肝谭,所有需要使用一個(gè)適配器去請(qǐng)求掘宪,理解為微服務(wù)里面我們服務(wù)間的接口調(diào)用。

同理我們對(duì)于發(fā)放獎(jiǎng)品領(lǐng)域服務(wù)可以得出如下的建模


上面就是領(lǐng)域模型的建模過(guò)程了攘烛,現(xiàn)在把剛剛的業(yè)務(wù)整理到對(duì)應(yīng)的模塊里面魏滚,接下來(lái)直接上偽代碼了。

DDD工程實(shí)現(xiàn)

在對(duì)上下文進(jìn)行細(xì)化后坟漱,我們開(kāi)始在工程中真正落地DDD鼠次。

模塊

模塊(Module)是DDD中明確提到的一種控制限界上下文的手段,在我們的工程中,一般盡量用一個(gè)模塊來(lái)表示一個(gè)領(lǐng)域的限界上下文腥寇。

如代碼中所示成翩,一般的工程中包的組織方式為{com.公司名.組織架構(gòu).業(yè)務(wù).上下文.*},這樣的組織結(jié)構(gòu)能夠明確的將一個(gè)上下文限定在包的內(nèi)部赦役。

代碼演示1? 抽獎(jiǎng)模塊


代碼演示1:LotteryCondition(活動(dòng)限制聚合根)


? ? ? 從中可以看到抽獎(jiǎng)限制聚合根的主要功能就是整合幾個(gè)實(shí)體或健對(duì)象對(duì)用戶的活動(dòng)權(quán)限進(jìn)行控制麻敌。這一步是純業(yè)務(wù)性的,沒(méi)有涉及到db掂摔,緩存庸论,等的操作,因?yàn)榛A(chǔ)資源性的東西不應(yīng)該耦合在業(yè)務(wù)里面棒呛。

代碼模塊2:UserInfoFacde (用戶信息防腐層)


這一步可以理解為就是使用適配的方式調(diào)用第三方服務(wù)(微服務(wù))聂示。因?yàn)榈谌降姆?wù)的參數(shù)總是和我們需要使用到的時(shí)候是不一樣的,我們需要使用適配器的思維調(diào)用簇秒。

代碼模塊3:ActivityCondition


重點(diǎn)是checkActivityCondition()方法鱼喉,做邏輯處理

代碼模塊4?:LotteryChance



發(fā)放獎(jiǎng)品聚合根就不上代碼了,關(guān)于資源庫(kù)如何引入趋观,我們我們可以看下Prize代碼



將資源庫(kù)的部分從原來(lái)的service中抽取出來(lái)扛禽,和業(yè)務(wù)分離開(kāi)來(lái),這是很有必要的皱坛,業(yè)務(wù)本身就不用管你的數(shù)據(jù)怎么樣來(lái)编曼,只是負(fù)責(zé)業(yè)務(wù)的邏輯。包括現(xiàn)在很流行的六邊形架構(gòu)剩辟,整潔架構(gòu)等都是這個(gè)思想掐场。把業(yè)務(wù)和底層分離,這個(gè)底層可以是框架本身贩猎,數(shù)據(jù)庫(kù)等熊户。

我之前公司由于需要把mysql讀取的換成redis或者是本地緩存。如果把mapper代碼放到service里面的話吭服,這改動(dòng)起來(lái)是非常巨大的一個(gè)工作嚷堡,還會(huì)導(dǎo)致邏輯代碼的改動(dòng)。如果使用DDD的話是不是更加的符合面向?qū)ο蟮拈_(kāi)閉原則呢艇棕?

最后上一下整個(gè)抽獎(jiǎng)服務(wù)的代碼



把具體的邏輯封裝到獨(dú)立的領(lǐng)域里面蝌戒,這樣看起來(lái)不是比各種狀態(tài)散落在service里面舒服的多?服務(wù)里面只有領(lǐng)域?qū)ο笳恿穑蛘呤蔷酆系缺惫丁<词挂膭?dòng)數(shù)據(jù)的存儲(chǔ)也不用改動(dòng)到業(yè)務(wù)邏輯。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末刺桃,一起剝皮案震驚了整個(gè)濱河市粹淋,隨后出現(xiàn)的幾起案子吸祟,更是在濱河造成了極大的恐慌瑟慈,老刑警劉巖桃移,帶你破解...
    沈念sama閱讀 216,402評(píng)論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異葛碧,居然都是意外死亡借杰,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén)进泼,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)蔗衡,“玉大人,你說(shuō)我怎么就攤上這事乳绕〗实耄” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,483評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵洋措,是天一觀的道長(zhǎng)济蝉。 經(jīng)常有香客問(wèn)我踪栋,道長(zhǎng)漱逸,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,165評(píng)論 1 292
  • 正文 為了忘掉前任际起,我火速辦了婚禮滓鸠,結(jié)果婚禮上雁乡,老公的妹妹穿的比我還像新娘。我一直安慰自己糜俗,他們只是感情好踱稍,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,176評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著悠抹,像睡著了一般寞射。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上锌钮,一...
    開(kāi)封第一講書(shū)人閱讀 51,146評(píng)論 1 297
  • 那天桥温,我揣著相機(jī)與錄音,去河邊找鬼梁丘。 笑死侵浸,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的氛谜。 我是一名探鬼主播掏觉,決...
    沈念sama閱讀 40,032評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼值漫!你這毒婦竟也來(lái)了澳腹?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 38,896評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎酱塔,沒(méi)想到半個(gè)月后沥邻,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,311評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡羊娃,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,536評(píng)論 2 332
  • 正文 我和宋清朗相戀三年唐全,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蕊玷。...
    茶點(diǎn)故事閱讀 39,696評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡邮利,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出垃帅,到底是詐尸還是另有隱情延届,我是刑警寧澤,帶...
    沈念sama閱讀 35,413評(píng)論 5 343
  • 正文 年R本政府宣布贸诚,位于F島的核電站方庭,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏赦颇。R本人自食惡果不足惜二鳄,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,008評(píng)論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望媒怯。 院中可真熱鬧订讼,春花似錦、人聲如沸扇苞。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)鳖敷。三九已至脖苏,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間定踱,已是汗流浹背棍潘。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,815評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留崖媚,地道東北人亦歉。 一個(gè)月前我還...
    沈念sama閱讀 47,698評(píng)論 2 368
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像畅哑,于是被迫代替她去往敵國(guó)和親肴楷。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,592評(píng)論 2 353

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