萬字長(zhǎng)文詳解從軟件復(fù)雜度的角度去理解DDD
一、作為業(yè)務(wù)開發(fā),我們的主要的職責(zé)是什么的
業(yè)務(wù)開發(fā)的職責(zé)
在文章的開始我想和大家一起思考一個(gè)問題:作為一個(gè)工程開發(fā),我們最主要的職責(zé)是什么??我極度認(rèn)可 <<淺談什么是技術(shù)一號(hào)位>>文章的觀點(diǎn) -?切實(shí)解決業(yè)務(wù)問題才是每一個(gè)工程開發(fā)最主要的職責(zé)?- 所以每個(gè)業(yè)務(wù)開發(fā)都必須要結(jié)合業(yè)務(wù)的視角去思考自己系統(tǒng)的建設(shè)和發(fā)展,而不是只是做一個(gè)“編程的”碼農(nóng)。
這里摘錄一下文章中要點(diǎn)
技術(shù)一號(hào)位是負(fù)責(zé)使用技術(shù)能力解決業(yè)務(wù)問題,提供穩(wěn)定可靠的技術(shù)支撐;
負(fù)責(zé)向業(yè)務(wù)各方提供各種必要的技術(shù)支撐,通過合理的數(shù)據(jù)分析為業(yè)務(wù)決策提供依據(jù);
通過對(duì)技術(shù)領(lǐng)域的積累和發(fā)展,通過業(yè)務(wù)領(lǐng)域的理解和落地影響業(yè)務(wù)決策;
負(fù)責(zé)構(gòu)建梯隊(duì)完整、能力全面、制度完善的技術(shù)團(tuán)隊(duì)來支撐業(yè)務(wù)發(fā)展。
文中也提到了雖然不是每個(gè)人都負(fù)責(zé)一塊完成的業(yè)務(wù),也不是每個(gè)人都帶領(lǐng)團(tuán)隊(duì),但是至少每個(gè)人都是自己所負(fù)責(zé)的那塊系統(tǒng)的技術(shù)一號(hào)位。
業(yè)務(wù)在實(shí)際開展中遇到的問題
那實(shí)際業(yè)務(wù)開展中,業(yè)務(wù)到底會(huì)遇到有哪些問題呢?我們按業(yè)務(wù)的生命周期進(jìn)行切分,然后具體查看每個(gè)業(yè)務(wù)生命周期的訴求:
業(yè)務(wù)啟動(dòng)期:業(yè)務(wù)能力快速搭建 - 系統(tǒng)提供快速試錯(cuò)的能力
業(yè)務(wù)發(fā)展期:業(yè)務(wù)能力擴(kuò)展 - 系統(tǒng)需要支持原來越多的業(yè)務(wù)功能
業(yè)務(wù)平臺(tái)期:業(yè)務(wù)能力復(fù)制 - 系統(tǒng)需要支持原來越多的業(yè)務(wù)場(chǎng)景
業(yè)務(wù)衰退期:業(yè)務(wù)能力創(chuàng)新 - 系統(tǒng)提高生產(chǎn)力延長(zhǎng)業(yè)務(wù)的生命周期

我們技術(shù)要做的事情是:在業(yè)務(wù)驗(yàn)證沒有問題的情況下,如果盡可能的延長(zhǎng)業(yè)務(wù)的發(fā)展和平臺(tái)期,讓業(yè)務(wù)獲取的利益最大化。所以為了支持業(yè)務(wù)的發(fā)展,業(yè)務(wù)的本身的功能支持訴求以及業(yè)務(wù)對(duì)技術(shù)的要求也會(huì)越來多,在這種情況下考驗(yàn)軟件開發(fā)人員的一個(gè)非常關(guān)鍵的能力就是:?軟件復(fù)雜度的控制的能力。
軟件復(fù)雜度
軟件復(fù)雜度其實(shí)是一種多維度的概念,其可能來源于多個(gè)方面,前阿里資深技術(shù)專家李運(yùn)華在他的《從0開始學(xué)架構(gòu)的》課程中從6個(gè)方面闡述了軟件復(fù)雜度【2】,列舉如下:
高性能
單機(jī)性能
集群性能
高可用
計(jì)算高可用
存儲(chǔ)高可用
可擴(kuò)展性
低成本
安全
規(guī)模
業(yè)務(wù)規(guī)模
系統(tǒng)物理規(guī)模
二、DDD的本質(zhì)是什么
DDD本質(zhì)上我認(rèn)為就是一種減低軟件復(fù)雜度的手段, 其推薦的方法論可以適用于上面包括了業(yè)務(wù)規(guī)模,可擴(kuò)展性兩個(gè)維度的復(fù)雜度應(yīng)對(duì)。其實(shí)業(yè)務(wù)規(guī)模的復(fù)雜度的處理包括了對(duì)可擴(kuò)展性的支持。
DDD實(shí)施給系統(tǒng)之后,我們依然需要關(guān)注系統(tǒng)其它的復(fù)雜度,這里列舉一些示例措施:
容量規(guī)劃
架構(gòu)設(shè)計(jì)
數(shù)據(jù)庫(kù)設(shè)計(jì)
緩存設(shè)計(jì)
框架選型
發(fā)布方案
數(shù)據(jù)遷移、同步方案
分庫(kù)分表方案
回滾方案
高并發(fā)解決方案
一致性選型
性能壓測(cè)方案
監(jiān)控報(bào)警方案
那么我們進(jìn)一步對(duì)業(yè)務(wù)規(guī)模的復(fù)雜度進(jìn)行拆解,又分為下面兩類:
1、領(lǐng)域復(fù)雜度
領(lǐng)域模型描述問題域的準(zhǔn)確性
2、技術(shù)實(shí)現(xiàn)的復(fù)雜性
代碼沒有按照業(yè)務(wù)綁定的”分析模型”去編碼,軟件變成一個(gè)大泥潭
軟件的可擴(kuò)展性較差
軟件變成面向過程
分層不合理
沒有規(guī)范
那DDD是如何處理上面提到的軟件復(fù)雜度的?
提供了一個(gè)領(lǐng)域劃分的方法:讓軟件系統(tǒng)產(chǎn)生邊界。
提供一個(gè)一系列的戰(zhàn)略模式:限界上下文的映射,分層架構(gòu)等。
提供一個(gè)一系列的戰(zhàn)術(shù)模式:如何規(guī)劃領(lǐng)域?qū)?內(nèi)部
DDD不是什么?
不光光只是一種編程方法
不光光只是一種架構(gòu)風(fēng)格
不具體指導(dǎo)如何具體建模
三、復(fù)雜度處理-領(lǐng)域模型描述問題域的準(zhǔn)確性
DDD的原名是模型驅(qū)動(dòng)的設(shè)計(jì)方法:通過領(lǐng)域模型(Domain Model)捕捉領(lǐng)域知識(shí),使用領(lǐng)域模型構(gòu)造更易維護(hù)的軟件。
合理性證明

