你修改了代码,但你没有重构代码。
昨天在 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