Google的工程实践指南(下):代码开发者指南

CL 描述是一项公开的记录,其内容包含修改了 什么为什么 这么修改。 虽然你的 CL 只是在你与审核者之间发生,但它是版本控制历史的一部分,若干年之后,很有可能会有成百上千的人阅读。

以后的开发者可能会根据描述搜到你以前写的 CL 。在没有精确数据的情况下,他可能根据自己的模糊记忆搜索 CL。如果所有的信息都只包含在代码里面,描述中几乎没有相关内容,那么定位到你的 CL 将会花费太多的时间。

第一行

  • 简短描述做了什么。
  • 完整的句子,祈使句。
  • 后面空一行。

CL 描述的 第一行 应该是一句简短的描述,用以说明 CL做了 什么 。在第一行后面留一空行。以后有开发者搜索版本控制历史的代码时,这是他们看到的第一行,所以第一行应该提供足够的信息,他们不必阅读代码,也不必阅读整个描述,只需扫一眼便知道 CL 做什么,他们节省时间。

一般而言,CL 描述的第一行是以命令口吻(祈使句)写的一句话。举例说明,我们应该写” 删除 FizzBuzz RPC,并用写的系统 替换 它。”,而不是写成 ” 删除了 FizzBuzz RPC,并 已经 用写的系统 替换 它。” 当然,第一行写成祈使句就可以了,其他内容不必如此。 (译者注:原文中的反面例子是现在进行时。但在中文中现在进行时与祈使句基本一致,不好翻译。此处改成了现在完成时。)

说明应提供足够的信息。

[En]

The description should provide sufficient information.

描述内容应该提供足够的信息。它可能包含一段关于问题的简短描述,为什么这是最好的解决方案。如果有更好的解决方案,也应该提及。如果有的话,相关的背景信息,如 bug 编号、基准结果和相关的设计文档也应包含在内。

即使是小的 CL,也应该包含这些信息。

糟糕的 CL 描述

“修复 bug”是一个很不恰当的描述。哪个 bug ?你做了哪些事情来修复它?通通都没有。类似糟糕的描述还包括:

  • “修复编译。”
  • “增加补丁。”
  • “把代码从 A 移到 B。”
  • “第一阶段。”
  • “增加方便的功能。”
  • “清除死链。”

以上这些都是我们在真实案例中见过的 CL 描述。作者可能认为他们提供了足够的信息,其实它们不符合 CL 的目的描述。

良好的 CL 描述

这里有几个描述得很好的例子。

[En]

Here are several well-described examples.

1.功能修改

RPC:移除 RPC 服务器的消息空闲列表的大小限制。

服务器(如 FizzBuzz)有大量的消息,可以从重用中受益。使空闲列表更大,并添加一个goroutine,随着时间的推移缓慢释放空闲列表,以便空闲 服务器最终释放所有空闲列表。

前面几句话描述了 CL 做什么的,接下来描述解决了什么问题,为什么这是一个好的解决方案,最后涉及到了一些实现细节。

2.重构

构建一个带 TimeKeeper 的 Task,以便使用它的 TimeStr 和 Now 方法。

在 Task 中增加一个 Now 方法,然后删掉 borglet() 方法(这个方法仅仅被 OOMCandidate 使用,它调用了 borglet 的 Now 方法)。这样就替换掉 Borglet的方法,把它委托给 TimeKeeper。

让 Tasks 提供 Now 是减少对 Borglet 的依赖所做的一小步。最终,从 Task 上调用 Now 的方式会替代成直接调用 TimeKeeper,我们会逐步实现。

继续重构 Borglet 层次的长期目标。

第一行描述了 CL 做什么的,以及过去它是怎么改变的。描述的其他部分谈到了具体实现、CL 的上下文,这种方法并不完美,但在朝着完美的方向前进。而且也解释了 为什么 应该这么改。

3.需要一些上下文的小 CL

为 status.py 创建一个 Python3 的编译。

