使用了DDD(領(lǐng)域驅(qū)動(dòng)設(shè)計(jì))后塔粒,代碼有什么不一樣呢结借?這可能是程序員們?cè)诮佑|DDD后最關(guān)心的一個(gè)問(wèn)題。這個(gè)系列文章會(huì)對(duì)一些優(yōu)秀的DDD實(shí)例代碼進(jìn)行分析窗怒,管中窺豹映跟,略見數(shù)斑。這是第一篇扬虚。
DDD中程序員最關(guān)心的部分
DDD(領(lǐng)域驅(qū)動(dòng)設(shè)計(jì))是一個(gè)復(fù)雜而全面的方法努隙,編碼只是最后一步。

但這是程序員最關(guān)心的部分辜昵,也是被問(wèn)到最多的問(wèn)題荸镊。
所以計(jì)劃寫個(gè)系列文章對(duì)一些優(yōu)秀的DDD實(shí)例代碼進(jìn)行分析,希望能解開一些困惑堪置。
IDDD(《實(shí)現(xiàn)領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)》)躬存,是最常被推薦的一本書。書中有一個(gè)關(guān)于構(gòu)建Scrum管理軟件的例子舀锨,我們先來(lái)分析這個(gè)經(jīng)典的例子的源碼(https://github.com/VaughnVernon/IDDD_Samples)岭洲。
第一篇先從單元測(cè)試和富領(lǐng)域模型說(shuō)起。
我所目睹單元測(cè)試之怪狀
關(guān)于自動(dòng)化的單元測(cè)試坎匿,無(wú)數(shù)人都心懷向往盾剩。
《The Clean Coder》里邊描述的測(cè)試金字塔給出了單元測(cè)試在整個(gè)測(cè)試中的位置雷激。

經(jīng)是好經(jīng),但大部分時(shí)候會(huì)被歪嘴和尚給念歪:
- 我遇到的第一個(gè)例子告私,比較普遍屎暇,開發(fā)人員用JUnit寫單元測(cè)試,每次本地開發(fā)的時(shí)候改一改驻粟,當(dāng)main方法用根悼,在構(gòu)建的時(shí)候都把test case都給skip掉
- 我遇到的第二個(gè)例子,是曾經(jīng)有一個(gè)質(zhì)量效能部門推動(dòng)對(duì)單測(cè)覆蓋率進(jìn)行考核蜀撑。結(jié)果各個(gè)開發(fā)團(tuán)隊(duì)有苦難言挤巡,只有一個(gè)開發(fā)團(tuán)隊(duì)做的比較好,質(zhì)量效能團(tuán)隊(duì)給發(fā)了個(gè)大獎(jiǎng)酷麦,后來(lái)有人發(fā)現(xiàn)這個(gè)團(tuán)隊(duì)的測(cè)試覆蓋率高玄柏,是因?yàn)樗麄儗懥艘粋€(gè)代碼自動(dòng)生成工具,給每個(gè)get/set方法都生成了JUnit測(cè)試……質(zhì)量效能團(tuán)隊(duì)被piapia打臉
- 我遇到的第三個(gè)例子贴铜,是一個(gè) 有追求的團(tuán)隊(duì),他們?cè)跇?gòu)建時(shí)不skip瀑晒,但每次做需求的時(shí)候绍坝,修改單元測(cè)試代碼的時(shí)間甚至?xí)^(guò)了編寫正式代碼的時(shí)間
- 我遇到的第四個(gè)例子,是一個(gè)更有追求的團(tuán)隊(duì)苔悦,他們想學(xué)習(xí)Google轩褐、Facebook搞主干開發(fā)模式,把CI/CD做的特別好玖详,但自動(dòng)化測(cè)試覆蓋率不夠還經(jīng)常跑不通把介,沒(méi)有了自動(dòng)化測(cè)試做保障,主干開發(fā)也不得不作罷
我在《當(dāng)我們?cè)谡務(wù)搯螠y(cè)時(shí)我們?cè)谡務(wù)撌裁础防锓治鲞^(guò)這個(gè)問(wèn)題: “自動(dòng)化單元測(cè)試 = 自動(dòng)化 + 單元 + 測(cè)試”蟋座,本質(zhì)原因是大部分代碼“單元化”程度很低拗踢,所以,這個(gè)前提不具備向臀,是折騰不成功的巢墅。
但DDD的富領(lǐng)域模型有助于達(dá)成這個(gè)前提。
富領(lǐng)域模型為什么有助于單測(cè)
DDD的代碼組織推薦六邊形模型券膀,一個(gè)重點(diǎn)是領(lǐng)域?qū)雍蛻?yīng)用層的分工君纫。

