编程开源技术交流,分享技术与知识

网站首页 > 开源技术 正文

爆肝5000字,一文梳理codeReview全流程

wxchong 2024-08-10 22:23:06 开源技术 30 ℃ 0 评论

晓蕾提交了代码,请求小明进行审查,他看了几行,就皱起了眉头,不满地说道:“你这代码一点设计也没有,你是认真的吗?”吧啦吧啦又说了一堆类似的话。晓蕾情绪爆发,直接爆粗口,两人的争吵越来越激烈。若非不是同事及时介入,俩人能干起来。类似这样的事也在别的厂屡见不鲜,CR是一个知易行难的事,审查者一定要注意态度和措辞。以下是小程关于代码审查的一些个人见解,虽然不够全面和权威,但希望能对大家有所帮助。文章末尾,我还将推荐10本有助于提升代码质量的书籍,以供参考。

为什么要CR

一言以蔽之,通过提高代码质量,来提升系统可维护性和稳健性。CR不仅对开发人员有益,而且对整个系统和团队领导都有积极的作用。

  • 开发人员

不管是被审查还是审查别人的代码,都是一个宝贵的学习机会,也算小型的知识分享。况且分享是实战,更值得学习。

  • 团队

代码不仅是写给自己看的,也是写给其他协作者和继任者看的。一致的代码规范和风格可以大大提高代码的可读性,使继任者能够快速上手。这不仅降低了学习成本,特别是对新入职的员工非常友好,而且也有助于提高团队的合作效率。

  • 系统

对系统而言,每一行代码都是一块砖,只有保证每一块砖的质量,才能保证整个系统的稳健,代码决定系统的下限,架构决定一个系统的上限

  • leader

代码审查可以帮助leader更清楚地了解团队成员的技术和业务能力。从而做出相应调整,从而促进团队的持续改进和发展。

哪些变更需要CR

其实没有一定之规。需要在有效利用工程师时间和维护代码质量之间进行权衡。

所以每个团队执行标准不一样,粗略的可以分以下3种

  1. 每次合并到master的代码
  1. 制定更细致的阈值,阈值下不需要审查
  1. 某些特殊情况,即使是微小的更改也可能需要进行代码审查

CR的时机

在符合规范的情况下,应该尽早发起CodeReview,并采用小步快跑的方式进行开发,以避免代码堆积过多,增加CR困难和错误几率

提交易于审查的代码

代码审查是一个费时间的工作,尤其对审查者来说是一次考验,提交者要提交易于审查的代码,以免浪费审核者的时间和精力。什么才是易于审查的代码

  1. 限定范围和规模

提交审查的代码应该有一个明确的、独立的范围。如下情况请拆分为多个独立的CR。

  • 文件超过5个
  • 代码超过400行
  • 时间超过1小时

把一次大的提交拆分成几个小分支,此时应该建大分支 feature/big-feature和多个辅助分支(例如feature/big-feature-api,feature/big-feature-core、big-feature-web 等),然后针对分支进行单独的代码审查。

  1. 提交完整的功能代码

提交CR的代码应具备完整的业务功能,以便审查者只需学习一次。若功能不完整,可能会导致审查者遗漏一些检查项,增加审查的难度和错误率。下次再审查时,审查者可能已经忘记了上次审查的内容,需要再次回想上次的代码审核内容。因此,为了提高代码审核的效率和准确性,请确保提交的代码具备完整的业务功能。

  1. 自己先审查

为了提高审阅效率,请在分配审查者之前,先对提交的代码进行测试,确保所有构建以及所有测试和代码质量检查在本地和CI服务器上均能通过。审阅者宝贵的时间应专注于程序逻辑,而不是纠缠于风格、语法或格式的争议。这些问题应该使用自动化工具(如Checkstyle、TSLint、ReviewBoard、阿里p3c)等来解决。

  1. 阅读体验要好
  • 代码逻辑是否合理
  • 是否有合理的注释
  • 变量和方法名称是否易于理解
  • 同一字段变量命是否一致不一致
  • API约定等方面与项目是否一致
  1. 相关文档同步更新

审查者是谁

审查者通常对业务和代码较为熟悉,一般是项目负责人或高级工程师。审查过程通常需要两个人,

