6

我正在使用事件源实现有界上下文,但遇到了问题。假设我正在模拟一场足球比赛,我对个人进球(谁进球等)和总分都感兴趣。因此,如果我有一个 Match 聚合根,理想情况下我希望引发名为 GoalScored 和 ScoreChanged 的​​事件。我希望像这样从域中明确说明分数的原因是我不希望许多不同的侦听器和可能的其他有界上下文都计算相同的东西。

这看起来很简单,但是:Match 对象有一个添加新目标的 Goal() 方法。本着事件溯源的精神,这不会直接改变 Match 状态,而是引发一个 GoalScored 事件,该事件在 Match 中处理,然后改变状态(以及被推送到非规范化器的事件)。因此,就提高 ScoreChanged 而言,在处理 GoalScored 事件之前,分数实际上并没有改变,所以我是否应该引发另一个事件来响应该事件 (ScoreChanged),从而有效地链接事件?我不这么认为,首先,当从事件存储重新加载聚合根时,每次都会创建大量额外事件以响应每个 GoalScored。

我还考虑过在引发 GoalScored 的命令处理程序中计算得分,这是一种“假设”的情况。然后我可以在命令处理程序中引发这两个事件。不过,我真的不想那样做——它看起来并不“正确”。计算分数对于足球来说很简单,但其他游戏(例如板球)需要更多的工作。

我可以将目标和得分都放在 GoalScored 事件中,这很公平,但又似乎不对 - 得分与 GoalScored 事件本身无关。

讨论事件溯源时使用的所有示例似乎都使用电子商务客户/订单域,而我从未见过与此类似的案例。

有没有人有处理这种情况的经验?

谢谢

4

3 回答 3

13

就像其他建模一样,选择干净的域事件应该导致在域中镜像的概念。您说“分数与 GoalScored 事件本身无关”。但确实如此。在足球比赛中,比分可以改变的唯一方式是进球是否进球。但是,进球可以被收回,例如通过越位判罚或其他处罚。目前尚不清楚您是否要对此进行建模。

域方法一次发出多个事件是很常见的。一个好的框架将很容易将它们视为一组,例如作为单个提交。为什么不同时发出 GoalScored 和 ScoreChanged 事件?

您可能还想考虑这个域是否有任何命令。足球比赛本身就是记录系统。来自比赛的事件已经成为历史的记录。您是否只是在编写一个将事件流处理成更多事件流的系统?

于 2013-01-15T16:05:13.823 回答
4

在考虑事件溯源时,通常会有所帮助的一件事是注意您的时态——您说的是 StartMatch,但在事件的意义上它实际上是事件 MatchStarted。

至于 ScoreChanged,您是否在 Match 之外使用此事件?如果不是,分数应该是唯一可公开访问的部分,而 GoalScored 事件只是改变了这一点。这以较小的方式保留了 CQRS(我如何获得分数并不取决于我如何更改它)。然后 Score 可以在内部保持一个状态,或者可以重播所有 GoalScored 事件以在每次调用它时得出一个数字。正确设计的事件源解决方案的“感觉”总是可以从事件中重新生成任何状态。

现在,如果 ScoreChanged 需要提醒系统的其他部分(例如玩家排名),您可以将事件多播到不同的根,或者您可能需要重构您的设计。在这种情况下,您是想实时更新球员,还是只在比赛结束后更新?

于 2014-06-13T18:44:28.390 回答
0

我在 scala 中有一个用于事件溯源的开源项目,其中包含篮子如何使用它的示例。以防万一对你有用https://github.com/politrons/Scalaydrated

于 2016-10-30T10:06:28.957 回答