65.9K
CodeProject 正在变化。 阅读更多。
Home

代码评审指南

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.84/5 (34投票s)

2013年1月8日

CPOL

11分钟阅读

viewsIcon

188941

代码评审是对计算机源代码进行的系统性检查(通常称为同行评审)。

什么是代码评审?

代码评审是对计算机源代码进行的系统性检查(通常称为同行评审)。它的目的是在初始开发阶段发现并修复被忽略的错误,从而提高软件的整体质量和开发人员的技能。

为什么评审很重要?

引用自《Code Complete》

.. 仅靠软件测试的有效性有限——单元测试的平均缺陷检测率仅为 25%,功能测试为 35%,集成测试为 45%。相比之下,设计和代码评审的平均有效性分别为 55% 和 60%。评审结果的案例研究令人印象深刻:

  • 在一个软件维护组织中,在引入代码评审之前,55% 的单行维护更改存在错误。引入评审后,只有 2% 的更改存在错误。考虑到所有更改,引入评审后,95% 的更改首次就能成功。在引入评审之前,首次成功的不到 20%。
  • 在一个由同一组人开发的 11 个程序中,前 5 个程序是在没有评审的情况下开发的。其余 6 个程序是在有评审的情况下开发的。所有程序发布到生产环境后,前 5 个程序平均每 100 行代码有 4.5 个错误。经过评审的 6 个程序平均每 100 行代码只有 0.82 个错误。评审将错误减少了 80% 以上。
  • Aetna 保险公司通过使用评审发现了程序中 82% 的错误,并将开发资源减少了 20%。
  • IBM 的 50 万行 Orbit 项目使用了 11 个级别的评审。该项目提前交付,并且只有正常预期错误的约 1%。
  • 一项针对 AT&T 拥有 200 多人的组织的研究报告称,该组织引入评审后,生产力提高了 14%,缺陷减少了 90%。
  • 喷气推进实验室估计,通过早期发现和修复缺陷,每次评审可节省约 25,000 美元。

代码评审的主要目标是:

  1. 在流程早期发现并修复缺陷。
  2. 团队成员互相学习,从而更好地共享代码库的理解。
  3. 有助于在设计和实现上保持一致性。
  4. 有助于识别团队中的常见缺陷,从而减少返工。
  5. 增强利益相关者对执行的技术质量的信心。
  6. 统一的理解将有助于在任何团队成员缺席时进行人员互换。
  7. 不同的视角。“另一双眼睛”增加了客观性。这与分离编码和测试团队的原因类似,同行评审提供了识别问题所需的距离。
  8. 自豪感/奖励。对许多程序员来说,认可编程才华是一种重要的奖励。
  9. 团队凝聚力。一起工作有助于拉近团队成员之间的距离。它也为编码经常带来的孤独感提供了一个短暂的喘息机会。

评审者关注的主要领域如下:

  • 通用单元测试
  • 注释和编码约定
  • 错误处理
  • 资源泄漏
  • 线程安全
  • 控制结构
  • 性能
  • 功能
  • 安全

角色和职责

  1. 开发者: 是编写待评审代码并发起评审请求的人。
  2. 评审者: 是将要评审代码并向开发者报告发现问题的人。
与任何技能一样,良好的同行评审需要练习。以下是一些可以帮助您走上正轨的技巧:

给开发者的建议

  1. 主要评审者是作者,即您。
  2. 为自己创建一个清单,列出代码评审通常关注的事项。这个清单中的一些项目应该很容易制定。它应该遵循编码标准文档的结构。因为这是您自己的清单,所以您可以专注于自己遇到的问题,而跳过您很少遇到的问题。使用清单检查您的代码并修复发现的任何问题。这不仅可以减少团队发现的问题数量,还可以缩短代码评审会议的完成时间——每个人都会乐于在评审上花费更少的时间。
  3. 您不是您的代码。 请记住,评审的重点是发现问题,而问题是会被发现的。当问题被揭示出来时,不要把它当作人身攻击。
  4. 理解并接受您会犯错。 重点在于及早发现错误,以免其进入生产环境。幸运的是,在我们这个行业中,除了少数为 JPL 开发火箭制导软件的人之外,错误很少是致命的,所以我们可以,也应该,学习、一笑而过,然后继续前进。
  5. 无论您有多么“懂功夫”,总会有人比您更懂。 这样的人可以通过询问教您一些新技巧。寻求并接受他人的意见,尤其是当您认为不需要的时候。
  6. 不要在未咨询的情况下重写代码。 “修复代码”和“重写代码”之间有一条微妙的界限。了解区别,并在代码评审的框架内进行风格上的更改,而不是独自一人强行执行。
  7. 世界上唯一不变的是变化。 对它持开放态度,并微笑着接受它。将需求、平台或工具的每次更改视为新的挑战,而不是需要对抗的严重不便。
  8. 为您的信念而战,但优雅地接受失败。 要明白,有时您的想法会被推翻。即使您最终被证明是正确的,也不要报复,最多说几次“我告诉过你了”,并且不要让你珍贵的想法变成牺牲品或号召。
  9. 不要成为“房间里的那个男人”。 不要成为那个在黑暗的办公室里编码,只出来买可乐的人。房间里的那个人脱节、隐身、失控,在开放、协作的环境中没有立足之地。
  10. 请注意,评审会议不是问题解决会议。
  11. 帮助维护编码标准。 对于讨论中未包含在编码标准中的内容,可以主动添加到编码标准中。开发人员在代码评审实践具有对抗性的组织中面临的挑战之一是,他们经常不知道下一个问题会来自哪里。如果您将每个问题记录到编码标准中,下次进行代码评审时就可以用清单进行检查。这也有助于巩固概念,使其更不容易错过使用反馈的机会。

给评审者的建议

  1. 批评代码而不是人——善待编码者,而不是善待代码。 尽可能使您的所有评论都积极向上,并以改进代码为导向。将评论与本地标准、程序规范、性能提升等联系起来。
  2. 尊重、礼貌和耐心地对待那些不如您懂的人。 经常与开发人员打交道的非技术人员几乎普遍认为,我们充其量是骄傲自大,最坏是爱哭鬼。不要用愤怒和不耐烦来强化这种刻板印象。
  3. 真正的权威只源于知识,而非职位。 知识产生权威,权威产生尊重——所以,如果您想在一个没有自负的环境中获得尊重,就培养知识。
  4. 请注意,评审会议不是问题解决会议。
  5. 提问而不是陈述。 陈述是带有指责意味的。“你没有遵循这里的标准”是一种攻击——无论是故意的还是无意的。问题“你当时采用这个方法是出于什么考虑?”是在寻求更多信息。显然,这个问题不能用讽刺或居高临下的语气说出来;但如果做得恰当,它常常能让开发人员说出自己的想法,然后询问是否有更好的方法。
  6. 避免问“为什么”。 尽管有时非常困难,但避免问“为什么”可以大大改善气氛。就像陈述带有指责意味一样,“为什么”的问题也是如此。大多数“为什么”的问题都可以改写成不包含“为什么”的问题,其效果可能非常显著。例如,“你为什么不遵循这里的标准……”与“你这里偏离标准的原因是什么……”
  7. 记住要赞扬。 代码评审的目的不仅仅是告诉开发人员如何改进,也不一定是他们做得很好。人的天性是我们希望并需要因成功而得到认可,而不仅仅是指出缺点。因为开发本质上是一项开发者倾注心血的创造性工作,它常常能触及他们的内心。这使得赞扬的需求更加关键。
  8. 确保您有良好的编码标准可供参考。 代码评审以组织的编码标准为基础。编码标准应该是开发人员之间就生成高质量、可维护代码达成的共识。如果您正在讨论的内容不在您的编码标准中,那么您需要做一些工作才能将其纳入编码标准。您应该定期问自己,讨论的内容是否在您的编码标准中。
  9. 请记住,解决问题往往有不止一种方法。 尽管开发者可能以不同于您的方式编写代码,但这不一定就是错误的。目标是高质量、可维护的代码。如果它达到了这些目标并遵循了编码标准,那么这就是您所能要求的。
  10. 您不应该匆忙完成代码评审——但同时,您需要及时完成。 您的同事正在等您。
  11. 一次评审的代码行数少于 200-400 行。

