限界上下文的分而治之
在第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ā):?