【发布时间】:2018-09-23 01:24:03
【问题描述】:
我研究 DDD 已经有一段时间了,偶然发现了 CQRS 和事件溯源 (ES) 等设计模式。这些模式可用于帮助以更少的努力实现 DDD 的某些概念。 在下面示例的架构中,聚合知道如何处理与自身相关的命令和事件。换句话说,事件处理程序和命令处理程序是聚合。
然后,我开始对一个示例域进行建模,以了解实现如何遵循业务逻辑。对于这个问题,这里是我的域(它基于this):
我知道这是一个糟糕的建模示例,但我只是将其用作示例。 因此,使用 ES,在操作结束时,我们会将所有事件(绿色箭头)保存到事件存储中(如果没有异常),每个事件都保存到其给定的事件流中(聚合类型 + 聚合 ID):
到目前为止,一切似乎都是正确的。所以如果我们想重建这个聚合的任何一个实例的内部状态,我们只需要更新它 (new()) 并以正确的顺序应用保存在其各自事件流中的所有事件。
我的问题与模型的变化有关。因为,软件开发是一个我们永远不会停止学习我们的领域的过程,我们总是会提出新的想法。那么,让我们分析一些变化场景:
改变场景一:
假设现在,如果 Reservation Aggregate 检查座位不可用,它应该发送一个事件(Seat not保留),并且此事件应由一个新的聚合来处理,该聚合将存储所有未保留座位的人:
假设旧系统已经正确处理了初始命令(Place order),并将所有事件保存到其各自的事件流中:
- 当我们想要重建此聚合的任何实例的内部状态时,我们只需对其进行更新 (new()) 并以正确的顺序应用保存在其各自事件流中的所有事件。 (没有改变)。唯一的问题是,旧模型中不存在新的用例。
改变场景2:
假设现在,当付款被接受时,我们在新的聚合(财务聚合)中处理此事件(已接受付款) em>) 并且不再在 Order Aggregate 中。它会向 Order Aggregate 发送一个新事件(Payment Received)。我知道这种情况结构不完善,但可能会发生类似的情况。
假设旧系统已经正确处理了初始命令(Place order),并将所有事件保存到其各自的事件流中:
- 当我们想要重建此聚合的任何实例的内部状态时,将聚合事件流中的事件应用到自身时会遇到问题:
现在,订单不再知道如何处理Payment Accepted事件。
问题
因此,如示例所示,每当系统更改反映在由不同事件处理程序(聚合)处理的事件中时,就会出现一些主要问题。因为,我们不能再重建内部状态了。 所以,这个问题可以有一些解决方案:
可能的解决方案
当一个事件未被存储在事件流中的聚合处理时,我们可以找到新的处理程序并创建一个新实例并将事件发送给它。但是为了保持内部状态正确,我们需要由 Order Aggregate 处理最后一个事件(Payment Received)强>。所以,我们让它分派事件(和可能的命令):
此解决方案可能存在一些问题。假设有一个新命令 (Place Order) 到达,它必须创建这个订单实例并保存新状态。现在我们会有:
灰色是系统尚未完成模型更改时已在上次调用中保存的事件。 我们可以看到为新聚合创建了一个新事件流 (Finance W)。我们可以看到 Event Streams 是仅追加的,所以 Order Y 事件中的 Payment Accepted 事件流仍然存在。 Finance W 事件流中的第一个 Payment Accepted 事件应该由 Order,但必须找到新的处理程序。 Order's 事件流中的 Yellow payment received 事件是由 Payment Accepted 的新处理程序生成的事件> 当 Order's 事件流中的 Payment Accepted 事件由 Finance 处理时。 所有其他绿色事件都是通过处理新模型中的 Place Order 命令生成的新事件。
解决方案的问题
下次需要重建聚合时,流中会有一个 Payment Accepted 事件(因为它是仅追加的),它会再次调用新的处理程序,但这已经完成并且 Payment接收到的事件已保存到流中。所以,没有必要再经历一次,我们可以忽略这个事件并继续。
问题
那么,我的问题是我们如何处理影响每个事件的处理者的模型更改?在这样的更改之后,我们如何重建聚合的内部状态? 我们是否需要构建一些事件流迁移,将事件从一个流更改为新模式(一个或多个流)?就像我们需要在关系数据库中一样? 我们永远不会被允许删除一个处理程序,所以我们只能添加新的处理程序吗?这会导致系统无法管理……
【问题讨论】:
-
Greg Young 有一本书涉及到这一点(参见“流边界错误”)-leanpub.com/esversioning
-
groups.google.com/forum/#!forum/dddcqrs如果你在谷歌CQRS群里问这个问题,你会得到比这里更丰富的答案。
标签: domain-driven-design cqrs event-sourcing