DDD中跨多上下文的校验逻辑应在何处实现?
DDD跨限界上下文校验逻辑实现方案(针对Customer、Order单体场景)
首先明确大前提:限界上下文的核心价值就是边界隔离,每个上下文只对自己的领域规则、数据资产负责,内部实现细节不对外部开放,跨上下文交互只能走对方明确暴露的公共接口。
针对第一个疑问:是否必须在Order服务中调用Customer的应用服务执行customerAS.exist(customerId)
这是最标准、耦合度最低的合规实现,但不是唯一的实现方式:
- 从职责划分上看,“判断customerId是否对应有效客户”完全是Customer上下文的内部领域规则,Order上下文不需要关心这个判断的具体逻辑——是查主库?查缓存?还是要附加判断客户是否已注销、是否完成实名认证?这些逻辑都应该封装在Customer上下文内部。
- 调用Customer对外暴露的应用服务接口做校验,两个上下文只依赖明确的接口契约,后续Customer内部不管怎么调整逻辑,只要接口入参出参不变,Order侧不需要做任何修改,维护成本极低。
- 如果是对性能有极高要求的场景,也可以由Customer上下文维护一份只读的有效客户Id快照(比如独立的缓存、只读表),Order侧直接读这份快照做校验。但要注意这份数据的所有权完全归Customer,Order侧只有读权限,所有数据更新、一致性维护都由Customer侧负责,本质还是走Customer开放的公共数据能力,没有越界。
针对第二个疑问:是否可以在Order应用服务中直接调用Customer的Repository
绝对不可以。
- Repository是上下文内部的基础设施层组件,属于典型的内部实现细节,本来就不应该暴露给其他上下文。
- 一旦Order直接注入调用Customer的Repository,等于直接打破了上下文边界:你在Order侧就直接感知了Customer的存储结构、查询逻辑,哪天Customer侧调整表结构、修改客户有效性的判断规则(比如加逻辑删除、过滤已注销账号),Order侧根本没有感知,很容易出线上bug。后续改起来所有跨上下文直接调用仓储的地方都要挨个改,代码很快就会耦合成改不动的大泥球。
- 同理,不要图省事在Order的仓储层写join Customer表的SQL做校验,这和直接调用Customer Repository没有本质区别,都是越界操作。
跨上下文校验的判断标准非常简单:哪段规则归哪个上下文所有,就找哪个上下文对外开放的公共入口做校验,绝对不要伸手碰其他上下文的内部组件。
内容的提问来源于stack exchange,提问作者lascarayf
相关产品推荐
相关产品推荐

