如何处理事件源应用程序中的域更改?

时间:2017-06-27 03:27:07

标签: scala event-sourcing

我目前正在使用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。您如何在事件源应用程序中解决此问题?

我的第一个想法是为事件存储中的所有事件设置默认值,但我知道当您进行事件采购时事件是不可变的,所以我决定听取更多有经验的用户的意见。

非常感谢任何输入!

2 个答案:

答案 0 :(得分:5)

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

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

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

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

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

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

两个事件都应该保持完整,两者都应该被处理,处理,等等。直觉可能暗示,第一个事件并非“现在无用”。恰恰相反:第一个事件记录了需求变更之前发生的事情,并且该记录很有价值。

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

答案 1 :(得分:2)

您所描述的内容被称为"版本控制"在事件采购中,尽管事件采购是一项相对较新的技术,但至少有两种解决方案:

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

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

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