发布于 2026-01-06 0 阅读
0

你修改了代码,但你没有重构代码。

你修改了代码,但你没有重构代码。

昨天在 Twitter 上就Laravel 框架的代码贡献展开了一场精彩的讨论。讨论最后提出了一些关于“重构”和“修改”代码之间区别的好问题。

虽然我想重点讨论这些区别,但我们先来关注一下代码更改。

以下是原始代码:

    public static function before($subject, $search)
    {
        if ($search == '') {
            return $subject;
        }

        $pos = strpos($subject, $search);

        if ($pos === false) {
            return $subject;
        }

        return substr($subject, 0, $pos);
    }

以及“重构后”的代码:

    public static function before($subject, $search)
    {
        return empty($search) ? $subject : explode($search, $subject)[0];
    }

简洁明了的一行代码。所有测试均已通过,代码已合并。

眼光敏锐的开发者可能已经注意到这个问题,但大多数人注意到我引用了重构

这是因为这段代码没有被重构,而是被修改了。让我们回顾一下“重构”的定义。

在不改变软件可观察行为的情况下重构软件

在这种情况下,由于新代码的行为与原始代码不同,因此可观察到的行为也发生了变化。

它的表现有何不同?

这需要敏锐的测试眼光,但一个简单的例子是当$search`is`时0。原始代码会在 `is` 范围内搜索并返回匹配项之前的$subject字符串。而新代码会提前返回匹配项。行为并不相同。0$subject

遗憾的是,现有的测试并没有发现这个问题。因此,贡献者需要自行发现这一行为变化——他们后来发现了,并提交了一个包含缺失测试的补丁。这样做之后,这才算真正完成了一次重构,也算是一项不错的贡献!

然而,这引出了另一个有趣的问题——既然所有现有的测试都通过了,那么最初的贡献是否算得上是一次成功的重构呢?

鉴于重构和测试之间的共生关系,有些人甚至将测试视为需求本身。因此,如果所有测试都通过,就说明满足了需求。

我认为这是一个危险的先例。对我来说,“重构”的定义本身就通过一个问题给出了答案——我们是否改变了可观察到的行为?

在这种情况下,是的——我们可以观察到行为发生了变化。因此,尽管测试通过,但最初的贡献并非真正的重构。

不过,我认为关于重构和测试还有一些其他有趣的观点,我会在以后的文章中探讨。现在,请记住,你是在真正地“重构”代码,而不是“修改”代码。

文章来源:https://dev.to/gonedark/you-changed-the-code-you-didnt-refactor-the-code