DDD 中限界上下文與通用語言的作用
通用語言, 最主要的目的就是減少交流中信息丟失, 在實(shí)際開發(fā)中, 可能關(guān)聯(lián)很多人, 例如有業(yè)務(wù)層面的業(yè)務(wù)細(xì)節(jié)制定者、領(lǐng)域?qū)<摇a(chǎn)品經(jīng)理、項(xiàng)目經(jīng)理 、架構(gòu)師、開發(fā)經(jīng)理、測試經(jīng)理等等, 即使確定了核心域, 但是對于同樣的領(lǐng)域知識, 每個人也有自己的理解, 舉個例子, 我們通常說的商品和貨物,是不是其實(shí)就是一個東西 ? 在銷售領(lǐng)域叫商品, 但是一旦進(jìn)入物流領(lǐng)域就叫貨物, 所以我們一說商品就知道這是在銷售子域, 一旦說貨物就知道這是在物流領(lǐng)域, 如果只用物品來進(jìn)行交流可能就會丟失信息,因?yàn)樵诓煌淖佑蜿P(guān)注的重點(diǎn)是不同的, 為了減少信息丟失, 確保大家交流的便利性, 將能夠簡單清晰準(zhǔn)確描述業(yè)務(wù)含義和規(guī)則的語言就是領(lǐng)域通用語言, 也就是通用語言是團(tuán)隊(duì)統(tǒng)一的語言, 只要你在這個領(lǐng)域, 那么在一個系統(tǒng)生命周期內(nèi)就應(yīng)該用通用語言進(jìn)行交流。
可見, 通用語言作用還是很清晰明了的, 解決溝通障礙節(jié)省時間成本, 讓大家更好進(jìn)行協(xié)作, 通用語言包含術(shù)語與應(yīng)用場景,并且能夠反映在代碼中, 例如給領(lǐng)域?qū)ο竺? 如商品、訂單等,對應(yīng)實(shí)體對象; 而動詞則表示一個動作或者事件, 例如商品已經(jīng)下單, 訂單已付款, 運(yùn)輸中等等, 對應(yīng)領(lǐng)域事件或者說命令。
通用語言貫穿 DDD 的整個設(shè)計(jì)過程。作為項(xiàng)目團(tuán)隊(duì)溝通和協(xié)商形成的統(tǒng)一語言,基于它,你就能夠開發(fā)出可讀性更好的代碼,將業(yè)務(wù)需求準(zhǔn)確轉(zhuǎn)化為代碼設(shè)計(jì)。

在事件風(fēng)暴的過程中,領(lǐng)域?qū)<視驮O(shè)計(jì)、開發(fā)人員一起建立領(lǐng)域模型,在領(lǐng)域建模的 過程中會形成通用的業(yè)務(wù)術(shù)語和用戶故事。事件風(fēng)暴也是一個項(xiàng)目團(tuán)隊(duì)統(tǒng)一語言的過 程。 通過用戶故事分析會形成一個個的領(lǐng)域?qū)ο?,這些領(lǐng)域?qū)ο髮?yīng)領(lǐng)域模型的業(yè)務(wù)對象, 每一個業(yè)務(wù)對象和領(lǐng)域?qū)ο蠖加型ㄓ玫拿~術(shù)語,并且一一映射。 微服務(wù)代碼模型來源于領(lǐng)域模型,每個代碼模型的代碼對象跟領(lǐng)域?qū)ο笠灰粚?yīng)。
設(shè)計(jì)過程中我們可以用一些表格,來記錄事件風(fēng)暴和微服務(wù)設(shè)計(jì)過程中產(chǎn)生的領(lǐng)域?qū)ο蠹捌鋵傩?。比如,領(lǐng)域?qū)ο笤?DDD 分層架構(gòu)中的位置、屬性、依賴關(guān)系以及與代碼模型對象的映射關(guān)系等。下面是一個微服務(wù)設(shè)計(jì)實(shí)例的部分?jǐn)?shù)據(jù),表格中的這些名詞術(shù)語就是項(xiàng)目團(tuán)隊(duì)在事件風(fēng)暴過程中達(dá)成一致、可用于團(tuán)隊(duì)內(nèi)部交流的通用語言。在這個表格里面我們可以看到,DDD 分析過程中所有的領(lǐng)域?qū)ο笠约八鼈兊膶傩远急挥涗浵聛砹?,除?DDD 的領(lǐng)域?qū)ο螅覀冞€記錄了在微服務(wù)設(shè)計(jì)過程中領(lǐng)域?qū)ο笏鶎?yīng)的代碼對象,并將它們一一映射。

