目录
0. 引言 1. 代码检视的指导思想 2. 代码检视的内容 3. 回归测试
0. 引言
代码检视(Code Review)是指软件开发人员在完成代码设计、编写、调试后展开的个人或群体性的代码阅读过程,代码检视的目的是发现代码中的设计问题、格式问题、逻辑问题、语法问题等,从而保证代码的高质量交付。从软件工程的角度讲,在代码检视阶段发现代码问题的成本是低廉的,所以严格认真的执行代码检视过程,是提升产品质量,降低产品维护成本的有效手段
Relevant Link:
http://www.distorage.com/code-review%E5%B0%8F%E8%AE%BA/ http://www.ibm.com/developerworks/cn/rational/11-proven-practices-for-peer-review/
1. 代码检视的指导思想
codereview主要包含以下几个观点
1. 一次评审少于 200–400 行的代码。 2. 目标为每小时低于 300–500 LOC 的检查速率。 3. 花足够的时间进行正确缓慢的评审,但是不要超过 60–90 分钟。 4. 确定代码开发者在评审开始之前就已经注释了源代码。 5. 为代码评审和获取制度建立可定量化的目标,这样您才能改进流程。 6. 使用检查列表,因为它可以极大地改进代码开发者和评审者的作品。 7. 确认缺陷确实得到修复了。 8. 培养良好的代码评审文化氛围,在这样的氛围中搜索缺陷被看做是积极的活动。 9. 警惕"老大"效应。 10. 最少评审一部分代码,就是您不能评审全部的代码,以从 Ego Effect 中受益。 11. 采用轻量级,能用工具支持的代码评审。
需要特别注意的是,即搜索缺陷是好的事情,而不是糟糕的,缺陷密度与开发员的能力并不是挂钩的。记住对一个团队来说,缺陷,尤其是团队成员所引入缺陷的数量不应该被回避,也不应该用作能力的评价参数。
代码检视作为一个勘误的过程,核心目的是提升代码质量,同时提升开发人员的能力,而不是批斗和责备开发人员,要积极引导参与人员的代码检视态度,把代码检视作为提升开发人员能力的一项活动来进行,这样才能达到代码检视的核心目的。同时,代码检视需要包含对设计的检视,更多的时候需要代码开发者讲解其设计思路
0x1: 一次评审量要低于 200–400 行代码
开发员的评审量要低于一次 200-400 行代码(LOC Line Of Code)。超过这个量,搜索缺陷的能力就会降低。以这个速度,您可以找到 70-90% 的缺陷。换句话说,如果存在 10 个缺陷,那么您可以找到其中的 7 到 9 个
图中描述了缺陷密度与评审代码行数量之间的关系,支持该规则。缺陷密度 就是每 1000 行代码之中所发现的错误(bug)数。评审代码行的数量超过 200 时,缺陷密度就会急剧地下降。
在这种情况下,缺陷密度就是"评审有效性"的评价手段。如果两个评审员评审相同的代码,其中一个发现了更多的错误(bug),那么我们就会认为该评审员更有效率
0x2: 每小时低于 300–500 LOC 检查率的目标
快速评审并不总是好的。研究结果显示检查率低于"300-500 LOC/小时"时,可以得到优化的结果。根据所作的决定,评审者的检查率有很大的变化,就算是相似的代码开发者、评审者,文件和评审规模,也存在巨大的差异。
为了找到优化的检查率,我们将 缺陷密度 与评审者检查代码的 速度 进行了比较。得到的结果再一次落在了我们的预料之中:如果在评审您不花足够的时间,那么您就不会发现太多的缺陷。如果评审者面临大量代码的压力,那么他就不会每一行代码投入相同的注意力。他不能研究同一位置处更改的所有版本
调查结果显示
1. 每小时小于 400 LOC 的评审速度下,效率是相对较高的 2. 每小时超过 400 LOC 的评审速度会降低效率
0x3: 花足够的时间进行适当缓慢的评审,但是不要超过 60-90 分钟
永远不要对一个原型代码评审超过 60-90 分钟
我们应该讨论,为了得到更好的结果,不应该过快地评价。但是您也不应该在一个位置花太多的时间。大约 60 分钟后,评审者就会感到疲劳,于是就不会找到额外的缺陷了。这个结论得到了许多其他研究的支持。实际上,根据我们的常识,当人们从事注意力高度集中的活动时,性能状态在 60-90 分钟之后就会降低了。考虑到人体方面的限制,评审者在性能降低之前,不能评审超过 300–600 行的代码。
但反过来说,评审代码所花的时间不得低于五分钟,就算代码只有一行也是如此。通常来说,单行的代码也会影响到整个的系统,所以花上五分钟时间去检查更改可能造成的结果是值得的。
0x4: 确定在评审开始之前代码开发者已经注释源代码了
0x5: 为代码评审创建可定量化的目标,并获取制度,这样您就可以改进流程了
有了项目,您就该决定代码评审过程的目标,以及怎样评价效率问题了。当您在定义特定的目标时,您就能够决定同行评审是否真的达到了您所需要的结果。最好从外部性的制度开始,例如
1. "将支持访问降低 20%" 2. "使开发引入的缺陷百分比减半"
这些信息使您能够更好地看清,从外部视角来看,代码能够做些什么,您还需要一个可定量化的评价手段,而不是"修复更多错误(bug)"的模糊目标
但是,在外部制度显示结果之前需要花上一段时间。例如
1. 支持性访问将不会得到影响,直到新的版本得到发布并交到客户手中为止
0x6: 使用检查表,因为它能极大地影响代码开发者和评审者的结果
使用检测表对于评审员非常重要,如果代码开发者忘记了某项任务,评审员也同样可能忘记
使用检查表的优点有
1. 使用检查表来避免可能会忘记的事情,它对代码开发者和评审者都有用。忽略是最难发现的缺陷 2. 评审不在那里的东西是很困难的一件事。检查表是解决这个问题的最好方式,因为它会提醒评审者和代码开发者花点时间去考虑一下可能被遗忘的事情 3. 检查表还会提醒代码开发者和评审者确定 1) 所有的错误(bug)都得到了处理 2) 软件功能已经通过了无效值测验 3) 而且已经创建了单元测试
0x7: 确认缺陷得到了修复
使用团队协作工具,例如JIRA是进行bug追踪的一个很好的方案
0x8: 培养良好的代码评审文化氛围,在这样的氛围中可以积极地评审缺陷
与其他我们能看到的大多数技术相比,代码评审对于真实团队构建能够发挥更大的作用,但是只是在管理人员能够以一种积极的,向上的,有技巧的方式进行交流时,这种优势才能发挥出来。将缺陷看做是不好的事物很容易(毕竟,它们是代码之中的错误(bug)),但是形成不好的缺陷检查态度,则会毁掉整个团队的努力,更不要说它会破坏错误(bug)检查过程了
软件代码评审的要点在于
1. 尽可能多的消除缺陷,不管是谁"导致"了错误(bug) 2. 管理人员必须建立缺陷是积极的这样的观点。毕竟,每一个缺陷的存在,都是改进代码的潜在机会,而错误(bug)评审过程的目的,就在于使代码尽可能地完美。每一个被发现并解决的缺陷,都是客户以后不会看到的缺陷,也是 QA
人员不必花费时间去解决的问题 3. 团队需要维持这样一种态度,就是发现缺陷,就意味着代码开发者和评审者 作为一个团队 去改进产品的质量成功了。而不是"代码开发者产生了一个缺陷,而评审者负责去发现它"。它更像是配对编程的一种有效形式。 4. 评审员要向所有的开发者展示收集坏习惯,学习新技巧,并展开功能的机会。开发员可以从他们的错误(bug)中学习,但是只是在他们警惕错误(bug)时才会这样。如果开发员害怕发现错误(bug),那么积极的结果就会消失。 5. 如果您是一名初级开发员,或者是一个团队的新成员,那么其他人发现缺陷时,就意味着您强有力的队友在帮助您成长为一个合格的开发员。这就比您单枪匹马地编程,没有具体的反馈时,要更快地进步
0x9: 警惕老大哥效应(Big Brother Effect)
0x10: 评审一部分的代码,就算您不能全部完成,以从自我效能感(Ego Effect)中获益
0x11: 采用轻量级,工具支持的代码评审
2. 代码检视的内容
既然有了代码检视的指导原则,那么在代码检视中,我们究竟检视些什么内容呢
1. 与详细设计方案的一致性 只要将检视的代码对照详细设计进行比较就很容易检查出代码是否和详细设计一致,采用逐行逐字阅读进行比较的方法进行。 2. 头文件检查 头文件检查主要关注以下方面: 1) 是否包含有多余的其他头文件 2) 头文件是否内聚,即是否多个模块共用一个头文件 3) 头文件内的内容是否清晰,是否分类排放好并给出了足够的注释 4) 是否使用了象 #ifdef __LIST_H__ 之类的宏定义保证头文件不被重复引用 3. 宏定义检查 1) 宏定义中有参数和表达式时,参数和表达式是否都用括号括起来了。例如: #define ADD(a, b) (a + b) //正确的应该是 ((a) + (b)) 这个定义中就没有将参数a和b括起来,如果使用时a和b是表达式的话,就会因为运算符顺序问题而出问题。 2) 续行符是否使用正确 4. 常量 常量方面主要检查的主要问题如下: 1) 常量是否使用了宏来进行定义 2) 程序中是否存在魔鬼数字 3) 16进制数据是否在前面加上了0x 4) 常量是否来自规格 5) 不来自规格的常量的值是否合理 5. 全局变量与共享变量需要检查的主要问题如下: 1) 全局变量是否必须的,是否可以改成局部变量 2) 是否有全局范围内变量和局部范围内变量重名情况 3) 是否有多个任务访问共享变量,是否进行了有效的保护 4) 当全局变量只限于本文件内使用时,是否定义成静态的 5) 多个任务读写共享变量时,是否可以将读写操作封装成独立函数,而不是在每个模块里都进行加锁解锁操作 6. 静态变量和函数 静态变量和函数检视时主要问题如下: 1) 静态变量的使用是否正确 2) 每次使用静态变量时是否需要重新初始化 3) 对不需要重新初始化的静态变量在多次使用后是否有溢出的问题。 4) 文件内部使用的函数是否要定义成静态的 7. 数据结构 数据结构方面考虑的主要问题如下: 1) 数据结构里的成员类型定义是否正确 2) 结构体里面变量顺序安排是否合理,数据是否对齐 3) 是否存在冗余未用的成员变量。 4) 类里面是否有私有变量和私有函数放到了公有的定义里去了 8. 初始化 初始化考虑的主要问题如下: 1) 变量使用前是否需要初始化 2) 类的构造函数中是否对需要初始化的成员都进行了初始化 3) 数组的初始化是否正确 4) 内存或数组在每次使用前是否需要初始化清零 5) 多个变量初始化赋值时是否存在顺序问题 6) 静态变量和全局变量的初始化是否存在初始化顺序问题 9. 字符串 1) 字符串是否以'