可能没有明确关于“我们需要找寻哪些问题”的文章,是因为有许多不同的要点需要考虑。正如任何其他的需求,各个团队对各个方面都有不同的优先级。

本文的目标是列出一些审查者可以找寻的要点,而各个方面的优先级就因各个团队而异了。

在我们继续之前,让我们考虑一下大家在代码审查时会讨论到的问题。对于代码的格式、样式和命名以及缺少测试这些问题是很常见的几点。如果你想拥有可持续的、可维护的代码,这些是有用的检查点。然而,在代码审查时讨论这些就有些浪费时间,因为很多这样的检查可以(也应该)被自动化。

那哪些要点是只能由人工进行审查而不能依靠工具的呢?

回答是有惊人数量的点只能由人工进行审查。在本文剩下的部分,我们会覆盖一系列广泛的特性,并深入其中的两点具体的区域:性能和安全。

设计

  • 如何让新代码与全局的架构保持一致?

  • 代码是否遵循SOLID原则,是否遵循团队使用的设计规范,如领域驱动开发等?

  • 新代码使用了什么设计模式?这样使用是否合适?

  • 基础代码是否有结合使用了一些标准或设计样式,新的代码是否遵循当前的规范?代码是否正确迁移,或参照了因不规范而淘汰的旧代码?

  • 代码的位置是否正确?比如涉及订单的新代码是否在订单服务相关的位置?

  • 新代码是否重用了现存的代码?新代码是否可以被现有代码重用?新代码是否有重复代码?如果是的话,是否应该重构成一个更可被重用的模式,还是当前还可以接受?

  • 新代码是否被过度设计了?是否引入现在还不需要的重用设计?团队如何平衡可重用和YAGNI(You Ain’t Gonna Need It)这两种观点?

可读性和可维护性

功能

  • 代码是否真的达到了预期的目标?如果有自动化测试来确保代码的正确性,测试的代码是否真的可以验证代码达到了协定的需求?

  • 代码看上去是否包含不明显的bug,比如使用错误的变量进行检查,或误把and写成or?

你是否考虑过……?

  • 是否需要满足相关监管需求?

  • 作者是否需要创建公共文档或修改现存的帮助文档?

  • 是否检查了面向用户的信息的正确性?

  • 是否有会在生产环境中导致应用停止运行的明显错误?代码是否会错误地指向测试数据库,是否存在应在真实服务中移除的硬编码的stub代码?

  • 你对性能的需求是什么,你是否考虑了安全问题?这些是需要覆盖到的重大区域也是至关重要的话题。

让我们深入探讨下性能,这是一个真正能从代码审查中获益的方面。

系统对性能方面的非功能性需求应当同所有架构、设计的领域一样被置于重要位置。无论你是开发只容许纳秒级延时的低延迟交易系统,还是管理“待办事项”的手机应用,你都应该了解用户所认为的“太慢”。

在考虑我们是否需要就代码性能进行代码审查之前,我们应该问自己几个关于具体需求是什么的问题。虽然一些应用确实不需要考虑每毫秒都花费在哪里,对于大部分应用,花费几个小时的折腾进行优化来获得的些许CPU下降的价值也是有限的,但有些地方还是审查者可以检查一下的,进而确保代码不会有一些常见可避免的性能缺陷。

这段代码是否有硬性的性能需求?

接受审查的代码是否涉及之前发布的服务等级协议(SLA)?或这个需求本身有特别的性能需求?

如果代码导致“登录页面加载太慢”,那原始的开发者需要找出合适的加载时间是多久,不然审查者或作者本人如何确保改进后的速度足够快?

如果有硬性的需求,是否有测试能证明满足了该需求?任何注重性能的系统应该就性能提供自动化测试,这能确保发布的SLA达到预期(如所有订单请求要在10毫秒内处理)。没有这些,你只能依靠你的用户来告诉你没有达到对应的SLA。这不仅是一种糟糕的用户体验,还会带来原本可避免的罚金和支出。

这个修复或新增的功能是否会反向影响到任何现存的性能测试结果

如果你定期运行性能测试或有测试套件可以按需运行它们,那你就需要检查新的代码是否使得性能关键区域的系统性能有所下降。这可以是一个自动化的流程,但由于在持续集成环境中更常运行单元测试而不是性能测试,所以值得特别指出可以在代码审查中检查这项。

调用外部的服务或应用的代价是昂贵的

