DDD - 領(lǐng)域驅(qū)動設(shè)計對軟件復(fù)雜度的應(yīng)對(下)

限界上下文的分而治之

在第1-4課中分析緩存訪問接口的歸屬時摆昧,我們將接口放在了系統(tǒng)的應(yīng)用層顿苇。從層次的職責(zé)來看峭咒,這樣的設(shè)計是合理的,但它卻使得系統(tǒng)的應(yīng)用層變得更加臃腫纪岁,職責(zé)也變得不夠單一了凑队。這是分層架構(gòu)與六邊形架構(gòu)的局限所在,因為這兩種架構(gòu)模式僅僅體現(xiàn)了軟件系統(tǒng)的邏輯劃分幔翰。倘若我們將一個軟件系統(tǒng)視為一個縱橫交錯的魔方漩氨,前述的邏輯劃分僅僅是一種水平方向的劃分;至于垂直方向的劃分遗增,則是面向垂直業(yè)務(wù)的切割叫惊。這種方式更利于控制軟件系統(tǒng)的規(guī)模,將一個龐大的軟件系統(tǒng)劃分為松散耦合的多個小系統(tǒng)的組合做修。

針對前述案例霍狰,我們可以將緩存視為一個獨立的子系統(tǒng),它同樣擁有自己的業(yè)務(wù)邏輯和技術(shù)實現(xiàn)饰及,因而也可以為其建立屬于緩存領(lǐng)域的分層架構(gòu)蔗坯。在架構(gòu)的宏觀視角,這個緩存子系統(tǒng)與訂單子系統(tǒng)處于同一個抽象層次燎含。這一概念在領(lǐng)域驅(qū)動設(shè)計中宾濒,被稱之為限界上下文(Bounded Context)。

針對龐大而復(fù)雜的問題域瘫镇,限界上下文采用了“分而治之”的思想對問題域進(jìn)行了分解鼎兽,有效地控制了問題域的規(guī)模答姥,進(jìn)而控制了整個系統(tǒng)的規(guī)模。一旦規(guī)模減小谚咬,無論業(yè)務(wù)復(fù)雜度還是技術(shù)復(fù)雜度鹦付,都會得到顯著的降低,在對領(lǐng)域進(jìn)行分析以及建模時择卦,也能變得更加容易敲长。限界上下文對整個系統(tǒng)進(jìn)行了劃分,在將一個大系統(tǒng)拆分為一個個小系統(tǒng)后秉继,我們再利用分層架構(gòu)與六邊形架構(gòu)思想對其進(jìn)行邏輯分層祈噪,以確保業(yè)務(wù)邏輯與技術(shù)實現(xiàn)的隔離,其設(shè)計會變得更易于把控尚辑,系統(tǒng)的架構(gòu)也會變得更加清晰辑鲤。

案例:限界上下文幫助架構(gòu)的演進(jìn)

國際報稅系統(tǒng)是為跨國公司的駐外出差雇員(系統(tǒng)中被稱之為 Assignee)提供方便一體化的稅收信息填報平臺「懿纾客戶是一家會計師事務(wù)所月褥,該事務(wù)所的專員(Admin)通過該平臺可以收集雇員提交的報稅信息,然后對這些信息進(jìn)行稅務(wù)評審瓢喉。如果 Admin 評審出信息有問題宁赤,則返回給 Assignee 重新修改和填報。一旦信息確認(rèn)無誤栓票,則進(jìn)行稅收分析和計算决左,并獲得最終的稅務(wù)報告提交給當(dāng)?shù)卣约肮蛦T本人。

系統(tǒng)主要涉及的功能包括:

駐外出差雇員的薪酬與福利

稅收計劃與合規(guī)評審

對稅收評審的分配管理

稅收策略設(shè)計與評審

對駐外出差雇員的稅收合規(guī)評審

全球的 Visa 服務(wù)

主要涉及的用戶角色包括:

Assignee:駐外出差雇員

Admin:稅務(wù)專員

Client:出差雇員的雇主

