1)编写无错代码的最好方法是把防止错误放在第一位。
注1:凡事预则立,不预则废。
2)使用编译程序所有的可选警告设施。
注1:提前发现隐患。
3)如果有单元测试,就进行单元测试,不要过分高估自己的编写正确代码的能力。
注1:测试是验证代码正确性的正规途径。
4)如果想要快速容易地发现错误,就要利用工具的相应特性对错误进行定位。
错误定位得越早,就能够越早地投身于更有兴趣的工作。
5)既要维护程序的交付版本,又要维护程序的调试版本。
关键是要保证调试代码不在最终产品中出现。
6)要使用断言对函数参数进行确认。
7)要从程序中删去无定义的特性,或者在程序中使用断言来检查出无定义特性的非法使用。
8)消除所做的隐式假定,或者利用断言检查其正确性。
9)利用断言来检查不可能发生的情况。
10)在进行防错性程序设计时,不要隐瞒错误。
11)要利用不同的算法对程序的结果进行确认。
12)不要等待错误发生,要使用初始检查程序。
13)暴露错误的关键是消除错误发生的随机性。
14)冲掉无用的信息,以免被错误地使用。
15)如果某件事甚少发生的话,设法使其经常发生。
16)自动保存调试信息,以便进行更强的错误检查。
注1:在实际项目开发中,调试信息是问题分析的重要工具。
17)建立详尽的子系统检查并且经常地进行这些检查。
18)详细设计程序的测试代码,任何选择都应该经过考虑。
注1:对各个分支情况进行测试。
19)最好的测试代码应该是透明的代码,努力做到透明的一致性检查。
20)不要把对交付版本的约束应用到相应的调试版本上,要用大小和速度来换取错误检查能力。
21)不要等到出了错误再对程序进行逐条跟踪。
22)当对代码进行逐条跟踪时,需要密切关注数据流。
23)对每条代码路径进行逐条跟踪。
24)对关键部分代码要进行汇编指令级的逐条跟踪。
25)要使用户不容易忽视错误情况,不要在正常地返回值中隐藏错误代码。
26)不要编写多种功能集于一身的函数,为了对参数进行更强的确认,要编写功能单一的函数。
27)不要模棱两可,要明确地定义函数的参数。
28)编写函数使其在给定有效的输入情况下不会失败。
29)编写注释突出可能的异常情况。
30)使用有严格定义的数据类型。
31)经常反问:“这个变量表达式会上溢或下溢吗?”
注1:避免越界访问。
32)尽可能精确地实现设计,近似地实现设计就可能出错。
33)一个“任务”应该一次完成。
34)避免无关紧要地if语句。
35)每种特殊情况只能处理一次。
36)避免使用嵌套的“?:”运算符。
37)避免使用有风险的语言惯用语。
38)不能毫无必要地将不用类型的操作符混合使用,如果必须将其混合使用,就用括号隔离开。
39)避免调用返回错误的函数。
40)只引用属于你自己的存储空间。
41)只有系统才能拥有空闲的存储区,程序员不能拥有。
42)指向输出的指针不是指向工作空间缓冲区的指针。
43)不要利用静态(或全局)量存储区传递数据。
44)紧凑的C代码并不能保证得到高效的机器代码。
45)为一般水平的程序员编写代码。
46)错误几乎不会“消失”(不会自己产生及改正)。
注1:随着AI的发展,未来很可能出现能够自主修复的程序。
47)马上修改错误,不要推迟到最后。
48)修改错误要治本,不要治表。
注1:需要找到问题的根本原因,否则很可能会引入其它问题。
49)除非关系产品的成败,否则不要整理代码。
50)不要实现没有战略意义的特征。
注1:避免需求蔓延。
51)不允许没有必要的灵活性。
52)在找到正确的解法之前,不要一味地“试”,要花时间寻求正确的解。
53)尽量编写和测试小块代码,即使测试代码会影响进度,也要坚持测试代码。
54)测试代码的责任不在测试员身上,而是程序员自己的责任。
55)不要责怪测试员发现了你的错误。
56)一个错误可能很轻微,但是它的存在本身就很严重。
57)建立自己的优先级列表并坚持之。