在原始的编译(Python2)旁创建一个 Python3 的编译,让已经使用过 Python3 编译的用户根据某些规则选择 Python3 还是 Python2,而不是依赖于某个路径。 它鼓励新用户尽可能使用 Python3 而不是 Python2,并大大简化了当前正在使用的某些自动编译文件重构工具。

第一句话描述做了什么,其他部分解释 为什么 要这么修改,并向审核者提供了不少额外的上下文信息。

提交 CL 之前审核描述

为什么应该写小 CL?

小 CL 有如下优点:

  • 相对让审核者单独拿出30分钟审核大 CL,不如让他花费几个5分钟审核代码。对审核者而言,后者更容易。
  • 审核更彻底。发生较大修改时,往往会反复审核、修改,审核者与开发者经常会因为过多的反复而在情绪上受到影响,以致于把精力放在修改上了,却忽略了 CL 中更重要的部分。
  • 引入新缺陷的可能性更小。如果修改的内容比较少,自然审核人的效率会更高,开发者与审核者都更容易判断是否引入了新的缺陷。
  • 如果被拒绝,浪费的时间更少。如果开发者花费了很大的精力开发了一个大 CL,直到审核的时候才知道整个开发的方向错了,那么之前的所有时间就全浪费了。
  • 更容易合并代码。大 CL 在合并代码时会花费很长的时间,在合并时需要花费大量时间,而且在写 CL 期间可能不得不频繁地合并。
  • 更易于设计。完善小 CL 的设计和修改要容易得多,多次微小的代码质量提高比一次大的设计改变更容易。
  • 减少阻塞审核的可能性。小 CL 通常是功能独立的部分,你可能正在修改很多代码(多个小 CL),在发送一个 CL 审核时,同时可以继续修改其他的代码,并不会因为当前 CL 的审核没有完成而阻塞。
  • 更容易回退。一个大 CL 开发的时间比较长,这意味从开发到代码提交这段期间,代码文件的变更会比较多。当回退代码时,情况会变得很复杂,因为所有中间的 CL 很有可能也需要回退。

请注意: 审核者有权因为你的 CL 太大而拒绝它。 通常,他们会感谢你为代码做出的贡献,但是会要求你把它拆分多个小 CL。一旦写好了代码之后,要把它拆分成小 CL 通常需要花很多时间,当然,你也可能会花费大量时间与审核者争论为什么他应该接受这个大 CL 。与其如此,不如设计之初就保证 CL 尽量小。

如何定义”小”?

一般而言,一个 CL 的大小就应该是 独立功能的修改。这意味着:

  • 一个 CL 尽量最小化,它只 做一件事。通常它只是一个功能的一部分,而不是整个功能。总体而言,CL 太小或太大都不好,二者取其轻的话,太小稍微好点。可以与审核者一起讨论,找出大多比较合适。
  • 审核者需要理解 CL 中包含的一切(除了以后可能要开发的功能之外),包括 CL 代码、描述、已存在的代码(或之前已经审核过的相关 CL )。
  • 在 CL 代码提交之后,无论是针对用户,还是针对开发人员,系统应该仍旧运行良好。
  • 如果代码难以理解,通常是因为 CL 还不够小。如果新增一个 API,同时应该同一个 CL 中附上这个 API 的使用方法,便于审核者理解如何使用,也方便以后的开发者理解。同时也可能有效防止提交的 API 无人使用。

没有直观的标准判断 CL “太大”应该符合哪些条件。 100行代码通常是一个合理的大小。1000行代码通常太大了,但也不能一概而论,这取决于审核者的判断。修改文件的个数也影响它的”大小”。在一个文件中修改200行可能没问题,如果这200行代码横跨50个文件,通常而言太大了。

记住,当你开始编写代码时,只有你最了解代码,而审核者通常不了解上下文。在你看起来很是一个合适大小的 CL,审核者可能会很困惑。毫无疑问,在写 CL 时,CL 的大小最好比自认为的还要小。审核者通常不会抱怨你的 CL 太小了。