DDD 分析和設(shè)計(jì)過程中的每一個環(huán)節(jié)都需要保證限界上下文內(nèi)術(shù)語的統(tǒng)一,在代碼模型設(shè)計(jì)的時侯就要建立領(lǐng)域?qū)ο蠛痛a對象的一一映射,從而保證業(yè)務(wù)模型和代碼模型的一致,實(shí)現(xiàn)業(yè)務(wù)語言與代碼語言的統(tǒng)一。
如果做到了這一點(diǎn),也就是建立了領(lǐng)域?qū)ο蠛痛a對象的映射關(guān)系,那就可以指導(dǎo)軟件開發(fā)人員準(zhǔn)確無誤地按照設(shè)計(jì)文檔完成微服務(wù)開發(fā)了。即使是不熟悉代碼的業(yè)務(wù)人員,也可以很快找到代碼的位置。
什么是限界上下文
剛剛有聊到通用語言, 而確定通用語言適用范圍, 準(zhǔn)確來說, 確定領(lǐng)域范圍的就是限界上下文邊界, 限界上下文邊界英文名bounded context, 如果直接翻譯成上下文邊界就更容易理解, 主要目的是為了避免同樣的概念在不同領(lǐng)域產(chǎn)生不同語義或歧義, DDD在戰(zhàn)略上提出"限界上下文"這個概念, 用來確定語義所在的領(lǐng)域邊界。
我們可以將限界上下文拆解成兩個詞語:限界和上下文。限界就是領(lǐng)域的邊界, 而上下文就是語義環(huán)境, 通過限界上下文讓所有交流的人知道我們聊的是在同一個領(lǐng)域邊界內(nèi)的事情, 合起來就是用來封裝通用語言和領(lǐng)域?qū)ο?,提供上下文環(huán)境,保證在領(lǐng)域之內(nèi)的一些術(shù)語、業(yè)務(wù)相關(guān)對象等(通用語言)有一個確切的含義,沒有二義性。這個邊界定義了模型的適用范圍,使團(tuán)隊(duì)所有成員能夠明確地知道什么應(yīng)該在模型中實(shí)現(xiàn),什么不應(yīng)該在模型中實(shí)現(xiàn)。
為什么要有限界上下文這個概念
都說中文這門語言非常豐富,在不同的時空和背景下,同樣的一句話會有不同的涵義。有一個例子你應(yīng)該聽說過。在一個明媚的早晨,孩子起床問媽媽:“今天應(yīng)該穿幾件衣服呀?”媽媽回答:“能穿多少就穿多少!”
那到底是穿多還是穿少呢?
如果沒有具體的語義環(huán)境,還真不太好理解。但是,如果你已經(jīng)知道了這句話的語義環(huán)境,比如是寒冬臘月或者是炎炎夏日,那理解這句話的涵義就會很容易了。所以語言離不開它的語義環(huán)境。而業(yè)務(wù)的通用語言就有它的業(yè)務(wù)邊界,我們不大可能用一個簡單的術(shù)語沒有歧義地去描述一個復(fù)雜的業(yè)務(wù)領(lǐng)域。限界上下文就是用來細(xì)分領(lǐng)域,從而定義通用語言所在的邊界?,F(xiàn)在我們用一個保險領(lǐng)域的例子來說明下術(shù)語的邊界。