DDD的核心思想,大家都清楚,就是分析模型要和代碼模型保持一致。?那么如果不保持一致到底會(huì)產(chǎn)生什么樣的負(fù)面影響

如果技術(shù)實(shí)現(xiàn)和業(yè)務(wù)實(shí)現(xiàn)不在用一水平線上,那技術(shù)模型的行進(jìn)路線只會(huì)考慮劈開技術(shù)障礙并且可能會(huì)撞在未來的業(yè)務(wù)障礙的墻上。這樣就很容易出現(xiàn),業(yè)務(wù)持續(xù)演進(jìn)等技術(shù)想實(shí)現(xiàn)的時(shí)候,卻發(fā)現(xiàn)當(dāng)前的實(shí)現(xiàn)依賴于“業(yè)務(wù)不會(huì)這樣發(fā)展”的假設(shè)上。這也是為什么會(huì)出現(xiàn)現(xiàn)在眾多業(yè)務(wù)需求,技術(shù)無法實(shí)現(xiàn)或者是需要花大量時(shí)間去實(shí)現(xiàn)的原因。但是如果技術(shù)和業(yè)務(wù)通過統(tǒng)一語言打破知識(shí)的壁壘保持一致,那么如果后面技術(shù)遇到問題即是業(yè)務(wù)碰到的問題,業(yè)務(wù)人員需求的變更和迭代會(huì)自然而然的幫助技術(shù)同學(xué)越過一些門檻。也就是說業(yè)務(wù)方與技術(shù)方參與到對(duì)方的工作中,就在雙方之間帶來了更好的協(xié)同,形成1+1>2的功效。
什么是問題域
根據(jù)百度百科的解釋【3】?在軟件工程中,問題域是指待開發(fā)系統(tǒng)的應(yīng)用領(lǐng)域,即在客觀世界中由該系統(tǒng)處理的業(yè)務(wù)范圍

那么問題域內(nèi)的組成是什么呢?就是我們的域模型。?這里直接摘抄一段前阿里P10"阿白"在阿里內(nèi)部發(fā)表的域模型的觀點(diǎn):域模型(domain model)英文又稱為問題域模型(problem space model)。維基百科(Wikipedia)對(duì)它的定義是” A conceptual model of all the topics related to a specific problem” 可以翻譯成:“域模型是針對(duì)某個(gè)特定問題的所有相關(guān)方面的抽象模型”。這個(gè)定義有幾個(gè)要點(diǎn):第一是“特定問題”, 也即是說域模型是針對(duì)性某個(gè)問題域而言的, 脫離的這個(gè)特定問題,域模型的構(gòu)建其實(shí)不存在一個(gè)最優(yōu)或者是最合理的構(gòu)建。第二是抽象, 域模型是一個(gè)抽象模型, 不是對(duì)某個(gè)問題的各個(gè)相關(guān)方面的一個(gè)映射, 也不是解決方案的構(gòu)建。?

如何實(shí)現(xiàn)問題域的分析
在 DDD 中,Eric Evans 提倡出一種叫做知識(shí)消化(Knowledge Crunching)的方法幫助我們?nèi)ヌ釤掝I(lǐng)域模型。簡(jiǎn)單來說就是五個(gè)步驟:
關(guān)聯(lián)模型與軟件實(shí)現(xiàn);
基于模型提取統(tǒng)一語言;
開發(fā)富含知識(shí)的模型;
精煉模型;
頭腦風(fēng)暴與試驗(yàn)。

開發(fā)人員和業(yè)務(wù)專家在一起通過一個(gè)個(gè)業(yè)務(wù)用例仔細(xì)討論應(yīng)用程序的應(yīng)用場(chǎng)景,從而使得業(yè)務(wù)人員深刻理解業(yè)務(wù)知識(shí),開發(fā)人員和業(yè)務(wù)人員就重要的業(yè)務(wù)概念建立起統(tǒng)一的語言,開發(fā)人員將這些概念根據(jù)業(yè)務(wù)用例的上下文抽象出模型,并且這些模型將會(huì)最終成為最終軟件實(shí)現(xiàn)中的領(lǐng)域模型。隨后隨著更多的業(yè)務(wù)用例的輸入,開發(fā)人員和業(yè)務(wù)人員會(huì)逐漸對(duì)已經(jīng)構(gòu)建的模型進(jìn)行精化,并且也會(huì)用新的用例去檢驗(yàn)之前構(gòu)建模型的合法性和適用性。DDD在這一步其實(shí)沒有給出詳實(shí)標(biāo)準(zhǔn)的如何建模的方法,畢竟建模還是來自于每個(gè)人的世界觀,其過程還是傾向于經(jīng)驗(yàn)的。但是還是有不少人總結(jié)一些標(biāo)準(zhǔn)的建模方法論例如:
1?四色原型法??
http://apframework.com/2020/03/22/ddd-color/
2 用例分析法?
https://baike.baidu.com/item/%E7%94%A8%E4%BE%8B%E5%88%86%E6%9E%90/2859078?fr=aladdin
問題域的拆分
大家應(yīng)該發(fā)現(xiàn)上面的知識(shí)消化的流程是一個(gè)非常耗時(shí)和復(fù)雜耗腦力的過程, 涉及到產(chǎn)品,業(yè)務(wù),技術(shù)等多方團(tuán)隊(duì), 所以為了讓有限的資源投入到最最核心的子域,我們需要對(duì)問題域進(jìn)行這份,把重點(diǎn)的精力放到最核心的領(lǐng)域上。核心領(lǐng)域一定是業(yè)務(wù)價(jià)值最高的,而非技術(shù)難度最高或者是基礎(chǔ)設(shè)施框架部分。?要切分問題域,首先需要了解問題域的種類:
1 通用域: 非應(yīng)用獨(dú)有的,多個(gè)應(yīng)用都會(huì)有的功能。例如發(fā)送郵件,觸達(dá)等
2 核心域:和競(jìng)爭(zhēng)對(duì)手區(qū)別開來的區(qū)域,或者是在市場(chǎng)上被賦予了競(jìng)爭(zhēng)優(yōu)勢(shì)的區(qū)域。
3 支撐子域:其余的區(qū)域如何確定核心域,這里有幾個(gè)提示:
系統(tǒng)哪部分最難用
手動(dòng)處理過程阻止了他們進(jìn)行了根據(jù)創(chuàng)造性, 有附加值的工作
哪些修改能提高收益
哪些修改能提高運(yùn)營(yíng)效率
取哪些提示,取決于業(yè)務(wù)系統(tǒng)的性質(zhì)。
那如何決定支撐子域/通用子域,以及支撐子域/通用子域的切分呢?目前在我查閱的資料中,還暫時(shí)沒有人提及到具體的操作方法,感覺主要還是依靠經(jīng)驗(yàn)主義在做劃分。我個(gè)人總結(jié)了一個(gè)方法,主要就是就是關(guān)注業(yè)務(wù)的核心實(shí)體和核心流程。以核心實(shí)體和核心流程作為切分支撐子域的基礎(chǔ)。核心實(shí)體:核心實(shí)體是存在于核心流程中,對(duì)核心流程的決策和扭轉(zhuǎn)可能起到關(guān)鍵的作用。有的時(shí)候業(yè)務(wù)上為了能讓核心實(shí)體在業(yè)務(wù)流程中起到更大或者更高效的作用,會(huì)添加一些讓核心實(shí)體更好服務(wù)于業(yè)務(wù)流程一些業(yè)務(wù)功能,從而使業(yè)務(wù)實(shí)體從整體上看變得相對(duì)復(fù)雜,這個(gè)時(shí)候我們應(yīng)該以核心實(shí)體為基礎(chǔ)進(jìn)行切割,把所有和核心實(shí)體CRUD相關(guān)的操作還有讓其變得更高效的業(yè)務(wù)功能劃分為單獨(dú)的一個(gè)領(lǐng)域。核心流程:?當(dāng)某個(gè)業(yè)務(wù)流程足夠復(fù)雜也可以當(dāng)成一個(gè)子域。在實(shí)現(xiàn)領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)【4】書中,提到了為在線拍賣網(wǎng)站系統(tǒng)劃分問題域的一個(gè)例子,我們以此來驗(yàn)證上面等構(gòu)想

