首页 > 解决方案 > 事件溯源中的值对象

问题描述

在事件源域模型中是否有值对象的位置?

让我们将值对象定义为具有不可变状态的对象,该对象保护其不变量并且没有特定标识符。

在这种情况下,事件源域模型是完全或部分事件源的域,这意味着它的当前状态可以通过应用过去发生的所有事件得出。即使随着时间的推移,事件本身也被认为是不可变的。

关于在事件中使用值对象的有效性已经发生了争论——这个问题稍微进一步:值对象在事件源域中是否有一席之地

使用值对象的(潜在)问题是,以不变量被收紧的方式改变域变得相当棘手。

这种情况的一个示例是有一个Username值对象,唯一的约束是名称必须介于 2 到 16 个字符之间。

虽然这在一段时间内运行良好,但该公司决定只允许至少 5 个字符的用户名。迁移期开始,名称少于 5 个字符的用户被要求更新其名称。

可以说该过程是成功的,应用了更正事件并且每个人都很高兴。我们收紧对Username值对象的约束,要求至少 5 个字符。

有一段时间每个人都很高兴,但随后我们发现快照存在问题并重播所有事件。

我们现在面临Username对象的一个​​异常:通过加载历史数据,我们破坏了域的不变量。

值对象的规则具有追溯性——这是否使它们天生不适合事件溯源?是否值得应用值对象的版本控制?有没有更简单的方法来避免此类问题?

标签: oopdomain-driven-designevent-sourcingvalue-objects

解决方案


我想说,在您重新定义Username含义的那一刻,并且您没有以某种方式迁移历史数据,您实际上已经创建了 2 个不同的Username含义。

因为这个词有 2 种不同的含义,所以你必须以某种方式在代码中明确说明。“版本控制”是一种方式,虽然我不会使用这样的通用解决方案,但有不同的建模选项。

您可以明确表示“用户名”的历史就是这样,历史。因此,例如创建一个HistoricUsername,它是事件源对象,如果您愿意,甚至是一个值对象。并创建一个Username始终是具有最新规则的用户名,它根本不会持久化,但HistoricUsername如果可以的话,它是从 a 创建的。

有些人建议有时从对象中提取“规则”,然后再重新应用。这样,对象本身在任何时候都是有效的,您可以要求它根据可能发生变化的规则来验证自己。我真的不喜欢这些解决方案,但它是一种选择,并且Username仍然是一个价值对象。

所以问题并不在于价值对象不适合事件溯源,而只是建模必须更准确。


推荐阅读