使用了DDD(領(lǐng)域驅(qū)動設(shè)計)后,代碼有什么不一樣呢?這可能是程序員們在接觸DDD后最關(guān)心的一個問題。這個系列文章會對一些優(yōu)秀的DDD實例代碼進(jìn)行分析,管中窺豹,略見數(shù)斑。這是第一篇。
DDD中程序員最關(guān)心的部分
DDD(領(lǐng)域驅(qū)動設(shè)計)是一個復(fù)雜而全面的方法,編碼只是最后一步。

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

經(jīng)是好經(jīng),但大部分時候會被歪嘴和尚給念歪:
- 我遇到的第一個例子,比較普遍,開發(fā)人員用JUnit寫單元測試,每次本地開發(fā)的時候改一改,當(dāng)main方法用,在構(gòu)建的時候都把test case都給skip掉
- 我遇到的第二個例子,是曾經(jīng)有一個質(zhì)量效能部門推動對單測覆蓋率進(jìn)行考核。結(jié)果各個開發(fā)團(tuán)隊有苦難言,只有一個開發(fā)團(tuán)隊做的比較好,質(zhì)量效能團(tuán)隊給發(fā)了個大獎,后來有人發(fā)現(xiàn)這個團(tuán)隊的測試覆蓋率高,是因為他們寫了一個代碼自動生成工具,給每個get/set方法都生成了JUnit測試……質(zhì)量效能團(tuán)隊被piapia打臉
- 我遇到的第三個例子,是一個 有追求的團(tuán)隊,他們在構(gòu)建時不skip,但每次做需求的時候,修改單元測試代碼的時間甚至?xí)^了編寫正式代碼的時間
- 我遇到的第四個例子,是一個更有追求的團(tuán)隊,他們想學(xué)習(xí)Google、Facebook搞主干開發(fā)模式,把CI/CD做的特別好,但自動化測試覆蓋率不夠還經(jīng)常跑不通,沒有了自動化測試做保障,主干開發(fā)也不得不作罷
我在《當(dāng)我們在談?wù)搯螠y時我們在談?wù)撌裁础防锓治鲞^這個問題: “自動化單元測試 = 自動化 + 單元 + 測試”,本質(zhì)原因是大部分代碼“單元化”程度很低,所以,這個前提不具備,是折騰不成功的。
但DDD的富領(lǐng)域模型有助于達(dá)成這個前提。
富領(lǐng)域模型為什么有助于單測
DDD的代碼組織推薦六邊形模型,一個重點是領(lǐng)域?qū)雍蛻?yīng)用層的分工。

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

領(lǐng)域?qū)哟a6943行,而應(yīng)用層只有750行,領(lǐng)域?qū)哟a占比達(dá)到了90%?。。∵@個比例是不是和我們平時寫的貧血模型代碼很不一樣?
下面我們看看領(lǐng)域?qū)拥臒o任何外部依賴的單元測試(不需要Mock,不需要準(zhǔn)備數(shù)據(jù)庫等)的測試覆蓋率:

行代碼覆蓋率有70%!?。∥铱戳艘幌?,這其中沒有被測試到的,是一些equals、get/set方法。除去這些,應(yīng)該會達(dá)到90%,或者繼續(xù)做的100%也并不難。
總結(jié)起來,這個應(yīng)用的90%的邏輯可以有90%的自動化單元測試覆蓋率 —— 不需要mock,不需要依賴數(shù)據(jù)庫、外部中間件、RPC等。
這得益于它使用了富領(lǐng)域模型,而不是貧血模型,得益于其正確地組織了業(yè)務(wù)邏輯代碼。測試覆蓋率也從側(cè)面展示了富領(lǐng)域模型到底有多富。
但是先不要急
我最擔(dān)心的是有人看到這里說:懂了,我們開始搞富領(lǐng)域模型吧!
這可能讓你從一個坑里爬出來,接著跳到另外一個坑里。
自動化單測難以推行,是因為“單元化”這個前提不具備。富領(lǐng)域模型可以幫助這個前提的達(dá)成。
但富領(lǐng)域模型的前提是什么?已經(jīng)具備了嗎?
且待下回分解。