任何一套业务架构都可能存在一定的历史问题,这是业务在不同阶段做技术选型必然出现的状况,如何用新的、合适的架构思想做恰到好处地改造,则是架构师们的必备能力。
今天的主角是供应链系统,又被称为进销存系统。这个系统主要是针对采购(进)—>入库(存)—>销售(销)动态链条的管理系统,核心能力是管理仓库货物库存,在电商体系中起到承上启下的作用,下图中的 Skynet 系统和 ERP 系统分别扮演着供应链系统的核心角色,负责订单发货、售后退货、采购补货、仓间调拨以及特殊出入库等核心流程。
![](https://filescdn.proginn.com/4b9aacf5550d34115dd1178a6f215b3e/d6dec06cf3bf60b5ba0ad12c4c04eac9.webp)
Skynet 系统和 ERP 系统作为元老级系统,自 Keep 开启电商赛道时开始建设,经过多年需求快速迭代,期间系统包袱越来越重,运营过程中的问题也越来越多。供应链系统相对于 Keep 电商业务发展明显滞后,甚至有可能进一步阻碍 Keep 电商业务发展,而当时的供应链系统因缺乏系统性规划、代码缺少规范,导致这个元老级系统积重难返。当时面临的主要问题如下:
![](https://filescdn.proginn.com/77ef63bde8c56cf2a0f669980b4a6b7e/4c742d872e48c705c69b50a54c8becaf.webp)
库存不准,库存变更上下文不清晰
业务新要求
店铺库存分配自动化
智能采购
库存准确率保障
履约率保障
提升运营效率
种种问题重压,在老系统上修改已无法根除系统问题,且无法满足未来业务发展需求,导致供应链系统正式提上日程。
重构思路主要包括三大类梳理,分别是:
![](https://filescdn.proginn.com/5f9c15741867208f108638702ad555c4/254420f8c7835f3d1038787cfdcd20db.webp)
![](https://filescdn.proginn.com/c60a2d6eec6cefa261602b567b793e43/19537c05fd9a15ebd80b40ddf485207e.webp)
梳理清楚之后,关于 DDD 架构选型也是要重点考虑的内容:
![](https://filescdn.proginn.com/bc56c2f12b71d8055ba94435267bd7f4/5d24900b6d10d879b60f941c26dfb2e1.webp)
![](https://filescdn.proginn.com/6a9e9b2345a89eab5ecd9b5f91e9c241/00cd7691c65627ececb6355c12e7a18f.webp)
我们通过引入 CQRS 模式,隔离命令与查询领域模型。
![](https://filescdn.proginn.com/26bab5e21516a75d4eadea2a5e23a723/4810699172ba00b3f95bd84c436639d4.webp)
如下图所示采购上下文通过防腐层 (ACL) 将仓储库存核心上下文中的仓库信息映射为自身上下文中的仓库值对象,防止仓库信息依赖腐化。
![](https://filescdn.proginn.com/d66418c125aebae05f2fdc1546e006ea/1ab85f716063c776819c85268edd017d.webp)
![](https://filescdn.proginn.com/3c3ebc1da53d00cc3050c7f949e775d4/f30db74e0ff65e6da939c37d200d227b.webp)
从库存变更场景中,可以看到围绕库存变更在不同的业务层存在不同的业务单据,上层业务层单据状态变更依赖底层仓储核心单据状态变更,如采购入库单入库状态变更为入库完成则采购单状态也会变更为已完成,如销售出库单状态变更为出库完成则销售发货单状态会变更为已发货。
![](https://filescdn.proginn.com/151f5c549565a6a103fa0be3bdc50a47/d31725c057556465acf4a36e849da5a4.webp)
最终我们采用 EventStore 方案,使用 EventStore 数据流程如下:
![](https://filescdn.proginn.com/32c8641e851043e5267614b279c51a6c/6a31b54c0e058c1834793f35b4f475ec.webp)
上图中黄色部分为领域事件异常处理。
![](https://filescdn.proginn.com/0c1b05a18d6fd892cabce5c8c325dbf5/2876cea15ba7b3a452c71149d7cdf1b4.webp)
![](https://filescdn.proginn.com/b5b07866632a1803627c63df66ae1ad7/3f0af70ba8ebdb56bde80dd6fb9fc6ca.webp)
![](https://filescdn.proginn.com/02410eb74bbcbd575d8e47b337f6b8c4/1961d6cda8fd274135ee9367f5e44741.webp)
![](https://filescdn.proginn.com/e30c815ce89a371e219dc3036b9db8de/b61c5b83169cf85d90a943a35c12d6db.webp)
在订阅组中声明订阅事件
![](https://filescdn.proginn.com/53bd45d15db4a2ea274b1ee46dc895c7/34da683ae2cb72d44f27c417fb74f8eb.webp)
核心领域模型添加单元测试,对应 Domain 测试
核心业务接口场景添加单元测试,对应 CmdExe 测试
引入 Mockito 库,mock 相关接口和数据,验证流程环节是否正确
在单测代码中造单测相关数据,保证单测数据可靠性
单测采用 H2 数据库,避免测试过后留痕,影响后续单测,同时提升单测执行效率
减少或不依赖其他中间件,如 Dubbo、Kafka 等,如依赖可考虑直接 Mock
git push 后 CI 开启自动单元测试
最终,回顾这次改造工作,我认为收益可以分为五点:
实际库存准确,彻底解决仓库库存不准问题,同时为校准销售库存提供基准参考;
功能扩展方便,如后续快速对接财务系统;
快速定位问题(代码结构清晰,库存变更有据可查且上下文清晰);
沉淀出较通用的事件组件 EventStore,后续在 Keep 电商内部快速推广复用;
沉淀出一套比较成熟的 DDD 最佳实践,后续快速推广至 Keep 电商库存系统重构、售后重构。
可以看出,收益还是非常喜人的。大部分同学关注 DDD 是因为微服务,没错,DDD 可以说是与微服务天生互补的,DDD 领域面向划分业务模型边界,微服务面向将单体架构拆分为多个微服务,至于如何拆微服务,DDD 领域拆分则是一个非常好的微服务拆分方式。
欢迎关于 DDD,如果你想进一步交流探讨,也可以在本文下留言,期待大家的分享能够带来更多的启发。
作者介绍
武清明,从业 12 年,近 8 年一直在互联网电商行业一线从事系统研发,之前在京东和万达电商负责过仓储系统、订单系统、促销系统等研发工作。目前在 Keep 负责商业化业务中台研发和规划工作。擅长电商业务系统架构设计,采用 DDD 合理简单化设计复杂电商系统,提升系统功能模块的复用性和扩展性。
出处:https://blog.csdn.net/zhipengfang/article/details/120500445