读《编程匠艺——编写卓越的代码》:防御性编程

田纳西.威廉斯(Tennessee Williams):
我们彼此猜忌,实属情非得已。这是我们防止背叛的唯一武器

一、编写优秀代码:

《程序设计原理》中M.A.Jackson写道:
软件工程师的智慧,就在于他们是否开始意识到:使程序能用和使程序正确,这两者之间有什么样的差别

  1. 可用的代码:提供常规输入集,代码给出常规输出;一旦有意外输入,代码崩溃。
  2. 正确的代码:对于所有输入集,有正确的输出;
  3. 优秀的代码:一定是正确的代码;逻辑容易理解;代码自然;容易维护。

产品级的代码,面对不常见的输入时不会崩溃,也不会出现错误的结果;同时,满足其他要求,包括『可重入』、『线程安全』、时间约束等

二、一种防止代码漏洞百出的手段——防御性编程

墨菲定律(Murphy's Law):
凡是可能出错的事,准会出错

防御性编程通过预见到(至少预先推测到)问题所在,断定代码中每个阶段可能出现的问题,并做出相应的防范措施,来防止这类意外产生

三、防御性编程技巧

  1. 使用好的编码风格和合理的设计
    命名合理;审慎地使用括号;
    编码前,设计好接口

  2. 避免闪电式编程
    每敲一个字,都想清楚你输入的是什么
    进入下一个环节之前,完成上一个代码段的所有任务

  3. 不要相信任何人
    任何人,包括你自己,都可能把缺陷引入你的程序逻辑中
    用怀疑的眼光审视所有的输入和所有的输出,直到确保正确为止。
    在程序各处添加安全检查

  4. 保持代码简单
    将复杂的代数运算拆分为一些列单独的语句,使逻辑清晰。

  5. 不要让任何人做他们不该做的修补工作
    面向对象语言中,将属性设置为private,并提供public函数操作它们;
    如果变量可以声明为函数内局部变量,不要在文件范围内声明;
    如果变量可以声明为循环体内局部变量,不要在函数范围内声明。

  6. 编译时开启所有警告开关
    编译器的警告能捕捉到许多愚蠢的编码错误;

  7. 使用静态分析工具
    编译器只能对代码进行有限的静态分析;
    静态分析工具:C语言的lint;.NET的FxCop

  8. 使用安全的数据结构
    最常见的安全隐患为缓冲溢出,缓冲溢出是由于不正确地使用固定大小的数据结构而造成的;
    避免的方法:
    使用更安全的不允许破坏程序的数据结构——使用类似C++的string类
    对不安全的数据结构使用更安全的操作

  9. 检查所有的返回值
    大多数难以察觉的错误都是因为程序员没有检查返回值而出现的

  10. 重视所有稀有资源,审慎地管理它们的获取和释放
    显式地终止那些不再使用或不会被自动清除的对象的引用
    不要循环引用(A引用B,B引用A)

  11. 在声明时对变量初始化

  12. 尽可能推迟变量的声明
    使变量声明的位置和使用它的位置尽量接近,从而防止干扰其他代码
    不要在多个地方重用同一个临时变量

  13. 使用标准化语言工具,写标准化语言

  14. 使用好的诊断信息日志工具

  15. 审慎地使用强制转换
    数据的强制转换会影响代码的可移植性

  16. 细则
    提供默认行为:如同switch语句都带default一样,写一个不带else的if语句应当深思;
    遵从语言习惯
    检查数值上下限:防止数值型变量上溢和下溢;确保每次运算可靠稳定(被除量不能为0)。
    正确的设置常量:尽可能把可以设置为常量的都设置为常量。

  17. 约束
    前置条件:输入一段代码前必须为真的条件,一般对参数作限定;
    后置条件:编写一段代码后必须为真的条件,一般对结果作判断;
    不变条件:每当程序执行到达特定点(循环中、方法调用等)时为真的条件,防止逻辑错误;
    断言:任何关于程序在给定位置状态的陈述;

  18. 约束的内容
    检查所有的数组访问是否都在边界内
    在废弃指针之前断言指针是非零的
    确保函数参数有效
    在函数结果返回之前对其进行充分检查

  19. 移除约束
    通常在程序构建的开发和调试阶段,才需要约束检验;确保程序逻辑正确后,理论上可以移除。
    C/C++标准库提供了公共机制——断言;指定为NDEBUG编译,可移除断言
    Java通过JVM启动或禁用断言机制
    .NET在框架Debug中提供断言机制

内容相关:

可重入代码:允许被多个进程同时访问和使用的一段代码,而且无论哪个进程调用它,所得到的结果都是一样。为了防止某一个进程的修改而导致不同进程的结果不同,可重入代码中一般采用局部变量不使用全局变量或静态变量。

线程安全:如果你的代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码。如果每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,表示你的代码是线程安全的。

静态分析:程序运行前,执行代码检查

你可能感兴趣的:(读《编程匠艺——编写卓越的代码》:防御性编程)