论坛首页 Java企业应用论坛

网站中异常设计思考

浏览 7625 次
精华帖 (2) :: 良好帖 (8) :: 新手帖 (0) :: 隐藏帖 (7)
作者 正文
   发表时间:2010-08-15   最后修改:2010-11-28
网站应用和其他应用(比如框架设计)有些不同之处,以下是对网站系统中异常设计和处理的一些思考。

1 异常
2 结果码
3 问题

1 异常

首先是关于异常的选择,Java的异常分为检查型异常和运行时异常,关于这两种异常的优缺点已经有无数人的无数文章做过讨论。
检查型异常是一个好东西,最大的优点是把异常作为了方法约定不可分割的一部分,强制性的要求方法调用者思考如果有异常该怎么处理。
但是缺点也是很明显的,比如异常淹没,过多的异常转化,代码的维护性降低等等。

从系统的角度看,发生异常有3种情况。

1 client的请求条件不满足,比如client输入参数错误,或者业务条件不满足,无法完成本次业务。
2 编程错误,程序员的问题,导致有异常。因为世界上没有完美的程序员,所以也没有完美的程序,我们需要考虑编程错误的处理方式。
3 系统错误,请求是合法的,编程是正确的,但是我们是在现实世界中,总有一些超时啊,连接不可用的异常。

对于1,可以使用检查型异常或者运行时异常。在界面上提示用户为什么本次操作不成功,引导用户继续操作。
对于2,建议使用运行时异常,在界面上提示用户系统暂时不可用,网站监控系统应该可以及时的发现这种异常,程序员又有bug可以搞了。
对于3,可以在系统级别进行重试,或者用运行时异常,用户界面提示用户系统繁忙,稍后重试。

异常的性能稍微差一点。
可以使用结果码来改进性能。

2 结果码

其实结果码的历史很长,现在的编程语言中也处处可以看到它的踪影。
和异常一样,结果码可以设计成全站唯一,也可以设计成各个子系统有自己的体系,这时各个系统的调用需要做结果码转化。
和异常一样,结果码也可以划分。
1 请求条件不满足的结果码。
2 编程错误用结果码很难表达,因为不知道哪里的代码有问题。这是废话,要是知道有问题,早就把它解决了。但是也是有一些可以预防的,比如case中没有考虑的情况等等。
3 系统错误结果码,包含系统异常,编程错误。系统异常被转化成系统错误结果码。在调用其他系统时,被调用系统的编程错误异常也会抛上来,也是要转化成系统错误结果码。
4 请求成功。
5 重发请求,对于重发请求各个业务根据自己的需要进行处理。

3 问题

不论是使用异常还是结果码,都面临一个核心的问题,如果底层的接口增加了异常情况怎么办?
对异常体系来说,可以设计出好的异常体系屏蔽掉子类型的增加对系统的影响。但是,问题在于客户就没有了友好的提示信息。当然友好的提示信息可以在异常生成的时候就设置,但是这也有问题,各个系统对业务的要求是不一样的,底层系统无法在被调用的时候知道上层的业务条件。
结果码面临的问题一样,当底层增加一个结果码的时候,上层的调用方必须增加对应的处理。
这个问题的实质就是:异常情况本身就是方法不可分割的一部分,改变了异常情况,就是改变了接口,所以所有调用方都会受到影响。

没有一个好的方法可以从编程层面解决这个问题。
以下只是一些措施。
1 重视增加异常情况的重要性,这个相当于接口变更,一定要慎重,并且通知系统的调用方。激进的做法是改动这个方法的签名,这样所有的系统都会自动知道该接口已经变更。
2 接口返回的结果码一定是调用方可以理解的,避免返回一大堆调用方不关心的结果码,这个在接口设计中如果接口设计的太粗,会有这个问题。调用方应该处理每一种结果码。当遗漏一些结果码的时候,可以很快的通过编程异常发现。
3 对结果分类,确保不会遗漏大的分类。
如:
if(result.ok()){
}else if(result.systemerror()){
}else if(result.programmingError()){
}else if(result.userError()){
}else if(result.isRepeat()){
}else{
throw new ProgrammingException();
}
   发表时间:2010-08-15  
zhang_xzhi_xjtu 写道
3 对结果分类,确保不会遗漏大的分类。
如:
if(result.ok()){
}else if(result.systemerror()){
}else if(result.programmingError()){
}else if(result.userError()){
}else if(result.isRepeat()){
}else{
throw new ProgrammingException();
}

统一异常处理机制,流行的web框架都是有的
例如struts2的global-exception-mappings
springmvc的HandlerExceptionResolver
.......
规定好什么情况抛什么异常就好了
0 请登录后投票
   发表时间:2010-08-15  