劃分子域

賣家 + 會(huì)員身份:這兩者都是核心實(shí)體,網(wǎng)站可能為了讓促進(jìn)會(huì)員能夠多參與拍賣可能提供了分層,或者積分等工功能。網(wǎng)站為了能讓賣家能夠更加提供更加有拍賣價(jià)值或者是轉(zhuǎn)化率高的品類可能為賣家提供了數(shù)據(jù)分析等業(yè)務(wù)功能。?
名冊(cè):這也就是核心實(shí)體,網(wǎng)站會(huì)對(duì)名冊(cè)提供一系列拍賣相關(guān)的功能,例如倒計(jì)時(shí),一口價(jià)等,所以也需要形成一個(gè)領(lǐng)域。?
拍賣:網(wǎng)站最核心的業(yè)務(wù)流程,核心域無疑。
爭(zhēng)議解決:買賣家的售后沖突解決流程向來很復(fù)雜,所以會(huì)獨(dú)立成為一個(gè)域無疑。
四、復(fù)雜度處理-進(jìn)一步降低問題域的復(fù)雜度-限界上下文
限界上下文的誕生背景
一般情況下,一個(gè)復(fù)雜系統(tǒng)由一系列的模型來表示解答域, 理想狀態(tài)是一個(gè)子域一個(gè)模型。但是有些當(dāng)業(yè)務(wù)需要且系統(tǒng)復(fù)雜的時(shí)候,一個(gè)模型可能被多個(gè)域共享,這個(gè)時(shí)候這個(gè)模型的概念可能變得不清楚。因此為了保護(hù)這些模型概念的完整性, 清晰的定義模型的責(zé)任邊界很重要。實(shí)現(xiàn)領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)【4】書中舉了下面這個(gè)例子:

為了維護(hù)模型的概念的完整性,最直觀的方法就是為這個(gè)模型化一個(gè)邊界,e.g. 這個(gè)商品所表現(xiàn)的意思就是履約的時(shí)候用到的"商品",而不是下單的時(shí)候的"商品"。只要有一個(gè)這樣的邊界定義,系統(tǒng)就會(huì)但是出現(xiàn)多個(gè)邊界,畢竟"商品"在不同業(yè)務(wù)上下文中有不同的含義, 例如庫(kù)存域的貨品,物流域的運(yùn)輸品, 價(jià)格域的商品等等。這樣的一個(gè)邊界就是DDD的“限界上下文”。?
限界上下文給人直觀的感受其實(shí)和子域很像,我很早以前曾讀過一些關(guān)于微服務(wù)的書籍,也提到過要把DDD中的限界上下文作為微服務(wù)劃分的重要依據(jù)。這里其實(shí)就給我很大的疑惑:
1 限界上下文到底是怎么劃分的?我們劃分限界上下文難道真的是用一個(gè)基礎(chǔ)概念,然后找這個(gè)基礎(chǔ)概念不同的“上下文”嗎?
2 限界上下文和子域到底區(qū)別是啥?
限界上下文的本質(zhì)
DDD理論中提到了DDD的四個(gè)邊界?

所以在DDD中是把限界上下文作為某個(gè)子域的內(nèi)部模塊的劃分,其實(shí)無論是子域的劃分,限界上下文的識(shí)別,和聚合的劃分他們的本質(zhì)是一樣的,他們都是對(duì)復(fù)雜問題的分解之后,然后歸類分組。只不過“聚合”面向的是領(lǐng)域?qū)觾?nèi)部,“領(lǐng)域”劃分面向的是業(yè)務(wù)問題域,而“限界上下文”面向的是解答域,但是我跟傾向于把限界上下文理解為更加深一層次的業(yè)務(wù)問題域的劃分,而不是面向的解答域。?如果這樣看的話,那么其實(shí)就可以回答上面的疑問, 領(lǐng)域和限界上下文沒有本質(zhì)的區(qū)別,就像樹的父節(jié)點(diǎn)和字節(jié)點(diǎn)一樣都是樹節(jié)點(diǎn)。而限界上下文的劃分完全可以使用子域劃分的理論。(可以回顧下上面問題域拆分的段落)
上下文映射
上下文的映射是什么, 簡(jiǎn)單來說就是描述不同上下文之間的關(guān)系的描述。舉個(gè)例子