任何通过网路来使用外部系统的方式通常会比没有很好优化的方法有更差的性能。考虑以下几点:

  1. 调用数据库:最坏的情况是问题隐藏在系统抽象中,如关系对象映射(ORM)中。但是在代码审查中你应该可以找到常见的导致性能问题的问题,如在循环中逐个调用数据库,一种情况就是加载ID列表之后,再在数据库中逐个查询ID对应的每条数据。

  2. 不必要的网络调用:就像数据库一样,远程服务有时也会被过度使用,原来只要一个远程调用就可实现的,或者可以使用批量或缓存防止昂贵网络调用的,却使用多个远程调用来实现。再次强调,像数据库一样,有时抽象类会隐藏调用远程API的方法。

  3. 移动或可穿戴应用过于频繁地调用后端程序:这基本上和“不必要的网络调用”相同,但是在移动设备上会产生其他问题,这不仅会产生不必要的调用后端使得性能变差,还会更快地消耗电量甚至导致用户的金钱支出。

有效且高效地使用资源

代码是否用锁来控制共享资源的访问?这是否会导致性能降低或死锁?

锁是一个性能开销大户,并在多线程环境中很难理清。考虑使用以下模式:单线程写或修改值,其余线程只读,或使用无锁算法。

  1. 是否存在内存泄露?Java中一些常见的原因会是:可变的静态字段,使用ThreadLocal变量和使用类加载器。

  2. 是否存在内存无限增长?这个和内存泄露不同,内存泄漏是指无用的对象不能被垃圾回收器回收。但对于任何语言,就算是没有垃圾回收的语言,也能创建无限变大的数据结构。作为审查者,如果你看见新的变量不断被加到list或map中,你就要问下,这个list或map什么时候失效或清除无用数据。

  3. 代码是否关闭了连接或数据流?关闭连接或文件、网络数据流很容易会被忘记。当你审查别人代码时,如果使用到文件、网络或数据库连接,就要确保它们被正确地关闭了。

  4. 资源池是否配置正确?针对一个环境的最佳配置取决于很多因素,所以作为审查者你很难马上知道像数据库连接池大小是否正确等这些问题。但是有一些是你一眼就可以看出来的,像资源池是否太小(比如大小设置为1)或太大(如数百万线程)。如果无法确定,就从默认值开始。没有使用默认值的就需要提供一定的测试或计算来证明这么配置的合理性。

审查者可以轻松找出的警告信号

一些代码一眼就能看出存在潜在性能问题。这依赖于所使用的语言和类库。

  • 反射:Java的反射比正常调用要慢。如果你在审查含有反射的代码,你就要问下是否必须使用它。

  • 超时:当你审查代码时,你可能不知道一个操作合适的超时时间,但是你要想一下“如果超时了,会对系统其他部分造成什么影响?”。作为审查者你应该考虑最坏的情况:当发生5分钟的延时,应用是否会阻塞?如果超时时间设置成1秒钟最坏的情况会是怎么样的?如果代码作者不能确定超时长度,你作为审查者也不知道一个选定的时间的好坏,那么是时候找一个理解这其中影响的人参与代码审查了。

  • 并行:代码是否使用多线程来运行一个简单的操作?这样是否花费了更多的时间以及复杂度而并没有提升性能?如果使用现代化的Java,那其中潜在的问题相较于显示创建线程中的问题更不容易被发现:代码是否使用Java 8新的并行流计算但并没有从并行中获益?比如,在少量元素上使用并行流计算,或者只是运行非常简单的操作,这可能比在顺序流上运算还要慢。

正确性

这些不一定影响系统的性能,但是它们与多线程环境运行关系密切,所以和这个主题有关:

  • 代码是否使用了正确的适合多线程的数据结构。

  • 代码是否存在竞态条件(race conditions)?多线程环境中代码非常容易造成不明显的竞态条件。作为审查者,可以查看不是原子操作的get和set。

  • 代码是否正确使用锁?和竞态条件相关,作为审查者你应该检查被审代码是否允许多个线程修改变量导致程序崩溃。代码可能需要同步、锁、原子变量来对代码块进行控制。

  • 代码的性能测试是否有价值?很容易将小型的性能测试代码写得很糟糕,或者使用不能代表生产环境数据的测试数据,这样只会得到错误的结果。

  • 缓存:虽然缓存是一种能防止过多高消耗请求的方式,但其本身也存在一些挑战。如果审查的代码使用了缓存,你应该关注一些常见的问题,如,不正确的缓存失效方式。

代码级优化

对大部分并不是要构建低延时应用的机构来说,代码级优化往往是过早优化,所以首先要知道代码级优化是否必要。

  • 代码是否在不需要的地方使用同步或锁操作?如果代码始终运行在单线程中,锁往往是不必要的。

  • 代码是否可以使用原子变量替代锁或同步操作?

  • 代码是否使用了不必要的线程安全的数据结构?比如是否可以使用ArrayList替代Vector?

  • 代码是否在通用的操作中使用了低性能的数据结构?如在经常需要查找某个特定元素的地方使用链表。

  • 代码是否可以使用懒加载并从中获得性能提升?

  • 条件判断语句或其他逻辑是否可以将最高效的求值语句放在前面来使其他语句短路?

  • 代码是否存在许多字符串格式化?是否有方法可以使之更高效?

  • 日志语句是否使用了字符串格式化?是否先使用条件判断语句校验了日志等级,或使用延迟求值?

简单的代码即高效的代码

Java代码中有一些简单的东西可以供审查者寻找,这些会使JVM很好地替你优化你的代码:

  • 短小的方法和类。

  • 简单的逻辑,即消除嵌套的条件或循环语句。

安全

理解你用到的依赖

第三方类库是侵蚀系统安全并引起漏洞的一个途径。当审查代码时至少你要检查是否引入了新的依赖(如第三方类库)。如果你还没有自动化检查漏洞,你应该检查新引入的类库中已知的问题。

你也应该尝试着最小化每个类库的版本,当然如果其他依赖有一个额外的间接依赖,这点可能达不到。但最简单的最小化自己代码暴露在他人代码的(通过类库或服务)安全问题中的方法有:

  • 尽可能使用源码并理解它的可信度。

  • 使用你所能得到的质量最高的类库。

  • 追踪你在何处使用了什么,当新的漏洞出现,你可以查看你受影响的程度。

检查是否新的路径和服务需要认证

无论你开发web应用、提供web服务或一些其他需要认证的API,当你增加一个新的URI或服务时,你应该确保它不能在没有认证的情况下被访问(假设认证是你系统的需求)。你只要简单地检查代码的开发者写了合适的测试用例来展示进行了认证。

你应该不只针对使用用户名和密码的人类用户来考虑认证。其他系统或自动化流程来访问你的应用或服务也会需要认证。这可能影响你们系统中对“用户”的定义。

数据是否需要加密

当你保存一些数据到磁盘或通过线缆传输,你需要了解数据是否应该被加密。显然密码永远不应该是简单文本,但是有诸多其他情况数据需要加密。如果被审查的代码通过线缆来传送数据或保存在某地或以其他方式离开你的系统,且你不知道它是否应该被加密,尝试询问下你组织中可以回答这个问题的人。

密码是否被很好地控制?

这里的密码包含密码(如用户密码、数据库密码或其他系统的密码)、秘钥、令牌等等。这些永远不应该存放在会提交到源码控制系统的代码或配置文件中,有其他方式管理这些密码,例如通过密码服务器(secret server)。当审查代码时,要确保这些密码不会悄悄进入你的版本控制系统中。

代码的运行是否应该被日志记录或监控?是否正确地使用?

日志和监控需求因各个项目而不同,一些需要合规,一些拥有比别人严格的行为、事件日志规范。如果你有规章规定哪些需要记录日志,何时、如何记录,那么作为代码审查者你应该检查提交的代码是否满足要求。如果你没有固定的规章,那么就考虑:

  • 代码是否改变了数据(如增删改操作)?是否应该记录由谁何时改变了什么?

  • 代码是否涉及关键性能的部分?是否应该在性能监控系统中记录开始时间和结束时间?

  • 每条日志的日志等级是否恰当?一个好的经验法则是“ERROR”触发一个提示发送到某处,如果你不想这些消息在凌晨3点叫醒谁,那么就将之降级为“INFO”或“DEBUG”。当在循环中或一条数据可能产生多条输出的情况下,一般不需要将它们记录到生产日志文件中,它们更应该被放在“DEBUG”级别。

记得叫上专家

安全是个很大的话题,大到足以让你的公司聘请技术安全专家。我们有安全专家就可以获得他们的帮助,如,邀请他们参加代码审查,或邀请他们在审查代码时和我们结对。如果这个无法实现,我们可以充分学习我们系统的环境,来理解我们有哪种安全需求(面向内部的企业级应用和面向客户的网页应用有不同的标准),所以我们可以更好地理解我们应该在代码审查中看什么。

总结

