由错误处理引发的联想-防御式编程

  前两天和一同学谈到程序出错应该如何处理的问题,他讲到错误处理的两个原则,

  第一,应该在错误发生时立即将它抛出,而且得抛的很明显,有些人采用静默出错的原则,尝试修复错误并继续运行,这回导致代码调试起来很困难,所以他认为,当程序逻辑出错时,应该立刻崩溃,并生成一段有意义的错误消息,立即崩溃是为了不让事情变得更糟,错误消息应担被写入永久的错误日志,以便过后查明是哪里出错。

  第二,就是抛错要快,也要文明,文明抛错,就是只有程序猿才能看到程序崩溃时产生的详细错误消息,程序的用户绝对不能看到这些消息,另一方面,用户也应该得到一些警告,让他们知道有错误发生这一情况,以及可以采取措施来补救。

  以上这两点,我觉得还是蛮有道理的,重要的业务逻辑出错了,程序应该停止执行,避免错误蔓延扩散,产生一些列不可预知的问题,到最后都不知道哪出错了。

  但是,我又在想,这些都是事后的处理,那么如何提高程序的健壮性呢?联想到了《代码大全》 里面的一章,防御式编程。还有《注重实效的程序员》 这本书里面也有相关防御式编程的介绍。主要的防御式编程手段有断言、错误处理技术、异常、隔离。

  1 断言

  断言是常用的软件设计技术,其实很简单,就是一个判断一个布尔表达式的语句,如果这个布尔表达式为真,不会有任何效果,但是如果为假,就会告诉程序员,这里有一个断言,去看一下。

  需要注意一下几点:

   (1) 用断言来处理绝不应该发生的状况,用断言去检查一些理论上不可能发生的情况,因为如果发生了就说明内部逻辑有问题,也就是有bug了。

   (2) 避免把需要执行的代码放到断言中

   (3) 用断言来注解并验证前条件和后条件,

   (4) 断言是用来检测程序内部逻辑的,如果是和外部有数据交流,就不是断言的范畴。

  2 错误处理

  程序员在编写软件的时候,应该尽可能的预测到可能发生的错误,并对这些错误进行处理,另外,为使程序结构更加清晰,可以将错误的处理交给其它或专门的处理程序,而本身只是报告发生的错误,然后返回相应的错误码。

  当错误发生时,我们应该如何处理:

  a) 遇到错误数据的最佳做法就是继续执行操操作并简单地返回一个没有危害的数值,数值计算可以返回0,系统记录下这个错误。

  b) 把警告信息记录到日志文件中。

  c) 返回一个错误码,其实就是把错误向上抛出,由上游会有子程序处理该错误。

  d) 当程序出错时,就立即在出错的地方处理。

  e) 关闭程序,安全或性命攸关的程序,遇到错误,关闭是最好的选择。

  还有一个重要的原则:对错误进行分类,

  1.重大错误,程序崩溃,内存溢出等。这类错误一般不可恢复,通常的做法都是报告后直接退出,

  2.无关用户的一般性错误,这类错误一般情况下不会导致程序退出,而且和用户没有直接的联系,这时可以写入日志,以便以后进行排查。

  3.与用户相关的一般性错误,这类错误通常是由于用户输入错误数据引起这个时候,通常需要告诉用户,哪出错了,

  理解错误处理最重要的就是分清楚项目需要处理错误的类型,并对不同的错误采取恰当的处理方式。

  3 异常

  异常是指程序无法预料到的情况引发的错误,异常不仅在开发中起到很好的防御式作用,它更是一个非常好的调试工具,通过不断地缩小捕获异常代码的范围,准确找出错误的准确位置。

  1. 异常和断言一样,都是来处理那些不仅罕见甚至永远不该发生的情况,但是不可滥用,它弱化了类的“封装”性,可能增加复杂度。

  2. 如果可以在局部处理异常,就不要抛出。

  3. 在异常消息中加入关于导致异常发生的全部信息。

  4. 创建一个集中的异常报告机制,这样做能确保异常处理的一致性。

  5. 把项目中对异常的使用标准化,目的是保持异常处理便于管理。

  4 隔离

  隔离是在设计上简化错误处理的策略,事实上,如果所有的代码都做异常和错误处理,会使代码变得臃肿,可读性下降,我们需要在高层次上面避免这种情况的发生,

  1. 把某些接口选定为“安全”区域的边界,在这些接口里对边界数据进行合法性校验

  2. 将类的公用方法设计为特殊的安全方法,负责检查数据并进行清理,确保安全后,传递给私有方法进行正式操作

  3. 在输入数据时将其转换为恰当的类型

  5 总结

  软件的质量与其健壮性有很大的联系,作为软件的开发人员,要有足够的重视,不要忽视任何的细节,不能依赖测试去发现bug,而是要不断地思考可能发生的问题并采取进行预防,这才是防御式编程的本质。

 

时间: 2024-10-27 15:58:47

由错误处理引发的联想-防御式编程的相关文章

契约式编程与防御式编程

背景 事情的来由还要从几十几亿年前的一次星球大爆炸说起,sorry,背错台词了,是从几天前讨论接口返回数据和几个月前讨论课件本地数据结构说起,简单的说,就是碰到约定好的内容出现异常,是我们在程序中内部作兼容处理,还是抛出去. 打个比方,我们要解析一段json,约定这个json的格式,只能是正常格式,或者是空,那么一旦返回json的方法返回了一个『既不是正常格式,又不是空的异常值』,程序该如何处理呢? 小花:一旦碰到约定异常,程序必须兼容处理,一定不能让程序Crash小Fa:一旦碰到约定异常,就必

华山论剑之契约式编程与防御式编程

背景 事情的来由还要从几十几亿年前的一次星球大爆炸说起,sorry,背错台词了,是从几天前讨论接口返回数据和几个月前讨论课件本地数据结构说起,简单的说,就是碰到约定好的内容出现异常,是我们在程序中内部作兼容处理,还是抛出去. 打个比方,我们要解析一段json,约定这个json的格式,只能是正常格式,或者是空,那么一旦返回json的方法返回了一个『既不是正常格式,又不是空的异常值』,程序该如何处理呢? 小花:一旦碰到约定异常,程序必须兼容处理,一定不能让程序Crash 小Fa:一旦碰到约定异常,就

微软-Visual Studio启动时遇到错误 TaskScheduler 引发了异常

问题描述 Visual Studio启动时遇到错误 TaskScheduler 引发了异常 求大神指教错误如下 Microsoft Visual Studio TaskScheduler 引发了异常. 解决方案 重装系统吧.电脑可能被360等病毒污染了.

Android 响应式编程的未来展望:RxJava 2 版本前瞻

本文讲的是Android 响应式编程的未来展望:RxJava 2 版本前瞻, 下一代的 RxJava 已经发布:RxJava 2.如果你现在的工作项目使用 RxJava 1,现在可以选择迁移至新版本.但我们是应该马上动手迁移,还是应该等待一段时间,先做些项目的其他工作? 要做出这个决定,你需要仔细考虑一下「投资回报(ROI)」,想想花费时间进行迁移能否在短期或长期内得到回报. 迁移的好处 响应流的兼容性 RxJava 2 其中一个结构性变化就是增加了对响应流(Reactive Streams) 

防守式编程的艺术

本文讲的是防守式编程的艺术, 为什么开发人员不编写安全代码? 我们不再在这里讨论 "干净的代码" .我们从一个纯粹的角度,软件的安全性来讨论更多的东西.是的,因为一个不安全的软件几乎是没用的.让我们来看看不安全的软件意味着什么. 欧洲航天局的 Ariane 5 Flight 501 在起飞后 40 秒(1996年6月4日)被毁.10 亿美元的原型火箭由于机载导航软件中的错误而自毁. 在 20 世纪 80 年代,一个治疗机中控制 Therac-25 辐射的的代码错误,导致其施用过量的 X

.net非控件式编程的优越性

上个月头因为幻想曲同志的的造访,使得VIEW进入了重构期.将原有的架构全部推翻,使用标准的工厂三层模式,代码全部重写,加入缓存依赖,简化存储过程,改进整个项目的容错机制,等等. 整整一个月的奋战总算是重构完成,在重构中仍然保持不使用框架,不使用可视化控件.其实在重构之前有些朋友强烈推荐我使用 EnterpriseLibrary, 以及 Nhibernate 作为数据访问层框架.不过抱着学习底层知识的态度,我没有使用,一切方法都是纯手工打造. 在重构中最头疼的就是写实体层(valueobject)

牛仔式编程和粉红色的大檐帽

"牛仔式编程",这个词我们用在这里是来描述那种直接在生产环境服务器上修改代码的行为.那的确不是一种好的工作方法,我们通常不鼓励这种行为,但总有时候,你不得不这样做 - 开发和部署工作通常都是由一些制定好的流程组成,包括开发工作中的代码复查,为业主和QA提供确认服务的模拟环境服务器,最后一步部署到生产环境.任何代码的改动都需要重新执行这些步骤.这种做法是经过时间考验过的做法,它能确保我们产出有质量.没有错误的代码. 可是这种流程需要时间,时间是消耗资金的.客户希望我们能反应敏捷:当客户希

PHP OPP机制和模式简介(抽象类、接口和契约式编程)_php实例

1.抽象类 抽象类机制中总是要定义一个公共的基类,而将特定的细节留给继承者来实现.通过抽象概念,可以在开发项目中创建扩展性很好的架构.任何一个类,如果它里面至少有一个方法是被声明为抽象的,那么这个类就必须被声明为抽象的.被定义为抽象的方法只是声明了其调用方式(参数),不能定义其具体的功能实现.在类的声明中使用 abstract 修饰符就可以将某个类声明为抽象的. 1.1方法原型(prototype) 是指方法的定义中剔除了方法体之后的签名.它包括存取级别.函数关键字.函数名称和参数.他不包含({

艾伟:.NET 4.0 中的契约式编程

契约式编程不是一门崭新的编程方法论.C/C++ 时代早已有之.Microsoft 在 .NET 4.0 中正式引入契约式编程库.博主以为契约式编程是一种相当不错的编程思想,每一个开发人员都应该掌握.它不但可以使开发人员的思维更清晰,而且对于提高程序性能很有帮助.值得一提的是,它对于并行程序设计也有莫大的益处. 我们先看一段很简单的,未使用契约式编程的代码示例. // .NET 代码示例 public class RationalNumber { private int numberator; p