在早期的架構(gòu)設(shè)計時走贪,架構(gòu)師并沒有對整個系統(tǒng)的問題域進(jìn)行拆分佛猛,而是基于用戶角色對系統(tǒng)進(jìn)行了簡單粗暴的劃分,分為了兩個相對獨立的子系統(tǒng):Frond End 與 Office End厉斟,這兩個子系統(tǒng)單獨部署挚躯,分別面向 Assignee 與 Admin。系統(tǒng)之間的集成則通過消息和 Web Service 進(jìn)行通信擦秽。兩個子系統(tǒng)的開發(fā)分屬不同的團(tuán)隊码荔,F(xiàn)rond End 由美國的團(tuán)隊負(fù)責(zé)開發(fā)與維護(hù),而 Office End 則由印度的團(tuán)隊負(fù)責(zé)感挥。整個架構(gòu)如下圖所示:

采用這種架構(gòu)面臨的問題如下:

龐大的代碼庫:整個 Front End 和 Office End 都沒有做物理分解缩搅,隨著需求的增多,代碼庫會變得格外龐大触幼。

分散的邏輯:系統(tǒng)分解的邊界是不合理的硼瓣,沒有按照業(yè)務(wù)分解,而是按照用戶的角色進(jìn)行分解,因而導(dǎo)致大量相似的邏輯分散在兩個不同的子系統(tǒng)中堂鲤。

重復(fù)的數(shù)據(jù):兩個子系統(tǒng)中存在業(yè)務(wù)重疊亿傅,因而也導(dǎo)致了部分?jǐn)?shù)據(jù)的重復(fù)。

復(fù)雜的集成:Front End 與 Office End 因為某些相關(guān)的業(yè)務(wù)需要彼此通信瘟栖,這種集成關(guān)系是雙向的葵擎,且由兩個不同的團(tuán)隊開發(fā),導(dǎo)致集成的接口混亂半哟,消息協(xié)議多樣化酬滤。

知識未形成共享:兩個團(tuán)隊完全獨立開發(fā),沒有掌握端對端的整體流程寓涨,團(tuán)隊之間沒有形成知識的共享盯串。

無法應(yīng)對需求變化:新增需求包括對國際旅游、Visa 的支持戒良,現(xiàn)有系統(tǒng)的架構(gòu)無法很好地支持這些變化体捏。

采用領(lǐng)域驅(qū)動設(shè)計,我們將架構(gòu)的主要關(guān)注點放在了“領(lǐng)域”蔬墩,與客戶進(jìn)行了充分的需求溝通和交流译打。通過分析已有系統(tǒng)的問題域,結(jié)合客戶提出的新需求拇颅,對整個問題域進(jìn)行了梳理,并利用限界上下文對問題域進(jìn)行了分解乔询,獲得了如下限界上下文:

Account Management:管理用戶的身份與配置信息樟插;

Calendar Management:管理用戶的日程與旅行足跡。

之后竿刁,客戶希望能改進(jìn)需求黄锤,做到全球范圍內(nèi)的工作指派與管理,目的在于提高公司的運營效率食拜。通過對領(lǐng)域的分析鸵熟,我們又識別出兩個限界上下文。在原有的系統(tǒng)架構(gòu)中负甸,這兩個限界上下文同時處于 Front End 與 Office End 之中流强,屬于重復(fù)開發(fā)的業(yè)務(wù)邏輯:

Work Record Management:實現(xiàn)工作的分配與任務(wù)的跟蹤;

File Sharing:目的是實現(xiàn)客戶與會計師事務(wù)所之間的文件交換呻待。

隨著我們對領(lǐng)域知識的逐漸深入理解與分析打月,又隨之識別出如下限界上下文:

Consent:管理合法的遵守法規(guī)的狀態(tài);

Notification:管理系統(tǒng)與客戶之間的交流蚕捉;

Questionnaire:對問卷調(diào)查的數(shù)據(jù)收集奏篙。

這個領(lǐng)域分析的過程實際上就是通過對領(lǐng)域的分析而引入限界上下文對問題域進(jìn)行分解,通過降低規(guī)模的方式來降低問題域的復(fù)雜度迫淹;同時秘通,通過為模型確定清晰的邊界为严,使得系統(tǒng)的結(jié)構(gòu)變得更加的清晰,從而保證了領(lǐng)域邏輯的一致性肺稀。一旦確定了清晰的領(lǐng)域模型梗脾,就能夠幫助我們更加容易地發(fā)現(xiàn)系統(tǒng)的可重用點與可擴(kuò)展點,并遵循“高內(nèi)聚盹靴、松耦合”的原則對系統(tǒng)職責(zé)進(jìn)行合理分配炸茧,再輔以分層架構(gòu)以劃分邏輯邊界,如下圖所示:

