官术网_书友最值得收藏!

理解限界上下文

不要忘了,限界上下文是一個(gè)顯式的邊界,領(lǐng)域模型便存在于這個(gè)邊界之內(nèi)。領(lǐng)域模型把通用語(yǔ)言表達(dá)成軟件模型。創(chuàng)建邊界的原因在于,每一個(gè)模型概念,包括它的屬性和操作,在邊界之內(nèi)都具有特殊的含義。如果你是建模團(tuán)隊(duì)中的一員,你便應(yīng)該知道這些概念的確切含義。

限界上下文是顯式的,充滿語(yǔ)義的

限界上下文是一個(gè)顯式邊界,領(lǐng)域模型便存在于邊界之內(nèi)。在邊界內(nèi),通用語(yǔ)言中的所有術(shù)語(yǔ)和詞組都有特定的含義,而模型需要準(zhǔn)確地反映通用語(yǔ)言。

在很多情況下,在不同模型中存在名字相同或相近的對(duì)象,但是它們的意思卻不同。當(dāng)模型被一個(gè)顯式的邊界所包圍時(shí),其中每個(gè)概念的含義便是確定的了。因此,限界上下文主要是一個(gè)語(yǔ)義上的邊界,我們應(yīng)該通過(guò)這一點(diǎn)來(lái)衡量對(duì)一個(gè)限界上下文的使用正確與否。

有些項(xiàng)目試圖創(chuàng)建一個(gè)“大而全”的軟件模型,其中每個(gè)概念在全局范圍之內(nèi)只有一種定義。這是一個(gè)陷阱。首先,要使所有人都對(duì)某個(gè)概念的定義達(dá)成一致幾乎不可能。有些項(xiàng)目太龐大,太復(fù)雜,以致于你根本無(wú)法將所有的利益相關(guān)方聚集到一起,更不用提達(dá)成一致了。即便是那些規(guī)模相對(duì)較小的公司,要維持一個(gè)全局性的,并且經(jīng)得住時(shí)間考驗(yàn)的概念定義也是困難的。因此,最好的方法是去正視這種不同,然后使用限界上下文對(duì)領(lǐng)域模型進(jìn)行分離。

限界上下文并不旨在創(chuàng)建單一的項(xiàng)目資產(chǎn),它并不是一個(gè)單獨(dú)的組件、文檔、或者框圖[1]。因此,它并不一個(gè)是JAR或者DLL,但是這些可以用來(lái)部署限界上下文,我們會(huì)在后面講到。

讓我們來(lái)看看一個(gè)賬戶(Account)模型在銀行上下文(Banking Context)和文學(xué)上下文(Literary Context)中的不同,如表2.1所示。

表2.1 賬戶的不同含義

img

在圖2.5中,光憑名字我們根本無(wú)法區(qū)分兩個(gè)賬戶的意思。只有通過(guò)它們所在的限界上下文我們才能看出它們之間的區(qū)別。

img

圖2.5 不同限界上下文中的Account對(duì)象具有完全不同的含義。

這兩個(gè)上限界上下文可能并不屬于同一個(gè)領(lǐng)域,這里我只是想說(shuō)明:上下文才是王道。

上下文才是王道

上下文才是王道,特別是在實(shí)施DDD的時(shí)候。

在金融領(lǐng)域,我們經(jīng)常談到證券(security)。 證券交易管理委員會(huì)(Securities and Exchange Commission,SEC)限制證券只能和股票(equities)一起使用。現(xiàn)在讓我們考慮這種情況:期權(quán)合同(futures contract)作為一種商品,它并不被SEC所管理。然而,有些金融公司卻將期權(quán)當(dāng)作一種證券,并且用標(biāo)準(zhǔn)類型(Standard Type,6)Futures來(lái)表示。

這是表示期權(quán)的最好方式嗎?這取決于它所處的領(lǐng)域。有人認(rèn)為期權(quán)顯然是一種證券,另有人則持反面意見(jiàn)。上下文同時(shí)也是具有文化屬性的。對(duì)于一個(gè)經(jīng)營(yíng)期權(quán)的公司,在通用語(yǔ)言中以證券來(lái)表示期權(quán)在文化上是合理的。