duooluu 写道
zhang_xzhi_xjtu 写道
3 对结果分类,确保不会遗漏大的分类。
如:
if(result.ok()){
}else if(result.systemerror()){
}else if(result.programmingError()){
}else if(result.userError()){
}else if(result.isRepeat()){
}else{
throw new ProgrammingException();
}

统一异常处理机制,流行的web框架都是有的
例如struts2的global-exception-mappings
springmvc的HandlerExceptionResolver
.......
规定好什么情况抛什么异常就好了


恩 这个是对结果的进一步细分,如果都采用配置,可能导致 1异常过多,配置过于麻烦。2 异常体系是扁平的,但是拿不到用户友好的信息。问题的核心还是如果增加了异常怎么办,这个问题框架并没有解决。
0 请登录后投票
   发表时间:2010-08-16  
zhang_xzhi_xjtu 写道

...
3 问题

不论是使用异常还是结果码,都面临一个核心的问题,如果底层的接口增加了异常情况怎么办?
对异常体系来说,可以设计出好的异常体系屏蔽掉子类型的增加对系统的影响。但是,问题在于客户就没有了友好的提示信息。当然友好的提示信息可以在异常生成的时候就设置,但是这也有问题,各个系统对业务的要求是不一样的,底层系统无法在被调用的时候知道上层的业务条件。
结果码面临的问题一样,当底层增加一个结果码的时候,上层的调用方必须增加对应的处理。
这个问题的实质就是:异常情况本身就是方法不可分割的一部分,改变了异常情况,就是改变了接口,所以所有调用方都会受到影响。

没有一个好的方法可以从编程层面解决这个问题。
以下只是一些措施。
...
2 接口返回的结果码一定是调用方可以理解的,避免返回一大堆调用方不关心的结果码,这个在接口设计中如果接口设计的太粗,会有这个问题。调用方应该处理每一种结果码。当遗漏一些结果码的时候,可以很快的通过编程异常发现。
...

同意楼主的观点。
异常应该被认为接口或方法本身的不可分割的一部分。
返回码的定义要保证“一定是调用方可以理解的”,这个也很同意。
0 请登录后投票
   发表时间:2010-08-17  
  其实我一直觉得异常处理是系统中很重要但也很容易忽视的一部分,从某种意义上说,从一个系统的异常处理部分大致能够看出开发团队的水平、层次或者素养。在系统详细设计过程中,就应该考虑到异常体系的设计,比如异常的分类、处理异常的分层(DAO层?业务层?展现层?)、接口功能中所可能发生的异常、异常发生后的处理(执行另一段代码?向上层抛出异常并最终以错误提示展现给用户?记入系统日志以方便进行错误追踪?)等等。这整个是一个很庞大的工程,而且在编码实现当中往往很枯燥繁杂,就算将这部分内容纳入编码规范,也会存在开发人员偷懒省工的可能,这个时候就考验团队的执行力以及QA的测试力度了。
0 请登录后投票
   发表时间:2010-08-17  
楼主淘宝架构师?
0 请登录后投票
   发表时间:2010-08-17  
抛出异常的爱 写道
楼主淘宝架构师?

老抛好敏锐

可惜不是
0 请登录后投票
   发表时间:2010-08-18  
Java中的Exception本来就很科学,可惜很多人不知道"珍惜"。大多数应用程序处理异常仅仅作为一种逻辑判断,殊不知异常既有层次,又可以归类。

可以学习一下数据库和操作系统,内建的 Error Code系统快速定位,并且友好的提示,并且引导客户处理异常。

无法避免的是,在一些接口中,异常类型不能细化的问题,那么不过多态性和Error code可以来帮助获取提示信息。同样,分类的异常也可以很好的解决,可以看一下HTTP协议的Response状态号。
0 请登录后投票
   发表时间:2010-08-18  
mercyblitz 写道
Java中的Exception本来就很科学,可惜很多人不知道"珍惜"。大多数应用程序处理异常仅仅作为一种逻辑判断,殊不知异常既有层次,又可以归类。

可以学习一下数据库和操作系统,内建的 Error Code系统快速定位,并且友好的提示,并且引导客户处理异常。

无法避免的是,在一些接口中,异常类型不能细化的问题,那么不过多态性和Error code可以来帮助获取提示信息。同样,分类的异常也可以很好的解决,可以看一下HTTP协议的Response状态号。


恩,我现在也觉得内建的Error Code是一个好东西了。
特别在系统到了一定的复杂性之后。
0 请登录后投票
   发表时间:2010-08-18   最后修改:2010-08-18
zhang_xzhi_xjtu 写道
抛出异常的爱 写道
楼主淘宝架构师?

老抛好敏锐

可惜不是

结果码
这种上个世纪的设计方式
使用起来令人有寻死的想法.

PS:现在流行的方式是
抛出一个runtimeexception
用aop或struts.xml
使用全局异常来处理.

把异常看作一个可以跨越方法边界的goto来使用.设计异常的人飘过.参考我的名子
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics