什么是适当的事件采购事件?

时间:2016-06-22 17:13:03

标签: event-handling event-sourcing

有时我无法确定事件应该代表什么。例如,以下是银行帐户的简化Ledger

Ledger {
    date : Date;
    amount : Int;
    cleared : String;
}

用户通过输入参考文本来清除分类帐。或者用户可以通过将文本设置为空字符串来删除清除。

我的问题是,在跟踪事件源的变化时,我应该为用户打算做什么创建事件,例如:

Event clearLedger(clearText : String)
Event removeClearing()

或者我应该为幕后发生的事情制作一个更通用的事件,这在两种情况下都有效:

Event updateLedger(clearText : String)

这可以一直到达一个非常基本的CRUD级别,最终会在数据库的事务日志级别结束,所以这里有指导吗?

3 个答案:

答案 0 :(得分:2)

马匹课程。

  

我的问题是,在跟踪事件来源的变化时,我应该为用户打算做什么创建事件

可能。在实体边界内,它并不重要;但是从外部看历史,能够识别事件变化的背景可能非常有用。想想吧/子;一旦你有一个实体写作事件,你可能想要开始订阅这些事件。

例如,考虑更改客户资料中的地址。这可能是对早期数据输入中的拼写错误的纠正(业务跟踪错误率,寻找可纠正的系统性问题以改善客户体验),或者是客户的重新安置(在这种情况下,我们希望向他们的新客户发送欢迎套件)地址;或启动审核以根据现有政策审核新地址。

如果所有内容都存在于单个AddressChanged事件的保护之下,则会失去灵活性。最好的情况是,您发现自己试图仅从数据中猜测变化的背景。

另一方面,如果这种灵活性没有带来任何价值,那么你就不需要了。

也就是说,事件采购CRUD很奇怪 - 如果你不把这些变化看作是头等公民,为什么事件来源实体呢?写出聚合状态要简单得多。

  

写出事件和写出聚合状态有什么区别?

不是很多;阅读它们会有点不同。

不那么隐秘:写出聚合状态类似于现在写出聚合的样子。通常,这由持久性组件完成,该组件将当前状态序列化为DTO。例如,我们可以使用JSON文档表示Ledger的当前状态

{ "date"    : "2016-07-06"
, "amount"  : 40
, "cleared" : null
}

要稍后重新创建分类帐,我们只需从永久存储中获取json文档,然后让对象映射器继续工作。

写出历史,即事件,看起来更像是

[ { "event_type" : "LedgerCreated"
  , "data" 
  : { "date" : "2016-07-06"
    , "amount" : 40
    }
  }
, { "event_type" : "LedgerCleared"
  , "data"
  : { "reason" : "Because I said so" 
    }
  }
, { "event_type" : "ClearingRemoved"
  , "data"
  : {}
  }
]

要稍后重新创建分类帐,我们需要将json文档从永久存储中取出,然后使用对象映射器创建有序的事件序列,在其初始“种子”状态下创建Ledger,然后< em>将这些事件重新应用到我们的新Ledger实体,通过重播其历史记录中的每个更改,有效地发现Ledger现在的样子。

答案 1 :(得分:1)

无论商业专家使用什么语言,我都会。如果他们使用UpdateLedger,那么使用它。如果他们使用LedgerCleared那就使用那个。

答案 2 :(得分:1)

事件代表了一些业务运营,它们本身具有重要价值,可供查看和分析。例如,您可能希望查看清除分类帐清除的次数。如果这是你想要的,这就是你的领域专家所说的 - 做到这一点。如果你想做CRUD,就像@VoiceOnUnreason写的那样,请不要使用事件源CRUD。从本质上讲,您可能不仅仅是在谈论域事件。例如,您的汇总方法clearLedgerremoveClearance将生成哪种域事件。如果两个不同的业务操作产生相同的事件时间,那将是奇怪的。

您的候选人UpdateLedger会生成通用LedgerUpdated。然后几周之后,你将另一个操作添加到UpdateLedger中,它将变成一个庞大的膨胀方法,其中包含许多参数,这些参数正在检查nulls / empties和许多if语句。这可能是每个基本DDD讲座/书籍/演示文稿的第一个例子,作为糟糕设计的一个例子,首先做DDD的原因......

关于这个问题有两个简单的规则:

  • 如果您在命令,方法和事件中使用CreateUpdateDelete,则会产生CRUD气味。如果您正在做的是DDD
  • ,请问自己
  • 在命令处理程序(即应用程序服务)中使用if语句,它检查参数并决定如何更改聚合状态或调用哪种聚合方法,这是一种没有足够的粒度,交叉关注和违规的气味单一责任原则