DDD - 限界上下文的控制力(下)

限界上下文封裝了應(yīng)用邊界

架構(gòu)師在劃分限界上下文時(shí)可柿,不能只滿(mǎn)足于業(yè)務(wù)邊界的確立丙者,還得從控制技術(shù)復(fù)雜度的角度來(lái)考慮技術(shù)實(shí)現(xiàn)械媒,從而做出對(duì)系統(tǒng)質(zhì)量屬性的響應(yīng)與承諾,這種技術(shù)因素影響限界上下文劃分的例子可謂是不勝枚舉痢虹。

高并發(fā)

一個(gè)外賣(mài)系統(tǒng)的訂單業(yè)務(wù)與門(mén)店奖唯、支付等領(lǐng)域存在業(yè)務(wù)相關(guān)性糜值,然而考慮外賣(mài)業(yè)務(wù)的特殊性,它往往會(huì)在某個(gè)特定的時(shí)間段比如中午 11 點(diǎn)到 13 點(diǎn)會(huì)達(dá)到訂單量的高峰值瓢阴。系統(tǒng)面臨高并發(fā)壓力荣恐,同時(shí)還需要快速地處理每一筆外賣(mài)訂單累贤,與電商系統(tǒng)的訂單業(yè)務(wù)不同臼膏,外賣(mài)訂單具有周期短的時(shí)效性,必須在規(guī)定較短的時(shí)間內(nèi)走完從下訂單嚷硫、支付、門(mén)店接單到配送等整個(gè)流程脆贵。如果我們將訂單業(yè)務(wù)從整個(gè)系統(tǒng)中剝離出來(lái)卖氨,作為一個(gè)單獨(dú)的限界上下文對(duì)其進(jìn)行設(shè)計(jì)负懦,就可以從物理架構(gòu)上保證它的獨(dú)立性纸厉,在資源分配上做到高優(yōu)先級(jí)地?cái)U(kuò)展,在針對(duì)領(lǐng)域進(jìn)行設(shè)計(jì)時(shí)村斟,盡可能地引入異步化與并行化,來(lái)提高服務(wù)的響應(yīng)能力孩灯。

功能重用

對(duì)于一個(gè)面向企業(yè)雇員的國(guó)際報(bào)稅系統(tǒng)峰档,報(bào)稅業(yè)務(wù)、旅游業(yè)務(wù)與 Visa 業(yè)務(wù)都需要賬戶(hù)功能的支撐掀亩。系統(tǒng)對(duì)用戶(hù)的注冊(cè)與登錄有較為復(fù)雜的業(yè)務(wù)處理流程槽棍。對(duì)于一個(gè)新用戶(hù)而言抬驴,系統(tǒng)會(huì)向客戶(hù)企業(yè)的雇員發(fā)送邀請(qǐng)信布持,收到邀請(qǐng)信的用戶(hù)只有通過(guò)了問(wèn)題驗(yàn)證才能成為合法的注冊(cè)用戶(hù),否則該用戶(hù)的賬戶(hù)就會(huì)被鎖定按傅,稱(chēng)之為 Registration Locked唯绍。在用戶(hù)使用期間,若違背了系統(tǒng)要求的驗(yàn)證條件裂问,也可能會(huì)根據(jù)不同的條件鎖定賬戶(hù)堪簿,分別稱(chēng)之為 Soft Locked 和 Hard Locked皮壁。只有用戶(hù)提供了可以證明其合法身份的材料,其賬戶(hù)才能被解鎖虑瀑。

賬戶(hù)管理并非系統(tǒng)的核心領(lǐng)域舌狗,但與賬戶(hù)相關(guān)的業(yè)務(wù)邏輯卻相對(duì)復(fù)雜痛侍。從功能重用的角度考慮魔市,我們應(yīng)該將賬戶(hù)管理作為一個(gè)單獨(dú)的限界上下文待德,以滿(mǎn)足不同核心領(lǐng)域?qū)@一功能的重用,避免了重復(fù)開(kāi)發(fā)和重復(fù)代碼绘闷。

實(shí)時(shí)性

