云效代码评审,助力“质效”提升

前言

代码质量涵盖的范围之广可谓触及产研流程的方方面面,多年来代码质量相关的方法论和依 此产生的工具更是不胜枚举,本文我们尝试从代码评审的切面入手,尝试从 CodeReview 视角介绍我们在云效 Codeup 产品评审能力的建设过程中,相关的一些思考和实践。

在代码评审的一些方法实践中,“小步快跑”一直是一个经常被提及的词语,我们认为的原因 主要有以下几点:

  • 及时发现问题:及时发现问题,避免问题的积累
  • 降低修正成本:如果一次代码评审设计的代码量较多或者内容不聚焦,那么发现问题后进行修正或重构成本较高。
  • 研发协作效率:让评审的参与者们,可以每次进行一小部分工作,降低评审压力和难度,最终完成评审过程。

1. CodeReview 的“小步快跑”为什么难以落地?

1.1 什么是“小步”

我们将“小步快跑”拆分为两个部分来看,首先我们来看“小步”。我们认为,“小步”就是指每 一次代码提交的内容要原子化,并且内容尽可能的少,即:一个提交做且只做一个事情。提 交能否做到原子化,会直接影响后续代码评审、代码合并以及持续集成的效率,是最容易被 忽略但是确最重要的前提之一。

1.1.1 成为更好的开发者,从学习做好一个提交开始

那么,一个“好”的提交具体应该如何评判呢?我们认为主要应该体现在三个方面:

  • 提交做小
  • 提交做对
  • 提交做好
1.1.1.1 提交做小

提交做小就是将要解决的问题解耦:“Do one thing and do it well”。一些质量较为严格的项目的 提交通常都很小,每个提交只修改一个到几个文件,每次只修改几行到几十行。

找一个你熟悉的开源项目,在仓库中执行下面的命令,可以很容易地统计出来每个提交的修改量。

$ git log --no-merges --pretty= --shortstat
2 files changed, 25 insertions(+), 4 deletions(-)
1 file changed, 4 insertions(+), 12 deletions(-)
2 files changed, 30 insertions(+), 1 deletion(-)
3 files changed, 15 insertions(+), 5 deletions(-)

而在很多项目则不是这样,有时候一个提交动辄修改成百上千的文件,涉及成千上万行的源 代码,这样的提交很难进行测试,代码评审也几乎难以进行。

在开发过程中,程序员一旦进入状态,往往才思如泉涌,不经意间就写出一个大提交。比如 一次向 Git 贡献代码时,提交还不算太大,就被 Git 的维护者 Junio 吐槽,要求拆分提 交,便于评审:

I think this patch should be in at least two parts:

Introduce the two-phase “collect in del_list, remove in a separate loop at the end” restructuring.

(optional, if you are feeling ambitious) Change the path that is stored in del_list relative to the prefix, so that all functions that operate on the string in the del_list do not have to do *_relative() thing. Some functions may instead have to prepend prefix but if they are minority compared to the users of *_relative(), it may be an overall win from the readability’s point of view.

Add the “interactively allow you to reduce the del_list” bit between the two phases.

关于提交拆分操作方法,可以观看 Codeup 团队的相关视频介绍: 《拒做无名之辈!写好提交,做一个有品味的程序员》

1.1.1.2 提交做对

“好的文章不是写出来的,而是改出来的。” 代码提交也是如此。

程序员写完代码,往往迫不及待地敲下:git commit,然后发现提交中少了一个文件,或 者提交了多余的文件,或者发现提交中包含错误无法编译,或者提交说明中出现了错别字。

Git 提供了一个命令:git commit --amend 来把此次更改附加到当前提交上, 防止我们做 的是同一件事情,但是产生了多余的提交,从而破坏了提交的原子化。

如果你发现错误出现在上一个提交或其他历史提交中怎么办呢?比如发现历史提交 a1234567 中包含错误,我们可直接在当前工作区中针对这个错误进行修改,然后执行下 面命令git commit --fixup a1234567。你会发现使用了 --fixup 参数的提交命令,不 再询问你提交说明如何书写,而是直接把错误提交 a1234567 的提交说明的第一行拿来,在 前面增加一个前缀“fixup!”,如下:

fixup! 原提交说明

那么当开发工作完成后,待推送/评审的提交中出现大量的包含“fixup!”前缀的提交该如何 处理呢?

如果你执行过一次下面的命令,即针对错误提交 a1234567 及其后面所有提交执行交互式变 基(注意其中的 --autosquash 参数),你就会惊叹 Git 设计的是这么巧妙:

$ git rebase -i --autosquash a1234567^

交互式 rebase 弹出的编辑器内自动对提交进行排序,将提交 a1234567 连同它的所有修正 提交压缩为一个提交, 这样我们就完成了针对历史提交的修正,让提交保持原子化。

1.1.1.3 提交做好

仅仅做到提交做小、提交做对,往往还不够,还要通过撰写详细的提交说明让评审者信服, 这样才能够让提交尽快通过评审合入项目仓库中。几年前,我们无意发现 Git 服务器上的 一个异常,最终将问题定位到 Git 工具本身。整个代码改动只有区区一行:

提交:receive-pack: crash when checking with non-exist HEAD

你能猜到提交说明写了多少么?写了20多行!

    receive-pack: crash when checking with non-exist HEAD

    If HEAD of a repository points to a conflict reference, such as:

    * There exist a reference named 'refs/heads/jx/feature1', but HEAD
      points to 'refs/heads/jx', or

    * There exist a reference named 'refs/heads/feature', but HEAD points
      to 'refs/heads/feature/bad'.

    When we push to delete a reference for this repo, such as:

            git push /path/to/bad-head-repo.git :some/good/reference

    The git-receive-pack process will crash.

    This is because if HEAD points to a conflict reference, the function
    `resolve_refdup("HEAD", ...)` does not return a valid reference name,
    but a null buffer.  Later matching the delete reference against the null
    buffer will cause git-receive-pack crash.

    Signed-off-by: Jiang Xin <worldhello.net@gmail.com>
    Signed-off-by: Junio C Hamano <gitster@pobox.com>

让我们来看看关于提交说明的一些约定俗成的规定:

  • 提交说明第一行是提交标题,是整个提交的概要性描述。提交标题的长度要求:尽量不要 超过 50 个字符。 这是因为对于像 Linux、Git 这样的开源项目,是以邮件列表作为代 码评审的平台,提交标题要作为邮件的标题,而邮件标题本身有长度上的限制。虽然我们 很多日常开发是企业内的项目,但是我们应该遵守这一点,有益而无坏。

  • 提交标题使用英文,尽量不要出现中文。这是因为一些 git 工具如 git format-patch 将提交转换补丁,或以邮件方式交换提交补丁的时候,会丢失中文(中文转换为空白字 符!)

  • 建议在提交标题中添加前缀,对改动范围进行区分(例如用模块名做前缀: receive-pack:)。

  • 不要在提交标题后面添加标点符号(如句号.)。一个原因是提交标题的长度要求,不要 浪费。

  • 提交标题后的空行。必须要在提交说明的第一行(subject)和后续的提交说明(body) 中间留一个空行!如果没有这个空行,很多 Git 客户端会将连续几行的提交说明合在一 起作为提交的简要描述(git log --oneline),这样显然查看起结果来太糟了。

  • 提交说明也有长度的限制,最好以72字节为限,超过则断行。提交说明主体中要写什么内 容呢? 例如:本次提交要解决什么问题?如何解决的?为什么这么做是最合理的。

  • 签名区: git commit 命令有一个 -s 参数,会自动在提交说明最后添加 “sob** 签名。 为什么要在提交后面添加签名呢?因为一个提交的元信息中只有作者(author)、提交者 (committer)两个字段,而一段代码的诞生,参与的人往往不止于此,还可能有问题报 告者(Reported-by)、代码评审者(Reviewed-by)、上游 Committer 的签名 (Signed-off-by)。为此一些开源项目(如 Git、Linux)的一个约定俗成的习惯,是在 提交的最后加上签名,每个贡献者一行,从上到下可以看到这段代码诞生的过程。对帮助 过你的人致谢吧,加上你的代码签名。

1.2 “快跑”:提交之间的逻辑化组织

