Domain driven design 使用事件源,如何使代表报告/索赔/记录的事件失效并更正?

Domain driven design 使用事件源,如何使代表报告/索赔/记录的事件失效并更正?,domain-driven-design,event-sourcing,Domain Driven Design,Event Sourcing,我是活动采购的新手,我正在考虑将其用于工业应用,以跟踪生产设施中储罐、管道和各种物理组件之间的连接 我最初的想法是使用命令和事件,例如ConnectPipeToTank→ 管道连接到存储库。然而,“记录簿”不是应用程序本身,而是生产设施中实际发生的事情。因此,使用命令和事件(如ReportPipeConnectedToTank→ 管道连接到数据库已报告 这样的事件仍然是一个事实,但事实的真正意义只不过是用户在给定时间点对另一个时间点发生的事件所做的报告/声明/记录。其他用户将根据这些报告作出决定

我是活动采购的新手,我正在考虑将其用于工业应用,以跟踪生产设施中储罐、管道和各种物理组件之间的连接

我最初的想法是使用命令和事件,例如
ConnectPipeToTank
→ <代码>管道连接到存储库。然而,“记录簿”不是应用程序本身,而是生产设施中实际发生的事情。因此,使用命令和事件(如
ReportPipeConnectedToTank
→ <代码>管道连接到数据库已报告

这样的事件仍然是一个事实,但事实的真正意义只不过是用户在给定时间点对另一个时间点发生的事件所做的报告/声明/记录。其他用户将根据这些报告作出决定

但当然,没有任何东西可以保证这些报告是准确的(打字错误、恶意输入、输入时不完整的知识等)。因此,我们需要一种在不消除报告在某个时间点不正确的知识的情况下更正报告的方法:我们需要能够修改报告。我们希望双时态系统能够执行审计

在事件源中,事件是不可变的,那么如何正确地使表示报告的事件失效和更正呢

我想到了两种处理方法:

我提供了一对新的命令和事件来更正报告
correctedPipeConnectedToTankReport
→ <代码>管道连接到坦克报告已更正 以及使报告无效
invalidateEpiSeconnectedToTankReport
→ <代码>PipeConnectedToTankReportInvalidated 这些事件将引用初始事件

或者,我提供了一个新的通用事件来使表示报表的任何其他事件无效:
ReportInvalidated
,该事件将引用相关事件。 然后,更正报告
correctedPipeConnectedToTankReport
→ <代码>报告无效,
管道连接到已报告的银行
使报告无效
invalidateEpiSeconnectedToTankReport
→ <代码>报告无效

这似乎不是我的领域特有的问题,因此我认为有一种适当的方法来解决

我是活动采购的新手,我正在考虑将其用于工业应用,以跟踪生产设施中储罐、管道和各种物理组件之间的连接

“记录簿”不是应用程序本身,而是生产设施中实际发生的事情

Greg Young讨论的是一个好的评论谈话

我的建议是:将从生产设施传输到系统的消息视为事件,而不是命令,可能更容易理解。记录簿是一种工具,您的解决方案是维护记录簿的缓存副本

在你的情况下,事情变得更加复杂,因为你收到的信息可能不准确。这可能意味着某种补偿事件来处理数据错误,可能是通过显式地对有效时间和报告时间进行建模


它可以像支持回溯事件一样直接,也可以像简单的
ReportRetracted
事件一样,表示管道中的其他事件应该被忽略。

马丁·福勒在其关于的网站上回答了这个问题

[…]追溯事件本身始终是一个事件。考虑拒绝事件事件,这是事件日志中事件的删除。然而,事件日志的全部要点是,我们从不删除事件。因此,我们可以做的是将拒绝事件插入日志[…]

因此,要拒绝(或使之无效)报告/索赔/记录事件,只需发布一个
EventRejected
,其中包含需要拒绝的事件的
event\u id


要更正报告/索赔/记录事件,请首先发布一个
EventRejected
,其中包含需要拒绝的事件的
event\u id
,然后发布一个带有更正数据的新报告/索赔/记录事件。

这是我长期以来一直担心的问题,但我从未花时间为自己回答或寻求答案。你提出的解决方案是我想到的,但是有很多隐藏的复杂性。例如,如果系统强制执行一些不变量,如最大连接管道数b/c管道在现实生活中只有x个连接器,那么更改单个事件可能无法在系统中带来一致性,这意味着您必须创建一种机制,以同时批处理多个更正。如果对事件的顺序有规则的话,这可能会变得相当复杂。此外,特定日期的报告仍然需要考虑未来的事件(更正)。我看到的另一个问题是,您真正想要做的是修补命令,而不是事件。命令不会总是将1-1与事件匹配,纠正此类过程变得更加复杂。此外,如果您允许替换事件,这意味着它们现在必须有单独的ID,并且域必须知道,除非您决定在较低级别修补流。修复任意过去状态有很多复杂的考虑因素。这显然不像固定账户余额那么简单。也许Greg在他关于版本控制的事件资源书中谈到了这一点(还没有时间阅读)。当我有时间的时候,我会一直考虑这个问题…@plalx:你的评论很有趣。Greg Young提到了一个接近可被视为报告事件的事件。为了澄清:我的系统是(将是)主要生产设施系统,并且位于设施本身。这些报告由人工用户直接在系统中输入。我的答案是否定的