关于作者

整天说Code Review重要,你知道应该关注哪些关键点吗?相关推荐

  1. 如何在团队中做好Code Review

    一.Code Review的好处 想要做好Code Review,必须让参与的工程师充分认识到Code Review的好处 1.互相学习,彼此成就 无论是高手云集的架构师团队,还是以CURD为主的业务 ...

  2. Google是如何做Code Review的?| CSDN原力计划

    作者 | 帅昕 xindoo 编辑 | 屠敏 出品 | CSDN 博客 我和几个小伙伴一起翻译了Google前一段时间放出来的Google's Engineering Practices docume ...

  3. 刚进美团,就被各种Code Review,真的有必要吗?

    点击关注公众号,Java干货及时送达 众所周知,Code Review是开发过程中一个非常重要的环节,但是很多公司或者团队是没有这一环节的,今天笔者结合自己所在团队,浅谈Code Review的价值及 ...

  4. 刚入职,就被各种 Code Review,真的有必要吗?

    点击上方蓝色"方志朋",选择"设为星标" 回复"666"获取独家整理的学习资料! 来源:juejin.cn/post/ 6882333635 ...

  5. 有必要做 Code Review 吗???

    点击上方蓝色"方志朋",选择"设为星标" 回复"666"获取独家整理的学习资料!作者:梨香 链接:https://juejin.im/pos ...

  6. 你太菜了,竟然不知道Code Review...

    点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试资料 作者:宝玉   来源:http://1t.click/aA4h 我 ...

  7. 从零开始 Code Review,两年实战经验分享!

    点击上方"方志朋",选择"置顶公众号" 技术文章第一时间送达! 来源:http://t.cn/RtHE14S 前几天看了<Code Review 程序员的 ...

  8. 作为CTO,我为什么必须要求代码进行Code Review!

    来源:宝玉 链接:https://cnblogs.com/dotey/p/11216430.html 我一直认为Code Review(代码审查)是软件开发中的最佳实践之一,可以有效提高整体代码质量, ...

  9. 万字详文告诉你如何做 Code Review

    点击上方"小白学视觉",选择加"星标"或"置顶" 重磅干货,第一时间送达本文转自|机器学习实验室 前言 作为公司代码委员会 golang 分 ...

  10. 论新时代软件测试人员的工作之道(三)让Code Review常态化

    在百度,阿里等很多大型互联网公司,测试人员都会参与到code review中,我们团队也在去年开始开展起code review,为什么我们要这么做,首先老生常谈一下代码评审的诸多优点: 1. 通过大家 ...

最新文章

  1. 简析平衡树(三)——浅谈Splay
  2. Java面试中最高频的那20%知识点是什么?
  3. 横空出世,比Visio快10倍的画图工具来了。
  4. 案例驱动python编程入门-python监听socket客户端连接(驱动串口屏幕)
  5. html5 初试 indexedDB
  6. 程序员Web面试之JSON
  7. 格密码教程(三):基础域概念,体积等;阿达马不等式,行列式
  8. php安装oci8和pdo_oci扩展实现连接oracle数据库
  9. Pycharm安装完出现interpreter field is empty
  10. Unity中实现列表中元素随机排序
  11. Git提交项目到GitHub完整流程
  12. 1u服务器支持的显卡体积,1u服务器加独立显卡(1u服务器装显卡)
  13. Windows电脑如何控制安卓手机
  14. 学习 STM32之九轴姿态传感器(BWT901CL)串口通信读取数据
  15. 用python的列表构建一棵树
  16. Android集成GMS服务及GMS认证方案
  17. 添加权限,获取到用户信息,就用户当前部门进行下拉选择
  18. 【视频异常检测-论文阅读】Anomaly Detection in Video via Self-Supervised and Multi-Task Learning
  19. 空气源热泵控制系统解决方案
  20. css中div的宽度和高度设置指的是什么

热门文章

  1. IDC:2017年全球公有云服务开支将达1225亿美元
  2. 代码随想录程序员求职攻略完整pdf开放下载
  3. 「代码随想录」474.一和零【动态规划】力扣详解!
  4. C++经典书籍推荐 .
  5. inDesign教程,如何创建灵活的标头设计?
  6. 苹果发布 Safari 技术预览版 131,其中包含错误修复和性能改进
  7. 2-10 TreeView 控件
  8. NodeJS基础2---1 Promise小球运动
  9. RestEasy传值方式
  10. linux系统工程师修改打开文件数限制代码教程。服务器运维技术