什么时候可以有大 CL?

当然,也有一些例外情形,允许 CL 比较大:

  • 删除文件和修改行没有太大区别,因为审核者不会花费太多时间。
    [En]

    deleting a file is not much different from modifying a line, because it doesn’t take too much time for the reviewer.*

  • 有时候,一个大 CL 可能是由可靠的自动代码重构工具生成的,审核者的工作主要是检查它是否做了它应该做的工作。虽然符合以上提到的注意事项(例如合并和测试),这类 CL 也可能比较大。

以文件来拆分

另外一种拆分大 CL 的方法是:对 CL 中涉及的文件进行分组,这就要求不同独立功能的修改需要相应的审核者。

例如:你提交了一个 CL,这个 CL 修改了协议缓冲区,而且另外一个 CL 用到它。因此我们先提交第一个 CL,再提交第二个 CL,并让两个 CL 同时审核。此时,你应分别向两个 CL 的审核者告知另外一个 CL 的内容,以便他们知道上下文。

以代码和配置文件进行拆分。例如,你提交了2个 CL:其中一个 CL 修改了一段代码,另外一个 CL 调用了这段代码或代码的相关配置;当需要代码回滚时,这也比较容易,因为配置或调用文件有时候推送到产品比代码修改相对容易。

单独重构

在修改功能或修复缺陷的 CL 中,不建议把重构也加进来,而是建议把它放到单独的 CL 中。例如,修改类名或把某个类移到其他包内是一个 CL,修复这个类中的某个缺陷是一个 CL,不要把它们合并到一个 CL 中。把它们拆分出来更有利于审核者理解代码的变化。

有些代码清理工作,如修改某个类中的一个变量的名称,可以把它包含在一个功能修改或缺陷修复的 CL 中。那标准是什么呢?这取决开发者与审核者的判断,这种重构是否大到让审核工作变得很困难。

把测试代码包含到对应功能的 CL 中

避免单独提交测试代码。测试代码用以验证代码功能,应该把它与代码提交到相同的 CL 中,虽然它会增大 CL 的代码行数。

  • 为过去提交的现有代码创建新的测试代码。
    [En]

    create new test code for existing code that was submitted in the past.*

  • 重构测试代码(例如,引入 helper 函数)。
  • 引入测试框架代码(例如集成测试)。
    [En]

    introduce test framework code (for example, integration testing).*

不要破坏编译

如果同时在审核的有多个 CL,并且这些 CL 之间存在依赖关系,你需要找到一种方式,确保依次提交 CL 时,保证整个系统仍旧运行良好。否则,可能在提交某个 CL 之后,让系统编译错误。此时,你的同事在更新代码后,不得不花时间查看你的 CL 历史并回退代码以确保本地编译没有问题(如果你之后的 CL 提交出了问题,可能会花费更多时间)。

无法将其变小

在某些情形下,好像你没法然 CL 变得更小,这种情况很少发生。如果开发者经常写小 CL,那么他往往都能找到一种把 CL 拆得更小的方法。

如果在写代码之前就估计这个 CL 比较大,此时应该考虑是否先提交一个代码重构的 CL,让已有的代码实现更清晰。或者,与团队其他成员讨论下,看是否有人能帮你指出,怎样在提交小 CL 的前提下实现当前功能。

如果以上所有方法都试过,还是不可行(当然,这种情况比较罕见),那就先与所有的审核者沟通一下,告知他们你将会提交一个大 CL,让他们先有心理准备。出现这种情况时,审核过程往往会比较长,同事需要写大量的测试用例。需要警惕,不要引入新的 bug。

在发出 CL 之后,审核者一般会给出反馈(评论),让你修改代码。下面我们就来详细描述如何处理这些评论。

不要情绪化

代码审核的目标是保证提交到的代码库中代码的质量,进而保证产品的质量。当审核者提出一些批判性的评论时,开发者应该告诉自己,对方在尝试帮助你,保证代码库的质量,帮助 Google,而不是针对你的人身攻击或个人能力的怀疑。

有时,评论者感到沮丧,并在评论中表达了这一点。其实,这并不是正确的方式,但作为一名开发人员,你应该有面对这种情况的心理准备。问问你自己,“我能从评论者的评论中读到什么有建设性的评论?”想象他们用这种建设性的语气对你说话,然后听从这个建议。

[En]

Sometimes the reviewer felt frustrated and expressed it in the comments. In fact, this is not the right way, but as a developer, you should be psychologically prepared to face this situation. Ask yourself, “what constructive comments can I read from the reviewer’s comments?” Imagine that they speak to you in this constructive tone, and then follow this advice.

不要在代码审核中带着情绪回复评论。 在审核代码过程中,违反专业礼仪是件很严重的事情,但我们永远没法确保别人不违反专业礼仪。我们可以保证自己不要违反它。如果你很生气或恼火,以致于无法友好地回复,那就离开电脑一会儿,或者先换一件事情做直到心态平静下来,再礼貌地回复。

一般来说,如果评审员没有以建设性的方式提供反馈,反馈就不够礼貌,可以私下与他沟通。如果私下或通过视频电话与他进行远程沟通不方便,可以单独给他发一封电子邮件。在电子邮件中,以友好的方式向他解释,你很难接受这种反馈,并期待他以不同的方式沟通。如果他仍然以一种不具建设性的方式回应你,或未能达到预期的结果,升级为他的主管。

[En]

In general, if the reviewer does not provide feedback in a constructive manner, the feedback is not polite enough and can be communicated with him in private. If it is not convenient to communicate with him in private or remotely through a video phone, you can send him a separate email. In the email, explain to him in a friendly manner that it is difficult for you to accept this kind of feedback and expect him to communicate in a different way. If he still responds to you in an unconstructive way or fails to achieve the desired results, upgrade to his supervisor.

修复代码

如果审查者说他不理解您的代码中的某些内容,您的第一反应是澄清代码本身。如果无法澄清代码,请添加注释以解释为什么以这种方式编写代码。如果此注释在代码中没有意义,则应将其作为反馈解释包含在代码评审的注释中。

[En]

If the reviewer says he doesn’t understand something in your code, your first reaction is to clarify the code itself. If the code cannot be clarified, add a comment to explain why the code is written this way. If this comment is meaningless in the code, it should be included in the comments on the code review as a feedback explanation.

如果审查者不能理解一段代码,其他代码阅读器也很可能不会理解它。在代码审查工具中回复它对未来的代码读者没有好处。在这种情况下,您应该尝试清理代码或添加一些必要的注释以帮助他们阅读。

[En]

If the reviewer cannot understand a piece of code, it is likely that other code readers will not understand it either. Replying to it in the code review tool is not good for future code readers. In this case, you should try to clean up the code or add some necessary comments to help them read.

首先,想想你是否还有改进的空间。

[En]

First think about whether you have room for improvement.

写一个 CL 会耗费大量精力。在提交一个 CL 审核时,开发者会往往会产生几乎快要完成的幻觉,自认为无需进一步修改。当审核者回复需要修改某些代码时,开发者容易条件反射地认为反馈不正确,审核者没必要阻碍自己的开发,他应该让这个 CL 审核通过 。 然而, 无论你有多确定 这点,最好还是先退一步,仔细考虑审核者是否在反馈中提供了有价值的内容,可以帮助提高代码库的质量。你的第一个问题应该永远都是,”审核者说得对吗?”

如果不能回答这个问题,审查员很可能需要进一步澄清评论。

[En]

If this question cannot be answered, it is likely that the reviewer will need to further clarify the comments.

如果你 已经 思考过,并确认你是对的,那就在回复中解释为什么你的方法比较好(相对已有的代码、用户)。通常,审核者也会提供 建议 ,他们希望你比较一下哪个更好。你可能知道一些关于用户、代码库或 CL的内容,而这些正是审核者不了解的,那么就把这些写出来,提供更多的上下文。通常,你在技术上可以与审核者达成一致。