在電商系統(tǒng)中簸喂,商品自然是核心燎潮,而價(jià)格(Price)則是商品概念的一個(gè)重要屬性确封。倘若僅僅從業(yè)務(wù)的角度考慮再菊,在進(jìn)行領(lǐng)域建模時(shí)纠拔,價(jià)格僅僅是一個(gè)普通的領(lǐng)域值對(duì)象泛豪,可倘若該電商系統(tǒng)的商品數(shù)量達(dá)到數(shù)十億種诡曙,每天獲取商品信息的調(diào)用量在峰值達(dá)到數(shù)億乃至數(shù)百億次時(shí)价卤,價(jià)格就不再是業(yè)務(wù)問(wèn)題,而變成了技術(shù)問(wèn)題床嫌。對(duì)價(jià)格的每一次變更都需要及時(shí)同步厌处,真實(shí)地反饋給電商客戶(hù)盖文。

為了保證這種在高并發(fā)情況下的實(shí)時(shí)性五续,我們就需要專(zhuān)門(mén)針對(duì)價(jià)格領(lǐng)域提供特定的技術(shù)方案龄恋,例如郭毕,通過(guò)讀寫(xiě)分離、引入 Redis 緩存扳肛、異步數(shù)據(jù)同步等設(shè)計(jì)方法挖息。此時(shí)兽肤,價(jià)格領(lǐng)域?qū)⒆鳛橐粋€(gè)獨(dú)立的限界上下文,形成自己與眾不同的架構(gòu)方案幢码,同時(shí)症副,為價(jià)格限界上下文提供專(zhuān)門(mén)的資源政基,并在服務(wù)設(shè)計(jì)上保證無(wú)狀態(tài),從而滿(mǎn)足快速擴(kuò)容的架構(gòu)約束腋么。

第三方服務(wù)集成

一個(gè)電商系統(tǒng)需要支持多種常見(jiàn)的支付渠道咕娄,如微信支付、支付寶珊擂、中國(guó)銀聯(lián)以及各大主要銀行的支付圣勒。買(mǎi)家在購(gòu)買(mǎi)商品以及進(jìn)行退貨業(yè)務(wù)時(shí),可以選擇適合自己的支付渠道完成支付摧扇。電商系統(tǒng)需要與這些第三方支付系統(tǒng)進(jìn)行集成圣贸。不同的支付系統(tǒng)公開(kāi)的 API 并不相同,安全扛稽、加密以及支付流程對(duì)支付的要求也不相同吁峻。

在技術(shù)實(shí)現(xiàn)上在张,一方面我們希望為支付服務(wù)的客戶(hù)端提供完全統(tǒng)一的支付接口用含,以保證調(diào)用上的便利性與一致性,另一方面我們希望能解除第三方支付服務(wù)與電商系統(tǒng)內(nèi)部模塊之間的耦合帮匾,避免引起“供應(yīng)商鎖定(Vender Lock)”啄骇,也能更好地應(yīng)對(duì)第三方支付服務(wù)的變化。因此瘟斜,我們需要將這種集成劃分為一個(gè)單獨(dú)的限界上下文缸夹。

遺留系統(tǒng)

當(dāng)我們?cè)谶\(yùn)用領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)對(duì)北美醫(yī)療內(nèi)容管理系統(tǒng)提出的新需求進(jìn)行設(shè)計(jì)與開(kāi)發(fā)時(shí),這個(gè)系統(tǒng)的已有功能已經(jīng)運(yùn)行了數(shù)年時(shí)間螺句。我們的任務(wù)是在現(xiàn)有系統(tǒng)中增加一個(gè)全新的 Find & Replace 模塊虽惭,其目的是為系統(tǒng)中的醫(yī)療內(nèi)容提供針對(duì)醫(yī)療術(shù)語(yǔ)、藥品以及藥品成分的查詢(xún)與替換蛇尚。這個(gè)系統(tǒng)已經(jīng)定義了自己的領(lǐng)域模型芽唇。這些領(lǐng)域模型與新增模塊的領(lǐng)域有相似之處。但是佣蓉,為了避免已有模型對(duì)新開(kāi)發(fā)模塊的影響披摄,我們應(yīng)該將這些已有功能視為具有技術(shù)債的遺留系統(tǒng)亲雪,并將該遺留系統(tǒng)整體視為一個(gè)限界上下文。

通過(guò)這個(gè)遺留系統(tǒng)限界上下文的邊界保護(hù)疚膊,就可以避免我們?cè)陂_(kāi)發(fā)過(guò)程中陷入遺留系統(tǒng)龐大代碼庫(kù)的泥沼义辕。由于新增需求與原有系統(tǒng)在業(yè)務(wù)上存在交叉功能,因而可能失去了部分代碼的重用機(jī)會(huì)寓盗,卻能讓我們甩開(kāi)遺留系統(tǒng)的束縛灌砖,放開(kāi)雙手運(yùn)用領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)的思想建立自己的領(lǐng)域模型與架構(gòu)。只有在需要調(diào)用遺留系統(tǒng)的時(shí)候傀蚌,作為調(diào)用者站在遺留系統(tǒng)限界上下文之外基显,去思考我們需要的服務(wù),然后酌情地考慮模型對(duì)象之間的轉(zhuǎn)換以及服務(wù)接口的提取善炫。

如上的諸多案例都是從技術(shù)層面而非業(yè)務(wù)層面為系統(tǒng)劃分了應(yīng)用邊界撩幽,這種邊界是由限界上下文完成的,通過(guò)它形成了對(duì)技術(shù)實(shí)現(xiàn)的隔離箩艺,避免不同的技術(shù)方案選擇互相干擾導(dǎo)致架構(gòu)的混亂窜醉。

案例:生成稅務(wù)報(bào)告的技術(shù)風(fēng)險(xiǎn)

國(guó)際稅務(wù)系統(tǒng)需要在政府指定的周期提交稅務(wù)報(bào)告,凡是滿(mǎn)足條件的 Assignee 都需要在規(guī)定時(shí)間內(nèi)生成稅務(wù)報(bào)告艺谆。在生成稅務(wù)報(bào)告時(shí)榨惰,需要對(duì) Assignee 提交的 Questionnaire 數(shù)據(jù)進(jìn)行合并,并基于稅收策略與 Assignee 個(gè)人情況執(zhí)行計(jì)算静汤。生成稅務(wù)報(bào)告的時(shí)序圖如下所示:

代碼如下所示:

public class TaxReportGenerator {? ? @Service

? ? private HtmlReportProvider provider;? ? @Service

? ? private PdfConverter converter;? ? @Repository

? ? private ReportRepository repository;? ? public void generateReports(String calendarReportName) {

? ? ? ? Byte[]? bytes = provider.getHtmlBytes(calendarReportName);

? ? ? ? Byte[] pdfBytes = converter.getPdfBytes(bytes, provider.getTitle());

? ? ? ? repository.save(new TaxReport(pdfBytes));

? ? }

}

由于每個(gè) Assignee 的報(bào)告內(nèi)容多琅催,生成的 PDF 文件較大,使得生成稅務(wù)報(bào)告的單位時(shí)間也較長(zhǎng)虫给。在最初用戶(hù)量較少的情況下藤抡,所有稅務(wù)報(bào)告的生成時(shí)間在客戶(hù)預(yù)期范圍內(nèi),因而并未針對(duì)報(bào)告生成功能做特別的架構(gòu)設(shè)計(jì)狰右。后來(lái)杰捂,隨著系統(tǒng)的 Assignee 用戶(hù)數(shù)增多,在提交稅務(wù)報(bào)告的高峰期時(shí)棋蚌,報(bào)告生成的時(shí)間越來(lái)越長(zhǎng)。以高峰期需要提交 2000 個(gè)稅務(wù)報(bào)告為例挨队,如果每個(gè)稅務(wù)報(bào)告的提交時(shí)間為 1 分鐘谷暮,在只有一個(gè) worker 的情況下,我們需要2000*1/60=33小時(shí)盛垦。

由于單個(gè)稅務(wù)報(bào)告的生成性能已經(jīng)達(dá)到瓶頸湿弦,沒(méi)有優(yōu)化的空間,因而需要在架構(gòu)層面對(duì)方案進(jìn)行優(yōu)化腾夯,包括如下兩方面:

引入消息隊(duì)列颊埃,將整個(gè)稅務(wù)報(bào)告生成過(guò)程拆分為消息隊(duì)列的生產(chǎn)者和消費(fèi)者蔬充。處于應(yīng)用服務(wù)器一端的生產(chǎn)者僅負(fù)責(zé)收集稅務(wù)報(bào)告需要的數(shù)據(jù),而將生成報(bào)告的職責(zé)交給消息隊(duì)列的消費(fèi)者班利,從而減輕應(yīng)用服務(wù)器的壓力饥漫。

