pro*_*mer 10 error-handling domain-driven-design exception-handling
我正在尝试找一篇关于DDD实体如何处理错误的好文章/示例(以及将被视为异常错误和什么不会错误)以及它们如何将它们传递到调用应用程序层(通常包含事务中的操作)那将需要回滚).
目前我正在考虑将所有会破坏聚合事务(例如验证)的错误视为异常.这样我就可以在"catch"块中回滚事务.例如:
SomeApplicationService:
// start transaction here
// ...
try
{
$user = $userRepository->userOfId($id);
$user->doSomething();
$user->doSomethingElse(); // <-- imagine an error thrown here
$userRepository->save($user);
}
catch (CustomFriendlyForUIException $e)
{
// Custom Friendly for UI error
// Rollback transaction and add error/message to UI payload DTO
// ...
}
catch (AnotherCustomException $e)
{
// Not friendly to UI, so use general error message for UI
// Rollback transaction and add error/message to UI payload DTO
// ...
}
catch (Exception $e)
{
// Catch all other exceptions, use general error message for UI
// Rollback transaction and add error/message to UI payload DTO
// ...
}
// end transaction
Run Code Online (Sandbox Code Playgroud)
这是正确的方法,还是我错过了什么?
小智 7
通常,有两种类型的错误:
具有商业意义的商业错误。例如,StockFullError、ProductNotAvailableError等。这些错误是预料之中的,因为它们是在代码中显式创建的。
此类错误可以使用异常或使用函数方式来实现:在返回类型中显式显示错误。例如:Either<Error, T>。
异常使代码更简单。处理错误的函数式编程方式使代码更容易推理并且更可预测。我建议后者。
基础设施错误是与数据库、网络、外部服务等相关的错误。这些错误通常是意外的。
发生错误。当错误发生时,您不希望应用程序处于不一致的状态。例如,您希望避免将一半的聚合存储在数据存储中。
这里的关键问题是保持总体完整性。关键点是何时必须将聚合写入数据存储中。我可以看到两种情况:
一旦您的数据存储可以提供原子操作,就不必担心数据完整性,因为原子操作的结果要么失败,要么成功。不存在部分写入。
这意味着你可以让你的 http 层处理异常并返回 500 例如。
有时,确保原子性是不可能的。
如果您需要将聚合存储在多个表中,有一些解决方案:
当您发送电子邮件并将某些内容保存在数据库中时,您无法将电子邮件包含在事务中。
在这种情况下,您可以使用 SAGA。这个想法是,有时,您无法通过一个大事务来强制执行原子性。然而,通常很容易进行几笔小额交易。
SAGA 的想法是将每一个事务与一个补偿事务相关联。例如,给定“交易”:发送电子邮件以确认购买了产品,补偿性“交易”可以发送一封电子邮件以使用优惠券道歉。
每笔交易都运行小交易。如果其中之一失败,则会运行补偿事务。最终,这能够获得原子性。
| 归档时间: |
|
| 查看次数: |
1777 次 |
| 最近记录: |