DDD對(duì)于限界上下文直接提煉了幾種方式,這里這邊阿里內(nèi)部文章《領(lǐng)域驅(qū)動(dòng)設(shè)計(jì):軟件復(fù)雜性應(yīng)對(duì)之道》解釋的比較好,描述如下:
shared kernel
共享內(nèi)核 shared kernel :通常是共享核心領(lǐng)域或者是一組通用子領(lǐng)域。

customer/supplier
客戶/供應(yīng)商關(guān)系 customer/supplier:上下游關(guān)系。不同客戶需要協(xié)商來平衡,上游團(tuán)隊(duì)需要有自動(dòng)測(cè)試套件。

conformist
跟隨者模式 conformist:?jiǎn)畏矫娓S模式。上游的設(shè)計(jì)質(zhì)量較好,容易兼容,可以采用嚴(yán)格遵循上游團(tuán)隊(duì)的模型。

anticorruption layer
防腐層 anticorruption layer:防腐層、隔離層,使用 facade or adapter 等模式。可以減少其它系統(tǒng)變動(dòng)對(duì)本系統(tǒng)的影響。

separate way
各行其道 separate way:聲明一個(gè)與其它上下文毫無關(guān)聯(lián)的 bounded context,使開發(fā)人員能夠在這個(gè)小范圍內(nèi)找到簡(jiǎn)單、專用的解決方案。

open host service
開放主機(jī)服務(wù) open host service:開放子系統(tǒng)供其他系統(tǒng)訪問。其核心思想是開放出一個(gè)標(biāo)準(zhǔn)的各個(gè)領(lǐng)域都認(rèn)可的協(xié)議,減輕各個(gè)領(lǐng)域?qū)嵤〢CL的負(fù)擔(dān)和成本。

published language
共享語言 published language:把一個(gè)良好文檔化、能夠表達(dá)領(lǐng)域信息的共享語言作為公共的通信媒介,必要時(shí)在其它信息與該語言之間進(jìn)行轉(zhuǎn)換。
在當(dāng)前電商領(lǐng)域的范疇,目前我個(gè)人覺得只有ACL,Seperate Way, publish language 有比較好可行性,其他的關(guān)系都不是很靠譜:
shared kernel:如果使用共享二方庫(kù),誰來維護(hù)這個(gè)二方庫(kù),如何防止在不同上下文使用不同kernal版本所帶來的問題。?
如果一定能保證shared kernel的維護(hù)在一個(gè)團(tuán)隊(duì)內(nèi),且所有使用shared kernel版本一定能保持一致, 那是可以使用的。?
customer/supplier:我曾經(jīng)因?yàn)閰R率包升級(jí)而去重構(gòu)一個(gè)應(yīng)用,因?yàn)閰R率包變更太大,且應(yīng)用沒有防腐層,所以不論從開發(fā)還是測(cè)試都是非常痛苦的過程。
conformist:和customer/supplier類似, 但是在互聯(lián)網(wǎng)領(lǐng)域沒有靠譜的設(shè)計(jì), 只有有人維護(hù)和沒有人維護(hù)的設(shè)計(jì)。conformist從長(zhǎng)期來看其實(shí)就是customer/supplier。
Open Host Service 沒有任何一個(gè)領(lǐng)域保證自己的接口一定不會(huì)變,就算不會(huì),其他領(lǐng)域的同學(xué)會(huì)相信嗎,他們會(huì)忍住不用ACL嗎?如果他們用ACL,OHS的意義何在?
publish language 目前阿里內(nèi)部MTOP,TOP等協(xié)議正是使用這樣的協(xié)議。
另外限界上下文之間真的能夠隨便無規(guī)則無條件的互相依賴,互相調(diào)用嗎?在下面的章節(jié)將會(huì)解釋論述。
五、復(fù)雜度處理 - 分層不合理
架構(gòu)分層主要的作用就是關(guān)注點(diǎn)隔離,如果和今天的話題聯(lián)系起來就是領(lǐng)域模型和技術(shù)的關(guān)注點(diǎn)隔離(領(lǐng)域和存儲(chǔ),領(lǐng)域和展示)。
傳統(tǒng)的三層架構(gòu)

這種傳統(tǒng)架構(gòu)的缺點(diǎn)1、業(yè)務(wù)邏輯層和數(shù)據(jù)訪問層有明顯的耦合。?2、沒有領(lǐng)域的概念,所有的邏輯沉淀到service中。所以傳統(tǒng)架構(gòu)只能針對(duì)小型的,沒有過多的業(yè)務(wù)邏輯場(chǎng)景。由于這種架構(gòu)能夠保有領(lǐng)域能力的沉淀,所以在現(xiàn)在電商業(yè)務(wù)場(chǎng)景基本不會(huì)被使用。
六邊形架構(gòu)
Alistair?Cockburn在 2005 年時(shí)演示了?六邊形架構(gòu)


從六邊形架構(gòu)開始,其強(qiáng)調(diào)了領(lǐng)域模型。并且確立了領(lǐng)域模型的核心位置,以及其不應(yīng)該依賴于其他的層次。六邊形架構(gòu)也強(qiáng)化了適配器的概念,其還把適配器分類為input適配器,和output適配器。所有input適配器用于對(duì)接不用的外部請(qǐng)求形式, 所有output適配器用于對(duì)外部的依賴 (e.g. 數(shù)據(jù)庫(kù), 外部服務(wù),內(nèi)存調(diào)用等)這種結(jié)構(gòu)模式樹立了以領(lǐng)域模型為核心的先河,但是其忽略了在領(lǐng)域?qū)又锌缒P蜆I(yè)務(wù)邏輯的實(shí)現(xiàn)方式-領(lǐng)域服務(wù)的沉淀。這也間接導(dǎo)致了其需要強(qiáng)化應(yīng)用層,并且通過應(yīng)用層和output適配器的聯(lián)合去完成一些可以應(yīng)該在領(lǐng)域?qū)討?yīng)該完成的事情。?
洋蔥架構(gòu)