第一个人可以是同事,进行初步审查。

如果审查通过,将提交给最终审查人,并将代码合并到master分支。

项目所有者应该订阅其项目以接收CR通知。

审查者注意点

审查代码有时间和精力的挑战,并可能给被审查者带来困扰。审查者应注意措辞和态度,以确保友好和有效的沟通。在审查过程中,审查人员应该提供积极的反馈和建议。关注问题的本质,而不是个人攻击或指责。以下是一些细节

  • 像对手一样思考,但要友善
  • 要赞扬好的代码
  • 评论应简洁并以中性语言撰写。评价代码,而不是作者。
  • 在批注中尽量不要用指代人称,如「你」,如果要用可以用「我们」来替代「你」。
  • 以客观的技术因素与数据为准,而非个人偏好。
  • 不要凸显自己的牛,自己技术比别人好的优越感,更不要因此说出侮辱性的语言,比如写的这是什么呀。写了个玩具之类的话。
  • 要认真负责,不要因为代码和你无关就懈怠,在CR过程中也能学习到他人的优点

如何推行CR

顺利推行CR还是比较困难的,尤其是在初创公司和业务主导的公司,那如何推行呢

  1. 把CR作为项目的必要流程,而非可选项

每次提交到master的代码,必须通过一位审查者和终极审查者。

如果时间充裕,可以组织团队内所以成员参与CR,并把每次提出建议的成员记录下来,如果经过多次CR,有些成员都没有提出过合理的建议,leader会和该成员进行沟通,一方面是了解情况,另一方面是给审查者压力,要正视CR。因为就算CR不认真也不会影响到审查者,责任还是被审查者。

  1. 把CodeReview变成团队文化

仅仅作为制度执行,成员可能会敷衍,甚至反感,这就失去了CR的意义。最终要把CR作为团队的文化,让CR成为大家乐意做的一件事

  1. 普及CR的好处,其实这点最简单,大部分程序员了解
  1. 做CR的时候是轻松的,是讨论而非审判
  1. 审查者一定要注意言辞和态度
  1. 被审查者也不要太玻璃心。
  1. leader要做表率,自己些的代码也要被CR
  1. 团队内每个成员都需要轮流担任审查者和被审查者的角色。由于每个人的代码都难免存在不足之处,相互指出问题在心理上是平等的。但如果长期固定某些成员为审查者,而其他成员只能被动接受审查,就可能导致不必要的等级感,从而增加团队矛盾的风险。

常见CR问题总结

CR代码质量时,可借鉴《重构》一书中列举的22种常见问题。和《阿里巴巴编码规范》中提到的一些常见问题,那些都是他们踩过的坑。此次主要关注其中几个常见问题。

  1. 基础规范

比如代码format格式,每行最多不超过多少行,硬编码等。当然这些都交给工具校验

  1. 异常处理

常见的异常处理规范包括如下:

  • try监控的代码块要最小粒度,要有层次,把异常造成的影响缩小
  • catch中必须处理异常,在finally应当尽可能回收内存资源
  • 不要通过catch异常来处理业务逻辑
  • 优先使用专门的异常处理,最后再用Exception异常来兜底
  • 在适当的层次处理异常:在代码中应该在适当的层次处理异常,而不是在每个方法中都捕获异常。这样可以使代码更加清晰和易于维护。
  • 遇到异常如果无法处理,逐层往上抛
  • 未捕获潜在的异常,调用API接口、库函数或系统服务等
  • 记录异常信息:在捕获异常时,应该记录异常信息,以便于排查问题和调试代码。
  • 优先处理高级别异常:例如致命错误或者安全问题,而不是低级别的异常。
  • 避免在finally块中使用return语句:在finally块中使用return语句可能会导致意外的结果,因此应该避免这种情况的出现。
  • 建议try-with-resources语句块来自动关闭资源
  1. 并发问题

并发问题在代码审查时并不容易发现,需要多测试

  • 线程安全问题:是否正确处理了共享数据的并发访问。确保在多线程环境下,对共享变量的读写操作都被正确地同步、加锁或使用线程安全的类。
  • 竞态条件:多个线程对同一资源进行并发操作,导致结果不确定或错误。需要确保对共享资源的操作是原子的,避免出现数据竞争问题。
  • 死锁:多个线程相互等待对方释放所持有的资源,导致程序无法继续执行。需要确保对锁的获取和释放是有序的,避免死锁情况的发生。
  • 共享资源管理:检查代码中对共享资源的管理方式,确保资源的正确分配、共享和释放。例如,对于连接池、线程池等共享资源,需要适当地设置和管理资源池的大小,避免资源耗尽或资源浪费的问题。
  • 并发集合使用:检查代码中对并发集合的使用,例如ConcurrentHashMap、ConcurrentLinkedQueue等。确保对并发集合的操作是线程安全的。
  • 数据一致性:检查代码中对数据的读写操作,确定在多线程环境下是否会出现数据不一致的问题。需要使用适当的同步机制来保证数据的一致性。
  1. 日志打印

系统日志打印有以下原则:

  • 隔离性:日志输出不能影响系统正常运行。
  • 安全性:日志打印本身不能存在逻辑异常或漏洞,导致产生安全问题。
  • 数据安全:不允许输出机密、敏感信息,如用户联系方式、身份证号码、token等。
  • 可监控分析:日志可以提供给监控进行监控,分析系统进行分析。
  • 可定位排查:日志信息输出需有意义,需具有可读性,可供日常开发同学排查线上问题。
  • 应当添加适当的Info日志;对于异常,应当捕获并添加Error日志。
  1. 性能问题
  • 循环问题:检查循环是否存在无限循环或过多的嵌套循环
  • 字符串拼接:避免在循环中频繁使用字符串拼接操作,尤其是在大型循环中。建议使用StringBuilder或StringBuffer来进行字符串拼接,以提高性能。
  • 集合操作:检查集合操作是否高效。例如,避免在循环中频繁地添加和移除元素,这可能会导致性能下降。可以考虑使用更适合的集合类型,如ArrayList、HashSet等。
  • 数据库操作:检查数据库查询和更新操作是否高效。避免频繁的数据库交互,可以考虑使用批处理操作、适当的索引以及缓存机制来提高性能。
  • 合理使用算法和数据结构:评估代码中使用的算法和数据结构是否能够高效处理数据。根据实际场景选择合适的数据结构和算法,以提高性能。
  • 冗余计算:查找并消除冗余的计算或重复的代码。例如,可以检查是否存在可以缓存的计算结果,避免重复执行相同的操作。
  • I/O操作:检查代码中是否存在频繁的磁盘或网络I/O操作,这些操作通常是性能瓶颈之一。可以考虑合并操作、异步操作或使用缓冲机制来提高性能。
  1. 事务问题

主要集中在spring的事务

  • 调用同一个类的方法,@transaction注解无效
  • 事务传播属性:检查代码中的事务传播属性是否设置正确。事务的传播属性定义了一个方法调用如何与已存在的事务进行互动。
  • 事务隔离级别:检查代码中的事务隔离级别是否设置正确。事务隔离级别定义了同时运行的多个事务之间的可见性和隔离程度。根据实际需求,选择适当的事务隔离级别以及优化性能。
  • 事务超时:检查代码中是否设置了合适的事务超时时间。
  • 事务异常处理:检查代码中是否正确处理了事务的异常。确保在事务方法中捕获并处理事务相关的异常,以确保事务的正确回滚和异常的适当处理。
  • 事务的范围:检查代码中事务的范围是否合理。在某些情况下,可能需要在更细粒度的方法中使用事务,避免将整个方法设置为事务,从而提高性能和并发性。
  • 事务和异常回滚:确保代码中事务的正确回滚机制。对于RuntimeException或派生自RuntimeException的异常,Spring默认会回滚事务,但对其他类型的异常需要显式配置回滚规则。
  • 不需要事务的方法:是否有不需要事务管理的方法。对于只有读取操作并不需要事务的方法,可以设置对应的事务传播属性为SUPPORTS或者使用@ReadOnly注解。
  1. 资源泄露
  • 文件处理:检查代码中对文件的打开和关闭操作是否正确。
  • 线程、锁等资源:检查代码中对线程、锁等资源的获取和释放,防止出现死锁、资源争用等问题。
  • 内存:检查代码中的内存分配和使用是否合理。特别注意避免内存泄露问题,确保及时的对象回收。
  • 网络连接:检查代码中对网络连接的获取和释放,特别是在使用Socket、Http连接等网络资源时,要确保及时释放资源,防止出现连接泄露。
  • 其他资源:如JMS连接、JNDI等也需要进行正确的获取和释放,防止出现资源泄露问题。

