如何有效地进⾏代码Review?
研发都知道代码 Review 的重要性,在腾讯代码 Review 也越来越受⼤家重视,作为腾讯专有云平台研发的⼀员,我参与了⼤量的代码 Review,明显地感受到有效的代码 Review 不但能提⾼代码的质量,更能促进团队沟通协作,建⽴更⾼的⼯程质量标
准,⽆论对个⼈还是团队都有着重要的价值。本⽂就为什么要做代码 Review 以及如何有效地做代码 Review 分享⼀下个⼈的看法。
为什么要做代码 Review
为什么要代码 Review,相信每个⼈⼼中都有⽐较⼀致的答案,Google 搜索⼀下也能到⼀⼤堆的⽂章。这⾥简单总结⼏点:
1)提⾼代码质量
这是代码 Review 的初衷,也是代码 Review 最直接的价值。Reviewers 根据各⾃的经验,思考⽅式,看问题的⾓度给代码提出各种可能的改进意见,从⽽形成更好的代码以及产品质量。
我们知道产品问题越晚提出解决它的代价就越⼤,参与进去的⼈、要⾛的流程都会越来越多。代码 Revie
w 可以说是早期解决问题最有效的途径之⼀了,在代码 Review 中解决掉哪怕⼀个⼩问题都能避免后续⼀堆的⿇烦事。
2)形成团队统⼀的⾼质量标准
有效的代码 Review 最终会在团队范围内建⽴起统⼀的质量标准,并且会随着团队成员的互相学习和促进形成更⾼的标准。参与者会在代码Review 的过程中基于具体问题从不同⾓度提出改进意见,并最终做出当前最佳的选择并形成共识。随着代码 Review 的有效进⾏,团队成员会有意识地关注代码质量,从⽽形成越来越⾼的事实上的质量标准。
3)个⼈快速成长
通过有效的代码 Review,Author 和 Reviewer 都将获得成长,在 Review 过程中参与⼈就具体的问题展开深⼊的讨论,⽆论是怎么写出整洁的代码、怎么更好地更全⾯地思考问题、怎么最佳地解决问题,参与⼈都可以互相取长补短,互相提⾼。通过具体代码实现进⾏的讨论往往是最深⼊和有效的,代码 Review 是开发者提⾼代码能⼒最重要的途径之⼀。
有的⼈认为代码 Review 就是 Reviewer 帮助查代码中的 Bug,其实代码 Review 不应该是⼀个单向的过程,⽽应该是个双向交流的过程,Reviewer 帮助 Author 提出代码改进意见的同时,也是向优秀的 Au
thor 学习的过程。我们都知道提⾼代码能⼒⼀个有效的途径是阅读优秀的项⽬代码,但是阅读项⽬代码有着不⼩的难度,这也是⼤部分⼈没有去执⾏的原因,⽽ Review 资深同事的代码,我们在阅读代码的同时能够直接进⾏有效的沟通,这是⼀个快速有效的学习途径,尤其对开发经验还不算丰富的开发者⽽⾔。
如何做好代码 Review
2.1. 什么时候发起 Review
在代码 Review 上,Author 需要意识到:Reviewer 的时间是昂贵的。因此在正式邀请 Reviewer 发起代码 Review 前,Author 有⼏项需要注意的点,这些都能提⾼代码 Review 的效率,节省 Reviewer 的时间。
2.1.1. MR (Merge Request)
也称为 PR(Pull Request), MR 是我们进⾏代码 Review 的地⽅,它记录着代码的具体改动,参与者具体的讨论过程。好的 MR 应该做到以下⼏点:
单⼀:⼀个 MR 应该只解决⼀个单⼀的问题,⽆论是修复⼀个 bug,还是实现⼀个新 feature。Author 应该避免⼀个 MR 包含不同意图的代码改动。单⼀的 MR 能帮助 Reviewer 快速地了解代码改动的动机,
能有针对性地进⾏ Review。
短⼩:MR 应该尽量地⼩,⽐如⼀个 feature 引⼊了较多的改动,需要考虑是否可以拆成独⽴的⼏块实现,分开提 MR,⽐如接⼝定义、接⼝实现、逻辑对接等拆分开。
详细: 这⾥说的详细是指 MR 应该尽可能地详细描述它的背景和动机,可以是在 MR 的描述中详细体现,也可以是连接到具体 issue 或tapd 单中。需要达到的⽬的是,其他⼈翻开⼀个 MR 能知道当时做这个改动的背景以及动机。
2.1.2. Commit Message
之前翻看了不少现存的项⽬代码,看到不少的 Commit Message 写得⽐较简单,例如⼀连串的 "update", "fix",从这些 Commit Message 中完全看不出做了什么改动,想想如果之后想要定位之前的某个改动,该从哪⾥下⼿。
⽬前 Commit Message 规范⽐较常见的有,并由此衍⽣出了,可以参照此 Specification 约定 Commit Message 格式规范。
<type>(<scope>): <subject><BLANK LINE><body><BLANK LINE><footer>
⼤体分三⾏:
【标题⾏】必填, 描述主要修改类型和内容。
【主题内容】描述为什么修改, 做了什么样的修改, 以及这么做的思路等等。
【页脚注释】放 Breaking Changes 或 Closed Issues
其中 type 是 Commit 的类型,可以有以下取值:
feat:新特性
fix:修改 bug
refactor:代码重构
docs:⽂档更新
style:代码格式修改
test:测试⽤例修改
chore:其他修改, ⽐如构建流程, 依赖管理
其中 scope 表⽰的是 Commit 影响的范围,⽐如 ui,utils,build 等,是⼀个可选内容。
其中 subject 是 Commit 的概述,body 是 Commit 的具体内容。
例如:
fix: correct minor typos in codesee the issue for details on typos fixed.Refs #133
Commit Message 可以在 git 中配置模板,这样可以在 vim 中展⽰出模板,另外可有⼯具帮助我们⽣成和约束 Commit Message,例如commitizen/cz-cli,这⾥不再具体说明。
2.1.
3. CI 通过
CI(Continuous Integration),持续集成可以帮助我们⾃动发现很多代码中的基本问题,在合适的静态代码检查(lint)配置和良好的单元测试覆盖下,CI 可以有效地提⾼代码的质量。很多⼈都低估了静态代码检查的能⼒,实际上现在常见语⾔的静态代码检查已经能帮助发现不少的 bug 和隐患。对于 Go 语⾔,可以配置 golangci-lint 来做代码检查,单元测试根据实际情况可以制定相应的标准,⽐如覆盖率 60%,其中关键的代码逻辑尽量全⾯覆盖。
提交代码 Review 前需要确保 CI 执⾏通过,这也是为了节省 Reviewer 的时间,能够通过⾃动化解决的事情,尽量不要让 Reviewer 来做,⽽ Reviewer 发现 CI 未过的 MR 也可以要求 Author 先解决 CI 问题。
2.1.4. Self-Review
我们⼀般代码 Review 都是他⼈来进⾏ Review,其实负责任的 Author 在邀请他⼈来代码 Review 前也需要⾃⼰简单 Review ⼀遍,即Self-Review。
Self-Review 的⽬的包括:
发现那些明显的疏忽,如代码 debug 过程中留下的不必要的痕迹,⽐如 fmt.Println(...),不⼩⼼注释掉的代码。
之前被 Reviewer 多次提出过的问题。
Commits 是否正常,在多⼈协作的情况下 MR 中否带⼊了不相关的 Commit。
Commit Message 是否合适。
Self-Review 是⼀个⾮常快速的过程,从我个⼈的经验,⼀般 1-2 分钟即可完成,所以推荐⼤家养成 Self-Review 的习惯。
2.2. 该谁来 Review
从⽬的出发,可以从以下⼏⽅⾯考虑 Reviewer:
提⾼代码质量。所以⾸先应该和代码改动紧密相关的研发⼈员参与 Review,⽐如⼀起开发某个功能,某个项⽬,或者⼀起参与了⽅案设计讨论并给出了有价值意见的研发。
获取意见。有相关经验的资深研发帮忙 Review,⽐如 Java 语⾔资深的研发、写过相同或类似系统/功能的研发。
形成共识。如果涉及到不同团队或模块间的接⼝改动,或其他会影响其他⼈的改动,可以邀请相关团队或模块的接⼝⼈参与 Review,以对改动形成共识。
质量把关。对于重要的代码库,可能会执⾏⽐较严格的质量把控,如果设置了必须的 Reviewer,这些 Reviewer 也会参与进来。
变动告知。很多情况下⼀个代码库可能只有⼀个⼈维护,如果做了些⽐较特殊的变动,其他⼈很难发现。
因此在做⼀些重要的但是理解起来不那么直接的地⽅的时候,最好告知⼀下相关的研发,以便他们能⼤概知道发⽣了什么。
2.3. 都 Review 些什么
经常会有 Reviewer 拿到 MR 不知道该 Review 些什么,其实⽆论你参与对应项⽬的深⼊如何,都可以对代码进⾏ Review,也⿎励不同⼈从不同的深度、⾓度去帮助 Review。代码 Review 没有固定的形式,它更像是⼀门艺术,唯⼀的提⾼办法就是实际参与进去。
Review 的时候可以从以下⼏个⽅⾯⼊⼿:
1)简单的 Review
在 CI 通过的情况下,最简单的 Review ⽅式可能只需要这样:
Reviewer:在实际环境中都验证过了吗?
Author:当然验证过了
Reviewer:LGTM
这是⼀种提醒式的 Review。确认⼀句:是否在环境中验证过了,或者进⼀步把能想到的重要的验收点提出来确认⼀遍。即使是这种最简单的 Review 实际上也是有价值的,我们很难保证所有研发都会在提 MR 前实际在环境中验证⾃⼰所做的修改,也很难保证单元测试、e2e 测
试能 Cover 住所有的情况,Reviewer 基本上也不可能都⾃⼰去环境上跑⼀遍。让 Author 去确认实际上就是提醒 Author 去确保改动⾄少是真实有效的,尤其是对⼀些已发布版本的 Bugfix,⼀定要提醒实际⾃测通过。
类似的提醒还包括:相关的⽂档(外部的)是否相应更新了、这个改动是否会有兼容性的问题、性能是否有影响。他们的本质就是提醒Author ⾃⼰去思考他们可能遗漏的问题。
2)常规的 Review
代码 Review ⼀般都会从代码风格、变量命名、语法统⼀处⼊⼿,当然这些应该更多的借助于 CI 等⾃动化⼿段来保证,但是在相关流程还不是很完善的前提下还是有必要进⾏关注。
此外代码可读性、代码健壮性、代码可扩展性都是 Review 时关注的点。每⼀个关注的点都依赖于 Reviewer 的实际经验,这⾥只简单举⼏个例⼦:
{ 代码可读性 }
代码是写给⼈看的,因为没有不需要维护的代码,⽆论是 Author ⾃⼰后续维护代码,还是他⼈接⼿代码,能快速地理解代码逻辑是⾮常必要的。
代码 Review 的时候可以关注以下⼏点:
变量、⽅法的命名是否合适,是否真实反映了他们的⽬的,这⽅⾯⽹上可以到不少的资料说明。
实现的逻辑是否已有现成的库可以替代。如果有成熟的库可以使⽤,尽量不要⾃⼰去实现,因为可能会引⼊不必要的 bug。从我个⼈的⾓度,简洁(⼤⽩话就是代码少)是可读性⼀个很重要的指标。
关于注释。代码注释不求多,⽽在于有效,以前也经历过代码注释要求⾄少达到 30% 以上的年代,现在看来过多依赖注释其实是对代码质量的不⾃信,好的代码应该尽量做到⾃解释。在实际过程中偶尔能看到代码逻辑实际已经清晰明了,但是⽤语句不怎么通的英⽂注释了⼀通,最后反⽽是看懂了代码才能理解注释到底说了啥。因此 Review 的时候,不必要的注释可以建议去掉。
不好理解的地⽅要有恰当的注释。代码中如果有特殊处理、特殊的常量、或者不符合⼀般⽤法的逻辑需要特别注释说明⼀下。
代码的组织。良好的代码应该有较好的封装以及层级,使得代码看起来清晰明了,⽐如 DAO 层、Service 层。
{ 代码健壮性 }
代码的改动是否会影响其他功能。
⽤户参数是否做和细致的校验。
有没有 Panic 的可能(针对 Go 的说法)。
是否会破坏 API 的兼容性。
{ 可扩展性 }
当前的实现⽅式是否能兼容以后类似的扩展需求。⽐如在新增接⼝、API 或者调整参数以解决某⼀问题上,可以考虑是否后续会有其他类似情况发⽣。举⼏个例⼦:
假设我们需要定义⼀个 API 接⼝去获取⼀个⽤户的某些信息,例如联系⽅式等,我们定义的 API 就不能只返回这些信息,⽽是应该把⽤户相关的信息都返回。
假设我要定义⼀个参数,虽然当前定义成单个元素即可满⾜,例如 string, int,但是以后是否会涉及到多个元素的场景,是否定义成[]stirng, []int 是更优的。
这⾥只是举了有限的⼀些例⼦,在实际 Review 过程中,Reviewer 可以根据⾃⾝的经验从各个⾓度提出优化的意见。⼀般需要重点看看:
你看不懂或疑惑的地⽅。
打破你常规的地⽅。
复杂的地⽅。
2.4. 如何进⾏
Review 过程中⿎励 Reviewer ⼤胆 Comment,有不理解的地⽅,或者觉得不合适的地⽅都直接表达出来,Author 对 MR 的每个 Comment 也要做出反馈,⽆论是展开讨论还是简单的给个 OK 都是有效的反馈。
Review 的过程可以是:
Author 在各项确认⼯作完成后,发起 Review,如果⽐较急,可以给重要的 Reviewer 发消息请求帮忙 Review。
Reviewer 看到 MR 后应该先确认 MR 的背景和⽬的,如果不清楚也⽆法从 MR 中获取该信息,最好直接和 Author 沟通。
Reviewer 直接在 MR 上提出⾃⼰的建议或者问题。
Author 对每个 Comment 进⾏反馈,并展开必要的讨论。
复杂的话题可以采⽤线下讨论以提⾼沟通效率。
Author 处理完了所有的 Comment,也修改了代码后,需要在 MR ⾥ @ ⼀下相关 Reviewer 告知所有优化已经提交,如果时间⽐较急也可以直接和 Reviewer 沟通。
Reviewer 确认没问题,给 MR 进⾏ Approve,⼀般简单的回复是 LGTM(Lood Good To Me),也可以对 Author 的⼯作进⾏赞赏,⽐如 “God Job” 等。
Approve 后 MR 由谁来合并这个看⾃⼰选择。
如果 Reviewer 提供了很多有⽤的建议帮助优化代码,Author 也可以礼貌性地感谢⼀下 Reviewer。
2.5. 关于 Comment
代码 Review 很⼤程度上就是给代码挑⽑病,⽽且⼀般预期挑的越多越好,但代码是 Author 写的,很多情况下或多或少会对 Author 造成不适。所以在 Comment 的时候需要尽量注意措辞,尤其是⼀些主观的东西,⼀般以建议的⽅式给出。当然对于原则性的问题,是要坚守质量标准的,甚⾄可以直接 Deny 掉 MR。
另外,参与者也不要吝啬你的溢美之词,⽆论是 Author 还是 Reviewer,在 Review 中发现了好的地⽅或好的建议,请给予对⽅以肯定和赞美,这样有助于 Review 有效的进⾏。
2.6. 参与者该抱着怎样的⼼态
2.6.1. Author
接口文档怎么看⾸先需要明确⼀点,是 Author ⾃⼰对代码的质量负责,因此应当怀着感恩的⼼去看待坚持认真帮你 Review 代码的 Reviewer,因为并不是所有你加的 Reviewer 都有时间和精⼒来帮你提⾼代码质量。
也正式因为 Author 是⾃⼰代码的 owner,所以不要依赖于 Reviewer 去帮你守代码质量的⼤门,像 “代码 Review 的时候你怎么就没看出来”,“这不是你建议我这么做的吗” 这样的话千万别说。Reviewer 只是帮你提⾼代码质量,因此我们该做的⼯作都要去做,⽐如细致的Reviewer 可能某些情况下直接提出了代码优化的建议,Comment 时贴上了优化的代码⽚段,Author 不能直接假设它⼀定是能正常⼯作的,⽽应该对它进⾏完整的验证。
对 Reviewer 给出的 Comment,不要有抵触的情绪,对你觉得不合理的建议,可以委婉地进⾏拒绝,或者详细说明⾃⼰的看法以及这么做的原因。有时候⼀个你觉得不合理的建议可能代表⼀个新的思考⾓度,也可能代表 Reviewer ⾃⾝代码能⼒上的不⾜,⽆论是哪个,⽆论最终是 Author 还是 Reviewer 得到了提⾼,都应该是好事。
2.6.2. Reviewer
Review 代码既是帮助提⾼代码质量的过程,也是 Reviewer 提⾼⾃⼰代码能⼒和沟通能⼒的过程。因此应该在 Review 的同时保持⼀个学习者的⼼态,既要发现对⽅代码中的缺陷,也要努⼒去发现代码中的亮点。切记单纯以挑⽑病的⼼态去 Review 代码。
有不少 Reviewer 在写 Comment 的时候会犹豫,担⼼⾃⼰提出的问题或建议⽐较“蠢”,因此犹犹豫豫下看完了代码抱着⼀堆疑虑最终啥也没留下。其实在代码 Review 的时候⼤可不必有什么⼼⾥负担,有什么疑惑的、不清楚的地⽅或者有什么⾃⼰的想法,可以直接提出来,有时候⼀个简单的 Comment 就可能会激起 Author 和你的 Comment 毫不相⼲的新思路。再者你即使没帮 Author 提⾼代码,让 Author 帮你提⾼思考不也是建不错的事情吗。
Reviewer 也不需要去关注⾃⼰的“产出”,并不是⼀定要提出⼀堆问题才是好的代码 Review,Author 代码写得很棒也是很正常的,如果从你的⾓度觉得代码没问题,⼤胆给个 LGTM 甚⾄是 Approve。
转⾃知乎

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。