洋蔥架構(gòu)的提出更加進(jìn)化了一步,推出了域服務(wù)層,并且支持域服務(wù)層是支持了那些需要多個(gè)領(lǐng)域?qū)嶓w聯(lián)合中作用的領(lǐng)域邏輯. 其層次由外向內(nèi)依次是領(lǐng)域模型,領(lǐng)域服務(wù),應(yīng)用服務(wù)和外層的基礎(chǔ)設(shè)施和用戶終端。其依賴的關(guān)系也只能是由外向內(nèi). 在洋蔥結(jié)構(gòu)中其把存儲(chǔ)層,文件系統(tǒng)和網(wǎng)絡(luò)服務(wù)放到了基礎(chǔ)設(shè)施層。由于基礎(chǔ)設(shè)施和用戶終端一樣在最外層,所以洋蔥架構(gòu)也提倡用依賴倒置來解決應(yīng)用邏輯和基礎(chǔ)設(shè)施的耦合問題。洋蔥架構(gòu)的架構(gòu)圖從其依賴順序上來看,其依賴應(yīng)用層必須先依賴域服務(wù)層,再依賴域模型層, 這樣很容易造成領(lǐng)域模型的邏輯外泄到領(lǐng)域服務(wù)層,造成領(lǐng)域模型變成貧血模型。
DDD 架構(gòu)

DDD的架構(gòu)大家都非常熟悉了,領(lǐng)域服務(wù)和領(lǐng)域模型都?xì)w屬域領(lǐng)域?qū)?。適配層依賴域應(yīng)用層,應(yīng)用層依賴域領(lǐng)域?qū)?,也可以直接直接調(diào)用基礎(chǔ)設(shè)施層(大多數(shù)是查詢場(chǎng)景)。領(lǐng)域?qū)永碚撋喜灰蕾囉谌魏螌哟危渫ㄟ^依賴倒置和基礎(chǔ)設(shè)施層產(chǎn)生關(guān)聯(lián)。在DDD架構(gòu)中,應(yīng)用層是可以通過直接訪問聚合根(某個(gè)實(shí)體類),并進(jìn)行方法的執(zhí)行和操作的。應(yīng)用層也可以直接訪問基礎(chǔ)設(shè)施層。可以看出DDD的架構(gòu)其實(shí)更加的貼切實(shí)際一些。?

上面這張圖也很好的闡述了DDD各個(gè)架構(gòu)層次依賴的關(guān)系。
CQRS
很多情況產(chǎn)品構(gòu)建出來的數(shù)據(jù)展示,需要橫跨幾個(gè)領(lǐng)域的數(shù)據(jù)的支撐,也就是我們?nèi)粘?gòu)建的大寬表,在這種情況使用CQRS模式可以完美解決這個(gè)問題。其主導(dǎo)視圖模型和領(lǐng)域模型分開,讓領(lǐng)域模型更加專注業(yè)務(wù)邏輯,流程和規(guī)則而非業(yè)務(wù)視圖。?

CQRS的思想很簡(jiǎn)單,就是把服務(wù)中對(duì)數(shù)據(jù)的更新操作(Command)和讀取操作(Query)分離, 一部分邏輯只處理和數(shù)據(jù)更新有關(guān)的業(yè)務(wù),另外一部分只處理和數(shù)據(jù)讀取有關(guān)的邏輯。這種處理方式,可以讓我們辛苦構(gòu)建的領(lǐng)域模型不被業(yè)務(wù)中所需要的這類視圖需求所干擾。?CQRS 的兩種實(shí)現(xiàn)方式基于event- sourcing

不基于event - sourcing

以上的圖片摘自于文章《CQRS模式及其應(yīng)用》
我們團(tuán)隊(duì)里面的架構(gòu)實(shí)踐
在我們自己的應(yīng)用中我們構(gòu)建了基于COLA【5】規(guī)范的層次架構(gòu),如下圖:?