我們將識別出來的限界上下文定義為微服務(wù)稿静,并對外公開 REST 服務(wù)接口梭冠。UI Applications 是一個薄薄的展現(xiàn)層改备,它會調(diào)用后端的 RESTful 服務(wù)控漠,也使得服務(wù)在保證接口不變的前提下能夠單獨演化。每個服務(wù)都是獨立的悬钳,可以單獨部署盐捷,因而可以針對服務(wù)建立單獨的代碼庫和對應(yīng)的特性團(tuán)隊(Feature Team)。服務(wù)的重用性和可擴(kuò)展性也有了更好的保障默勾,服務(wù)與 UI 之間的集成變得更簡單碉渡,整個架構(gòu)會更加清晰。

領(lǐng)域模型對領(lǐng)域知識的抽象

領(lǐng)域模型是對業(yè)務(wù)需求的一種抽象母剥,其表達(dá)了領(lǐng)域概念滞诺、領(lǐng)域規(guī)則以及領(lǐng)域概念之間的關(guān)系。一個好的領(lǐng)域模型是對統(tǒng)一語言的可視化表示环疼,通過它可以減少需求溝通可能出現(xiàn)的歧義习霹;通過提煉領(lǐng)域知識,并運用抽象的領(lǐng)域模型去表達(dá)炫隶,就可以達(dá)到對領(lǐng)域邏輯的化繁為簡淋叶。模型是封裝,實現(xiàn)了對業(yè)務(wù)細(xì)節(jié)的隱藏伪阶;模型是抽象煞檩,提取了領(lǐng)域知識的共同特征,保留了面對變化時能夠良好擴(kuò)展的可能性望门。

案例:項目管理系統(tǒng)的領(lǐng)域模型

我們開發(fā)的項目管理系統(tǒng)需要支持多種軟件項目管理流程形娇,如瀑布、RUP筹误、XP 或者 Scrum桐早,這些項目管理流程是迥然不同的,如果需要各自提供不同的解決方案,則會使得系統(tǒng)的模型變得非常復(fù)雜哄酝,也可能會引入許多不必要的重復(fù)友存。通過領(lǐng)域建模,我們可以對項目管理領(lǐng)域的知識進(jìn)行抽象陶衅,尋找具有共同特征的領(lǐng)域概念屡立。這就需要分析各種項目管理流程的主要特征與表現(xiàn),才能從中提煉出領(lǐng)域模型搀军。

瀑布式軟件開發(fā)由需求膨俐、分析、設(shè)計罩句、編碼焚刺、測試、驗收六個階段構(gòu)成门烂,每個階段都由不同的活動構(gòu)成乳愉,這些活動可能是設(shè)計或開發(fā)任務(wù),也可能是召開評審會屯远。流程如下圖所示:

RUP 清晰地劃分了四個階段:先啟階段(Inception)蔓姚、細(xì)化階段(Elaboration)、構(gòu)造階段(Construction)與交付階段(Transition)慨丐,每個階段可以包含一到多個迭代坡脐,每個迭代有不同的工作,如業(yè)務(wù)建模咖气、分析設(shè)計挨措、配置與變更管理等,RUP 的流程如下圖所示:

XP 作為一種敏捷方法崩溪,采用了迭代的增量式開發(fā),提倡為客戶交付具有業(yè)務(wù)價值的可運行軟件斩松。在執(zhí)行交付計劃之前伶唯,XP 要求團(tuán)隊對系統(tǒng)的架構(gòu)做一次預(yù)研(Architectual Spike,又被譯為架構(gòu)穿刺)惧盹。當(dāng)架構(gòu)的初始方案確定后乳幸,就可以進(jìn)入每次小版本的交付。每個小版本交付又被劃分為多個周期相同的迭代钧椰。在迭代過程中粹断,要求執(zhí)行一些必須的活動,如編寫用戶故事嫡霞、故事點估算瓶埋、驗收測試等。XP 的流程如下圖所示:

