【发布时间】:2024-01-21 17:48:01
【问题描述】:
我实现了事件源实体(在域驱动设计中它被称为聚合)。创建丰富的域模型是一种很好的做法。领域驱动设计 (DDD) 建议尽可能将所有与业务相关的事物放入核心实体和价值对象中。
但是将这种方法与事件溯源结合使用时会出现问题。与事件源系统中的传统方法相比,首先存储事件,然后在构建实体以执行某些方法时应用所有事件。
基于此,最大的问题是在哪里放置业务逻辑。通常,我希望有一个类似的方法:
public void addNewAppointment(...)
在这种情况下,我希望该方法确保不违反任何业务规则。如果是这种情况,将引发异常。
但是当使用事件溯源时,我必须创建一个事件:
Event event = new AppointmentAddedEvent(...);
event store.save(event);
目前,我探索了两种在存储事件之前检查业务规则的方法。
首先,检查应用层内的业务规则。 DDD 中的应用层是委托层。实际上,它不应该包含任何业务逻辑。它应该只委托诸如获取核心实体、调用方法和保存东西之类的事情。在此示例中,将违反此规则:
List<Event> events = store.getEventsForConference(id);
// all events are applied to create the conference entity
Conference conf = factory.build(events);
if(conf.getState() == CANCELED) {
throw new ConferenceClosed()
}
Event event = new AppointmentAddedEvent(...);
event store.save(event);
显然,将约会添加到已取消会议的业务规则不应泄露到非核心组件中。
我知道的第二种方法是将命令的处理方法添加到核心实体:
class Conference {
// ...
public List<Event> process(AddAppointmentCommand command) {
if(this.state == CANCELED) {
throw new ConferenceClosed()
}
return Array.asList(new AppointmentAddedEvent(...));
}
// ...
}
在这种情况下,好处是业务规则是核心实体的一部分。但是这违反了关注点分离原则。现在,实体负责创建存储在事件存储中的事件。除此之外,一个实体负责创建事件感觉很奇怪。我可以争论为什么一个实体可以处理事件是很自然的。但是为存储而不是自然发布而创建领域事件感觉不对。
你们中有人遇到过类似的问题吗?您是如何解决这些问题的?
现在,我将只讨论应用程序服务解决方案中的业务规则。它仍然是一个地方,还可以,但它违反了一些 DDD 原则。
我期待您在 DDD、事件溯源和传入更改验证方面的想法和经验。
提前致谢
【问题讨论】:
-
一些implementations 在事件溯源出现之前就已经从领域层发出了领域事件。仅仅因为一个远程副作用是事件最终存储在某个地方并不意味着您的实体受到持久性逻辑的污染。
标签: domain-driven-design cqrs event-sourcing