將報(bào)告生成識(shí)別為限界上下文,定義為可以單獨(dú)部署的微服務(wù)罗标,以便于靈活地實(shí)現(xiàn)水平擴(kuò)展庸队。

如下圖是我們基于技術(shù)實(shí)現(xiàn)識(shí)別出來(lái)的 report 限界上下文。在上下文邊界內(nèi)闯割,引入了消息隊(duì)列彻消。server 作為生成者,在收集了稅務(wù)數(shù)據(jù)后組裝消息宙拉,然后將消息入隊(duì)宾尚;作為消費(fèi)者的 worker 訂閱該消息,一旦消息傳遞到達(dá)谢澈,則負(fù)責(zé)生成報(bào)告:

無(wú)論是 server 還是 worker央勒,皆為并行執(zhí)行,且在理論上可以無(wú)限制地水平擴(kuò)展澳化。倘若在性能上無(wú)法滿(mǎn)足要求崔步,我們可以增加 server 或 worker 節(jié)點(diǎn)。例如缎谷,我們希望所有稅務(wù)報(bào)告能夠在 4 小時(shí)內(nèi)處理完畢井濒,通過(guò)公式2000*1/60/4計(jì)算,預(yù)估需要 7 個(gè) worker 并行執(zhí)行即可滿(mǎn)足目標(biāo)列林。

分享交流:

我們?yōu)榉窒斫涣鲃?chuàng)建了微信交流群瑞你,以方便更有針對(duì)性地討論課程相關(guān)問(wèn)題。入群方式請(qǐng)?zhí)砑幼髡呶⑿盘?hào):「Robynn-D」希痴,并注明「DDD」者甲,謝謝~

本文首發(fā):

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市砌创,隨后出現(xiàn)的幾起案子虏缸,更是在濱河造成了極大的恐慌,老刑警劉巖嫩实,帶你破解...
    沈念sama閱讀 206,839評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件刽辙,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡甲献,警方通過(guò)查閱死者的電腦和手機(jī)宰缤,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人慨灭,你說(shuō)我怎么就攤上這事朦乏。” “怎么了氧骤?”我有些...
    開(kāi)封第一講書(shū)人閱讀 153,116評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵呻疹,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我语淘,道長(zhǎng)诲宇,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,371評(píng)論 1 279
  • 正文 為了忘掉前任惶翻,我火速辦了婚禮姑蓝,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘吕粗。我一直安慰自己纺荧,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,384評(píng)論 5 374
  • 文/花漫 我一把揭開(kāi)白布颅筋。 她就那樣靜靜地躺著宙暇,像睡著了一般。 火紅的嫁衣襯著肌膚如雪议泵。 梳的紋絲不亂的頭發(fā)上占贫,一...
    開(kāi)封第一講書(shū)人閱讀 49,111評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音先口,去河邊找鬼型奥。 笑死,一個(gè)胖子當(dāng)著我的面吹牛碉京,可吹牛的內(nèi)容都是我干的厢汹。 我是一名探鬼主播,決...
    沈念sama閱讀 38,416評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼谐宙,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼烫葬!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起凡蜻,我...
    開(kāi)封第一講書(shū)人閱讀 37,053評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤搭综,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后咽瓷,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體设凹,經(jīng)...
    沈念sama閱讀 43,558評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,007評(píng)論 2 325
  • 正文 我和宋清朗相戀三年茅姜,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,117評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡钻洒,死狀恐怖奋姿,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情素标,我是刑警寧澤称诗,帶...
    沈念sama閱讀 33,756評(píng)論 4 324
  • 正文 年R本政府宣布,位于F島的核電站头遭,受9級(jí)特大地震影響寓免,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜计维,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,324評(píng)論 3 307
  • 文/蒙蒙 一袜香、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧鲫惶,春花似錦蜈首、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,315評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至赏淌,卻和暖如春踩寇,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背六水。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,539評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工俺孙, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人缩擂。 一個(gè)月前我還...
    沈念sama閱讀 45,578評(píng)論 2 355
  • 正文 我出身青樓鼠冕,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親胯盯。 傳聞我的和親對(duì)象是個(gè)殘疾皇子懈费,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,877評(píng)論 2 345

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