防御式编程的思想体现在两个方面:
程序对内部错误表现出来的极端脆弱
程序对外部错误表现出来的极端顽强
内部错误是指程序的基本逻辑错误,例如在 zmq 中 套接字范式如果用错,程序会立即崩溃。
外部错误是指由于网络波动、硬盘空间不足等出现的问题。对这类问题应当最大程度进行容忍。
zmq 中就使用了这种思想。 |
内部错误
断言是让程序变得脆弱的一种方式。当断言条件不满足时,程序会立即退出。当一种错误无论如何都不应当发生时,可以使用断言进行检查,断言可以用来检查:
输入参数或输出参数在预期范围内:例如传入了一个错误地端口号
指针非空
断言只发生在开发和维护阶段,在成品代码中不应当出现断言消息。
此外,当发生了内存不足之类的问题,程序唯一能做的应该是立即关闭程序,不要再运行了。
外部错误
程序应当避免来自外部错误的影响,所谓外部错误也可以用来当作预期会发生的情况,主要方式有:
读输入数据进行检查:
检查所有来源于外部的数据
检查函数中所有输入参数的值
当输入数据不合法时,程序可以采取以下行为:
返回一个中立值。例如空字符串
返回一个错误代码
抛出异常
返回上一次正确的数据
返回最接近的合法值
在日志中记录警告消息,然后继续执行
调用错误处理子程序
辅助调试的代码
开发期间的代码允许滥用资源以换取对开发效率的支持,而不需要遵循产品代码中对效率、安全等的要求。
尽早进入辅助调试的代码
计划移除辅助调试的代码
进攻式编程
进攻式编程时这样一种思想:在开发阶段让异常情况暴露出来,异常越大越好,而在代码运行期间让其能够容忍这些错误,主要方式有:
一旦出现问题,直接使用断言终止程序。不要给程序员留下继续执行的机会
对分配的所有内存进行填充。以此检查内存分配错误
对分配的文件或流进行填充。依次排除文件格式错误
确保每个 switch 中的 default 或者 else 分支都被断言终止
在删除一个对象之前把他填满一个垃圾数据
在软件发布后将错误保存到日志文件中。
产品代码中需要保留多少防御式代码
保留检查重要错误的代码。例如如果 excel 的计算引擎部分出现问题,应当立即终止
去掉检查细微错误的代码。这里的去掉并不是直接删掉,而是使用预编译等将其删除,抑或是检查到错误后记录到日志中
去掉可以导致程序硬性崩溃的代码。这种代码应当只存在于开发期间
保留能够让程序稳定崩溃的代码。这种程序的崩溃在自己的控制中,可以保留一些调试信息
确保错误消息是友好的