前言
本篇是在領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)理論上加以思考后提出的一些觀點(diǎn)莫绣,適用于對DDD 有一定了解的人員閱讀陨闹,另外本篇偏向于實(shí)踐而不是論述理論。請悉知~
1. Domain 層的模型驅(qū)動(dòng)開發(fā)
在DDD 的項(xiàng)目上穆桂,當(dāng)我們經(jīng)歷過了事件風(fēng)暴->命令風(fēng)暴->劃分限界上下文后熔脂。我們就會(huì)產(chǎn)出一份基本上可以映射至代碼實(shí)現(xiàn)的領(lǐng)域模型了。這份模型圖上已經(jīng)包含了entity铜犬、value object舞终、聚合根等類。且對應(yīng)的類圖上已經(jīng)有了屬性以及實(shí)現(xiàn)的方法翎苫。我們可以基于這種領(lǐng)域模型很輕松的實(shí)現(xiàn)我們的代碼权埠。這就是Domain 層的模型驅(qū)動(dòng)開發(fā)榨了,我們在實(shí)現(xiàn)Domain層的邏輯時(shí)煎谍,確實(shí)是完完整整的參照領(lǐng)域模型里的圖來實(shí)現(xiàn)代碼的。領(lǐng)域模型樣例如下圖:
當(dāng)我們有了領(lǐng)域模型后龙屉,我們會(huì)發(fā)現(xiàn)實(shí)現(xiàn)Domain的代碼是如此簡單呐粘。它其實(shí)是將我們代碼設(shè)計(jì)過程提前了满俗,且可視化出來了。這樣能夠讓大家都有一致的理解作岖,也能夠更早的發(fā)現(xiàn)問題唆垃。
不過值得一提的是,有時(shí)候在根據(jù)領(lǐng)域模型實(shí)現(xiàn)代碼時(shí)痘儡,我們會(huì)發(fā)現(xiàn)之前在建模時(shí)沒有考慮到的地方亦或設(shè)計(jì)不合理的地方辕万。這個(gè)時(shí)候我們并不會(huì)繼續(xù)照搬模型,我們應(yīng)該對模型進(jìn)行重新建模沉删,在沒有問題之后再繼續(xù)實(shí)現(xiàn)我們的代碼渐尿。它就像測試驅(qū)動(dòng)開發(fā)一樣,是一個(gè)雙向綁定的過程矾瑰,我們既能夠通過模型分析出設(shè)計(jì)不合理的地方砖茸,也能夠在實(shí)現(xiàn)模型的過程中發(fā)現(xiàn)設(shè)計(jì)不合理的地方并及時(shí)更新模型。它是一個(gè)雙向驗(yàn)證的關(guān)系殴穴。
在Domain層凉夯,我們已經(jīng)可以通過之前的領(lǐng)域建模實(shí)現(xiàn)出領(lǐng)域?qū)拥拇a了,但是這些模型并沒有指示我們應(yīng)該如何實(shí)現(xiàn)應(yīng)用層的代碼采幌,比如:我們的接口應(yīng)如何暴露劲够、數(shù)據(jù)如何存儲(chǔ)、和其它系統(tǒng)或服務(wù)之間的交互應(yīng)如何實(shí)現(xiàn)呢休傍?我們僅有領(lǐng)域建模來驅(qū)動(dòng)是不夠的再沧,所以我們還需要另外一層的模型來驅(qū)動(dòng)開發(fā)。
2. Application 層的模型驅(qū)動(dòng)開發(fā)
既然我們要使用Application 層的模型驅(qū)動(dòng)開發(fā)尊残,那么我們首先要有模型可依炒瘸,所以我們要先對它進(jìn)行建模。我們依然使用工具畫出我們期望實(shí)現(xiàn)的交互方式寝衫,這一步的建模就不再需要一個(gè)團(tuán)隊(duì)來討論完成了顷扩,它是由當(dāng)前開發(fā)某一功能的開發(fā)人員來繪制的。這個(gè)模型圖上描繪了要暴露的功能是什么慰毅,要用到的Domain功能有哪些隘截,還會(huì)與哪些服務(wù)或外部系統(tǒng)來交互等。
當(dāng)我們完成了Application 層的建模汹胃,那么我們就可以按照我們建好的模型進(jìn)行開發(fā)實(shí)現(xiàn)了婶芭。同樣,模型與代碼也是一個(gè)雙向綁定的過程着饥。我們在實(shí)現(xiàn)代碼時(shí)犀农,同樣會(huì)進(jìn)行更細(xì)致的考慮,當(dāng)我們發(fā)現(xiàn)設(shè)計(jì)的模型存在缺陷時(shí)宰掉,我們應(yīng)重新調(diào)整模型呵哨,然后再繼續(xù)開發(fā)實(shí)現(xiàn)赁濒。這樣就形成了模型指導(dǎo)開發(fā),開發(fā)驗(yàn)證模型是否完備孟害,最終我們會(huì)產(chǎn)出一份能夠完全映射代碼實(shí)現(xiàn)的模型與實(shí)現(xiàn)的代碼拒炎。
2.1 Application 層的建模工具推薦
我在實(shí)踐時(shí)一直使用的Plant UML來進(jìn)行建模,它可以讓我們向開發(fā)代碼一樣來編寫我們的模型挨务。
強(qiáng)烈推薦使用如下的框架來構(gòu)建模型击你,因?yàn)樗唵我子们夷P途?/p>
// import 鏈接,直接放在文件最上層就可以使用
!includeurl https://raw.githubusercontent.com/RicardoNiepel/C4-PlantUML/master/C4_Component.puml
2.2 Application 層的建模并不會(huì)影響開發(fā)效率
我們要認(rèn)識(shí)到一點(diǎn)谎柄,我們在對Application進(jìn)行建模時(shí)果漾,并不會(huì)影響我們的開發(fā)效率,相反谷誓,它反而會(huì)幫我們理順?biāo)悸啡拚希瑴p少代碼返工以及bug的產(chǎn)生。
因?yàn)槲覀冊诮5倪^程捍歪,其實(shí)就是開發(fā)人員在實(shí)現(xiàn)代碼前拆分task的過程户辱。有一個(gè)可能大家有過的經(jīng)歷,在做一個(gè)復(fù)雜的功能時(shí)糙臼,沒有提前拆分task庐镐,在實(shí)現(xiàn)的過程中經(jīng)常遺漏各種要實(shí)現(xiàn)的細(xì)節(jié)。而現(xiàn)在我們在建模時(shí)变逃,就會(huì)考慮這些實(shí)現(xiàn)細(xì)節(jié)必逆,待我們實(shí)現(xiàn)時(shí),就按照模型上的描述一步一步實(shí)現(xiàn)就可以揽乱。
2.3 將Application 層的建模保存至代碼實(shí)現(xiàn)的同一目錄下
我們可以將開發(fā)階段建立的Application模型與代碼一同存放至Application層名眉,推薦與Controller 放在一起,一個(gè)Controller與其對應(yīng)的多個(gè)模型圖放在同一個(gè)包下凰棉。
那么我們?yōu)槭裁匆娣胚@些模型圖呢损拢?你們可能會(huì)想,如果我們想了解代碼怎么實(shí)現(xiàn)的話撒犀,直接看代碼就可以了福压,何必要多此一舉呢?其實(shí)不是這樣的或舞,下面我們來看一個(gè)我真實(shí)經(jīng)歷過的例子荆姆。
這是一個(gè)有關(guān)系統(tǒng)的登錄功能的開發(fā),我先以流水線的方式敘述一下它的登錄功能映凳。
- 用戶訪問登錄頁面
- 前端首先需要掉后端的某A接口獲取加密后的第三方單點(diǎn)登錄鏈接來進(jìn)行前端頁面的跳轉(zhuǎn)
- 用戶在第三方登錄完成后胆筒,前端會(huì)從第三方頁面拿到一個(gè)code,再次調(diào)用后端某B接口來解析Code拿到用戶的username在后端校驗(yàn)后并暫時(shí)緩存
- code解析成功后魏宽,用戶需要進(jìn)行短信驗(yàn)證碼驗(yàn)證腐泻,這時(shí)前端又會(huì)調(diào)用后端某接口C來發(fā)送驗(yàn)證碼(單拎出來發(fā)送驗(yàn)證碼的接口是為了重復(fù)發(fā)送驗(yàn)證碼)
- 用戶輸入完驗(yàn)證碼后决乎,前端再調(diào)用后端某D接口來驗(yàn)證是否正確队询,至此登錄完成派桩。
可以看到,在登錄這一流程里蚌斩,前端總共向后端調(diào)用了4次接口铆惑,而且在這個(gè)過程中前后端的交互是緊密聯(lián)系在一起的。這4個(gè)接口在后端確實(shí)放在同一個(gè)Controller下送膳,但是我們單看這四個(gè)接口的代碼實(shí)現(xiàn)员魏,并不能清楚的理解到登錄的實(shí)現(xiàn)流程。況且前后端聯(lián)系這么緊密叠聋,肯定是需要前后端實(shí)現(xiàn)一起看才能弄清楚實(shí)現(xiàn)的撕阎。
這就是一個(gè)典型的例子,我們是需要一個(gè)模型圖來描述我們的邏輯實(shí)現(xiàn)的碌补。如果我們在設(shè)計(jì)之初就構(gòu)建好了這樣的模型圖虏束,那么后人在理解起來就容易的多了。
當(dāng)然我在實(shí)現(xiàn)的時(shí)候是有對它進(jìn)行建模的厦章,以下是我當(dāng)時(shí)的模型圖镇匀,大家可以體會(huì)一下模型圖的作用。
寫在最后
本篇文章在DDD的基礎(chǔ)上袜啃,討論了如何利用模型來驅(qū)動(dòng)開發(fā)汗侵。本文意旨通過模型來反應(yīng)我們的實(shí)現(xiàn)代碼,當(dāng)我們將要對代碼發(fā)生變動(dòng)時(shí)群发,我們要先將對應(yīng)的模型實(shí)現(xiàn)晰韵,然后再去實(shí)現(xiàn)代碼。
值得注意的是熟妓,模型驅(qū)動(dòng)開發(fā)跟TDD有點(diǎn)像宫屠,但是它也是一個(gè)雙向驗(yàn)證的關(guān)系,我們是可以通過模型圖來反應(yīng)代碼設(shè)計(jì)的滑蚯,但是開發(fā)過程中浪蹂,模型圖并不是一成不變的,我們有可能會(huì)發(fā)現(xiàn)一些之前在建模過程中沒有考慮到的細(xì)節(jié)告材,這時(shí)我們需要對現(xiàn)有模型進(jìn)行調(diào)整坤次,然后再進(jìn)行開發(fā)。不過我們要保證在建模期間盡可能的將所有場景都考慮清楚斥赋,就像我們開發(fā)某一功能前缰猴,拆分task一樣。
以上就是我有關(guān)模型驅(qū)動(dòng)開發(fā)的一些觀點(diǎn)疤剑,大家如有什么觀點(diǎn)滑绒,歡迎討論闷堡。