我正在构建一个遵循简洁架构方法的应用程序。它试图确保领域层独立于任何基础设施层。但我正在查看很多实现事件源聚合的示例。奇怪的是,几乎所有示例在基本聚合类上都有一个
Version
属性。像这样的东西
abstract class Aggregate {
public ID: string;
public version: string;
// the rest
}
我看到这个
version
属性对整个域逻辑没有任何价值。它存在的唯一原因是为了帮助解决事件溯源和事务并发原因。对我来说这似乎是一个泄漏。但我不知道替代方案是什么。
所以我的问题是首先验证这是否是泄漏。其次,是询问如何解决这个问题。
所以我的问题是首先验证这是否是泄漏。
是的,是的。
其次,是询问如何解决这个问题。
大多数人只是忽略它。真的。
您在这里看到的是大多数人希望在写入事件流时使用乐观并发这一事实的副作用。
为此,您需要从数据库中获取一些信息read,以便在执行数据库write时可用 - 换句话说,类似于“比较和交换”的东西。 (曾经有过 git 存储库因为其他人先推送而拒绝你的推送吗?同样的想法。)
因此,无论采取何种形式,元数据都需要在执行过程中创建消息以将更改保存到事件存储中时可用。
(注意:这不仅仅是一个事件存储约束 - 如果您在共享文档存储或共享关系数据库上使用乐观并发,您也会遇到类似的问题。)
所以谜题就变成了:我愿意做出哪些权衡才能将我需要的信息送到我需要的地方。
其中一个是这样的问题:您是要每次都从实体的历史记录中构建实体的新副本,还是要重新使用上次使用实体时的缓存副本?
如果您要使用实体的缓存副本,那么您需要有一些可用的机制来确定您拥有的实体的副本是否与您拥有的历史记录的副本一致。
用另一种方式表达相同的想法:内存中的实体是单一“真理来源”的概念本身就是一个有漏洞的抽象,如果我们的目标是一个可靠的系统,那么我们需要解决抽象与现实之间的差异。
解决这个问题的第一步是评估它是否是需要解决的问题。
没有人会奖励那些完美分离领域和持久性的实现。在模型中使用持久性元数据设计的解决方案仍然可以为客户提供价值。
但替代方案包括:
允许模型中存在元数据,但仅作为不透明令牌。域模型独立于令牌的任何特定实现,因此您的依赖关系图仍然指向正确的方向(即,您可以更改持久性而无需修改域代码)。
将元数据保留在“信封上”;不在域对象中,而是在保存实体的缓存副本的值中。
不要缓存,只需每次从头开始重建实体,并在本地保留元数据可用,直到不再需要它为止。
将领域行为与数据模型分开;换句话说,将域逻辑实现为特征/混合的集合,并创建持久性特定数据模型来托管它们。
这些都不是伟大的——你放弃一些这个来得到一些。所以你可以做出最好的交易并继续下去。