保險業(yè)務(wù)領(lǐng)域有投保單、核保、財務(wù)、回訪、保全等保險術(shù)語,它們分別應(yīng)用于保險的不同業(yè)務(wù)流程。
客戶投保時,業(yè)務(wù)人員記錄投保信息,系統(tǒng)對應(yīng)有投保單實(shí)體對象。 繳費(fèi)完成后,業(yè)務(wù)人員將投保單轉(zhuǎn)為保單,系統(tǒng)對應(yīng)有保單實(shí)體對象,保單實(shí)體與投保單實(shí)體關(guān)聯(lián)。 如客戶需要修改保單信息,保單變?yōu)榕鷨危斜H到y(tǒng)對應(yīng)有批單實(shí)體對象,批單實(shí)體與保單實(shí)體關(guān)聯(lián)。 如果客戶發(fā)生理賠,生成賠案,系統(tǒng)對應(yīng)有報案實(shí)體對象,報案實(shí)體對象與保單或者批單實(shí)體關(guān)聯(lián)。投保單、保單、批單、賠案等,這些術(shù)語雖然都跟保單有關(guān),但不能將保單這個術(shù)語作用在保險全業(yè)務(wù)領(lǐng)域。因?yàn)樾g(shù)語有它的邊界,超出了邊界理解上就會出現(xiàn)問題。 正如電商領(lǐng)域的商品一樣,商品在不同的階段有不同的術(shù)語,在銷售階段是商品,而在運(yùn)輸階段則變成了貨物。同樣的一個東西,由于業(yè)務(wù)領(lǐng)域的不同,賦予了這些術(shù)語不同的涵義和職責(zé)邊界,這個邊界就可能會成為未來微服務(wù)設(shè)計(jì)的邊界??吹竭@,我想你應(yīng)該非常清楚了,領(lǐng)域邊界就是通過限界上下文來定義的。
限界上下文在微服務(wù)設(shè)計(jì)中作用以及意義是什么
接下來,我們對這個概念做進(jìn)一步的延伸??纯聪藿缟舷挛暮臀⒎?wù)具體存在怎樣的關(guān)系。我想你買過保險吧,或者聽過吧。保險承保的流程包含了投保、繳費(fèi)、出單等幾個主要流程。如果出險了還會有報案、查勘、定損、理算等理賠流程。
首先,領(lǐng)域可以拆分為多個子領(lǐng)域。一個領(lǐng)域相當(dāng)于一個問題域,領(lǐng)域拆分為子域的過程就是大問題拆分為小問題的過程。在這個圖里面保險領(lǐng)域被拆分為:投保、支付、保單管理和理賠四個子域。
子域還可根據(jù)需要進(jìn)一步拆分為子子域,比如,支付子域可繼續(xù)拆分為收款和付款子子域。拆到一定程度后,有些子子域的領(lǐng)域邊界就可能變成限界上下文的邊界了。子域可能會包含多個限界上下文,如理賠子域就包括報案、查勘和定損等多個限界上下文(限界上下文與理賠的子子域領(lǐng)域邊界重合)。也有可能子域本身的邊界就是限界上下文邊界,如投保子域。
每個領(lǐng)域模型都有它對應(yīng)的限界上下文,團(tuán)隊(duì)在限界上下文內(nèi)用通用語言交流。領(lǐng)域內(nèi)所有限界上下文的領(lǐng)域模型構(gòu)成整個領(lǐng)域的領(lǐng)域模型。理論上限界上下文就是微服務(wù)的邊界。我們將限界上下文內(nèi)的領(lǐng)域模型映射到微服務(wù),就完成了從問題域到軟件的解決方案。
可以說,限界上下文是微服務(wù)設(shè)計(jì)和拆分的主要依據(jù)。在領(lǐng)域模型中,如果不考慮技術(shù)異構(gòu)、團(tuán)隊(duì)溝通等其它外部因素,一個限界上下文理論上就可以設(shè)計(jì)為一個微服務(wù)。不過,這里還是要提示一下:除了理論,微服務(wù)的拆分還是有很多限制因素的,在設(shè)計(jì)中不宜過度拆分。那這個度怎么把握好呢?有關(guān)微服務(wù)設(shè)計(jì)和具體的拆分方法,我會在實(shí)戰(zhàn)篇中詳細(xì)講解。
總結(jié)
通用語言確定了項(xiàng)目團(tuán)隊(duì)內(nèi)部交流的統(tǒng)一語言,而這個語言所在的語義環(huán)境則是由限界上下文來限定的,以確保語義的唯一性。而領(lǐng)域?qū)<?、架?gòu)師和開發(fā)人員的主要工作就是通過事件風(fēng)暴來劃分限界上下文。限界上下文確定了微服務(wù)的設(shè)計(jì)和拆分方向,是微服務(wù)設(shè)計(jì)和拆分的主要依據(jù)。如果不考慮技術(shù)異構(gòu)、團(tuán)隊(duì)溝通等其它外部因素,一個限界上下文理論上就可以設(shè)計(jì)為一個微服務(wù)??梢哉f,限界上下文在微服務(wù)設(shè)計(jì)中具有很重要的意義,如果限界上下文的方向偏離,那微服務(wù)的設(shè)計(jì)結(jié)果也就可想而知了。因此,我們只有理解了限界上下文的真正涵義以及它在微服務(wù)設(shè)計(jì)中的作用,才能真正發(fā)揮 DDD 的價值,這是基礎(chǔ)也是前提。
作者:等不到的口琴
原文:https://www.cnblogs.com/Courage129/p/14854367.html
END

【干貨】你的 Redis 做讀寫分離有什么問題?

35 張圖帶你 MySQL 調(diào)優(yōu)
