一個(gè)電商供應(yīng)鏈系統(tǒng)的DDD實(shí)戰(zhàn)
作者 | 武清明
任何一套業(yè)務(wù)架構(gòu)都可能存在一定的歷史問(wèn)題,這是業(yè)務(wù)在不同階段做技術(shù)選型必然出現(xiàn)的狀況,如何用新的、合適的架構(gòu)思想做恰到好處地改造,則是架構(gòu)師們的必備能力。本文是 Keep 利用 DDD 改造電商供應(yīng)鏈系統(tǒng)的一次精彩實(shí)戰(zhàn),InfoQ 架構(gòu)頭條獨(dú)家分享,以供大家參考交流。 文章作者:武清明,目前他在 Keep 負(fù)責(zé)商業(yè)化業(yè)務(wù)中臺(tái)研發(fā)和規(guī)劃工作,擅長(zhǎng)電商業(yè)務(wù)系統(tǒng)架構(gòu)設(shè)計(jì),采用 DDD 合理簡(jiǎn)單化設(shè)計(jì)復(fù)雜電商系統(tǒng),提升系統(tǒng)功能模塊的復(fù)用性和擴(kuò)展性。
今天的主角是供應(yīng)鏈系統(tǒng),又被稱為進(jìn)銷存系統(tǒng)。這個(gè)系統(tǒng)主要是針對(duì)采購(gòu)(進(jìn))—>入庫(kù)(存)—>銷售(銷)動(dòng)態(tài)鏈條的管理系統(tǒng),核心能力是管理倉(cāng)庫(kù)貨物庫(kù)存,在電商體系中起到承上啟下的作用,下圖中的 Skynet 系統(tǒng)和 ERP 系統(tǒng)分別扮演著供應(yīng)鏈系統(tǒng)的核心角色,負(fù)責(zé)訂單發(fā)貨、售后退貨、采購(gòu)補(bǔ)貨、倉(cāng)間調(diào)撥以及特殊出入庫(kù)等核心流程。

Skynet 系統(tǒng)和 ERP 系統(tǒng)作為元老級(jí)系統(tǒng),自 Keep 開啟電商賽道時(shí)開始建設(shè),經(jīng)過(guò)多年需求快速迭代,期間系統(tǒng)包袱越來(lái)越重,運(yùn)營(yíng)過(guò)程中的問(wèn)題也越來(lái)越多。供應(yīng)鏈系統(tǒng)相對(duì)于 Keep 電商業(yè)務(wù)發(fā)展明顯滯后,甚至有可能進(jìn)一步阻礙 Keep 電商業(yè)務(wù)發(fā)展,而當(dāng)時(shí)的供應(yīng)鏈系統(tǒng)因缺乏系統(tǒng)性規(guī)劃、代碼缺少規(guī)范,導(dǎo)致這個(gè)元老級(jí)系統(tǒng)積重難返。當(dāng)時(shí)面臨的主要問(wèn)題如下:
系統(tǒng)邊界不清晰
架構(gòu)混亂,系統(tǒng)內(nèi)部分層不清晰
越來(lái)越模糊 usecase,導(dǎo)致代碼邊界和事務(wù)不清晰; 分層后各層職責(zé)和接口職責(zé)不清晰,導(dǎo)致接口依賴混亂,甚至出現(xiàn)循環(huán)依賴。

庫(kù)存不準(zhǔn),庫(kù)存變更上下文不清晰 庫(kù)存不準(zhǔn),超賣甚至少賣情況頻繁 庫(kù)存變更日志不規(guī)范,上下文不清晰,出現(xiàn)庫(kù)存問(wèn)題時(shí),查找原因困難重重 庫(kù)存與庫(kù)存變更日志無(wú)法自證正確
業(yè)務(wù)新要求 庫(kù)存準(zhǔn)確率保障 履約率保障 提升運(yùn)營(yíng)效率 店鋪庫(kù)存分配自動(dòng)化 智能采購(gòu)
種種問(wèn)題重壓,在老系統(tǒng)上修改已無(wú)法根除系統(tǒng)問(wèn)題,且無(wú)法滿足未來(lái)業(yè)務(wù)發(fā)展需求,導(dǎo)致供應(yīng)鏈系統(tǒng)正式提上日程。
梳理庫(kù)存業(yè)務(wù)場(chǎng)景

梳理限界上下文

梳理庫(kù)存模型 占用庫(kù)存:已售賣未出庫(kù)庫(kù)存數(shù) 可用庫(kù)存:倉(cāng)庫(kù)實(shí)物庫(kù)存 - 占用庫(kù)存 實(shí)物庫(kù)存:倉(cāng)庫(kù)中的實(shí)際庫(kù)存數(shù) 在途庫(kù)存:已采購(gòu)未入庫(kù)庫(kù)存數(shù) 凍結(jié)庫(kù)存:因秒殺等促銷活動(dòng)或倉(cāng)間調(diào)撥等預(yù)占的庫(kù)存數(shù)
梳理領(lǐng)域模型與非領(lǐng)域模型之間關(guān)系 - 六邊形架構(gòu)

保證核心領(lǐng)域模型的穩(wěn)定性
分層設(shè)計(jì)采用依賴倒置原則,保證核心領(lǐng)域模型的穩(wěn)定性,領(lǐng)域?qū)硬灰蕾嚾魏纹渌麑樱讓臃?wù)可以依賴高層服務(wù)所提供的接口。