在通常情況下,我們所面對(duì)的都是一些區(qū)別甚小的概念定義。原因在于:在一個(gè)上下文中,團(tuán)隊(duì)通常根據(jù)通用語(yǔ)言來(lái)命名某個(gè)概念。我們并不會(huì)隨意地命名一個(gè)概念以刻意地保持與其他上下文的不同。比如兩個(gè)銀行上下文,一個(gè)用于支票賬戶,另一個(gè)用于儲(chǔ)蓄賬戶[2]。在支票上下文(Checking Context)中,我們不必使用支票賬戶(Checking Account);在儲(chǔ)蓄上下文(Saving Context)中我們也不必使用儲(chǔ)蓄賬戶(Saving Account)。兩個(gè)概念都可以使用賬戶(Account)來(lái)表示,因?yàn)橄藿缟舷挛囊呀?jīng)對(duì)此做了區(qū)分。當(dāng)然,我們并沒(méi)有規(guī)定不能使用更具體的名字,這只是團(tuán)隊(duì)自己的選擇而已。

當(dāng)需要集成時(shí),我們必須在不同的限界上下文之間進(jìn)行概念映射。在DDD中,這可能是復(fù)雜的,因此我們應(yīng)該特別留意。在上下文邊界之外,我們通常不會(huì)使用該上下文之內(nèi)的對(duì)象實(shí)例,但是不同上下文中彼此關(guān)聯(lián)的對(duì)象可能共享一些狀態(tài)。

再看另一個(gè)例子,該例中同一個(gè)領(lǐng)域的不同限界上下文使用了相同的概念名。考慮一個(gè)圖書出版機(jī)構(gòu),它需要處理圖書生命周期的不同階段。粗略地講,我們可以認(rèn)為這些不同的階段對(duì)應(yīng)于以下不同的上下文環(huán)境:

? 概念設(shè)計(jì),計(jì)劃出書

? 聯(lián)系作者,簽訂合同

? 管理圖書的編輯過(guò)程

? 設(shè)計(jì)圖書布局,包括插圖

? 將圖書翻譯成其他語(yǔ)言

? 出版紙質(zhì)版或電子版圖書

? 市場(chǎng)營(yíng)銷

? 將圖書賣給銷售商或直接賣給讀者

? 將圖書發(fā)送給銷售商或讀者

在以上所有階段中,我們可以用一個(gè)單一的概念對(duì)圖書建模嗎?顯然不行。在每個(gè)階段中,“圖書”都有不同的定義。一本書只有在和作者簽訂了合同之后才能擁有書名,而書名可能在編輯過(guò)程進(jìn)行修改。在編輯過(guò)程中,圖書包含了一系列的稿件,其中包括注釋和校正等,之后會(huì)有一份最終稿件。頁(yè)面布局由專門的圖形設(shè)計(jì)師完成。圖書印刷方使用頁(yè)面布局和封面板式印制圖書。市場(chǎng)營(yíng)銷員不需要編輯稿件或圖書印制成品,他們可能只需要圖書的簡(jiǎn)介即可。對(duì)于圖書的售后物流,我們需要的是圖書的標(biāo)識(shí)碼、物流目的地、數(shù)目、尺寸和重量等。

想象一下,如果我們使用一個(gè)單一模型來(lái)處理所有這些階段會(huì)發(fā)生什么?概念混淆、意見(jiàn)分歧和爭(zhēng)論是不可避免的,我們所交付的軟件也沒(méi)有多大價(jià)值。即便有時(shí)我們可能會(huì)得到一個(gè)正確的公共模型,但這種模型并不具有持久性。

為了解決這個(gè)問(wèn)題,我們應(yīng)該為每個(gè)階段創(chuàng)建各自的限界上下文。在每個(gè)限界上下文中,都存在某種類型的圖書(Book)。在幾乎所有的上下文中,不同類型的圖書對(duì)象將共享一個(gè)身份標(biāo)識(shí)(identity),這個(gè)標(biāo)識(shí)可能是在概念設(shè)計(jì)階段創(chuàng)建的。然而,不同上下文中的圖書模型卻是不同的。當(dāng)某個(gè)限界上下文的團(tuán)隊(duì)說(shuō)到圖書時(shí),該“圖書”正好能表示該上下文所需要的意思。如此這般,我們根據(jù)不同的需求很自然地創(chuàng)建了不同類型的圖書,但這并不表示這種建模過(guò)程就是可以輕易達(dá)到的。不管如何,在使用顯式限界上下文的情況下,我們可以定期地、增量式的交付軟件,同時(shí)所交付的軟件又能滿足特定的業(yè)務(wù)需求。