我們也對(duì)自己的架構(gòu)定義的一些額外的規(guī)范:
1、依賴關(guān)系(除了依賴倒置)只能是從上當(dāng)下;
2、同層之間永遠(yuǎn)不能互相依賴;
3、如果同層之間需要互相用到對(duì)方的服務(wù),那么就需要下沉出一層。例如在上圖中,我們的業(yè)務(wù)層就分為了兩層 "Executor"層次和 “Handler”層此, Handler層次用來保存業(yè)務(wù)的一些通用邏輯。
六、復(fù)雜度 -?軟件變成一個(gè)大泥潭
從這一章節(jié)開始介紹DDD的"戰(zhàn)術(shù)模式",也就是向大家介紹DDD是如何構(gòu)建和組織自己領(lǐng)域?qū)拥摹V档靡惶岬氖窃贒DD中,領(lǐng)域的劃分, 領(lǐng)域?qū)哟蔚慕? 領(lǐng)域之間關(guān)系的建立我們一般叫做DDD的"戰(zhàn)略模式",而此章節(jié)提到的值對(duì)象,實(shí)體,域服務(wù),工廠,repository, 聚合/聚合根, 領(lǐng)域事件等都是DDD的戰(zhàn)術(shù)模式。戰(zhàn)略模式的重要性是要遠(yuǎn)大于DDD的戰(zhàn)術(shù)模式的,我們?nèi)绻陬I(lǐng)域劃分,領(lǐng)域通信協(xié)議,分層方面沒有大的問題, 那么即使再糟糕系統(tǒng)整體也還是可控的。?在領(lǐng)域?qū)用妫?DDD通過聚合/聚合根的概念來劃分單個(gè)領(lǐng)域中的類似于類集合的邊界,從而降低單個(gè)領(lǐng)域?qū)拥膹?fù)雜度。DDD通過實(shí)體,值對(duì)象,領(lǐng)域服務(wù),repository, factory 來規(guī)劃集合內(nèi)部的類組織, 另外DDD也通過領(lǐng)域事件來處理領(lǐng)域之間的交互,來匹配異步和需要解耦的業(yè)務(wù)場(chǎng)景。
實(shí)體
當(dāng)我們需要考慮一個(gè)對(duì)象的個(gè)性特征,獲取需要區(qū)分對(duì)象的時(shí)候,就需要引入實(shí)體。一般我們發(fā)現(xiàn)實(shí)體概念,是在和業(yè)務(wù)產(chǎn)品人員或者領(lǐng)域?qū)<矣懻摪l(fā)現(xiàn)的那些需要有唯一標(biāo)示性或者生命周期連續(xù)性很重要的時(shí)候。舉個(gè)例子加入用戶需要預(yù)定酒店,如果領(lǐng)域?qū)<艺f了我們定了A酒店了,就不能定B酒店了,哪怕A,B其他的屬性完全一樣。從領(lǐng)域?qū)<铱壑形覀兛梢宰R(shí)別出酒店是有唯一標(biāo)示性的,且哪怕A,B屬性一樣,也不能認(rèn)為A,B 是一樣的,這也說明了酒店的唯一性不是從屬性來的。這兩點(diǎn)我們可以推斷酒店是一個(gè)實(shí)體。唯一標(biāo)示性可以是現(xiàn)實(shí)有意義的,例如工商注冊(cè)號(hào),也可以無現(xiàn)實(shí)意義,例如數(shù)據(jù)庫(kù)主鍵。?
實(shí)體建模的注意點(diǎn)
1、為實(shí)體分配唯一標(biāo)識(shí)符
現(xiàn)實(shí)意義標(biāo)識(shí)符
人工生成的標(biāo)識(shí)
自增
guid/uuid/
數(shù)據(jù)庫(kù)主鍵
自定義sequence
2、驗(yàn)證和不變行
實(shí)體必須自己負(fù)責(zé)自己保持自己狀態(tài)的合法性 (validation) 和不變性(Invariants)。他們的區(qū)別是合法性是根據(jù)上下文的,而不變性是不用考慮上下文且必須正確的。例如酒店必須有房間這個(gè)就是不變性,而酒店的營(yíng)業(yè)時(shí)間就是validation. 一般使用規(guī)則和規(guī)約模式來實(shí)現(xiàn)validation和invariants。
規(guī)模模式:?
https://baijiahao.baidu.com/s?id=1717403406288752234&wfr=spider&for=pc3、聚焦在行為,而不是屬性狀態(tài)不要暴露屬性給外面,如果外面得到屬性,很可能就自己實(shí)現(xiàn)了一些領(lǐng)域邏輯,那么領(lǐng)域邏輯就外漏了。?4、把一些行為邏輯下方到值對(duì)象中需要警惕實(shí)體邏輯膨脹,從而混繞了實(shí)體所要表達(dá)的概念。?例如預(yù)定是一個(gè)實(shí)體, 現(xiàn)在要加上邏輯預(yù)定的天數(shù)不能小于N天。這個(gè)時(shí)候我們可以為Booking 抽象出 Stay 對(duì)象,讓Stay對(duì)象去管理規(guī)則邏輯。而不是讓預(yù)定這個(gè)實(shí)體去做。讓預(yù)定只關(guān)注預(yù)定。?5、不要為世界建模不要過度設(shè)計(jì),只要滿足需求就好。不要讓技術(shù)需求污染領(lǐng)域設(shè)計(jì),除非真的萬不得已。6、分布式的設(shè)計(jì)不需要讓領(lǐng)域概念橫跨多個(gè)bounded context, 如果我們域模型所涉及的概念橫跨了,我們就需要用兩種設(shè)計(jì)方法.
只是用id引用
value objects
值對(duì)象
什么時(shí)候需要使用到值對(duì)象?
概念需要凸顯的時(shí)候。?
e.g. 拍賣系統(tǒng)的能夠一口價(jià)獲取拍賣的價(jià)格, 就算是我們用一個(gè)int 就能表示也需要用類來凸顯概念
public class WinningBid
{...public int Price { get; private set; }...}
表述一個(gè)描述性的,但是沒有實(shí)體編號(hào)的概念的時(shí)候。?
值對(duì)象的特征
無標(biāo)識(shí):他們只是標(biāo)識(shí)對(duì)象的屬性。
基于屬性的相等性: 所有的屬性值相等即值對(duì)象相等
富含行為:值對(duì)象實(shí)現(xiàn)業(yè)務(wù)概念的抽象,其也有自己的行為
內(nèi)聚:將不同的相關(guān)屬性組成一個(gè)概念整體,例如Money, 是由一個(gè)long 和一個(gè)currency組成的
不變性:值對(duì)象是不變的對(duì)象,如果需要改變屬性,那最好是建立一個(gè)新的對(duì)象并且進(jìn)行值對(duì)象替換。如果一定是需要改變,那就需要考慮設(shè)置為值對(duì)象是否合理。
不變性是值對(duì)象非常重要的一個(gè)屬性,是可以保障值對(duì)象不會(huì)被"壞味道"代碼侵入的一個(gè)原則之一。?例如如果一個(gè)值對(duì)象引入了另外一個(gè)類實(shí)例, 另外一個(gè)值對(duì)象也引入了相同的類實(shí)例, 如果值對(duì)象允許改動(dòng),當(dāng)一個(gè)值對(duì)象對(duì)這個(gè)類實(shí)例的內(nèi)容進(jìn)行修改,勢(shì)必會(huì)影響另外一個(gè)值對(duì)象。?所以最安全的方式還是通過對(duì)象替換的方式。
域服務(wù)?
什么時(shí)候用域服務(wù)
發(fā)現(xiàn)和多個(gè)實(shí)體相關(guān)聯(lián),但是放入任何一個(gè)單獨(dú)的實(shí)體都不適合,這個(gè)適合用域服務(wù).
域服務(wù)應(yīng)該包含什么內(nèi)容
域服務(wù)應(yīng)該包含業(yè)務(wù)/系統(tǒng)流程和業(yè)務(wù)規(guī)則,不應(yīng)該包含技術(shù)的元素在內(nèi),技術(shù)的元素都應(yīng)該在業(yè)務(wù)服務(wù)(Application Service)中實(shí)現(xiàn)。
應(yīng)用服務(wù)與領(lǐng)域服務(wù)的區(qū)別:
一些可以在網(wǎng)上搜索到的老生常談:
應(yīng)用服務(wù)里不要處理業(yè)務(wù)邏輯,只在領(lǐng)域服務(wù)里處理業(yè)務(wù)邏輯。(如何判斷某段邏輯是否是業(yè)務(wù)邏輯?)
領(lǐng)域服務(wù)掌握領(lǐng)域知識(shí),而應(yīng)用服務(wù)只是對(duì)領(lǐng)域服務(wù)的編排。
應(yīng)用服務(wù)是領(lǐng)域服務(wù)的客戶方,也就是說應(yīng)用服務(wù)會(huì)調(diào)用領(lǐng)域服務(wù)里的方法。
當(dāng)領(lǐng)域中的某個(gè)操作過程不屬于實(shí)體或者值對(duì)象的職責(zé)時(shí),需要將個(gè)操作放在領(lǐng)域服務(wù)中。而且確保領(lǐng)域服務(wù)是無狀態(tài)的(這句話很有意思,也就是說領(lǐng)域服務(wù)中不應(yīng)該有任何記錄狀態(tài)的行為,在任何情況下調(diào)用這個(gè)服務(wù),它都不會(huì)有副作用,也就是說它是個(gè)純內(nèi)存操作)。
領(lǐng)域服務(wù)中包含的是業(yè)務(wù)邏輯,而應(yīng)用服務(wù)關(guān)注的應(yīng)該是安全和事務(wù)等非業(yè)務(wù)邏輯。
對(duì)事務(wù)的管理絕對(duì)不能放在領(lǐng)域服務(wù)層,事務(wù)管理需要放在應(yīng)用服務(wù)層。因?yàn)楹皖I(lǐng)域模型相關(guān)的操作的粒度都很細(xì),無法用于事務(wù)管理。而且領(lǐng)域模型也不應(yīng)該意識(shí)到事務(wù)的存在。
通常的可以放在應(yīng)用服務(wù)中的邏輯有:參數(shù)驗(yàn)證、錯(cuò)誤處理、監(jiān)控日志、事務(wù)處理、認(rèn)證與授權(quán)。
除了第一條之外,上面的條例只是舉出了應(yīng)用服務(wù)與領(lǐng)域服務(wù)兩者非常易于告之的差別,但是會(huì)有一些“業(yè)務(wù)邏輯”比較難以取舍, 例如
例如轉(zhuǎn)賬操作:
A ->B
A.accountDecrease(10);
B.accountIncrease(10);我們?cè)诂F(xiàn)在可以非??隙ǖ恼f上面的轉(zhuǎn)賬一定在領(lǐng)域服務(wù),因?yàn)?#34;轉(zhuǎn)賬"就是一個(gè)領(lǐng)域概念。但是如果假設(shè)世面上所有的銀行以前只有存錢和取錢兩種功能,"轉(zhuǎn)賬"是一個(gè)新概念和業(yè)務(wù)的時(shí)候,技術(shù)就沒有那么容易判別轉(zhuǎn)賬是一個(gè)臨時(shí)性的一次性的需求,還是會(huì)長(zhǎng)久發(fā)展。這個(gè)時(shí)候技術(shù)有兩個(gè)選擇:1、構(gòu)建轉(zhuǎn)賬域服務(wù),讓應(yīng)用服務(wù)調(diào)用域服務(wù)2、讓應(yīng)用服務(wù)獲取A,B的實(shí)體,然后在應(yīng)用層直接調(diào)用方法,在應(yīng)用層做事務(wù)保持一致性。如果域能力在其他團(tuán)隊(duì)手里,我相信大多數(shù)的團(tuán)隊(duì)會(huì)使用第二種。那遇到這種情況我們到底應(yīng)該怎么辦?我個(gè)人的意見和阿里前技術(shù)高級(jí)專家張建飛在他的文章《一文教會(huì)你如何寫復(fù)雜業(yè)務(wù)代碼》的觀點(diǎn)保持一致:

我們?cè)谛逻壿嫵霈F(xiàn)難以判斷的時(shí)候優(yōu)先講能力放入到app層,如果我們發(fā)現(xiàn)會(huì)有第二個(gè)業(yè)務(wù)場(chǎng)景使用到了相同的能力,就需要考慮是否應(yīng)該把此能力下發(fā)到領(lǐng)域?qū)右栽鰪?qiáng)內(nèi)聚性和復(fù)用性。
工廠
只負(fù)責(zé)復(fù)雜邏輯對(duì)象的構(gòu)建,讓構(gòu)建邏輯中心化
減少外部對(duì)象對(duì)構(gòu)建對(duì)象內(nèi)部變量的理解
工廠方式不是在任何構(gòu)建對(duì)象的時(shí)候使用,一定用在對(duì)象構(gòu)建邏輯復(fù)雜,有子依賴或者是有invariant規(guī)則的場(chǎng)景。?
Repository
reponsitory主要用來處理集合根的存儲(chǔ)和獲取的。提供一個(gè)facade接口且是面向domain層的,是domain model和data model的橋梁。其最大的作用就是通過反向依賴的方式充分隔離數(shù)據(jù)層和領(lǐng)域?qū)印epository最常見的用法是被applicaiton service層去使用獲取聚合根。在repository實(shí)現(xiàn)中,我們一般會(huì)有下面的一些邏輯:
uniqe ID 的生成
數(shù)據(jù)庫(kù)的操作
數(shù)據(jù)模型到領(lǐng)域模型的相互
橫跨多個(gè)數(shù)據(jù)模型構(gòu)建出一個(gè)實(shí)體模型。
repository的反模式
定義出比較通用化的接口, e.g.
List<Customer> findBy(CusomterQuery query)
使用了延遲加載,延遲加載就是設(shè)計(jì)錯(cuò)誤的標(biāo)志, 有可能說明我們聚合的邊界不催。?
不要為了報(bào)表的訴求使用reponsitory, 領(lǐng)域的case和業(yè)務(wù)報(bào)告很不一樣,可能需要多個(gè)聚合的數(shù)據(jù),這種情況可以考慮用一個(gè)離線的store去做,和其他的讀服務(wù)去做,不見得一定需要用領(lǐng)域的Repository模式。
領(lǐng)域事件
領(lǐng)域事件所想要解決的問題其實(shí)和metaQ消息機(jī)制想要解決的問題一致,都是跨領(lǐng)域驅(qū)動(dòng)型業(yè)務(wù)邏輯實(shí)現(xiàn)的最佳方法,讓領(lǐng)域和領(lǐng)域之前解耦。領(lǐng)域事件消費(fèi)教科書的說法是可以在領(lǐng)域?qū)樱?也可以在應(yīng)用服務(wù)層, 但是我覺得領(lǐng)域消息如果用metaQ是這樣的消息中間件去實(shí)現(xiàn)的話,那用領(lǐng)域?qū)雍蛻?yīng)用服務(wù)層去消費(fèi)就不是很方便,有可能破壞一些分層原則。所以我個(gè)人傾向于在adapter層去承接消費(fèi),統(tǒng)一化掉。當(dāng)前可以實(shí)現(xiàn)領(lǐng)域事件和消費(fèi)比較方便的工具有:
google guava - EventBus
COLA框架 - 事件支持
聚合/聚合根
聚合是什么?
其實(shí)聚合的原理和領(lǐng)域劃分,限界上下文劃分的原理是一致的,都是為了通過歸類分組的方式讓整個(gè)系統(tǒng)宏觀上 N * N 的關(guān)系復(fù)雜度減低為 T * T 的復(fù)雜度。?T遠(yuǎn)小于N。?聚合前:?

聚合后