一般会建议开发人员使用try-with-resources语句块来自动关闭资源,或使用finally语句块在完成操作后手动关闭资源。同时,还要注意不要在代码中出现过多的资源占用,可以考虑使用缓存、池化等机制来优化资源使用。

  1. sql
  • sql注入,使用 iBatis 的预编译语句(PreparedStatement)来防止 SQL 注入。
  • 避免使用 ${} 进行参数替换
  • 避免使用动态 SQL
  • 避免直接拼接 SQL
  • 索引是否合理
  • 分页效率limit优化
  • join表过多
  • 禁止在sql中参入业务逻辑
  1. 业务逻辑

除了代码层面的CR,还需要注意业务逻辑是否正确

推荐书籍

  1. 《代码审查之道》(Code Complete):作者Steve McConnell是软件工程领域的知名专家,这本书是一本经典的软件开发指南,其中有大量关于代码审查的内容,包括审查的目的、流程、技巧和最佳实践等。
  1. 《代码审查实战》(Effective Code Review):作者Tracy Kidder和Tom DeMarco是软件工程领域的著名作者,这本书介绍了如何进行高效的代码审查,包括如何选择审查对象、如何提供有价值的反馈、如何处理审查结果等。
  1. 《代码审查艺术》(The Art of Code Review):作者Adam Gordon是一位软件工程师和培训师,这本书介绍了如何进行高质量的代码审查,包括审查的目标、流程、技巧和最佳实践等。
  1. 《代码审查指南》(Code Reviewer's Guide):作者Matthew Skelton和Gerd Zobel是软件工程领域的专家,这本书介绍了如何进行有效的代码审查,包括审查的目的、流程、技巧和最佳实践等。
  1. 《重构》:这本书的作者是Martin Fowler,书中讲到了诸多代码的坏味道,并且给出了相应的改进方法,是作者一手开发经验的总结输出。推荐本书的原因倒不是说书里面的内容有多真知灼见、让人耳目一新,而是这本书的内容总结得非常全面,很适合帮你去做一个整体、系统的梳理。
  1. 《重构与模式》设计模式一个重要的应用场景就是代码重构。这本书主要讲如何应用设计模式来重构代码,改善代码设计。
  1. 《代码整洁之道》(Clean Code: A Handbook of Agile Software Craftsmanship):作者Robert C. Martin(Uncle Bob)是软件工程领域的知名专家,这本书介绍了如何编写整洁、可读性强的代码,包括重构的概念、原则和技巧。
  1. 《重构与测试驱动开发》(Refactoring: Ruby Edition):作者Jay Fields、Shane Harvie和Martin Fowler结合了重构和测试驱动开发(TDD),介绍了如何通过重构来改进代码设计,并使用TDD进行验证和测试。
  1. 《重构改善既有代码的设计》(Working Effectively with Legacy Code):作者Michael Feathers讨论了如何处理和改善既有的、难以修改的遗留代码,介绍了一系列重构技术和策略。
  1. 《Software Engineering at Google》Google公司的软件工程实践是业界公认的最佳实践之一,本书是Google公司的软件工程实践指南,这本书总结了Google在软件开发方面的经验和最佳实践,涵盖了软件工程的各个方面,包括开发、测试、部署、监控等。这本书的内容非常丰富,包括如何进行代码审查、如何使用持续集成和持续交付、如何进行测试和性能优化、如何管理分布式系统等等。此外,书中还介绍了Google公司的一些工具和框架,如Bazel构建系统、Protocol Buffers数据序列化框架、gRPC远程过程调用框架等。

reference:

CR哪些项:https://www.cnblogs.com/lovesqcc/p/9271781.html

代码Review常见问题:https://blog.csdn.net/cm15835106905/article/details/104690023

Code Review最佳实践: https://zhuanlan.zhihu.com/p/73809355

一文梳理Code Review方法论与实践总结:https://mp.weixin.qq.com/s/_4MFrQSYOIGYRdDGOJPDKQ

Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表