13

在大多数情况下,我理解 CQRS + ES 系统中命令和事件之间的区别。但是,有一种情况我无法弄清楚。

假设我正在构建一个个人财务跟踪系统,用户可以在其中输入借项/贷项。显然,这些是命令,一旦它们被验证,域模型就会更新并发布一个事件。然而,假设贷记/借记信息也直接来自外部系统,例如,用户的花店发送一条消息,说明他已经从用户的信用卡中收取了他经常性的母亲节递送费用。在这种情况下,消息看起来像是一个事件(收费已经发生),但消息可能格式不正确并被拒绝。那么它真的是一个命令吗?但随后需要一种发送 ACK/NACK 的方法,但这里不是这种情况(花店只有在知道借记发生后才发送消息)。

编辑:澄清一下,我不是在谈论外部系统对我的事件和/或命令一无所知。我有一个组件从外部系统接收数据,然后必须发布事件或发送命令。问题是,我的组件应该使用哪个事件或命令?

4

2 回答 2

15

这是有界上下文的完美示例。

在表示相同或业务流程步骤的另一个系统(或有界上下文)中发生的事件不应被视为已在接收系统中发生的事件。

花店系统借记事件的结构可能与财务跟踪系统中发生的借记事件不同。

为了解决这个问题,我将有一个端点来监听 Florist System 事件,然后我会让 Finance Tracking System 根据事件中的信息发出命令,并在需要时将其与 Finance Tracking System 中的信息结合起来。发生这种情况的地方可以被认为是财务跟踪系统的客户,或者如果你愿意的话,甚至可能是“域服务”。

在这种特殊情况下,来自 Florist 系统的事件与 Florist 系统中发生的交易信息(有界上下文)一起出现。我不会在域服务中做出任何决定,而是向财务跟踪系统域发出命令,在该域中进行决策并可能发出财务跟踪系统事件。如果 Florist 系统事件在 Finance Tracking System 中出现格式错误,您可能不想以 Request/Response 或 Ack/Nack 的方式告诉 Florist 系统。该事件是从 Florist 发布的,如果您实现类似的东西,您将破坏消息传递模式。您的消息传递基础架构应该允许您重试消息,甚至修复接收代码并使用新代码重试消息。

但是,如果您确实需要回传 Florist 有界上下文,Florist 系统可以订阅来自 Finance Tracking System 的事件,以查明交易是否已成功处理。只有在主系统决定是否发生交易时才需要这样做。

如果您描述的财务跟踪系统更像是一个事务日志,那么您唯一要做的就是不要将花店事件视为财务跟踪系统事件。在导致财务跟踪系统事件的发出命令之间放置一些东西。

编辑:

作为对您的编辑的回应。您接收组件应将命令发送到 Finance Tracking System 域,该域又会发出事件(像往常一样)。

于 2012-08-10T07:55:40.910 回答
3

我在想同样的事情时发现了这个问题。

我喜欢 Mikael 的回答并投了赞成票。但是,我在 DDD/CQRS 论坛上找到了另一个采用不同方法的答案,所以我想我会把它贴在这里给其他正在寻找的人。

这是 Greg Young关于跟踪外部状态的类似问题的引述:

在大多数库存系统中,没有命令。

或者换个说法:

专门跟踪外部状态的系统将没有命令。

让我们回过头来思考一下您的系统可能会如何基于这个想法发展(我们还假设您不是为自己构建它):

  • 您决定创建一个个人财务跟踪器来记录来自外部世界的交易、显示图表、汇总总计等。
  • 因为事件用于跟踪状态变化,而不是命令,所以你记录了这些。您还可以在事件处理程序中编写预测,以将事件聚合为总数和图形数据点。
  • 然后你得到用户。他们称赞该应用程序,但使用率仍然很低。深入挖掘后,您会发现他们仍然使用其他应用程序来跟踪财务状况,例如,本地卡片商店没有用于定期母亲节卡片的 API,他们想将外部交易“拆分”为多个,他们的银行没有在线访问,他们想要跟踪现金等。
  • 因此,您添加了用户输入的交易。为此,您可以添加跟踪用户输入事务的命令。现在我们与您的问题处于同一系统。

请注意,此变体同时接受命令和事件。您不会因为您现在允许用户更改内容而返回并将所有现有事件转换为命令。相反,您有一个系统接受外部事务事件、用户输入事务的命令和事务更正(创建修改内部状态的事件),以及将这些内部和外部事件结合起来在应用程序中显示的预测。

不过我很好奇。事后看来,接受的答案最终是否是一个好方法?还是像 Greg 建议的那样直接记录和处理来自花店的事件会更好?

于 2016-09-24T19:20:07.093 回答