這里,讓我們快速瀏覽一下SaaSOvation的協(xié)作團(tuán)隊(duì)是如何解決圖2.3中的建模問(wèn)題的。

前面已經(jīng)提到,協(xié)作上下文的領(lǐng)域?qū)<也](méi)有從用戶和權(quán)限的角度去描述協(xié)作工具的使用者,而是以他們所扮演的角色進(jìn)行描述,比如作者、擁有者、參與者和主持者等。個(gè)人的聯(lián)系方式可能出現(xiàn)在該上下文中,但我們并不需要所有的聯(lián)系信息。另一方面,只有在身份與訪問(wèn)上下文中我們才會(huì)談及到用戶。在該上下文中,用戶對(duì)象包含了某人的用戶名和一些詳細(xì)信息,其中便包含了該用戶的聯(lián)系方式。

然而,我們也不會(huì)憑空創(chuàng)建一個(gè)Author對(duì)象,因?yàn)槊恳粋€(gè)協(xié)作者(collaborator)都需要事先進(jìn)行資格認(rèn)證才能使用協(xié)作軟件。在身份與訪問(wèn)上下文中,我們將驗(yàn)證擁有某種角色的用戶是否存在,驗(yàn)證信息將隨著請(qǐng)求傳給身份與訪問(wèn)上下文。要?jiǎng)?chuàng)建一個(gè)協(xié)作對(duì)象,比如一個(gè)Moderator,我們將使用對(duì)應(yīng)用戶的一部分屬性,另外還需要一個(gè)角色名。如何從另一個(gè)限界上下文中獲取對(duì)象狀態(tài)(本書后續(xù)章節(jié)將對(duì)此做詳細(xì)講解)并不重要,重要的是,兩個(gè)不同的概念既有相似之處,又有不同之處,不同之處由限界上下文決定。在圖2.6中,一個(gè)限界上下文中的User和Role信息被另一個(gè)限界上下文用來(lái)創(chuàng)建Moderator對(duì)象。

img

圖2.6 協(xié)作上下文中的Moderator對(duì)象是基于身份與訪問(wèn)上下文中的User和Role對(duì)象的。

白板時(shí)間

? 在你自己的領(lǐng)域中,看看你能否在不同的限界上下文中識(shí)別出那些區(qū)別微小的概念。

? 看看這些概念是不是得到了正確的分離,或者你只是簡(jiǎn)單地將相應(yīng)代碼從一個(gè)地方復(fù)制到另一個(gè)地方。

通常情況下,你是可以識(shí)別出那些概念分離正確的情況的,因?yàn)橛行┫嗨频膶?duì)象擁有不同的屬性和行為,此時(shí)我們可以認(rèn)為上下文邊界的劃分是合理的。然而,如果你在不同的限界上下文中看到了完全相同的對(duì)象,這通常意味著你的模型是錯(cuò)誤的,除非這些限界上下文使用了共享內(nèi)核(Shared Kernel,3)。

限界上下文不僅僅只包含模型

一個(gè)限界上下文并不是只包含領(lǐng)域模型。誠(chéng)然,模型是限界上下文的主要“公民”。但是,限界上下文并不只局限于容納模型,它通常標(biāo)定了一個(gè)系統(tǒng)、一個(gè)應(yīng)用程序或者一種業(yè)務(wù)服務(wù)[3]。有時(shí),限界上下文所包含的內(nèi)容可能比較少,比如,一個(gè)通用子域便可以只包含領(lǐng)域模型。

當(dāng)模型驅(qū)動(dòng)著數(shù)據(jù)庫(kù)Schema的設(shè)計(jì)時(shí),此時(shí)的數(shù)據(jù)庫(kù)Schema也應(yīng)該位于該模型所處的上下文邊界之內(nèi)。這是因?yàn)閿?shù)據(jù)庫(kù)Schema是由建模團(tuán)隊(duì)設(shè)計(jì)、開(kāi)發(fā)并維護(hù)的。這也意味著數(shù)據(jù)庫(kù)中表和列的名字應(yīng)該和模型的名字保持一致。比如,對(duì)于模型中包含的BacklogItem類,它擁有值對(duì)象屬性backlogItemId和businessPriority:

在數(shù)據(jù)庫(kù)中對(duì)應(yīng)的表定義為:

另一方面,如果數(shù)據(jù)庫(kù)Schema已經(jīng)存在,或者另有一個(gè)專門的數(shù)據(jù)建模團(tuán)隊(duì)要求有別于模型的數(shù)據(jù)庫(kù)Schema設(shè)計(jì),此時(shí)的Schema便不能和模型位于同一個(gè)限界上下文中了。

如果用戶界面(User Interface,14)被用于渲染模型,并且驅(qū)動(dòng)著模型的行為設(shè)計(jì)時(shí),同樣,該用戶界面也應(yīng)該屬于模型所在的上下文邊界之內(nèi)。但是,這并不表示我們應(yīng)該在用戶界面中對(duì)領(lǐng)域進(jìn)行建模,因?yàn)檫@樣將導(dǎo)致貧血領(lǐng)域?qū)ο蟆N覀儜?yīng)該拒絕使用智能UI反模式(Smart UI Anti-Pattern)[Evans],或者任何試圖將領(lǐng)域概念帶到領(lǐng)域模型之外的舉措。

通常情況下,一個(gè)系統(tǒng)/應(yīng)用程序的使用者并不只是人,還可能是另外的計(jì)算機(jī)系統(tǒng)。系統(tǒng)中有可能存在諸如Web服務(wù)(Web services)之類的組件。我們也可以使用REST資源來(lái)與模型交互,此時(shí)的REST資源即被稱為開(kāi)放主機(jī)服務(wù)(Open Host Service,3,13)。或者,我們可以使用SOAP或消息服務(wù)端點(diǎn)。在以上所有情況中,那些面向服務(wù)的組件都應(yīng)該位于上下文邊界之內(nèi)。

用戶界面和面向服務(wù)端點(diǎn)都會(huì)將操作委派給應(yīng)用服務(wù)(14)。應(yīng)用服務(wù)包含了不同類型的服務(wù),比如安全和事務(wù)管理等。對(duì)于模型來(lái)說(shuō),應(yīng)用服務(wù)扮演的是一種門面模式Fa?ade [Gamma etal.]。同時(shí),應(yīng)用服務(wù)還具有任務(wù)管理功能,它將來(lái)自用例流(Use Case Flow)的請(qǐng)求轉(zhuǎn)換成領(lǐng)域邏輯的執(zhí)行流。應(yīng)用服務(wù)也是位于上下文邊界之內(nèi)的。

更多關(guān)于架構(gòu)和應(yīng)用程序的知識(shí)

請(qǐng)參考架構(gòu)(4)以了解不同的DDD架構(gòu)風(fēng)格。另外,應(yīng)用服務(wù)將在應(yīng)用程序(14)中做詳細(xì)講解。這兩個(gè)章節(jié)都包含了有用的架構(gòu)框圖和代碼示例。

限界上下文主要用來(lái)封裝通用語(yǔ)言和領(lǐng)域?qū)ο螅瑫r(shí)它也包含了那些為領(lǐng)域模型提供交互手段和輔助功能的內(nèi)容。需要注意的是,對(duì)于架構(gòu)中的每個(gè)組件,我們都應(yīng)該將其放在適當(dāng)?shù)牡胤健?/p>

白板時(shí)間

? 看看白板上的每一個(gè)限界上下文,你能想到有哪些非領(lǐng)域模型的組件可以放在限界上下文之內(nèi)嗎?

? 如果存在用戶界面和應(yīng)用服務(wù),請(qǐng)確保它們是位于上下文邊界之內(nèi)的(要表示不同的組件,可以參考圖2.8、圖2.9和圖2.10)。

? 如果你的數(shù)據(jù)庫(kù)Schema,或者其他持久化存儲(chǔ)方案,是根據(jù)模型來(lái)設(shè)計(jì)的,那么請(qǐng)確保它們也是位于上下文邊界之內(nèi)的(要表示數(shù)據(jù)庫(kù)Schema,可以參考圖2.8、圖2.9和圖2.10)。