Scrum 同樣是迭代的增量開發(fā)過程。項目在開始之初养筒,需要在準(zhǔn)備階段確定系統(tǒng)愿景曾撤、梳理業(yè)務(wù)用例、確定產(chǎn)品待辦項(Product Backlog)晕粪、制定發(fā)布計劃以及組建團(tuán)隊挤悉。一旦在確定了產(chǎn)品待辦項以及發(fā)布計劃之后,就進(jìn)入了 Sprint 迭代階段巫湘。Sprint 迭代過程是一個固定時長的項目過程装悲,在這個過程中,整個團(tuán)隊需要召開計劃會議尚氛、每日站會诀诊、評審會議和回顧會議。Scrum 的流程如下圖所示:

不同的項目管理流程具有不同的業(yè)務(wù)概念怠褐。例如畏梆,瀑布式開發(fā)分為了六個階段,但卻沒有發(fā)布和迭代的概念奈懒;RUP 沒有發(fā)布的概念奠涌,而 Scrum 又為迭代引入了 Sprint 的概念。

不同的項目管理流程具有不同的業(yè)務(wù)規(guī)則磷杏。例如溜畅,RUP 的四個階段會包含多個迭代周期,每個迭代周期都需要完成對應(yīng)的工作极祸,只是不同的工作在不同階段所占的比重不同慈格。XP 需要在進(jìn)入發(fā)布階段之前,進(jìn)行架構(gòu)預(yù)研遥金,而在每次小版本發(fā)布之前浴捆,都需要進(jìn)行驗收測試和客戶驗收。Scrum 的 Sprint 是一個基本固定的流程稿械,每個迭代召開的四會(計劃會議选泻、評審會議、回顧會議與每日站會)都有明確的目標(biāo)美莫。

領(lǐng)域建模就是要從這些紛繁復(fù)雜的領(lǐng)域邏輯中尋找到能夠表示項目管理領(lǐng)域的概念页眯,并利用面向?qū)ο蠼7妒交蚱渌妒綄Ω拍钸M(jìn)行抽象,并確定它們之間的關(guān)系厢呵。經(jīng)過對這些項目管理流程的分析窝撵,我們雖然發(fā)現(xiàn)在業(yè)務(wù)概念和規(guī)則上確有不同之處,但由于它們都?xì)w屬于軟件開發(fā)領(lǐng)域襟铭,我們自然也能尋找到某些共同特征的蛛絲馬跡碌奉。

首先短曾,從項目管理系統(tǒng)的角度看,無論針對何種項目管理流程道批,我們的主題需求是不變的错英,就是要為這些管理流程制定軟件開發(fā)計劃(Plan)。不同之處在于隆豹,計劃可以由多個階段(Phase)組成椭岩,也可以由多個發(fā)布(Release)組成。一些項目管理流程沒有發(fā)布的概念璃赡,我們可以認(rèn)為是一個發(fā)布判哥。那么,到底是發(fā)布包含了多個階段碉考,還是階段包含了多個發(fā)布呢塌计?我們發(fā)現(xiàn)在 XP 中,明顯地劃分了兩個階段:Architecture Spike 與 Release Planning侯谁,而發(fā)布只屬于 Release Planning 階段锌仅。因而從概念內(nèi)涵上,我們可以認(rèn)為是階段(Phase)包含了發(fā)布(Release)墙贱。每個發(fā)布又包含了一到多個迭代(Iteration)热芹,至于 Scrum 的 Sprint 概念其實可以看做是迭代的一種特例。每個迭代可以開展多種不同的活動(Activity)惨撇,這些活動可以是整個團(tuán)隊參與的會議伊脓,也可以是部分成員或特定角色執(zhí)行的實踐。對于計劃而言魁衙,我們還需要跟蹤任務(wù)(Task)报腔。與活動不同,任務(wù)具有明確的計劃起止時間剖淀、實際起止時間纯蛾、工作量、優(yōu)先級與承擔(dān)人纵隔。

于是茅撞,我們提煉出如下的統(tǒng)一領(lǐng)域模型:

為了項目管理者更加方便地制定項目計劃,產(chǎn)品經(jīng)理提出了計劃模板功能巨朦。當(dāng)管理者選擇對應(yīng)的項目管理生命周期類型后,系統(tǒng)會自動創(chuàng)建滿足其規(guī)則的初始計劃剑令『龋基于該需求,我們更新了之前的領(lǐng)域模型:

