我们的产品负责人告诉我们,如果客户在
片刻,并创建了一个设置将对此有效的过程
如果客户端不更新它,则处理它。如果客户离开支付
然后进行一些设置,当客户想要更新我们的流程时
系统将不允许更新它,因为实际设置不会
适合过程数据
这使得实施更加容易,因为基于流程设置的验证只需要在流程创建/更新场景中进行。此外,我猜想竞争条件也与业务无关,例如如果在创建/更新流程的同时更改设置。
有鉴于此,我们可以假设ProcessSettings 和Process 可以处于不同的一致性边界。换句话说,两者都可以是单独聚合根的一部分。
此外,重要的是要认识到基于设置的验证不是Process 不变量,这意味着Process 本身不应该负责执行这些规则。由于这些不是不变量,因此您也不应该争取始终有效的策略,而应使用延迟验证策略。
从那时起,有很多很好的方法可以对这个用例进行建模,这些都可以归结为:
//Application layer service
void createProcess(processId, applicationId, data) {
application = applicationRepository.applicationOfId(applicationId);
process = application.createProcess(processId, data);
processRepository.add(process);
}
//Application AR
Process createProcess(processId, data) {
process = new Process(processId, this.id, data);
this.processSettings.ensureRespectedBy(process);
return process;
}
如果ProcessSettings 是Application AR 的一部分,那么在Application 上放置一个工厂方法来创建进程可能是有意义的,因为它拥有执行验证所需的状态,就像上面的例子一样。这样就无需为任务引入专用域服务,例如独立工厂。
如果ProcessSettings 可以是它自己的聚合根,您总是可以这样做,但为设置引入查找域服务:
//Application AR
Process createProcess(processId, data, settingsLookupService) {
process = new Process(processId, this.id, data);
processSettings = settingsLookupService.findByApplicationId(this.id);
processSettings.ensureRespectedBy(process);
return process;
}
有些人可能会说您的聚合不再是纯粹的,因为它通过调用settingsLookupService 执行间接 IO。如果你想避免这种依赖,可以引入ProcessDomainService之类的域服务来封装创建/更新逻辑,甚至可以考虑查找逻辑不够复杂,直接放在应用层。
//Application layer service
void createProcess(processId, applicationId, data) {
processSettings = processRepository.findByApplicationId(applicationId);
process = application.createProcess(processId, data, processSettings);
processRepository.add(process);
}
我们无法判断哪种方法在您的特定情况下更好,有时甚至没有完美的方法,而且许多不同的方法可能同样好。根据经验,保持聚合纯粹是一个好主意,因为它更容易进行单元测试(更少模拟)。