防止定制化查詢腐化領(lǐng)域模型

防止與其他限界上下文交互導(dǎo)致領(lǐng)域模型腐化
如下圖所示采購(gòu)上下文通過(guò)防腐層 (ACL) 將倉(cāng)儲(chǔ)庫(kù)存核心上下文中的倉(cāng)庫(kù)信息映射為自身上下文中的倉(cāng)庫(kù)值對(duì)象,防止倉(cāng)庫(kù)信息依賴腐化。

架構(gòu)最終落地 -COLA

庫(kù)存變更場(chǎng)景相關(guān)單據(jù)狀態(tài)一致性保障
從庫(kù)存變更場(chǎng)景中,可以看到圍繞庫(kù)存變更在不同的業(yè)務(wù)層存在不同的業(yè)務(wù)單據(jù),上層業(yè)務(wù)層單據(jù)狀態(tài)變更依賴底層倉(cāng)儲(chǔ)核心單據(jù)狀態(tài)變更,如采購(gòu)入庫(kù)單入庫(kù)狀態(tài)變更為入庫(kù)完成則采購(gòu)單狀態(tài)也會(huì)變更為已完成,如銷售出庫(kù)單狀態(tài)變更為出庫(kù)完成則銷售發(fā)貨單狀態(tài)會(huì)變更為已發(fā)貨。
方案選擇

最終我們采用 EventStore 方案,使用 EventStore 數(shù)據(jù)流程如下:

上圖中黃色部分為領(lǐng)域事件異常處理。
發(fā)布領(lǐng)域事件代碼如下:



訂閱領(lǐng)域事件 注冊(cè)訂閱組

在訂閱組中聲明訂閱事件

在持續(xù)集成開發(fā)過(guò)程中如何同時(shí)保障效率和質(zhì)量 - 單元測(cè)試保駕護(hù)航 核心領(lǐng)域模型添加單元測(cè)試,對(duì)應(yīng) Domain 測(cè)試
核心業(yè)務(wù)接口場(chǎng)景添加單元測(cè)試,對(duì)應(yīng) CmdExe 測(cè)試
引入 Mockito 庫(kù),mock 相關(guān)接口和數(shù)據(jù),驗(yàn)證流程環(huán)節(jié)是否正確
在單測(cè)代碼中造單測(cè)相關(guān)數(shù)據(jù),保證單測(cè)數(shù)據(jù)可靠性
單測(cè)采用 H2 數(shù)據(jù)庫(kù),避免測(cè)試過(guò)后留痕,影響后續(xù)單測(cè),同時(shí)提升單測(cè)執(zhí)行效率
減少或不依賴其他中間件,如 Dubbo、Kafka 等,如依賴可考慮直接 Mock
git push 后 CI 開啟自動(dòng)單元測(cè)試
最終,回顧這次改造工作,我認(rèn)為收益可以分為五點(diǎn):
實(shí)際庫(kù)存準(zhǔn)確,徹底解決倉(cāng)庫(kù)庫(kù)存不準(zhǔn)問(wèn)題,同時(shí)為校準(zhǔn)銷售庫(kù)存提供基準(zhǔn)參考; 功能擴(kuò)展方便,如后續(xù)快速對(duì)接財(cái)務(wù)系統(tǒng); 快速定位問(wèn)題(代碼結(jié)構(gòu)清晰,庫(kù)存變更有據(jù)可查且上下文清晰); 沉淀出較通用的事件組件 EventStore,后續(xù)在 Keep 電商內(nèi)部快速推廣復(fù)用; 沉淀出一套比較成熟的 DDD 最佳實(shí)踐,后續(xù)快速推廣至 Keep 電商庫(kù)存系統(tǒng)重構(gòu)、售后重構(gòu)。
可以看出,收益還是非常喜人的。大部分同學(xué)關(guān)注 DDD 是因?yàn)槲⒎?wù),沒(méi)錯(cuò),DDD 可以說(shuō)是與微服務(wù)天生互補(bǔ)的,DDD 領(lǐng)域面向劃分業(yè)務(wù)模型邊界,微服務(wù)面向?qū)误w架構(gòu)拆分為多個(gè)微服務(wù),至于如何拆微服務(wù),DDD 領(lǐng)域拆分則是一個(gè)非常好的微服務(wù)拆分方式。
歡迎關(guān)于 DDD,如果你想進(jìn)一步交流探討,也可以在本文下留言,期待大家的分享能夠帶來(lái)更多的啟發(fā)。
作者介紹
武清明,從業(yè) 12 年,近 8 年一直在互聯(lián)網(wǎng)電商行業(yè)一線從事系統(tǒng)研發(fā),之前在京東和萬(wàn)達(dá)電商負(fù)責(zé)過(guò)倉(cāng)儲(chǔ)系統(tǒng)、訂單系統(tǒng)、促銷系統(tǒng)等研發(fā)工作。目前在 Keep 負(fù)責(zé)商業(yè)化業(yè)務(wù)中臺(tái)研發(fā)和規(guī)劃工作。擅長(zhǎng)電商業(yè)務(wù)系統(tǒng)架構(gòu)設(shè)計(jì),采用 DDD 合理簡(jiǎn)單化設(shè)計(jì)復(fù)雜電商系統(tǒng),提升系統(tǒng)功能模塊的復(fù)用性和擴(kuò)展性。