在增加的領(lǐng)域模型中吁津,LifeCycle Specification 是一個隱含的概念棚蓄,遵循領(lǐng)域驅(qū)動設(shè)計提出的規(guī)格(Specification)模式堕扶,封裝了項目開發(fā)生命周期的約束規(guī)則。

領(lǐng)域模型以可視化的方式清晰地表達(dá)了業(yè)務(wù)含義梭依,我們可以根據(jù)這個模型來指導(dǎo)后面的程序設(shè)計與編碼實現(xiàn)稍算。當(dāng)增加新的需求或者需求發(fā)生變化時,我們能夠敏銳地捕捉到現(xiàn)有模型的不匹配之處役拴,并對其進(jìn)行更新糊探。領(lǐng)域模型傳遞了知識,可以作為交流的載體河闰,符合人們的心智模型科平,有利于讓開發(fā)人員從紛繁復(fù)雜的業(yè)務(wù)中解脫出來。這是領(lǐng)域驅(qū)動設(shè)計針對第04課中遇到的第三個問題——控制業(yè)務(wù)復(fù)雜度的解答姜性。

分享交流

我們?yōu)榉窒斫涣鲃?chuàng)建了微信交流群瞪慧,以方便更有針對性地討論課程相關(guān)問題。入群方式請?zhí)砑幼髡呶⑿盘枺骸窻obynn-D」部念,并注明「DDD」弃酌,謝謝~

你的分享不僅幫助他人,更會提升自己儡炼。

本文首發(fā):?

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末妓湘,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子射赛,更是在濱河造成了極大的恐慌多柑,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,464評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件楣责,死亡現(xiàn)場離奇詭異竣灌,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)秆麸,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,033評論 3 399
  • 文/潘曉璐 我一進(jìn)店門初嘹,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人沮趣,你說我怎么就攤上這事屯烦。” “怎么了房铭?”我有些...
    開封第一講書人閱讀 169,078評論 0 362
  • 文/不壞的土叔 我叫張陵驻龟,是天一觀的道長。 經(jīng)常有香客問我缸匪,道長翁狐,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,979評論 1 299
  • 正文 為了忘掉前任凌蔬,我火速辦了婚禮露懒,結(jié)果婚禮上闯冷,老公的妹妹穿的比我還像新娘。我一直安慰自己懈词,他們只是感情好蛇耀,可當(dāng)我...
    茶點故事閱讀 69,001評論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著坎弯,像睡著了一般纺涤。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上荞怒,一...
    開封第一講書人閱讀 52,584評論 1 312
  • 那天洒琢,我揣著相機(jī)與錄音,去河邊找鬼褐桌。 笑死衰抑,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的荧嵌。 我是一名探鬼主播呛踊,決...
    沈念sama閱讀 41,085評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼啦撮!你這毒婦竟也來了谭网?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 40,023評論 0 277
  • 序言:老撾萬榮一對情侶失蹤赃春,失蹤者是張志新(化名)和其女友劉穎愉择,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體织中,經(jīng)...
    沈念sama閱讀 46,555評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡锥涕,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,626評論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了狭吼。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片层坠。...
    茶點故事閱讀 40,769評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖刁笙,靈堂內(nèi)的尸體忽然破棺而出破花,到底是詐尸還是另有隱情,我是刑警寧澤疲吸,帶...
    沈念sama閱讀 36,439評論 5 351
  • 正文 年R本政府宣布座每,位于F島的核電站,受9級特大地震影響摘悴,放射性物質(zhì)發(fā)生泄漏尺栖。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 42,115評論 3 335
  • 文/蒙蒙 一烦租、第九天 我趴在偏房一處隱蔽的房頂上張望延赌。 院中可真熱鬧,春花似錦叉橱、人聲如沸挫以。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,601評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽掐松。三九已至,卻和暖如春粪小,著一層夾襖步出監(jiān)牢的瞬間大磺,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,702評論 1 274
  • 我被黑心中介騙來泰國打工探膊, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留杠愧,地道東北人。 一個月前我還...
    沈念sama閱讀 49,191評論 3 378
  • 正文 我出身青樓逞壁,卻偏偏與公主長得像流济,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子腌闯,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,781評論 2 361

推薦閱讀更多精彩內(nèi)容