如何劃分聚合
1、根據(jù)業(yè)務(wù)規(guī)則和不變量來決定。例如 customer 聚合是有一套業(yè)務(wù)規(guī)則來維持的,例如信用卡要存在,必須先有一個(gè)customer, 有customer 必須有address, address必須有code.2、強(qiáng)關(guān)聯(lián)的對(duì)象應(yīng)該放在一塊。什么是強(qiáng)關(guān)聯(lián),那就是必須生命周期是一樣的。例如customer和creditcard在,電商網(wǎng)站中,如果customer被刪除了,那么他的信用卡也應(yīng)該被設(shè)置為失效的。而訂單和客戶不一樣,客戶下了個(gè)訂單,然后客戶注銷,但是訂單還是一直存在的。所以customer 和 creditcard 在一個(gè)聚合中, 而用戶和訂單則不在。訂單里面可以有客戶的ID或者是一個(gè)值對(duì)象。?3、靈活設(shè)置:有些可以根據(jù)業(yè)務(wù)情況,進(jìn)行可以靈活的設(shè)置,下面列舉一個(gè)論壇系統(tǒng),帖子和回復(fù)聚合思考的例子:大家都知道一個(gè)帖子有多個(gè)回復(fù),沒有帖子,回復(fù)就沒有意義;所以很多人就會(huì)認(rèn)為帖子應(yīng)該聚合回復(fù);但實(shí)際上不需要這樣,如果你這樣做了,那對(duì)于一個(gè)論壇來說,同一個(gè)帖子被多個(gè)人同時(shí)回復(fù)的可能性是非常高的,那這樣的話,多個(gè)人同時(shí)回復(fù)一個(gè)帖子,就會(huì)導(dǎo)致多個(gè)人同時(shí)修改同一個(gè)帖子對(duì)象,那就導(dǎo)致大家都回復(fù)不了,因?yàn)闀?huì)有并發(fā)沖突或者數(shù)據(jù)庫(kù)事務(wù)的等待超時(shí),因?yàn)榇蠹叶荚谛薷耐粋€(gè)帖子聚合根;實(shí)際上如果我們從業(yè)務(wù)規(guī)則的角度去思考一下,那可以發(fā)現(xiàn),其實(shí)帖子和回復(fù)之間,只有一個(gè)簡(jiǎn)單的規(guī)則,那就是回復(fù)一旦被創(chuàng)建,那他所對(duì)應(yīng)的帖子不能被修改即可;這樣的話,要實(shí)現(xiàn)這個(gè)規(guī)則其實(shí)很簡(jiǎn)單,把回復(fù)作為聚合根,然后把帖子傳入回復(fù)聚合根的構(gòu)造函數(shù),然后回復(fù)保存帖子ID,然后回復(fù)將帖子ID設(shè)置為不允許外部修改(private set;即可),這樣我們就實(shí)現(xiàn)了這個(gè)業(yè)務(wù)規(guī)則,同時(shí)還做到了多人同時(shí)推一個(gè)帖子回復(fù)時(shí),不會(huì)對(duì)同一個(gè)帖子對(duì)象就并發(fā)修改,而是每個(gè)回復(fù)都是并行的往數(shù)據(jù)庫(kù)插入一條回復(fù)記錄即可。-- 摘自阿里內(nèi)部文檔<<關(guān)于DDD領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)中聚合設(shè)計(jì)的一些思考>>
聚合設(shè)計(jì)的原則
聚合是用來封裝真正的不變性,而不是簡(jiǎn)單的將對(duì)象組合在一起;
聚合應(yīng)盡量設(shè)計(jì)的?。?/p>
聚合之間的關(guān)聯(lián)通過ID,而不是對(duì)象引用;
聚合內(nèi)強(qiáng)一致性,聚合之間最終一致性;
什么是聚合根
聚合根就是聚合的入口,聚合外部只能通過聚合根和聚合內(nèi)部通信。由于聚合外部只能通過聚合根和聚合內(nèi)部通信, 這也就意味著外部不能操作除聚合根以外的任何類進(jìn)行數(shù)據(jù)庫(kù)操作,因?yàn)檫@樣有可能會(huì)導(dǎo)致破壞業(yè)務(wù)的規(guī)則。舉個(gè)例子,一個(gè)汽車四個(gè)輪子,如果我們用 Repo 直接操作輪子,對(duì)輪子采取delete,而這個(gè)時(shí)候汽車對(duì)象的狀態(tài)卻可能是 "running".
如何選出聚合根
1、聚合根一定至少有一個(gè)對(duì)應(yīng)的datastore?
2、聚合根一定更夠完全描述一組后者多組業(yè)務(wù)規(guī)則(invariant)。絕對(duì)不會(huì)存在一個(gè)業(yè)務(wù)規(guī)則需要多個(gè)聚合根聯(lián)合作用才能做判斷的。
3、聚合根一定有自己的獨(dú)立的生命周期。?
七、規(guī)范設(shè)計(jì)
項(xiàng)目/應(yīng)用的規(guī)范設(shè)計(jì)的長(zhǎng)期價(jià)值一定是不可忽視的,規(guī)范就相當(dāng)于一個(gè)架構(gòu)內(nèi)部組件的收納的容器,架構(gòu)指定了這些組件在邏輯上的組織形式,但而規(guī)范則是則是妥妥的物理組織形式。如果沒有合理清晰的規(guī)范設(shè)計(jì),項(xiàng)目很快就會(huì)因?yàn)閭€(gè)人開發(fā)習(xí)慣的不同,導(dǎo)致物理結(jié)構(gòu)混亂,給接下來的應(yīng)用/項(xiàng)目的維護(hù)和擴(kuò)展產(chǎn)生影響。規(guī)范設(shè)計(jì)總共分為兩類:
放對(duì)位置
程序架構(gòu)目錄
貼好標(biāo)簽
類名約定
方法名約定
錯(cuò)誤碼約定
Domain Event約定
測(cè)試約定
下面是我們小團(tuán)隊(duì)參考了阿里COLA框架建議的命名規(guī)范做出的開發(fā)規(guī)范:
程序架構(gòu)組織

類命名規(guī)范

錯(cuò)誤碼規(guī)范?

擴(kuò)展規(guī)范
使用COLA的擴(kuò)展框架去實(shí)現(xiàn)。COLA的擴(kuò)展框架的功能不在贅訴,這里討論的是COLA框架的BizScenario的劃分。?
BizScenario
private?String bizId =?"#defaultBizId#";?
private?String useCase =?"#defaultUseCase#";
private?String scenario =?"#defaultScenario#";
bizId: 業(yè)務(wù),對(duì)應(yīng)某個(gè)業(yè)務(wù)訴求, e.g. 新品孵化。
useCase: 業(yè)務(wù)用例, e.g. 策略定義
scenario:用例下的某個(gè)場(chǎng)景。e.g. 定義商家事件任務(wù), 定義小二事件任務(wù)