对于代码评审来说,光把单个提交做好还不够。我们认为:代码评审要关注过程,要由远及 近地看每一个提交,不能只看前后两个版本之间的差异。有人认为这样的评审方式多此一举, 并认为这样做可能是在浪费时间。有的时候,给一个提交不规范的开发者做代码评审,的确 头疼又浪费时间:看到一个提交中的代码问题,花了几分钟写评论,然后发现下一个提交中 这个问题被修正(fixup)了,这样的情况时有发生,让人无奈。

1.2.1 提交之间组织或编排,往往被人忽略

一些开发者会将 提交(git commit)和推送(git push进行混淆,commit实际上是我们本地 编写和组织改动的过程,而推送实际上是本地与远端 Git 服务器之间的交互行为。我们都 知道,从开发到不断修正的过程中,可能经历多次 `git push, 每一次中间都可能包含多 个提交同时事我们可以把每一次推送的版本称之为补丁(Patch)。

在一个补丁中包含多个提交的情况时有发生,因为我们要保持原子化不是吗? 那么接下来 的问题就是,这些提交应该如何组织和编排呢?

1.2.2 提交编排的基本原则
  • Cleanup
  • Preparation
    • Refactor
    • Test cases supplyment
  • Implementation
  • Test cases
  • Documentation
1.2.2.1 Cleanup 提交

首先,Cleanup 可以理解为当我们真正开始开发一个补丁(patch)之前,可能我们顺带发 现了之前相关联代码的一些问题,为了更好的实现我们的特性或者缺陷修复,我们需要尽量 修复之前的问题,不论是新发现的缺陷还是格式化的问题,Cleanup 的提交都应该在率先完 成。Cleanup 可能包括多个提交,比如一个提交用于修复代码格式化问题,另一个提交用于 修复错误的文档和注释等等。

1.2.2.2 Preparation 提交

在完成 Cleanup 提交之后,我们可能还需要进行一些重构工作,以及如果是缺陷修复的情 况可能还务必需要首先补充对应的测试(虽然对于重构来说最好也需要检查测试是否需要补 充)。这些提交和 Cleanup提交 通常我们称之为前置提交,他们很有必要拆分出来(实际 上应该一开始就按照独立提交设计编排,因为拆分提交要困难得多),这些提交的实现不应 该 break 原有的功能行为,这样无疑可以让评审者的评审效率以及作者后续的补丁编写效 率大幅度的提升。Preparation 可能包括多个提交,比如一个提交用于修改不恰当的函数名 称,另一个提交用于抽象和提取公共函数等等。

让我们通过前置提交的方式,更好的体现开发者的解耦功力,让“快跑”成为可能吧!

1.2.2.3 Implementation 提交

接下来,就开始真正的实现层面的提交了,不论是缺陷修复或者是特性开发, Implementation 提交都有可能包含多个,我们需要依次实现即可,比如我们需要对某业务 提供一个新的 API:

  • IMP 提交 1:进行 API 接口的设计(此时可以推送补丁 A 到远端,评审者收到通知后便会进行评审)
  • IMP 提交 2:进行 DAO 层的逻辑实现(此时可以推送补丁 B 到远端,评审者收到通知后便会进行评审)
  • IMP 提交 3:进行 Service 层的逻辑实现(此时可以推送补丁 C 到远端,评审者收到通知后便会进行评审)
  • IMP 提交 4:进行 Controller 层的逻辑实现(此时可以推送补丁 D 到远端,评审者收到通知后便会进行评审)

我们可以发现, 当我们把提交的内容尽量解耦并让其具备原子性之后,我们可以频繁发送 最新的补丁(基于补丁(patch)的评审工作流),告知评审者们我工作的进展,而评 审者每次评审的内容也基于递进式的方式,变得更加可控和高效。对于评审作者,我们也会 更加及时的获取各方评审者的反馈,让我们得到更多提前修正的机会。

就上面的例子来说,试想如果在 API 接口的定义上存在问题,那么在补丁版本 A 对应 的评审上就可以提前得知,试想如果我们开发了一周之后,在代码评审时被告知 API 接口 的设计存在问题,那么最坏的情况下我们需要修改 IMP 1~4 4个提交,这显然糟糕透了!我 们似乎抓到了“快跑”的一点诀窍,看上去也没有那么复杂,不是吗?

1.2.2.4 Test cases 提交 和 Documentation 提交

针对我们的补丁,我们通常需要在本工程中进行测试用例的补充,我们可以单独的拆分对应 的提交,但是这并不是必须的。有些时候,测试用例的改动以及文档的改动可能会连同 Implementation 提交压缩在一起,这在一些情况下是非常必要的,尤其在添加或者删除某 个特性的时候,例如:

https://github.com/git/git/commit/425b4d7f47bd2be561ced14eac36056390862e8c

这个提交中既包含一个新的选项的支持,同时在提交中还包括测试用例和文档的改动,他们 之前有强关联性,因为他们都是 “Do One Thing”。对于 Git 开源项目来说,在测试用例和 文档质量上的要求尤为严格(只改了 7 行代码,但是对应的测试用例和文档改动却有 135 行!),从而每一个提交都可以通过完整的测试用例集。对于可能存在功能性 break 的情 况时,连同测试用例和对应的改动压缩为一个提交是非常必要的,评审者可以知晓改动在向 后兼容性和破坏性方面的问题。而对于文档改动的提交也同理,很多工程的文档同样需要构 建,例如提供对外的 API 文档等,这部分内容同样要尽量保持同步修改。

但有些时候,压缩在一起也不是必须的,比如可能补丁本身的工作就编写测试用例和文档。

1.2.3 基于补丁(Patch)的评审工作流

刚才我们通过介绍在一个补丁中进行提交编排的重要性,引出了基于补丁的评审工作流 的概念。在“小步快跑”的方法实践中,了解这种工作流的运转方式其实非常关键:

  • 根据代码评审意见,代码评审的作者每次推送会产生新的 patch
  • 代码评审者以 patch 为粒度,了解编排好的提交,对 patch 的演进有最直观了解
  • 支持老 patch 与当前 patch 之间的文件改动
  • 对于已经 review 过的历史 patch,同样支持通过指定 patch 区间评审特定版本之间的变更
  • 保存历史 patch 衍生的全部数据(测试结果、评审意见、评论等),可追溯特定 patch 的评审上下文信息

云效 Codeup 的新版代码评审支持基于补丁(patch)的评审工作流,提供该方法论的支撑落地方案:

patch based CR

1.2.4 提交编排在补丁之间的变化

我们很难做到每次补丁中的提交编排都非常正确,我们仍旧按照上面的实现API的例子来说明:

  • IMP 提交 1:进行 DAO 层的逻辑实现(此时可以推送补丁 A 到远端,评审者收到通知后便会进行评审)
  • IMP 提交 2:进行 Service 层的逻辑实现(此时可以推送补丁 B 到远端,评审者收到通知后便会进行评审)
  • IMP 提交 3:进行 Controller 层的逻辑实现(此时可以推送补丁 C 到远端,评审者收到通知后便会进行评审)

假设我们作为评审者,从补丁 C 开始评审,我们根据上述的补丁情况,我们希望开发者可 以将提交 3 拆分为两个提交,将 API 的接口设计和具体实现进行解耦, 评审者根据我们的 评审意见,推送了补丁 D 即:

  • IMP 提交 1:进行 API 接口的设计(此时可以推送补丁 A 到远端,评审者收到通知后便会进行评审)
  • IMP 提交 2:进行 DAO 层的逻辑实现(此时可以推送补丁 B 到远端,评审者收到通知后便会进行评审)
  • IMP 提交 3:进行 Service 层的逻辑实现(此时可以推送补丁 C 到远端,评审者收到通知后便会进行评审)
  • IMP 提交 4:进行 Controller 层的逻辑实现(此时可以推送补丁 D 到远端,评审者收到通知后便会进行评审)

其中在最新的补丁 D 中,评审制对于提交 2 和 提交 3 无需关注, 因为他们对比上次评 审的版本没有变化, 只需要关注拆分出来新的提交 1 以及 提交 4, Git 支持 range-diff 命令来查看补丁之间的提交差异:

$ git range-diff 34d57b4..3cfc130 34d57b4..ce628af
-:  ------- > 1:  5b6048e api: design and mock membership GET API
1:  63a70e5 = 2:  8318c31 dao: introduce query membership INF
2:  7ab068a = 3:  c11a747 service: introduce getQueryMembershio INF
3:  3cfc130 < -:  ------- api: introduce membership GET API
-:  ------- > 4:  ce628af controller: query membership API to mature

可以清楚的看到,对比旧的补丁,在新的补丁中评审作者新增了提交 1 和提交 4 ,删 除了提交 3。通过补丁之间的提交差异,对于整个评审效率的提升无疑是巨大的,一方面 我们关注的改动范围得到的缩小, 另一方面我们可以更加了解评审作者的编码思路和设计。

云效 Codeup 的新版代码评审支持查看补丁之间的提交维度的改动,提供该方法论的支撑落 地方案:

range-diff

当我们真正将提交做好,并且结合基于补丁的代码评审方式来完成编码工作流的时候,不论 是对于作者和评审者的效率提升都是非常巨大的, 二者是让这一切自然发生的基础。但其 实二者的收益不止于此,在持续集成方面也将带来巨大的正向收益。

2. 代码评审与持续集成的紧密结合

2.1 为什么越多的人倾向于在代码评审中进行持续集成?

通过代码评审中进行持续集成,主要有如下好处:

  • 更快地发现问题:持续集成可以让代码在提交后自动构建和测试,从而更快地发现问题, 尤其是一些隐藏的问题。这样可以避免问题在后期才被发现,从而节省时间和成本。

  • 自动化测试:持续集成可以自动运行测试套件,从而提高测试覆盖率和代码质量。这样可 以确保每个提交都已经通过了测试,并且没有引入新的问题。

  • 提高开发效率:持续集成可以自动化构建和测试,从而减少了手动操作的时间和成本。这 样可以让开发人员更加专注于编写代码,并且更快地构建和测试代码。

  • 实时反馈:持续集成可以在提交后立即运行,从而提供实时反馈。这样可以让开发人员及 时了解他们的代码是否通过了测试,以及是否存在任何问题。

  • 优化 Code Review 流程:持续集成可以让 Code Review 流程更加高效。在 Code Review 过程中,开发人员可以更加专注于代码质量和设计。

  • 自然映射:持续集成中产生的问题,例如 foo.bar 文件的第 20 行导致编译失败,可以比较顺滑的 与评审的代码内容进行准确映射。

2.2 软件质量和安全的诉求,对评审自动化检测能力提出更高要求

随着现代软件开发过程中测试工具不断演进,软件开发对自动化检测方面的诉求正在不断增加:

  • 开箱即用:在代码评审中支持一站式DevOps中内置的流水线等能力支持。

  • 可扩展性:随着软件开发的不断发展,自动化检测需要具备可扩展性, 例如支持外部三 方检测工具集成。

  • 多样性:软件开发对检测能力的多样化要求越来越高。一方面开发人员可能需要使用多种 语言、框架和配套工具,自然而然的就希望能有对应的检测能力支持。 另一方面,在安 全合规等维度的检测也已经成为软件质量的重要一环,例如安全漏洞、依赖包漏洞、开源 合规检测等等。

云效 Codeup 的新版代码评审支持丰富的自动化检测能力和三方接入能力(灰度中),提供该 方法论的支撑落地方案:

  • 内置流水线:支持关联云效 Flow 流水线,开箱即用。

  • 三方集成:支持提交状态检查集成、三方应用检查等 CI 工具集成,支持三方自定义 markdown 模版。

  • Patch 追溯:支持查看特定 patch 的自动化检查结果。

CI

3. 轻评审流程还是重评审流程?

3.1 轻量级评审

轻评审即轻量级评审,适合将迭代速度放在第一优先级的产研团队,对代码质量和上线后的风险方面有一定包容度。

在研发资源极度紧张,业务需求井喷的场景下,质量和速度是鱼和熊掌不可兼得的事,很多初创企业的管理者或者是技术Leader都选择接受一定的技术债务,在研发流程上,不要求一定满足严格的评审合入准则, 在这种情况下,轻评审是比较不错的选择。

3.2 重量级评审

重量级评审与轻量级评审采取不同的策略,通常常见于以下常见的场景:

  1. 业务类:对于代码质量要求较高
  2. 服务类:应用、中台类应用、工具等
  3. 开源类:开源贡献场景,通常对于代码质量的要求较高

重量级评审通常对于质量上的流程把控比较严格,要求评审合入之前需要通过一系列的

3.3 灵活的卡点支持

不管是轻量级评审还是重量级评审,不同的企业对于代码评审的卡点支持上,通常主要关注 通用性、扩展性和灵活性三个维度。

3.3.1 通用性

通用卡点主要包括:

  • 支持代码冲突检测结果作为合并卡点

  • 待解决评论作为合并卡点

  • 评审人评审是否通过作为合并卡点

3.3.2 扩展性

扩展性主要体现在,根据自身业务诉求,在基础卡点类型基础之上,支持扩展平台内置或者 三方接入的自定义卡点:

  • 代码风格:支持 code-style 检测结果作为合并卡点。

  • 代码规范:支持代码规范类检测结果作为合并卡点。

  • 代码测试:支持单元测试、集成测试、可交付测试等测试结果作为合并卡点。

  • 安全合规:支持依赖包漏洞检测、代码漏洞检测、代码扫描检测、开源合规检测等检测结 果作为合并卡点。

  • 其他自定义卡点类型。

3.3.3 灵活性

通常在一些特殊的场景下,尽管设置了代码评审的相关卡点,你可能仍旧希望在特定规则下, 可以灵活的控制卡点的生效逻辑,包括:

  • 可灵活选择卡点结果是否作为卡点,例如只希望代码风格的卡点进行检查和结果查看,但 是不作为真正卡点阻碍代码的合并。

  • 在紧急发布情况下,本地已经验证通过,希望临时将某些卡点检查自动跳过,从而尽快进 行合并从而修复线上缺陷。

基于以上通用性、扩展性的灵活性的卡点的考虑,代码评审应该灵活支持企业内不同的团队 对于轻量级评审和重量级评审的不同诉求。云效 Codeup 的新版代码评审通过对于合并卡点 的理解和抽象,支持常见基础卡点以及自定义卡点(灰度中),进而提供该方法论的支撑落地 方案:

merge-checklist

4. 评审协同效率中一些细节的思考

4.1 为评审的发起与更新提速

一般情况下,代码评审通常是在特性分支推送之后,由作者在页面进行创建。时至今日,越 来越多的产品选择支持基于命令行直接创建和更新代码评审。当然除了追求速度和操作上的 遍历之外,最核心的问题还包括“谁能创建代码评审?谁能向仓库中贡献?”的问题, 我们 在2020年对外公开了内部实现的 AGit-Flow 的集中式工作流,亦或称之为 Codeup 主干研 发模式。

关于 AGit-Flow 可以参考蒋鑫老师的文章《新一代高效Git协同模型AGit-Flow详解》: https://developer.aliyun.com/article/760537

既然有了 AGit-Flow,那么有没有这样一种方式,在不需要安装任何工具的情况下,执行 git push 就可以自动创建或更新评审?这样的好处有:

  • 向仓库贡献代码,发起代码评审,不再需要创建新的分支,直接在主干上进行修改并提交 即可,避免了冗余的分支管理成本。

  • git push 不再直接推送分支内容,而是创建/更新代码评审。

  • 如果代码需要修补,提交后继续执行 git push,已发起的评审会自动更新。

  • 向仓库贡献代码不再需要授予开发者权限,拥有仓库的浏览者权限即可贡献代码,而且贡 献的代码需要经过评审才能正式合入代码库。因此可以将直接写库的权限最小化到少数管 理者手中,而大部分开发者仅需要读权限即可,降低了代码库被意外修改的风险。

  • 支持指定 push option 来控制具体的推送行为。

关于推送评审,我们已经在2022年发布上线,具体可参考云效官方文档: https://help.aliyun.com/document_detail/460320.html

推送评审模式实操演示:

4.2 化零为整,评审操作更专注

经常参与评审的同学一定有一些体感,那就是完成一次评审通常需要多种较为松散的操作,其中主要包括:

  • 创建草稿评论
  • 发表评审意见
  • 回复某一评论
  • 增加评审人和抄送人
  • 希望针对本次评审过程,最终发表全局评论

这些操作通常都是评审人较为关注的点,为了进一步提升评审者的评审效率,化零为整是十 分重要的手段,具体解决两类问题:

  • 将评审过程中各类常见操作进行聚合。
  • 支持发表评审意见前,再次 review 和修订本次评审操作的关键内容。

云效 Codeup 的新版代码评审通过统一评审操作视图的产品支持,大幅提升在评审意见发表 和review环节的评审效率:

unify-review-window

4.3 化繁为简,评审待办更直观

对于评审作者,当提交当前补丁之后,在最终合并之前,可能要经过多轮的 review,需要关注的点通常比较繁杂,例如:

  • 待解决评论的及时回复
  • 持续集成的运行结果
  • 代码中存在的安全漏洞

总之,在代码评审的过程中,作者不仅需要提交和推送代码,还需要回答问题、解释代码、 接受评审意见、修复测试用例和漏洞等等。针对这种情况,云效 Codeup 的新版代码评审中 提供了 Todolist 功能组件,帮助评审作者简化繁杂的各类待办信息,进而更加高效的解决 当前评审的遗留问题,该功能主要包括:

  • 快速浏览和定位待解决评论
  • 快速浏览和定位自动化检测问题
  • 快捷键支持

todolist

4.4 化腐为奇,评审评论可追溯

在代码评审中,评论需要具备以下功能:

  • 支持代码文件的行内评论。
  • 评论的跳转和定位。
  • 支持代码评审的全局评论。
  • 支持创建草稿评论。
  • 评论支持markdown格式。
  • 支持动态表情评论。

云效 Codeup 的新版代码评审中除了以上能力的支持之外,还另外支持追溯 outdated 评论 (例如:早前补丁中对应行存在评论,但在当前补丁对应行已经被删除或修改,此时评论仍 然有价值被当前评审者关注)。于此同时,我们提供了几个充满个性的动态表情,帮助研发 团队打造轻松的评审氛围。

outdated-comments

5. AIGC时代的代码评审, 我们已经在路上

最近 AIGC 的话题持续火热,我们同时也看到了在DevOps领域爆发出的强大能量, 首当其冲 的就是由 Github 和 OpenAI 共同开发的一个基于机器学习的代码自动补全工具 Github Copilot, 它可以根据上下文和语法,提供有用的建议和代码片段,从而帮助开发人员更快 地编写高质量的代码。

Github Copilot 的核心技术基于 OpenAI 的 GPT-3 模型,它是一种强大的自然语言处理模 型,可以根据上下文和语法判断接下来可能的代码,并生成合适的代码片段。使用 Github Copilot,开发人员可以在编写代码时获得有用的提示和建议,从而提高编码效率和准确度。 Github Copilot 目前支持多种编程语言,包括 Python、JavaScript、TypeScript 等。它 可以与多种编程工具和开发环境集成,包括 Visual Studio Code、Atom、Sublime Text 等, 使用起来非常方便,同时近期 Github 也发布 Copilot X,可见其在研发工作流中与工具结 合进行产品持续演进的目标,我们认为代码评审一定将作为重要的着力点,甚至将改变现存 的代码评审的核心流程和产品形态。

除了微软之外,就在几个月之前 Google 也在代码评审场景尝试与机器学习技术结合在内部 评审工具 Gerrit 上进行尝试并取得了不错的效果:

google-gerrit-ML

原文: https://ai.googleblog.com/2023/05/resolving-code-review-comments-with-ml.html

云效后续也会在 AIGC 等技术与达摩院进行深度合作, 为广大开发者、企业和团队打造更多 出色的工具、更加优秀的产品以及更加开放的平台。

总结

本文为大家介绍了云效 Codeup 团队对于代码评审上对于效、质、智的一些思考和实践的经 历,同时也分享了在产品和工具上的一系列落地途径,希望以上内容能够帮助到对于代码评 审还存在一定疑惑的一线研发团队,从而让创新、创业以及企业数字化转型的优秀案例不断 发生。

Copyright © 2025 Dyrone Teng