【发布时间】:2017-05-12 18:47:00
【问题描述】:
在 CQRS + ES 和 DDD 中,聚合小型读取模型以从其他聚合或有界上下文获取数据是一件好事吗?
例如,在订单验证(In Order 聚合)中,有一个业务规则仅在未标记客户的情况下验证订单。标志信息通过同步域事件放入读取模型(特定于聚合)中。
您对此有何看法?
【问题讨论】:
在 CQRS + ES 和 DDD 中,聚合小型读取模型以从其他聚合或有界上下文获取数据是一件好事吗?
例如,在订单验证(In Order 聚合)中,有一个业务规则仅在未标记客户的情况下验证订单。标志信息通过同步域事件放入读取模型(特定于聚合)中。
您对此有何看法?
【问题讨论】:
聚合小型读取模型以从其他聚合或有界上下文中获取数据是一件好事吗?
这并不理想。聚合,由于其性质,不擅长执行涉及自身外部状态的一致性。
这通常意味着当两个聚合产生不可接受的状态时,业务将需要某种方式来响应。
您还可以选择在对聚合运行 placeOrder 命令之前检查标志。对标志的检查可以在命令处理程序中完成,也可以在客户端中完成——基本上,您已经“验证”了该命令在将其传递给聚合之前应该成功。
也就是说,如果在处理命令时尝试查询读取模型很关键,那么一种方法是使用“域服务”;您将服务提供者作为命令的一部分传递给聚合,并让接口抽象出运行查询需要查看聚合之外的事实。
这为您提供了保持聚合可测试所需的一些解耦。
【讨论】:
这是可行的,但不是以读取模型的形式,而是聚合中的值对象(因为我们在写入端)。
如果您在Order 中已经有一个CustomerId,您只需用它和一个Flagged 成员组成一个VO。
当然,由于数据来自Customer,因此这仍然容易出现跨聚合通信的所有问题。 Order 必须与其客户的标记状态保持同步,这可能需要相当多的工作。
在任何情况下,您可能应该首先与您的领域专家确定即时一致性是否是绝对要求(在这种情况下,您必须以某种方式将客户 + 订单包装在事务中)或者您是否可以承受标记新鲜度的小延迟在执行该不变量时。
如果是后者,您可以选择在Order 聚合中复制标记或@VoiceOfUnreason 给出的第一个选项 - 主要区别可能是如果数据在聚合中,您将在域级别免费获得它如果您在多个场合都需要它,而不是在应用程序级别的多个用例/命令处理程序中重复检查。
【讨论】: