关于业务代码的错误处理,我的理解:
封装好的业务逻辑方法( HelperClass, Utils ),应当返回一个 Result。这个 Result 可以组织成这个结构:
{
ErrorCode String
Data Dictionary<string, string>
}
ErrorCode:用于给前端传递约定好的错误代码,例如'NicknameAlreadyExist'。
Data:用于给前端传递进一步细化错误的数据。例如前端传过来一个请求,要转账 400 元。你和前端约定,如果不足 400 元,为了告诉用户更多信息,就将它的余额{money: 300}加在 data 里面。
还可以设置一些字段支持多个错误代码,但我觉得大部分时间没必要。
还可以设置一些字段来告诉 http 请求发起者更多信息,详见各大 api 规范,例如
https://github.com/Microsoft/api-guidelines/blob/master/Guidelines.md 。
还可以设置一些字段来储存调试信息,这些信息可能会帮助到你再看错误日志的时候快速 debug。
但是,这样做有几个需要注意到的要点。
这样设计 HelperMethod 实际上是 Try-Parse Pattern。
HelperMethod 可能会被直接拿去用,也可能会被 HelperMethod 嵌套使用。当直接用的时候,调用者相当于客户端。当被其他 HelperMethod 嵌套调用的时候,大部分情况是像 GoLang 一样返回。也还有其他情况,例如:在方法 A 中,我调用方法 B。方法 A 的代码已经对一些条件进行了数据库的查询、检查。这些检查,可能碰巧的涵盖了方法 B 的检查。所以,方法 A 此时认为,对 B 的调用是一定会返回 success 的。所以如果返回了一个 error,那么就应当直接抛出异常(或者在 error 里附带这一层的某些有助于调试的信息),Exception.Data 里面附带这个 error。这很自然,因为这个内层的 error 不该返回给前端,因为用户会对这个 error 里面的内容可能会不知所云。
异常抛出了,然后被你的 http 框架( spring/WebApi )捕获,然后被你的 logger 记录。你去看 log,里面你记录的调试信息就可能会帮助你还原问题,尽快 debug.
---
跳出异常的话题。HelperClass 虽然被广泛使用,但有很多弊端。
在性能上,可能重复查数据库很多遍,检查某个条件。
在开发效率上,会出现领域知识的割裂、分散;持久层逻辑的污染;健忘。DDD 是解决方案。