1.什么時(shí)領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)
領(lǐng)域啟動(dòng)設(shè)計(jì)(DDD)是一種軟件開(kāi)發(fā)方法鲫凶,它可以幫助我們?cè)O(shè)計(jì)高質(zhì)量的軟件模型禀崖。
什么是領(lǐng)域模型?領(lǐng)域模型是關(guān)于某個(gè)特定業(yè)務(wù)領(lǐng)域的軟件模型螟炫。通常波附,領(lǐng)域模型通過(guò)對(duì)象模型來(lái)實(shí)現(xiàn),這些對(duì)象同時(shí)包含了數(shù)據(jù)和行為,并且表達(dá)了準(zhǔn)確的業(yè)務(wù)含義掸屡。
2.為什么需要DDD
DDD能夠幫助開(kāi)發(fā)人員與領(lǐng)域?qū)<医档蜏贤ǔ杀痉饽_(kāi)發(fā)出質(zhì)量更高的軟件模型。
3.什么是領(lǐng)域仅财?
廣義上講狈究,領(lǐng)域(Domain)即是一個(gè)組織所做的事件以及其中所包含的一切。每個(gè)組織都有它自己的業(yè)務(wù)范圍和做事方式盏求。這個(gè)業(yè)務(wù)范圍以及在其中所進(jìn)行的活動(dòng)便是領(lǐng)域抖锥。
領(lǐng)域既可表示整個(gè)業(yè)務(wù)系統(tǒng),也可以表示其中的某個(gè)核心域或支撐子域碎罚。當(dāng)談及到業(yè)務(wù)系統(tǒng)中的某個(gè)方面時(shí)宁改,使用”核心域“或”子域“以示區(qū)別。
為整個(gè)業(yè)務(wù)系統(tǒng)創(chuàng)建一個(gè)單一的魂莫、內(nèi)聚的还蹲、全功能式的模型。這并不是我們使用DDD的目的耙考。正好相反谜喊,DDD中,一個(gè)領(lǐng)域被分為若干子域倦始,領(lǐng)域模型在限界上下文中完成開(kāi)發(fā)斗遏。在開(kāi)發(fā)一個(gè)領(lǐng)域模型時(shí),我們關(guān)注的通常只是這個(gè)業(yè)務(wù)系統(tǒng)的某個(gè)方面鞋邑。試圖創(chuàng)建一個(gè)全功能的領(lǐng)域模型是非常困難的诵次,對(duì)領(lǐng)域拆分有助于我們成功。
幾乎所有軟件的領(lǐng)域都包含多個(gè)子域枚碗,這和軟件系統(tǒng)本身的復(fù)雜性沒(méi)有太大關(guān)系逾一。有時(shí)一個(gè)業(yè)務(wù)系統(tǒng)的成功取決于它所提供的多種功能,而將這些功能分開(kāi)對(duì)待是有好處的肮雨。
4.什么是子域
子域并不是一定要做得很大遵堵,并且包含很多功能。有時(shí)怨规,子域可以簡(jiǎn)單到只包含一套算法陌宿,但并不包含在核心域之中。簡(jiǎn)單的子域可以以模塊的形式從核心域中分離出來(lái)波丰,而不需要包含在笨重的子系統(tǒng)組件中壳坪。
很多軟件開(kāi)發(fā)者都認(rèn)為將所有東西都放在一個(gè)系統(tǒng)里面是一件好事。其實(shí)不管你向系統(tǒng)中添加多少功能掰烟,你都無(wú)法滿足每一個(gè)潛在客戶的需求爽蝴。如果不通過(guò)子域?qū)浖P瓦M(jìn)行劃分扩灯,事情將變得更加煩瑣,因?yàn)橄到y(tǒng)中的各個(gè)部分都是緊密聯(lián)系在一起的霜瘪。
5.什么是限界上下文
一般一個(gè)限界上下文對(duì)應(yīng)一個(gè)子域。另外一個(gè)限界上下文有可能包含的不只一個(gè)子域惧磺。
如一個(gè)圖書(shū)出版系統(tǒng)颖对,圖書(shū)生命周期的不同階段(不同的上下文環(huán)境)
概念設(shè)計(jì),計(jì)劃出書(shū)
聯(lián)系作者磨隘,簽訂合同
管理圖書(shū)的編輯過(guò)程
將圖書(shū)翻譯成其他語(yǔ)言
出版紙質(zhì)版或電子版圖書(shū)
市場(chǎng)營(yíng)銷
將圖書(shū)賣給銷售商或直接賣給讀者
將圖書(shū)發(fā)送給銷售商或讀者
以上所有階段缤底,我們用一個(gè)單一的概念對(duì)圖書(shū)建模顯然不行,每個(gè)階段“圖書(shū)都有不同的定義”番捂。一本書(shū)只有和作者簽訂了合同之后才能擁有書(shū)名个唧,而書(shū)名可能在編輯過(guò)程進(jìn)行修改。在編輯過(guò)程中设预,圖書(shū)包含了一系列的稿件徙歼,其中包括注釋和校正,走到最終定稿鳖枕。圖書(shū)印刷方使用頁(yè)面布局和封面板式印制圖書(shū)魄梯。營(yíng)銷員不需要編輯和印制,只需要圖書(shū)的簡(jiǎn)介宾符,圖書(shū)售后物流酿秸,勻人需要圖書(shū)的標(biāo)識(shí)碼、物流目的地魏烫、數(shù)目辣苏、尺寸和重量等。
如果我們用單一模型來(lái)處理所有這些階段會(huì)發(fā)生什么哄褒?概念混淆稀蟋、意見(jiàn)分歧和爭(zhēng)論是不可避免的。即使有時(shí)可能會(huì)得到一個(gè)正確的公共模型呐赡,但這種模型并不具有持久性糊治。
為解決這個(gè)問(wèn)題,我們應(yīng)該為每個(gè)階段創(chuàng)建各自的限界上下文罚舱,在每個(gè)限界上下文 井辜,都存在某種類型的圖書(shū)。在所有的上下文中管闷,不同類型的圖書(shū)對(duì)象將共享一個(gè)身份標(biāo)識(shí)粥脚,這個(gè)標(biāo)識(shí)可能是在概念設(shè)計(jì)階段創(chuàng)建的。然而包个,不同上下文中的圖書(shū)模型卻是不同的刷允。
如果在不同的限界上下文看到了完全相同的對(duì)象冤留,這通常意味著你的模型是錯(cuò)誤的,除非這些限界上下文使用了共享內(nèi)核(Shared Kernel)树灶。
限界上下文不僅僅只包含模型纤怒。雖然領(lǐng)域模型是限界上下文的主要“公民”。但是限界上下文并不只局限于容納模型天通,它通常標(biāo)定一個(gè)系統(tǒng)泊窘、一個(gè)應(yīng)該程序或一種業(yè)務(wù)服務(wù)(表示一系統(tǒng)用于實(shí)現(xiàn)業(yè)務(wù)用例的復(fù)雜組件)。有時(shí)像寒,限界上下文所包含的內(nèi)容可能比較少烘豹,比如,一個(gè)通用子域便可以只包含領(lǐng)域模型诺祸。
模型應(yīng)該用來(lái)驅(qū)動(dòng)數(shù)據(jù)庫(kù)和用戶界面的設(shè)計(jì)携悯,而不是反向驅(qū)動(dòng)。
如下模型驅(qū)動(dòng)數(shù)據(jù)庫(kù)設(shè)計(jì)筷笨。
`publicclassBacklogltemextendsEntity{privateBacklogItemld backlogltemld;privateBusinessPriority businessPriority;}CREATE TABLE'tbl_backlog_item'('backlog_item_id_id'varchar(36) NOTNULL,'business_priority_ratings_benefit'int NOTNULL,'business_priority_ratings_cost'int NOTNULL,'business_priority_ratings_penalty'int NOTNULL,'business_priority_ratings_risk'int NOTNULL,)ENGINE=InnoDB;
`
通常情況下憔鬼,系統(tǒng)/應(yīng)用程序的使用者并不只是人,還可能是另外的計(jì)算機(jī)系統(tǒng)胃夏。系統(tǒng)中有可能存在Web服務(wù)之類的組件逊彭。我們也可以使用REST資源來(lái)與模型交互,此時(shí)的REST資源即被稱為開(kāi)放主機(jī)服務(wù)(Open Host Service)构订,以上面向服務(wù)的組件都應(yīng)該位于上下文邊界之內(nèi)侮叮。
用戶界面和面向服務(wù)端點(diǎn)都會(huì)將操作委派給應(yīng)用服務(wù)。應(yīng)用服務(wù)包括比如安全和事務(wù)管理等悼瘾。對(duì)于模型來(lái)說(shuō)囊榜,應(yīng)用服務(wù)扮演的是一種門面模式Facade。同時(shí)亥宿,應(yīng)用服務(wù)還具有任務(wù)管理功能卸勺,它將來(lái)自用例流(Use Case Flow)的請(qǐng)求轉(zhuǎn)換成領(lǐng)域邏輯的執(zhí)行流。應(yīng)用服務(wù)也是位于上下文邊界之內(nèi)烫扼。
限界上下文主要用來(lái)封裝通用語(yǔ)言和領(lǐng)域?qū)ο笫锴螅瑫r(shí)它也包含了那些為領(lǐng)域模型提供交互手段和輔助功能 的內(nèi)容。
不要用架構(gòu)來(lái)指導(dǎo)設(shè)計(jì)映企,而不是通用語(yǔ)言悟狱。一些平臺(tái)、框架或者基礎(chǔ)設(shè)施通常是用來(lái)打包和部署組件堰氓,它們可能影響我們對(duì)限界上下文的設(shè)計(jì)挤渐,此時(shí)我們會(huì)從技術(shù)層面而不是語(yǔ)言邊界來(lái)考慮問(wèn)題。
不要為了分配任務(wù)而拆分限界上下文双絮。我們沒(méi)有必要為了管理技術(shù)資源而創(chuàng)建一些假的上下文邊界浴麻。
采用語(yǔ)言驅(qū)動(dòng)來(lái)實(shí)施DDD得问,這里地底線:如果沒(méi)有采用語(yǔ)言驅(qū)動(dòng),那么你就不算在和領(lǐng)域?qū)<乙黄鸸ぷ鱽?lái)創(chuàng)建限界上下文软免。認(rèn)真考慮限界上下文的大小宫纬,不要急于將其小型化。
與技術(shù)組件保護(hù)一致膏萧。技術(shù)組件并不能定義限界上下文漓骚。一個(gè)限界上下文通常就一個(gè)工程項(xiàng)目。VS中在同一個(gè)解決方案中將用戶界面向抢、應(yīng)用服務(wù)和領(lǐng)域?qū)ο蠓蛛x在不同的子項(xiàng)止中是合理的。項(xiàng)目源代碼可以只包含領(lǐng)域模型胚委,也可以包含一些周邊的層匱乏六邊形區(qū)域挟鸠。
在使用java時(shí),頂層包名通常表示限界上下文中頂層模塊的名字亩冬。