一、背景與問題
無論是企業(yè)內(nèi)部系統(tǒng)還是互聯(lián)網(wǎng)產(chǎn)品靡砌,多年來開發(fā)這種基于業(yè)務(wù)與數(shù)據(jù)庫的系統(tǒng)都是 IT 領(lǐng)域一個(gè)重要的內(nèi)容已脓。作為一個(gè) IT 開發(fā)團(tuán)隊(duì),無論是做外包還是自己的產(chǎn)品通殃,都面臨從產(chǎn)品經(jīng)理拿到需求度液,然后需要進(jìn)行兩方面重要的工作:一是把需求轉(zhuǎn)換為設(shè)計(jì)、二是從設(shè)計(jì)開始編寫代碼画舌。
以前我們開發(fā)這種基于業(yè)務(wù)的軟件產(chǎn)品堕担,通常都是基于開發(fā)人員自己的經(jīng)驗(yàn)和編寫代碼的習(xí)慣開始系統(tǒng)的設(shè)計(jì)與代碼的編寫。常見的方式是項(xiàng)目經(jīng)理或架構(gòu)師分析需求后曲聂,開始進(jìn)行數(shù)據(jù)庫表結(jié)構(gòu)的設(shè)計(jì)照宝,然后按照自己熟悉的分層架構(gòu),比如四層架構(gòu)(數(shù)據(jù)訪問層-業(yè)務(wù)邏輯層-WebApi-前端)進(jìn)行代碼組織句葵。從上述的實(shí)現(xiàn)可以看出幾個(gè)問題:
- 沒有描述需求的設(shè)計(jì)模型;而是直接通過數(shù)據(jù)庫表的方式體現(xiàn)兢仰,也就是需求與設(shè)計(jì)是脫節(jié)的乍丈。
- 編碼的架構(gòu)也沒有與設(shè)計(jì)和需求對(duì)應(yīng)起來。
- 業(yè)務(wù)邏輯與技術(shù)混在一起把将;業(yè)務(wù)邏輯可能直接調(diào)用的數(shù)據(jù)訪問轻专,這樣把業(yè)務(wù)邏輯與數(shù)據(jù)訪問的技術(shù)混在一起。
- 開發(fā)沒有層次感和節(jié)奏感察蹲;系統(tǒng)沒有一個(gè)統(tǒng)一的約束请垛,開發(fā)人員沒有一個(gè)統(tǒng)一的節(jié)奏,這主要體現(xiàn)在隨意的編碼洽议。
- Bug 定位困難:當(dāng)系統(tǒng)出現(xiàn)業(yè)務(wù)異常行為時(shí)宗收,無法快速準(zhǔn)確的定位出現(xiàn)問題的位置,因?yàn)橄到y(tǒng)不同開發(fā)人員的代碼放置隨意性亚兄。
- 需求變更響應(yīng)緩慢:在大型的系統(tǒng)或產(chǎn)品中混稽,當(dāng)需要增加功能或修改現(xiàn)有功能時(shí),因?yàn)榇a架構(gòu)的隨意性,可能會(huì)出現(xiàn)改了功能可能會(huì)影響到其他的功能匈勋,造成系統(tǒng)極不穩(wěn)定礼旅。 大家知道,萬事萬物都有其內(nèi)在規(guī)律洽洁,這就是套路痘系,軟件設(shè)計(jì)與開發(fā)也是如此。軟件設(shè)計(jì)與開發(fā)的套路就是領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)(簡稱 DDD)饿自。DDD 這個(gè)套路能夠靈活解決以上的問題汰翠,為我們提供一個(gè)好的設(shè)計(jì)、架構(gòu)以及高質(zhì)量的代碼璃俗。
二奴璃、為什么要學(xué)習(xí) DDD
DDD 是軟件行業(yè)的一種成熟的方法論和模式。通過應(yīng)用 DDD城豁,我們能夠很好的將需求應(yīng)對(duì)到設(shè)計(jì)苟穆,能夠讓開發(fā)聚焦業(yè)務(wù)本身而不是技術(shù),能夠讓代碼體現(xiàn)我們?cè)O(shè)計(jì)唱星,能夠讓團(tuán)隊(duì)在一個(gè)框架內(nèi)有節(jié)奏的開發(fā)雳旅。
1. DDD 核心概念
首先給大家描述一下 DDD 的概念:DDD 是一種開發(fā)理念,核心是維護(hù)一個(gè)反應(yīng)領(lǐng)域概念的模型(領(lǐng)域模型是軟件最核心的部分间聊,反應(yīng)了軟件的業(yè)務(wù)本質(zhì))攒盈,然后通過大量模式來指導(dǎo)模型設(shè)計(jì)與開發(fā)。
從上述定義可以看出哎榴,DDD 方法首先是需要將需求分析后型豁,形成一個(gè)反應(yīng)需求的領(lǐng)域模型。領(lǐng)域模型就是大家平常理解的類尚蝌、類的屬性迎变、類之間的關(guān)系等。當(dāng)然在 DDD 中飘言,為了更好的將領(lǐng)域模型反應(yīng)需求衣形,對(duì)類、類的屬性姿鸿、類之間的關(guān)系等有一些模式的指導(dǎo)谆吴。比如類的屬性可能是一般屬性,也可能是值對(duì)象苛预;比如有關(guān)系的類之間是否是代表一個(gè)整體概念句狼、有相同生命周期、需要統(tǒng)一持久化等热某。所以我們的領(lǐng)域模型除了能夠跑通需求外鲜锚,還要考慮聚合根突诬、實(shí)體、值對(duì)象芜繁、聚合等概念的應(yīng)用旺隙,這樣領(lǐng)域模型的設(shè)計(jì)才能更好的反應(yīng)需求,也能夠更好的將設(shè)計(jì)對(duì)應(yīng)成有約束力的代碼骏令。
另外 DDD 也提供了大量模式蔬捷,告訴我們應(yīng)該如何編寫對(duì)應(yīng)設(shè)計(jì)的代碼,能夠?qū)⑽覀兊拇a真正映射到設(shè)計(jì)榔袋;如何進(jìn)行業(yè)務(wù)邏輯與持久化機(jī)制的剝離周拐;如何進(jìn)行更好的架構(gòu)設(shè)計(jì)等。
2. DDD 能應(yīng)對(duì)復(fù)雜性
在軟件設(shè)計(jì)與開發(fā)過程中凰兑,復(fù)雜性主要體現(xiàn)在三個(gè)方面妥粟。一是技術(shù)維度,有業(yè)務(wù)代碼的實(shí)現(xiàn)吏够、有與數(shù)據(jù)庫或其他持久化存儲(chǔ)交互的實(shí)現(xiàn)勾给、有消息隊(duì)列的實(shí)現(xiàn)、有身份驗(yàn)證與授權(quán)的實(shí)現(xiàn)锅知、有 WebAPI 暴露的實(shí)現(xiàn)等播急;二是業(yè)務(wù)維度,有太多的模塊和功能需要去做售睹;三是時(shí)間維度桩警,需要快速的開發(fā),快速的響應(yīng)需求的變更昌妹,快速的修正 Bug捶枢。那么 DDD 是如何解決上述三個(gè)維度的復(fù)雜性呢?
- a. 技術(shù)維度:通過合理的架構(gòu)分層飞崖,能夠讓每層關(guān)注自己的事情烂叔,比如領(lǐng)域?qū)又魂P(guān)注業(yè)務(wù)邏輯的事情,倉儲(chǔ)實(shí)現(xiàn)層只關(guān)注持久化數(shù)據(jù)與查詢的事情蚜厉,應(yīng)用服務(wù)層只關(guān)注協(xié)調(diào)領(lǐng)域?qū)优c倉儲(chǔ)實(shí)現(xiàn)層完成用例的事情,接口層只關(guān)注暴露給前端的事情畜眨。
- b. 業(yè)務(wù)維度:通過將大系統(tǒng)劃分成多個(gè)界限上下文昼牛,可以讓不同團(tuán)隊(duì)和不同人只關(guān)注當(dāng)前上下文的開發(fā)。在當(dāng)前界限上下文中的領(lǐng)域?qū)涌的簟}儲(chǔ)實(shí)現(xiàn)層贰健、應(yīng)用服務(wù)層、接口層都與其他界限上下文獨(dú)立開來恬汁,這樣可以專注開發(fā)伶椿,并且在修改代碼與發(fā)布產(chǎn)品時(shí),影響面較小。
- c. 時(shí)間維度:通過敏捷式迭代快速驗(yàn)證脊另,快速修正导狡。
三、什么人適合學(xué)習(xí) DDD
從文章前面的部分大家可能有這樣的初步感覺:DDD 是一套設(shè)計(jì)偎痛、架構(gòu)和編碼指導(dǎo)的方法旱捧,通過靈活運(yùn)用 DDD,能夠設(shè)計(jì)出很好反應(yīng)產(chǎn)品需求的領(lǐng)域模型踩麦,另外通過更好的分層指導(dǎo)能夠讓我們的代碼很好的反映設(shè)計(jì)枚赡,其實(shí)最終解決的問題就是我們第一個(gè)部分提出的 6 大問題。所以只要具有業(yè)務(wù)屬性的產(chǎn)品或項(xiàng)目谓谦,在這個(gè)團(tuán)隊(duì)中的架構(gòu)師贫橙、主要后端開發(fā)人員都是比較適合去學(xué)習(xí) DDD 的。DDD 與語言無關(guān)反粥,無論是 C#卢肃、Java 還是其他的語言,只要我們是遵循 DDD 套路的設(shè)計(jì)與編碼架構(gòu)星压,那就代表我們很好的實(shí)踐了 DDD践剂。當(dāng)然為了你更好的入門 DDD,本文第五部分會(huì)有代碼的演示娜膘。在代碼演示部分使用了 C# 語言和 .net Core逊脯、EF Core、Unity竣贪、Asp.net Core WebAPI 等語言或基礎(chǔ)框架军洼,如果你是 Java 體系,也能夠找到對(duì)應(yīng)的框架實(shí)現(xiàn)的演怎。再次強(qiáng)調(diào)匕争,DDD 與語言和技術(shù)無關(guān)。
四爷耀、如何高效學(xué)習(xí) DDD
其實(shí)要學(xué)習(xí)一種方法論和架構(gòu)模式,就兩個(gè)步驟:一是了解它核心的概念和組件歹叮,二是將這些概念和組件靈活的運(yùn)用到產(chǎn)品開發(fā)中跑杭。
要高效的學(xué)習(xí) DDD咆耿,首先我們要搞清楚兩個(gè)方面的內(nèi)容:一是核心的組件和概念,二是 DDD 分層架構(gòu)萨螺。
核心組件和概念
- 界限上下文:首先要將大系統(tǒng)劃分為多個(gè)界限上下文窄做,比如一個(gè)經(jīng)銷商電商系統(tǒng)可以劃分為產(chǎn)品、經(jīng)銷商椭盏、訂單等幾個(gè)界限上下文组砚,每個(gè)界限上下文有自己的領(lǐng)域邏輯庸汗、數(shù)據(jù)持久化、用例蚯舱、接口等改化。每個(gè)界限上下文根據(jù)特點(diǎn)枉昏,具體實(shí)現(xiàn)方式又不同,比如有些界限上下文基本沒有業(yè)務(wù)邏輯兄裂,就是增刪改查,則可以使用 CRUD 最簡單的模式晰奖;有些界限上線文有一定的業(yè)務(wù)邏輯谈撒,但對(duì)高并發(fā)匾南、高性能沒要求,則可以使用經(jīng)典 DDD 模式蛆楞;有些界限上下文有一定的業(yè)務(wù)邏輯溯乒,而且有高性能要求豹爹,則可以使 CQRS 模式裆悄。 劃分界限上下文并且在每個(gè)上下文實(shí)現(xiàn)自己的業(yè)務(wù)邏輯、持久化臂聋、用例和接口作用是巨大大光稼,一是可以讓不同開發(fā)小組專注與此界限上下文的開發(fā),二是可以分別部署孩等,三是如果一個(gè)界限上下文出現(xiàn)問題艾君,并不影響其他界限上下文功能的使用。
- 實(shí)體:有業(yè)務(wù)生命周期的對(duì)象瞎访,采用業(yè)務(wù)標(biāo)識(shí)符進(jìn)行跟蹤腻贰。比如一個(gè)訂單就是實(shí)體吁恍,訂單有生命周期的扒秸,而且有一個(gè)訂單號(hào)唯一的標(biāo)識(shí)它自己播演,如果兩個(gè)訂單所有屬性值全部相同,但訂單號(hào)不同伴奥,也是不同的實(shí)體写烤。
- 值對(duì)象:無業(yè)務(wù)生命周期,無業(yè)務(wù)標(biāo)識(shí)符拾徙,通常用于描述實(shí)體洲炊。比如訂單的收貨地址、訂單支付的金額等就是值對(duì)象尼啡。值對(duì)象在數(shù)據(jù)庫中表的表現(xiàn)形式可以是兩種暂衡,一種是作為一個(gè)列或多個(gè)列與所屬的實(shí)體對(duì)象所對(duì)應(yīng)的表放在一起,另一種是單獨(dú)一個(gè)表崖瞭,通過ID與所屬的實(shí)體對(duì)象關(guān)聯(lián)狂巢。
- 領(lǐng)域服務(wù):無狀態(tài),有行為书聚,通常就是一個(gè)用例來協(xié)調(diào)多個(gè)領(lǐng)域邏輯完成功能唧领。
- 聚合:通常將多個(gè)實(shí)體和值對(duì)象組合到一個(gè)聚合中來表達(dá)一個(gè)完整的概念,比如訂單實(shí)體雌续、訂單明細(xì)實(shí)體斩个、訂單金額值對(duì)象就代表一個(gè)完整的訂單概念,而且生命周期是相同的驯杜,并且需要統(tǒng)一持久化到數(shù)據(jù)庫中受啥。
- 聚合根:將聚合中表達(dá)總概念的實(shí)體做成聚合根,比如訂單實(shí)體就是聚合根艇肴,對(duì)聚合中所有實(shí)體的狀態(tài)變更必須經(jīng)過聚合根腔呜,因?yàn)榫酆细鶇f(xié)調(diào)了整個(gè)聚合的邏輯,保證一致性再悼。當(dāng)然其他實(shí)體可以被外部直接臨時(shí)查詢調(diào)用核畴。
- 服務(wù):協(xié)調(diào)聚合之間的業(yè)務(wù)邏輯,并且完成用例谤草。
- 倉儲(chǔ):用于對(duì)聚合進(jìn)行持久化莺奸,通常為每個(gè)聚合根配備一個(gè)倉儲(chǔ)即可丑孩。倉儲(chǔ)能夠很好的解耦領(lǐng)域邏輯與數(shù)據(jù)庫温学。
DDD 經(jīng)典分層架構(gòu)
只有了解了經(jīng)典 DDD 的架構(gòu),你才能知道具體在哪層要實(shí)現(xiàn)哪些功能仗岖,編寫哪些代碼逃延,具體在開發(fā)支撐 DDD 的輕量級(jí)框架與具體模塊代碼實(shí)現(xiàn)時(shí)揽祥,才能做到有的放矢。
傳統(tǒng)三層架構(gòu)以及問題:問題:
- 過分注重?cái)?shù)據(jù)訪問層拄丰,而不重視領(lǐng)域俐末。
- 業(yè)務(wù)邏輯直接與數(shù)據(jù)訪問層耦合,與領(lǐng)域?yàn)楹诵牡?DDD 思想背道而馳卓箫。
- 沒有一系列的模式與方法論指導(dǎo)這種分層架構(gòu)的開發(fā)約束。