之前阅读的是《代码大全2》的前半部分,后来又读了后面的一部分,进行了如下的总结:
8、防御式编程
防御式编程的主要思想是:子程序应该不因传入错误数据而被破坏,哪怕是有其他子程序产生的错误数据。简单点讲就是容错性。
要点:
最终产品代码中对错误的处理方式要对“垃圾进,垃圾出”复杂得多。
防御式编程技术可以让出错误更容易发现、更容易修改,并减少错误对产品代码的破坏。
断言可以帮助人尽早发现错误,尤其是在大型系统和高可靠性的系统中,以及快速变化的代码中。包含C++
、Java和Microsoft Visual Basic在内的很多语言都支持断言
关于如何处理错误输入的决策是一项关键的错误处理决策,也是一项关键的高层设计决策。常用处理技术:返回中立值、换用一一个正确的数据、返回与前次相同的数据、换用最接近的合法值、把警告信息记录到日志文件中、返回一个错误码、调用错误处理子程序或对象、当错误发生时显示出错信息、用最妥当的方式在局部处理错误、闭关程序。
异常提供了一种与代码正常流程角度不同的错误处理手段。如果留心使用异常,它可以成为程序员们知识工具箱中一项有益补充,同时也应该在异常和其他错误处理手段之间进行权衡比较。常使用try- catch语句、try- catch-fianlly语句。
针对产品代码的限制并不适用于开发中的软件。你可以利用这一优势在开发中添加有助于更快地排查错误的代码。
9、伪代码编程过程
伪代码编程过程有助于减少设计和编写文档所需的工作量,同时提高这两项工作的质量。
要点:
创建类和子程序通常都是一个迭代的过程。在创建子程序的过程中获得的认识常常会反过来影响类的设计。
编写好的伪代码需要使用易懂的英语,要避免使用特定编程语言中才有的特性,同时要在意图的层面上为伪代码(即描述该做什么,而不是要怎么去做)。
伪代码编程过程是一个行之有效的做详细设计的工具,它同时让编码工作更容易。伪代码会直接转化为注释,从而确保了注释的准确度和实用性。
三、变量
10、使用变量的一般事项
要点:
数据初始化过程很容易出错,所以请用本章描述的初始化方法来避免由于非预期的初始值而造成的错误。
最小化每个变量的作用域。把同一变量的引用点集中在一起。把变量限定在子程序或者类的范围之内。避免使用全局数据。
把使用相同变量的语句尽可能集中在一起。
早期绑定会减少灵活性,但有助于减少复杂度。晚期绑定可以增加灵活性,同时增加复杂度。
把每个变量用于唯一的用途。
11、变量名的力量
变量命名规则可以参考著名的匈牙利命名法。
好的变量名提高程序可读性的一项关键要素。对特殊种类的变量,比如循环下标很状态变量,需要加以特殊的考虑。
名字要尽可能地具体。那些太模糊或者太通用以致于能够用于多种目的的名字都是很不好的。
命名规则应该能够区分局部数据、类数据和全局数据。它们还应当可以区分类型名、具名常量、枚举类型名字和变量名。
无论做那种类型项目,你都应该采用某种变量命名规则。你所采用的规则的种类取决于你程序的规模,以及项目成员的人数。
现在编程语言很少需要用到缩写。如果你真的要使用缩写,请使用项目缩写词典或者标准前缀来帮助理解缩写。
代码阅读的次数远远多于编写的次数。确保你所取的名字侧重于阅读方便而不是编写方便。
12、基本数据类型
数值、整数、浮点数、字符和字符串、布尔变量、枚举类型、具名常量、数组、创建类型
要点:
使用特定的数据类型就意味着要记住适用于各个类型的很多独立的原则。
如果你的语言支持,创建自定义类型会使得你的程序更容易修改,并更具有自描述性。
当你用typedef或者其等价方式创建了一个简单类型的时候,考虑是否更应该创建一个新的类。
13、不常见的数据类型
结构体、指针、全局数据
结构体可以使得程序更简单、更容易理解,以及更容易维护。
每当你打算使用结构体的时候,考虑采用类是不是会工作得更好。
指针很容易出错。用访问器子程序或者类以及防御式编程实践来保护自己的代码。
避免用全局变量,不只是因为它们很危险,还是因为你可以用其他更好的方法来取代它们。
如果你不得不使用全局变量,那么就通过访问器子程序来使用它。访问器子程序为你带来全局变量所能带来的一切优点,还有一些额外好处。
四、语句
14、组织直线型代码
顺序结构
要点:
组织直线型代码的最主要原则是按照依赖关系进行排列。
可以用好的子程序名、参数列表、注释。如果代码足够重要,内务管理变量来让依赖关系变得更明显。
如果代码之间没有顺序依赖关系,那就设法使相关的语句尽可能地接近。
15、使用条件语句
if-else,switch-case-default
要点:
对于简单的if-else语句,请注意if子句和else子句的顺序。
为了捕捉错误,可以使用case语句中的default子句,或者使用if-then-else语句中的最后那个esle子句。
16、控制循环
while for
要点:
循环很复杂。保持循环简单将有助于别人阅读你的代码。
保持循环简单的技巧包括:避免使用怪异的循环、减少嵌套层次、让入口和出口一目了然、把内务操作代码放在一处。
循环下标很容易被滥用。因此命名要准确,并且要把它们各自仅有用于一个用途。
仔细地考虑循环,确认它在每一种情况下都运行正常,并且在所有可能的条件下都能退出。
17、不常见的控制结构
子程序中的多出返回、递归、goto语句
要点:
多个return可以增强子程序的可读性和可维护性,同时可以避免产生很深的嵌套逻辑。
递归能够很优雅地解决一小部分问题。对它的使用要加倍小心。在使用递归的时候需要注意:确认递归能够停止、使用安全计数器防止出现无穷递归、留心栈空间、不要用递归去计算阶乘或者斐波那契数列。
除非万不得已最好不要使用goto,因为逻辑结构比较混乱。
18、表驱动法
表驱动法是一种编程模式,从表里面查找信息而不是使用逻辑语句。事实上,凡是能通过逻辑语句来选择的事物,都可以通过查表来选择。对于简单的情况而言,使用逻辑语句更为容易和直白。但随着逻辑链的越来越复杂,查表法也是愈发显示地更具有吸引力。
要点:
表提供了一种复杂的逻辑和继承结构的替换的方案。如果你发现自己对某个应用程序的逻辑和继承树关系感到困惑,那么问问自己它是否可以通过一个查询表来加以简化。
使用表的一项关键决策是决定如何去访问表。你可以采取直接访问、索引访问、阶梯访问。阶梯访问是通过确定每项命中的阶梯层次确定其归类,它命中的“台阶”确定其类属。
使用表的另一项关键决策是决定应该把什么内容放入表中。
19、一般控制问题
要点:
使用布尔表达式简单可读,将非常有助于提高你的代码的质量。
深层次的嵌套使得子程序变得难以理解。所幸的是,你可以相对容易地避免这么做。
结构化编程是一种简单并且仍然使用的思想,你可以通过顺序、选择、循环三者组合起来而开发出任何程序。
将复杂度降低到最低水平是编写高质量代码的关键。
五、代码改善
20、软件质量
软件同时拥有内在和外在的质量特性。外在特性指的是该产品的用户所能够感受到的部分,包括正确性、可用性、效率、可靠性、完整性、适应性、精确性、健壮性。内在特性包括可维护性、灵活性、可移植性、可重用性、可读性、可测试性、可理解性。
21、协同构建
协同构建包括结对编程、正式检查、非正式技术复查、文档阅读,以及其他开发人员共同承担创建代码及其他工作产品责任的技术。
22、开发者测试
单元测试、组件测试、集成测试
回归测试、自动化测试
要点:
开发人员测试是完整测试策略的一个关键部分。
同编码之后编写测试用例相比较,编码开始之前编写测试用例,工作量和花费的时间差不多,但是后者可以缩短缺陷-侦测-调试-修正这一周期。
即使考虑到了各种可用的测试手段,测试仍然只是良好软件质量计划的一部分。
你可以根据各种不同的思路产生很多测试用例,这些思路包括基础测试、数据流分析、边界分析、错误数据类型以及正确数据类型等。你还可以通过猜测错误的方式得到更多的测试用例。
错误往往集中在少数几个容易出错的类和子程序上,找出这部分代码,重新设计和编写它们。
23、调试
寻找缺陷的方法:
使用所有可用数据来构造你的假设。
不断提炼产生错误的测试用例。
在自己的单元测试族中测试代码。
借助可以获得的任何工具。
24、重构
数据级别重构:
用具名常量来代替神秘数值。
用更明确或更具信息量的名字来重命名变量。
将表达式内联化。
用函数来代替表达式。
引入中间变量。
将多用途变量转换为多个单一用途变量。
将一组类型码转化为类或枚举类型或含派生类的类。
将数组转化为对象。
封装群集。
25、代码调整策略
代码调整方法:
1)用设计良好的代码来开发软件,从而使程序易于理解和修改。
2)如果程序性能很差。
3)重复步骤2。
要点:
性能只是软件整体质量的一个方面,通常不是最重要的。
绝大多数的程序都有那么一小部分代码耗费了绝大部分的运行时间。如果没有测量,你不会知道是哪一部分代码。
26、代码调整技术
要点:
优化结果在不同的语言、编译器和环境下有很大的差异。如果没有对每一次的优化进行测量,你将无法判断优化到底是帮助还是损害了这个程序。
第一次优化通常不会是最好的。即使找到了效果很不错的,也不要停下扩大战果的步伐。