一個電商供應鏈系統的 DDD 實戰
作者 | 武清明
編輯 | 王一鵬
任何一套業務架構都可能存在一定的歷史問題,這是業務在不同階段做技術選型必然出現的狀況,如何用新的、合適的架構思想做恰到好處地改造,則是架構師們的必備能力。本文是 Keep 利用 DDD 改造電商供應鏈系統的一次精彩實戰,InfoQ 架構頭條獨家分享,以供大家參考交流。
文章作者:武清明,目前他在 Keep 負責商業化業務中臺研發和規劃工作,擅長電商業務系統架構設計,採用 DDD 合理簡單化設計複雜電商系統,提升系統功能模塊的複用性和擴展性。
今天的主角是供應鏈系統,又被稱爲進銷存系統。這個系統主要是針對採購(進)—> 入庫(存)—> 銷售(銷)動態鏈條的管理系統,核心能力是管理倉庫貨物庫存,在電商體系中起到承上啓下的作用,下圖中的 Skynet 系統和 ERP 系統分別扮演着供應鏈系統的核心角色,負責訂單發貨、售後退貨、採購補貨、倉間調撥以及特殊出入庫等核心流程。
Skynet 系統和 ERP 系統作爲元老級系統,自 Keep 開啓電商賽道時開始建設,經過多年需求快速迭代,期間系統包袱越來越重,運營過程中的問題也越來越多。供應鏈系統相對於 Keep 電商業務發展明顯滯後,甚至有可能進一步阻礙 Keep 電商業務發展,而當時的供應鏈系統因缺乏系統性規劃、代碼缺少規範,導致這個元老級系統積重難返。當時面臨的主要問題如下:
-
系統邊界不清晰
-
架構混亂,系統內部分層不清晰
-
越來越模糊 usecase,導致代碼邊界和事務不清晰;
-
分層後各層職責和接口職責不清晰,導致接口依賴混亂,甚至出現循環依賴。
-
庫存不準,庫存變更上下文不清晰
-
庫存不準,超賣甚至少賣情況頻繁
-
庫存變更日誌不規範,上下文不清晰,出現庫存問題時,查找原因困難重重
-
庫存與庫存變更日誌無法自證正確
-
業務新要求
-
庫存準確率保障
-
履約率保障
-
提升運營效率
-
店鋪庫存分配自動化
-
智能採購
種種問題重壓,在老系統上修改已無法根除系統問題,且無法滿足未來業務發展需求,導致供應鏈系統正式提上日程。
重構思路主要包括三大類梳理,分別是:
- 梳理庫存業務場景
- 梳理限界上下文
-
梳理庫存模型
-
佔用庫存:已售賣未出庫庫存數
-
可用庫存:倉庫實物庫存 - 佔用庫存
-
實物庫存:倉庫中的實際庫存數
-
在途庫存:已採購未入庫庫存數
-
凍結庫存:因秒殺等促銷活動或倉間調撥等預佔的庫存數
梳理清楚之後,關於 DDD 架構選型也是要重點考慮的內容:
- 梳理領域模型與非領域模型之間關係 - 六邊形架構
-
保證核心領域模型的穩定性
-
分層設計採用依賴倒置原則,保證核心領域模型的穩定性,領域層不依賴任何其他層,底層服務可以依賴高層服務所提供的接口。
- 防止定製化查詢腐化領域模型
我們通過引入 CQRS 模式,隔離命令與查詢領域模型。
- 防止與其他限界上下文交互導致領域模型腐化
如下圖所示採購上下文通過防腐層 (ACL) 將倉儲庫存核心上下文中的倉庫信息映射爲自身上下文中的倉庫值對象,防止倉庫信息依賴腐化。
- 架構最終落地 -COLA
- 庫存變更場景相關單據狀態一致性保障
從庫存變更場景中,可以看到圍繞庫存變更在不同的業務層存在不同的業務單據,上層業務層單據狀態變更依賴底層倉儲核心單據狀態變更,如採購入庫單入庫狀態變更爲入庫完成則採購單狀態也會變更爲已完成,如銷售出庫單狀態變更爲出庫完成則銷售發貨單狀態會變更爲已發貨。
- 方案選擇
最終我們採用 EventStore 方案,使用 EventStore 數據流程如下:
上圖中黃色部分爲領域事件異常處理。
- 發佈領域事件代碼如下:
-
訂閱領域事件
-
註冊訂閱組
- 在訂閱組中聲明訂閱事件
-
在持續集成開發過程中如何同時保障效率和質量 - 單元測試保駕護航
-
核心領域模型添加單元測試,對應 Domain 測試
-
核心業務接口場景添加單元測試,對應 CmdExe 測試
-
引入 Mockito 庫,mock 相關接口和數據,驗證流程環節是否正確
-
在單測代碼中造單測相關數據,保證單測數據可靠性
-
單測採用 H2 數據庫,避免測試過後留痕,影響後續單測,同時提升單測執行效率
-
減少或不依賴其他中間件,如 Dubbo、Kafka 等,如依賴可考慮直接 Mock
-
git push 後 CI 開啓自動單元測試
最終,回顧這次改造工作,我認爲收益可以分爲五點:
-
實際庫存準確,徹底解決倉庫庫存不准問題,同時爲校準銷售庫存提供基準參考;
-
功能擴展方便,如後續快速對接財務系統;
-
快速定位問題(代碼結構清晰,庫存變更有據可查且上下文清晰);
-
沉澱出較通用的事件組件 EventStore,後續在 Keep 電商內部快速推廣複用;
-
沉澱出一套比較成熟的 DDD 最佳實踐,後續快速推廣至 Keep 電商庫存系統重構、售後重構。
可以看出,收益還是非常喜人的。大部分同學關注 DDD 是因爲微服務,沒錯,DDD 可以說是與微服務天生互補的,DDD 領域面向劃分業務模型邊界,微服務面向將單體架構拆分爲多個微服務,至於如何拆微服務,DDD 領域拆分則是一個非常好的微服務拆分方式。
歡迎關於 DDD,如果你想進一步交流探討,也可以在本文下留言,期待大家的分享能夠帶來更多的啓發。
作者介紹
武清明,從業 12 年,近 8 年一直在互聯網電商行業一線從事系統研發,之前在京東和萬達電商負責過倉儲系統、訂單系統、促銷系統等研發工作。目前在 Keep 負責商業化業務中臺研發和規劃工作。擅長電商業務系統架構設計,採用 DDD 合理簡單化設計複雜電商系統,提升系統功能模塊的複用性和擴展性。
**技術瑣話 **
以分佈式設計、架構、體系思想爲基礎,兼論研發相關的點點滴滴,不限於代碼、質量體系和研發管理。
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/cWHAsjBqS_7ru4JR_1I2BQ