Distinguish Business Exceptions from Technical 21

Distinguish Business Exceptions from Technical

There are basically two reasons that things go wrong at runtime: technical problems that prevent us from using the application and business logic that prevents us from misusing the application. Most modern languages, such as LISP, Java, Smalltalk, and C#, use exceptions to signal both these situations. However, the two situations are so different that they should be carefully held apart. It is a potential source of confusion to represent them both using the same exception hierarchy, not to mention the same exception class.

An unresolvable technical problem can occur when there is a programming error. For example, if you try to access element 83 from an array of size 17, then the program is clearly off track, and some exception should result. The subtler version is calling some library code with inappropriate arguments, causing the same situation on the inside of the library.

It would be a mistake to attempt to resolve these situations you caused yourself. Instead we let the exception bubble up to the highest architectural level and let some general exception-handling mechanism do what it can to ensure the system is in a safe state, such as rolling back a transaction, logging and alerting administration, and reporting back (politely) to the user.

A variant of this situation is when you are in the “library situation” and a caller has broken the contract of your method, e.g., passing a totally bizarre argument or not having a dependent object set up properly. This is on a par with accessing 83rd element from 17: the caller should have checked; not doing so is a programmer error on the client side. The proper response is to throw a technical exception.

A different, but still technical, situation is when the program cannot proceed because of a problem in the execution environment, such as an unresponsive database. In this situation you must assume that the infrastructure did what it could to resolve the situation — repairing connections and retrying a reasonable number of times — and failed. Even if the cause is different, the situation for the calling code is similar: there is little it can do about it. So, we signal the situation through an exception that we let bubble up to the general exception handling mechanism.

In contrast to these, we have the situation where you cannot complete the call for a domain-logical reason. In this case we have encountered a situation that is an exception, i.e., unusual and undesirable, but not bizarre or programmatically in error. For example, if I try to withdraw money from an account with insufficient funds. In other words, this kind of situation is a part of the contract, and throwing an exception is just an alternative return path that is part of the model and that the client should be aware of and be prepared to handle. For these situations it is appropriate to create a specific exception or a separate exception hierarchy so that the client can handle the situation on its own terms.

Mixing technical exceptions and business exceptions in the same hierarchy blurs the distinction and confuses the caller about what the method contract is, what conditions it is required to ensure before calling, and what situations it is supposed to handle. Separating the cases gives clarity and increases the chances that technical exceptions will be handled by some application framework, while the business domain exceptions actually are considered and handled by the client code.

By Dan Bergh Johnsson

区分业务例外和技术例外
运行时出错的原因基本上有两个:阻止我们使用应用程序的技术问题和阻止我们滥用应用程序的业务逻辑。大多数现代语言,如LISP、Java、Smalltalk和C#,都使用异常来表示这两种情况。然而,这两种情况是如此不同,应该小心地将它们分开。使用相同的异常层次结构来表示它们,更不用说使用同一个异常类了,这可能会造成混淆。
当出现编程错误时,可能会出现无法解决的技术问题。例如,如果您试图从大小为17的数组中访问元素83,那么程序显然偏离了轨道,应该会出现一些异常。更微妙的版本是用不适当的参数调用一些库代码,导致库内部出现同样的情况。
试图解决你自己造成的这些情况是错误的。相反,我们让异常上升到最高的体系结构级别,并让一些通用的异常处理机制尽其所能确保系统处于安全状态,例如回滚事务、日志记录和警报管理,以及(礼貌地)向用户报告。
这种情况的一种变体是,当您处于“库情况”时,调用方违反了您方法的约定,例如,传递了一个完全奇怪的参数或没有正确设置依赖对象。这与访问17中的第83个元素是一样的:调用者应该已经检查过了;不这样做是客户端的程序员错误。正确的回应是抛出一个技术异常。
另一种不同但仍然是技术性的情况是,由于执行环境中的问题,例如数据库没有响应,程序无法继续。在这种情况下,您必须假设基础设施已经尽其所能解决了这种情况——修复连接并重试合理的次数——但失败了。即使原因不同,调用代码的情况也是相似的:它对此无能为力。因此,我们通过一个异常向通用异常处理机制发出信号。
与此相反,我们的情况是,由于域逻辑原因,您无法完成调用。在这种情况下,我们遇到了一种例外情况,即不寻常和不可取的情况,但并不奇怪或程序错误。例如,如果我试图从资金不足的账户中提取资金。换句话说,这种情况是合同的一部分,抛出异常只是一种替代的返回路径,它是模型的一部分并且客户应该意识到并准备好处理。对于这些情况,创建一个特定的异常或单独的异常层次结构是合适的,这样客户端就可以根据自己的条件处理这种情况。
将技术异常和业务异常混合在同一层次结构中会模糊区别,并使调用者混淆方法约定是什么、在调用之前需要确保什么条件以及应该处理什么情况。将案例分开可以使情况变得清晰,并增加了由某些应用程序框架处理技术异常的机会,而业务域异常实际上是由客户端代码考虑和处理的。
作者Dan Bergh Johnsson

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

CodingLife99

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值