冲突解决

有时候会有紧急的 CL。紧急情况发生时,必须尽快完成审核流程并提交。

哪些是紧急情况?

紧急 CL 应该是一个 修改:一个重要的发布版本需要包含某个功能(无法回滚),修复产品中严重影响用户的缺陷,处理紧迫的法律问题,关闭一个重要的安全漏洞,等等。

处于紧急情况时,我们应该关心整个代码审核流程的速度,而不仅仅是​​响应的速度​​。更准确地说,在这种情况下,审核者应该把审核速度与代码的正确性(代码是否解决了紧急问题?)放在首位。并且,当紧急情况发生时,它的审核优先级必须高于其他所有的代码审核。

哪些不是紧急情况?

需要明确的是,如下情形 不是 紧急情况:

  • 希望本周完成,而不是下周(除非有一些无法避免的​​硬期限​​,如合作伙伴之间的契约)。
  • 开发人员致力于这一功能已经很久了,他们希望尽快提交代码。
    [En]

    developers have been working on this feature for a long time and they hope to submit the code as soon as possible.*

  • 所有审计师不在同一时区,他们在半夜或下班。
    [En]

    all auditors are not in the same time zone and they are in the middle of the night or off duty.*

  • 周五是下班时间,如果开发者能在周末离开公司前提交代码,那就太好了。
    [En]

    it’s time to get off work on Friday, and it would be great if developers could submit code before leaving the company at the weekend.*

  • 经理说这个审核必须完成,CL 在今天必须提交因今天是​​截止日期​​(软期限,而非硬期限)。
  • 回滚一个造成测试失败或编译错误的 CL。等等。

什么是硬期限?

所谓硬期限(hard deadline),就是错过了就会有 灾难性的事情发生。例如:

  • 合同规定,你必须在某个特定日期之前提交 CL。
  • 如果产品不在特定日期前发布,很可能会影响销售,甚至导致产品市场失败
    [En]

    if the product is not released before a specific date, it is likely to affect sales and even lead to failure in the product market.*

  • 一些硬件厂商一年只发布一次产品。如果不在最后期限前将代码提交给他们,并且代码非常重要,很可能会产生灾难性的后果。
    [En]

    some hardware manufacturers release products only once a year. If the code is not submitted to them before the deadline, and the code is very important, it is likely to have disastrous consequences.*

将释放推迟一周并不是灾难性的。错过一次重要的会议可能是灾难性的,也可能不是。

[En]

Delaying the release by a week is not catastrophic. Missing an important meeting may or may not be catastrophic.

大多数截止日期都是软期限(soft deadline),并非是不可改变的。这些软期限期望在某个时间节点得到需要的功能。它们很重要,但不应该为了达到目标而破坏代码的健康状况。

如果发布周期很长(几个月),为了在下一个周期之前实现某个功能,很可能会牺牲代码质量。如果这种模式反复出现,就会给项目造成难以承受的技术债务,这是项目开发中常见的问题。如果开发人员经常在开发周期接近尾声时提交代码,则团队只能进行肤浅的代码审查。在这一点上,团队应该修改开发流程,并且应该在周期的早期进行较大的功能更改,以确保有足够的时间进行代码审查。

[En]

If the release cycle is long (several months), code quality is likely to be sacrificed in order to implement a function before the next cycle. If this pattern occurs repeatedly, it creates an unbearable technical debt for the project, which is a common problem in project development. If developers often submit code near the end of the development cycle, then the team must only do superficial code reviews. At this point, the team should modify the development process, and large functional changes should be made early in the cycle to ensure that there is sufficient time for code review.

Original: https://blog.51cto.com/u_15503184/5575500
Author: 软件质量保障
Title: Google的工程实践指南(下):代码开发者指南

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/508529/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球