限界上下文的大小

限界上下文中可以包含多少領(lǐng)域模型中的基礎(chǔ)部件呢,比如模塊(9)、聚合(10)、領(lǐng)域事件(8)和領(lǐng)域服務(wù)(7)等?這好像是在問(wèn)“一個(gè)字符串應(yīng)該有多長(zhǎng)?”一樣。限界上下文應(yīng)該足夠大,以能夠表達(dá)它所對(duì)應(yīng)的整套通用語(yǔ)言。

核心領(lǐng)域之外的概念不應(yīng)該包含在限界上下文中。如果一個(gè)概念不屬于你的通用語(yǔ)言,那么一開(kāi)始你就不應(yīng)該將其引入到模型中。此外,如果有外部概念“偷偷潛入”了你的限界上下文,你需要將其清除,它們可能屬于另外的支撐或者通用子域,或者根本就不屬于某個(gè)模型。

請(qǐng)注意,不要將本應(yīng)該屬于核心域的概念給清除掉了。你的模型應(yīng)該能夠完全地展現(xiàn)上下文中的通用語(yǔ)言,而不能遺漏任何重要的概念。此時(shí),我們需要做出正確的判斷,你可以借助諸如上下文映射圖(3)這樣的工具。

在電影《莫扎特傳》[4]中有這么一個(gè)場(chǎng)景:奧地利皇帝約瑟夫二世告訴莫扎特,說(shuō)他剛才演奏的音樂(lè)作品很不錯(cuò),就是音符太多了。莫扎特巧妙地回答道:“我需要的音符正好這么多,一個(gè)不多,一個(gè)不少。”這種回答也適用于我們現(xiàn)在所講的限界上下文。限界上下文所包含的領(lǐng)域模型概念應(yīng)該恰如其分,不多也不少。

要做到這一點(diǎn)并不是什么易事,莫扎特可以像給朋友寫信一樣創(chuàng)作交響樂(lè),而要?jiǎng)?chuàng)建一個(gè)恰到好處的限界上下文就不是這么簡(jiǎn)單了。任何時(shí)候,我們都有可能錯(cuò)失改進(jìn)領(lǐng)域模型的機(jī)會(huì)。在每個(gè)迭代中,我們都應(yīng)該對(duì)先前的假設(shè)提出挑戰(zhàn),這使得我們向模型中添加或刪除一些概念,或者改變概念的行為和協(xié)作方式等。但是主要的問(wèn)題是:我們總是面臨這樣的挑戰(zhàn)。在使用DDD原則時(shí),我們會(huì)認(rèn)真地思考應(yīng)該添加哪些概念,又應(yīng)該刪除哪些概念。使用限界上下文和上下文映射圖這樣的工具可以幫助我們分析出哪些概念的確應(yīng)該屬于核心域。我們并不隨意地采用非DDD的分離原則。

領(lǐng)域模型的優(yōu)美旋律

如果我們的模型是音樂(lè),那么它所表現(xiàn)的則是完整性、純潔性、力量、優(yōu)雅和美。

如果對(duì)限界上下文的限制過(guò)于嚴(yán)格,那么我們可能丟失一些上下文概念。相反,如果向模型中添加過(guò)多的概念,我們可能搞不清楚哪些概念是重要的。那么我們的目標(biāo)是什么呢?如果我們的模型是音樂(lè),那么它應(yīng)該表現(xiàn)出的是完整性、純潔性、力量、優(yōu)雅和美。其中的“音符”——模塊、聚合、事件和服務(wù)——的數(shù)量正好是設(shè)計(jì)所要求的那么多。模型的“聽(tīng)眾”不會(huì)問(wèn)及到像“為什么中間會(huì)有一些奇怪的音符?”這樣的問(wèn)題。同時(shí),它們也不會(huì)因?yàn)閬G失了某些“音符”而感到不解。

那么,哪些因素會(huì)導(dǎo)致我們創(chuàng)建大小不正確的限界上下文呢?我們可能錯(cuò)誤地采用架構(gòu)來(lái)指導(dǎo)設(shè)計(jì)開(kāi)發(fā),而不是通用語(yǔ)言 。一些平臺(tái)、框架或者基礎(chǔ)設(shè)施通常是用來(lái)打包和部署組件的,它們可能影響我們對(duì)限界上下文的設(shè)計(jì),此時(shí)我們會(huì)從技術(shù)層面而不是語(yǔ)義邊界來(lái)考慮問(wèn)題。

