产生新的错误时,应该包含必要的上下文信息。包括出错时的堆栈信息、必要参数、具体的错误信息。
我们常常看到无头无尾的错误日志,比如
- 网络库返回了一个 io timeout
- 数据库返回了一个 Not Found
- JSON序列化库返回了一个 can’t convert int to string
- HTTP API 返回了 system error
- 。。。
记录堆栈信息可以用来判断调用方是哪个入口函数。对应到 HTTP 接口层面,我们还应该记录请求方的信息,比如 ip、服务名称等。
记录引发错误的参数,可以用来复现错误。
记录具体的错误信息,可以让我们更清楚错在哪里。经常看到许多 JSON 反序列化库提示字段类型不对,但又不说明是哪个字段。导致开发同学一个个去尝试,浪费许多时间。
用户错误 vs 系统错误
系统错误一般我们预期之内的错误,比如网络超时、找不到文件等等。这些错误暴露给用户时,用户一定是看不懂的,也不知道接下来该如何做。通常情况下,我们需要把系统错误转变成用户可以看得懂的提示。
用户错误是指用户产生了不合规的数据,比如密码长度不够、帐号重复等。这类错误应该靠提前的断言来避免后续的连带错误,例如写入脏数据,或者长度不够时导致下游数组越界等。
复用代码,简化、标准化错误处理
许多人其实内心很清楚如何处理错误,之所以没有认真处理只是因为懒。懒并不是什么见不得人的缺点,毕竟每个人写代码时都有各种各样的压力和主要诉求。
对此,我们的处理方法是简化处理错误的时间成本,如果每次处理错误都需要你写一堆 if 或者 try catch。那么你自然会不由自主地偷懒和放弃。假如每次只需要一个简单的函数就可以处理错误,你也许就愿意写这个代码了。
参考
- https://www.ktanx.com/blog/p/5064JAVA中异常处理的最佳实践
- 关于JAVA异常处理的20个最佳实践 https://segmentfault.com/a/1190000015028573
- 异常和错误处理的新式 c + + 最佳做法 https://docs.microsoft.com/zh-cn/cpp/cpp/errors-and-exception-handling-modern-cpp?view=msvc-160
- 异常处理最佳实践 http://blog.zollty.com/b/archive/best-practice-for-exceptional-handling.html
- 错误码到底比异常优越在哪 https://www.zhihu.com/question/264724166