安全代码评审

如果应用程序需要非常关注安全性,那么 www.owasp.org 是获取资源的最佳去处。以下是一份非常好的安全代码评审文档可供参考:https://www.owasp.org/images/2/2e/OWASP_Code_Review_Guide-V1_1.pdf

为评审发现指定严重性

代码问题的严重性应如下。评审者必须首先关注高严重性问题,然后是中等严重性问题,最后是低严重性问题。

    1. 命名约定和编码风格 = 低
    2. 控制结构和逻辑问题 = 中或高
    3. 冗余代码 = 高
    4. 性能问题 = 高
    5. 安全问题 = 高
    6. 可伸缩性问题 = 高
    7. 功能性问题 = 高
    8. 错误处理 = 高
    9. 可重用性 = 中

开发人员和评审者的清单

清单是强烈推荐的方法,用于查找您忘记做的事情,并且对作者和评审者都有用。遗漏是最难发现的缺陷——毕竟,很难评审不存在的东西。清单是解决此问题的最佳方法,因为它会提醒评审者或作者花时间检查可能缺失的内容。清单会提醒作者和评审者确认所有错误都已处理,函数参数已针对无效值进行了测试,并且已创建了单元测试。
另一个有用的概念是个人清单。每个人通常都会犯同样的 15-20 个错误。如果您注意到自己典型的错误是什么,就可以制定自己的个人清单(PSP、SEI 和 CMMI 也推荐这样做)。评审者将负责确定您的常见错误。您要做的就是保留一份简短的清单,列出您工作中常见的缺陷,尤其是您经常忘记做的事情。一旦您开始在清单中记录您的缺陷,您就会开始犯更少的错误。规则会在您脑海中清晰起来,您的错误率就会下降。我们一次又一次地看到这种情况发生。

开发人员清单

描述

已确认?

我的代码已编译
我的代码已经过开发者测试,并包含单元测试
我的代码在适当的地方包含 javadoc
我的代码是整洁的(缩进、行长、无注释掉的代码、无拼写错误等)
我已考虑异常的正确使用
我已适当使用日志记录
我已删除未使用的导入
我已删除 Eclipse 警告
我已考虑可能的 NPEs
代码遵循编码标准
代码中是否有任何残留的存根或测试例程?
代码中是否仍有任何硬编码的、仅用于开发的设置?
是否考虑了性能?
是否考虑了安全性?
代码是否释放资源?(HTTP 连接、数据库连接、文件等)
边界情况是否已妥善记录,或是否有已知的框架限制的解决方法?
是否可以将任何代码替换为对外部可重用组件或库函数的调用?
线程安全性和可能的死锁

评审者清单

描述

已确认?

注释易于理解,并对代码的可维护性有所贡献
注释不多也不冗长
类型已尽可能泛化
已适当使用参数化类型
已适当使用异常
重复的代码已被提取
已适当使用框架——方法都已适当定义
命令类被设计为只执行一项任务
JSP 不包含业务逻辑
单元测试存在且正确
已检查常见错误
已尽可能消除潜在的线程问题
任何安全隐患都已得到解决
已考虑性能
功能符合当前的设计/架构
代码是可单元测试的
代码不使用不合理的静态方法/块
代码符合编码标准
日志记录使用恰当(正确的日志级别和详细程度)
NPEs 和 AIOBs

我还将它们制成了可打印的清单格式:CodeReview_ChecklistforDevelopersCodeReview_ChecklistforReviewers

参考文献

  1. http://www.codinghorror.com/blog/2006/05/the-ten-commandments-of-egoless-programming.html
  2. http://www.developer.com/java/other/article.php/3579756
  3. http://www.smartbear.com/docs/BestPracticesForPeerCodeReview.pdf
  4. http://www.amazon.com/Peer-Reviews-Software-Practical-Guide/dp/0201734850/ref=la_B001IGNXQS_1_3?ie=UTF8&qid=1354616082&sr=1-3
  5. http://www.techrepublic.com/article/developers-guide-to-peer-reviews/1050834
  6. http://smartbear.com/SmartBear/media/pdfs/best-kept-secrets-of-peer-code-review.pdf
© . All rights reserved.