另一個(gè)可能的陷阱是:根據(jù)開(kāi)發(fā)任務(wù)的分配來(lái)拆分限界上下文。技術(shù)帶頭人和項(xiàng)目經(jīng)理可能會(huì)想,小規(guī)模任務(wù)對(duì)于開(kāi)發(fā)者來(lái)說(shuō)將更加容易完成。這可能是有道理的,但是,為了分配任務(wù)而拆分限界上下文是一種錯(cuò)誤的上下文建模方式。事實(shí)上,我們沒(méi)有必要為了管理技術(shù)資源而創(chuàng)建一些假(fake)的上下文邊界。

這里有一個(gè)重要的問(wèn)題:領(lǐng)域?qū)<宜捎玫恼Z(yǔ)言是如何劃定上下文邊界的?

如果創(chuàng)建限界上下文只是為了架構(gòu)組件或開(kāi)發(fā)者資源這樣的考慮,那么此時(shí)的通用語(yǔ)言將變得四分五裂,其表達(dá)力也會(huì)喪失殆盡。因此,我們應(yīng)該考慮領(lǐng)域?qū)<宜v的通用語(yǔ)言,將核心域中的概念自然地組織成單一的限界上下文。這樣一來(lái),你便可以自然地識(shí)別出那些單一的、內(nèi)聚的模型組件。你應(yīng)該將這些組件放在限界上下文之內(nèi)。

有時(shí),我們可以使用模塊來(lái)避免創(chuàng)建一些微小的限界上下文。通過(guò)分析分散在不同限界上下文中的服務(wù),你可能會(huì)發(fā)現(xiàn),模塊可以將多個(gè)限界上下文減少到一個(gè)。模塊也可以用來(lái)拆分開(kāi)發(fā)者的任務(wù)職責(zé),因此我們可以使用更加戰(zhàn)術(shù)化的手段來(lái)管理團(tuán)隊(duì)的任務(wù)分配。

白板時(shí)間

? 為你當(dāng)前的模型繪制一個(gè)限界上下文。

即便你還沒(méi)有一個(gè)顯式的模型,你也應(yīng)該從通用語(yǔ)言的角度考慮問(wèn)題。

? 在這個(gè)限界上下文內(nèi),填上主要的領(lǐng)域概念的名字。看看你能否發(fā)現(xiàn)那些被遺漏的概念,再看看哪些概念不應(yīng)該出現(xiàn)在上下文中。對(duì)于這兩個(gè)問(wèn)題,你會(huì)怎么解決?

采用語(yǔ)言驅(qū)動(dòng)來(lái)實(shí)施DDD時(shí),你得小心

這里的底線是:如果你沒(méi)有采用語(yǔ)言驅(qū)動(dòng),那么你就不算在和領(lǐng)域?qū)<乙黄鸸ぷ鱽?lái)創(chuàng)建限界上下文。認(rèn)真考慮一下限界上下文的大小,不要急于將其小型化。

與技術(shù)組件保持一致

將限界上下文想成是技術(shù)組件并無(wú)大礙,只是我們需要記住:技術(shù)組件并不能定義限界上下文。讓我們來(lái)看看一些構(gòu)成和部署限界上下文的常見(jiàn)做法。

當(dāng)使用IDE時(shí),比如Eclipse或者IntelliJ IDEA,一個(gè)限界上下文通常就是一個(gè)工程項(xiàng)目。當(dāng)使用Visual Studio和.NET時(shí),在同一個(gè)解決方案中將用戶界面、應(yīng)用服務(wù)和領(lǐng)域?qū)ο蠓蛛x在不同的子項(xiàng)目中是合理的。項(xiàng)目的源代碼可以只包含領(lǐng)域模型,也可以包含一些周邊的層(4)六邊形(4)區(qū)域等。對(duì)于項(xiàng)目的劃分是很靈活的。在使用Java時(shí),頂層包名通常表示限界上下文中頂層模塊的名字。對(duì)于上文中提到的例子,我們可以采用以下方式來(lái)定義包名:

com.mycompany.optimalpurchasing

