A Few Valid Reasons to Reject a Bug Fix

The following text is a partial translation of the original English article, performed by ChatGPT (gpt-3.5-turbo) and this Jekyll plugin:

存在bug是指某些事物未按预期工作。bug修复基本上是对现有代码库的补丁(拉取请求),旨在解决问题并确保“某些事物”按预期工作。很多时候,这样的补丁修复了一个问题,却引发了许多其他问题。我认为有时候有必要拒绝一个bug修复,并要求作者重新进行补丁,以保护项目免受更大的问题。根据我的经验,有几个合理的理由可以拒绝这样的修复。

这是一个非常常见的情况:在一个地方进行了更改后,单元测试在其他地方失败。错误修复了,但可能与之无关的一些单元测试开始报告失败。在压力下或者仅仅因为我们懒,我们不修复它们;我们只是移除这些测试或将其标记为临时的“跳过”。问题解决了,构建干净了,所以我们合并补丁然后收工,对吗?错了!

即使我尽可能支持走捷径,但这就是我不建议你走的捷径。

单元测试的目的就是在压力下防止我们破坏产品。

显然,有些情况下,单元测试是错误的,我们必须删除它们。在这种情况下,不要忘记创建新的单元测试。

也有些情况下,必须在几分钟内修复错误以使系统恢复在线状态,而修复所有单元测试需要一个小时。这种情况是产品测试覆盖率存在严重问题的强烈指示。毫无疑问,我们必须进行修复并要求测试在一段时间内保持安静。但在这种情况下,请确保你的团队在错误修复发布后所要处理的下一个任务是修正那些被禁用的单元测试。我建议阅读迈克尔·菲瑟斯(Michael Feathers)的《与遗留代码高效工作》(http://amzn.to/1SdcZ8M),它正是处理这个主题的。

有时候,整个系统可能只因为一行代码中的一个小错误而崩溃。一个明显的错误修复方法是删除错误,但如果我们关心项目的质量,好的项目并不期望我们这样做。问题不在于错误拼写,而是缺乏在部署阶段能够捕捉到错误拼写的单元测试。

真正的问题是代码中这个特定部分缺乏测试代码覆盖率。通过删除错误拼写,我们不会对项目有任何帮助。而且,我们正在做一件对项目有害的事情——我们在掩盖真正的问题。

因此,无论问题有多么小或者是表面的,它的错误修复必须包含一个额外的测试,首先重现这个错误。如果没有这样一个测试,一个错误修复就是对项目资金的浪费。

此外,如果没有一个重现问题的单元测试,我们无法保证我们的错误修复不会引入更多的错误。我甚至可以说,我们的错误修复越多,的程度就越高。而降低这种不确定性的唯一方法就是用单元测试覆盖代码。没有测试,一个错误修复会给代码库带来更多的混乱。

错误修复不是功能;它们必须小而专注。程序员在修复错误时很容易陷入其中,并且在修复过程中引入一些重构。结果是补丁变得相当庞大且难以理解。我并不反对重构;对于项目来说,这是非常重要且积极的事情,但请在错误修复和合并之后单独进行重构。

在修复错误时不要进行重构!

创建一个新的单元测试,重现错误并提交。无论现有代码有多丑陋,都要在现有代码库中修复错误。创建新的错误,要求团队改善这个丑陋的代码库。如果感兴趣,可以将这些错误分配给自己。或者也许其他人对修复它们和重构代码感兴趣。但所有这些都将在其他拉取请求中的新代码审查和合并中进行。

这不是因为懒惰和不愿修复看起来不好的东西。这是一种纪律,比好意更重要。

始终一次只修复一个问题——就是这么简单。没有例外。当一个修复错误的补丁包含修复多个问题的代码更改时,很难理解哪个问题被测试,哪个问题被复现,以及它们之间的关系。将几个错误修复合并到一个拉取请求中是一种非常糟糕的做法。

无论修复有多简单,都要与其他问题分开处理。单独进行审查、测试和合并。这也会增加变更的可追溯性。始终能够很容易地理解谁进行了该修复,谁审查了代码,以及何时合并(和部署)。

Translated by ChatGPT gpt-3.5-turbo/42 on 2023-11-18 at 05:15

sixnines availability badge   GitHub stars