【问题标题】:How to handle domain changes in a event sourced application?如何处理事件源应用程序中的域更改?
【发布时间】:2017-06-27 13:42:23
【问题描述】:

我目前正在使用 Scala 和 Eventuate,但我认为这个问题适用于任何事件源环境:

假设您有以下事件:case class UserAdded(user: User),而Usercase class User(username:String, birthday: Date)

您的应用已经运行了一段时间,现在您需要收集用户的电话号码。所以现在我们需要将User 更改为case class User(username:String, birthday: Date, phoneNumber: String)

重播事件时,会抛出错误,因为过去的事件没有phoneNumber。您通常如何在事件源应用程序中解决这个问题?

我的第一个想法是为事件存储中的所有事件设置一个默认值,但我知道在进行事件溯源时事件是不可变的,因此我决定听取更有经验的用户的意见。

非常感谢任何输入!

【问题讨论】:

    标签: scala event-sourcing


    【解决方案1】:

    我认为这里有两个概念错误。

    首先,事件不应“引用”或“包含”域对象。事件是对所发生事件的记录,因此它应该明确记录表征它的数据点。在这种情况下 - usernamebirthday

    case class UserAdded(username:String, birthday: Date)
    

    现在,这个事件定义永远不会改变。发生了什么,发生了。过去没有改写。

    如果在某个时刻,业务需求发生变化,这意味着从现在开始会发生一种不同的事件:

    case class UserAdded2(username:String, birthday: Date, phoneNumber: String)
    

    这两个事件都应该保持原样,都应该被处理、处理等等。正如直觉所暗示的那样,第一个事件并非“现在无用”。恰恰相反:第一个事件记录了需求更改之前发生的事情,并且该记录很有价值。

    现在,根据您的平台允许的情况(我对 Eventuate 不熟悉),您或许可以在技术上将这两个事件实现为具有可选字段的单个类。但即使你这样做了,你也应该永远记住这个类代表两个不同的事件。出于这个原因,我宁愿将它们明确定义为单独的事物。

    【讨论】:

      【解决方案2】:

      您所描述的是事件溯源中的“版本控制”,尽管事件溯源是一项相对较新的技术,但至少有两种解决方案:

      1. 您保留旧事件(类和数据)并为将来的事件引入新的事件类型,例如 class UserAddedV2(username:String, birthday: Date, phoneNumber: String)。这样做的缺点是旧类将继续存在,尽管它不再被实例化。

      2. 您迁移整个事件流并将旧事件替换为新事件,并使用新字段的默认值。通过这种方式,您可以摆脱旧的事件类。

      我强烈推荐 Greg Young 的 book,因为它是我在这个主题上找到的最好的。

      【讨论】:

      • 我认为承认重写事件流的可能性是一个滑坡:在你知道之前,所有其他部署都需要重写历史记录。
      • @FyodorSoikin 事件以如此强大的方式将数据与代码联系起来,以至于只有历史重写才能打破这种耦合,恕我直言。无论如何,至少应该知道这种战术模式
      • 好书!我不知道。它涵盖了深入的问题,谢谢!
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多