限界上下文的源代碼結(jié)構(gòu)可以根據(jù)架構(gòu)職責(zé)做進(jìn)一步分解。下面是一些二級(jí)包名:

com.mycompany.optimalpurchasing.presentation

com.mycompany.optimalpurchasing.application

com.mycompany.optimalpurchasing.domain.model

com.mycompany.optimalpurchasing.infrastructure

請(qǐng)注意,即便存在這種模塊化的拆分,團(tuán)隊(duì)依然應(yīng)該只工作在一個(gè)限界上下文中。

一個(gè)團(tuán)隊(duì),一個(gè)限界上下文

將一個(gè)團(tuán)隊(duì)分配給一個(gè)限界上下文并不會(huì)限制團(tuán)隊(duì)的組織靈活性。這并不是說(shuō)團(tuán)隊(duì)不能按需安排,也不是說(shuō)一個(gè)團(tuán)隊(duì)中的成員不能到其他團(tuán)隊(duì)工作。一個(gè)公司應(yīng)該按照實(shí)際需要做出人事安排,這意味著我們需要組建一支組織良好的團(tuán)隊(duì),在該團(tuán)隊(duì)中,領(lǐng)域?qū)<液烷_(kāi)發(fā)者只關(guān)注于一個(gè)限界上下文的通用語(yǔ)言。如果你將多個(gè)團(tuán)隊(duì)分配給同一個(gè)限界上下文,那么每個(gè)團(tuán)隊(duì)都會(huì)使用各自的通用語(yǔ)言,這顯然是不好的。

兩個(gè)團(tuán)隊(duì)可能會(huì)合作設(shè)計(jì)一個(gè)共享內(nèi)核,而共享內(nèi)核并不是一個(gè)典型的限界上下文。這種上下文映射模式使兩個(gè)團(tuán)隊(duì)產(chǎn)生緊密的聯(lián)系,進(jìn)而需要兩個(gè)團(tuán)隊(duì)對(duì)模型的改變進(jìn)行不斷交流。這種建模方法并不常見(jiàn),并且我們應(yīng)該盡量避免這種情況。

在使用Java時(shí),我們可能從技術(shù)層面上將一個(gè)限界上下文放在一個(gè)JAR文件中,包括WAR或EAR文件。這種做法可能受到了模塊化的影響。松耦合的領(lǐng)域模型應(yīng)該放在不同的JAR文件中,這樣我們可以按照版本號(hào)對(duì)領(lǐng)域模型進(jìn)行單獨(dú)部署。對(duì)于大型的模型來(lái)說(shuō),這種做法是非常有用的。將單個(gè)大模型分成多個(gè)JAR文件也有助于版本管理,比如使用OSGi或者Java 8的Jigsaw模塊。因此,不同的高層模塊,包括它們的版本和依賴都可以通過(guò)捆包/模塊(bundles/modules)進(jìn)行管理。對(duì)于上文中的例子,至少存在4個(gè)以DDD的二級(jí)模塊表示的捆包/模塊。

對(duì)于Windows本地應(yīng)用程序的限界上下文來(lái)說(shuō),比如.NET平臺(tái),部署可以通過(guò)不同的DLL文件完成。這里我們可以將DLL文件等效于上述的JAR文件,對(duì)模型的分離也可以采用相似的方式。所有的公共語(yǔ)言運(yùn)行時(shí)(Common Language Runtime,CLR)模塊都是通過(guò)程序集(Assembly)進(jìn)行管理的。程序集的版本號(hào)和其所依賴程序集的版本號(hào)都記錄在程序集清單(Assembly Manifest)中。請(qǐng)參考[MSDN Assemblies]。

主站蜘蛛池模板: 张家川| 双流县| 迁安市| 墨江| 苏尼特左旗| 新宾| 南澳县| 分宜县| 西城区| 石城县| 德安县| 嘉定区| 潼南县| 麻阳| 海淀区| 扎囊县| 桃园市| 沧州市| 开原市| 张家口市| 赣榆县| 昭平县| 湟中县| 永修县| 克山县| 罗定市| 专栏| 外汇| 本溪市| 当阳市| 彰武县| 来安县| 彭州市| 万山特区| 岐山县| 白城市| 新余市| 梨树县| 六枝特区| 察隅县| 息烽县|