有两种原因会导致系统出错:一个是技术原因,如程序bug,网络中断,内存不足,死锁,系统容量不够。还有一个是业务逻辑原因,如业务状态异常。大多数现代语言如C#,java都用异常(Exception)来表示这两种情况。不管怎么样,这两种情况很不一样,理应区分处理。使用同样的异常栈来表示这两种情况是造成混乱的潜在源头,更别提还使用同样的异常类。
当编程有错误时,一个无法解决的技术问题会发生。如访问数组下标越界,程序会出错,异常抛出。更微妙的是调用某些库函数时使用了不恰当的参数,导致库函数内部也会抛出异常。
自己直接尝试在异常发生位置处理通常是错误的,我们应当选择让异常向上传递到最高架构层,使用某些异常处理机制去确保系统保持在一个安全的状态,如回滚事务,记录日志并告警,以善意易懂的方式告知终端用户。
这种情况的变体是当调用库函数失败时, 如传递了一个离奇的参数,或依赖的对象未正确设置。这种情况客户端调用前应该做参数合法性校验,如果未这样做就是一个编程错误。
一种不同的情况,但还是属于技术原因的异常,这种情况是程序执行环境(Execution Environment)异常,如数据库无响应。这种异常情况需要假设基础设施能尝试解决它,如进行一定次数的重试。如果最终还是失败,系统能做的有限,抛出一个异常并向上传递,让通用异常处理机制处理。
跟以上不同,当遇到业务异常时不能同样处理,如取钱时账户余额不足。即这种情况的异常是业务功能的一部分,抛出异常是一个可选的返回路径,是业务逻辑的一部分。接收的客户端应该了解并小心处理它。对应这种情况应当创建一个特定的异常或指定的异常体系结构以方便客户端识别并处理它。
小结
使用同样的异常体系会使调用者无法分清是技术异常还是业务异常。所以,在实际开发中一定要使用不同的异常体系将它们明确分开。