這里有幾個(gè)有助于用低成本(編寫和維護(hù))提升覆蓋測(cè)試率的條件:
- 領(lǐng)域?qū)永锏膶?shí)體對(duì)象不再只是有g(shù)et/set方法,還有很多業(yè)務(wù)邏輯芹彬。
- 領(lǐng)域?qū)嶓w是沒(méi)有任何外部依賴的蓄髓,也就是說(shuō),這些業(yè)務(wù)邏輯都是本地內(nèi)存中就可以執(zhí)行的
- 以聚合組織的領(lǐng)域?qū)嶓w內(nèi)聚性強(qiáng)
- 從圖上也可以看出舒帮,應(yīng)用層比較薄会喝,領(lǐng)域?qū)颖容^厚
我們看看IDDD_Sample這么做了以后陡叠,單元測(cè)試覆蓋率的達(dá)到理想的狀況嗎?
IDDD示例的單測(cè)覆蓋率統(tǒng)計(jì)
首先我們選擇agilepm這個(gè)模塊好乐,看看應(yīng)用層代碼行數(shù)和領(lǐng)域?qū)哟a行數(shù)的對(duì)比匾竿,看看是否符合領(lǐng)域?qū)颖容^厚的這個(gè)前提。

領(lǐng)域?qū)哟a6943行蔚万,而應(yīng)用層只有750行岭妖,領(lǐng)域?qū)哟a占比達(dá)到了90%!7戳А昵慌!這個(gè)比例是不是和我們平時(shí)寫的貧血模型代碼很不一樣?
下面我們看看領(lǐng)域?qū)拥臒o(wú)任何外部依賴的單元測(cè)試(不需要Mock淮蜈,不需要準(zhǔn)備數(shù)據(jù)庫(kù)等)的測(cè)試覆蓋率:

行代碼覆蓋率有70%U省!梧田!我看了一下淳蔼,這其中沒(méi)有被測(cè)試到的,是一些equals裁眯、get/set方法鹉梨。除去這些,應(yīng)該會(huì)達(dá)到90%穿稳,或者繼續(xù)做的100%也并不難存皂。
總結(jié)起來(lái),這個(gè)應(yīng)用的90%的邏輯可以有90%的自動(dòng)化單元測(cè)試覆蓋率 —— 不需要mock逢艘,不需要依賴數(shù)據(jù)庫(kù)旦袋、外部中間件、RPC等它改。
這得益于它使用了富領(lǐng)域模型疤孕,而不是貧血模型,得益于其正確地組織了業(yè)務(wù)邏輯代碼央拖。測(cè)試覆蓋率也從側(cè)面展示了富領(lǐng)域模型到底有多富胰柑。
但是先不要急
我最擔(dān)心的是有人看到這里說(shuō):懂了,我們開始搞富領(lǐng)域模型吧爬泥!
這可能讓你從一個(gè)坑里爬出來(lái)柬讨,接著跳到另外一個(gè)坑里。
自動(dòng)化單測(cè)難以推行袍啡,是因?yàn)椤皢卧边@個(gè)前提不具備踩官。富領(lǐng)域模型可以幫助這個(gè)前提的達(dá)成。
但富領(lǐng)域模型的前提是什么境输?已經(jīng)具備了嗎蔗牡?
且待下回分解颖系。