测试与代码质量

为什么遗留代码总是被吐槽(开发者都能共鸣的故事)

我至今仍清楚记得入职新公司的第一天,拿到代码仓库并第一次打开代码的那一刻。

3 分钟阅读
为什么遗留代码总是被吐槽(开发者都能共鸣的故事) 封面图

我至今仍清楚记得入职新公司的第一天,拿到代码仓库并第一次打开代码的那一刻。

一个 3000 行的文件里,混杂着各种逻辑。我不由自主地叹了口气。

“到底是谁写成这样的……”

然而几个月后,新人看着我写的代码,也露出了完全相同的表情。那时我才明白,遗留代码不是某一个人的错。

先说结论。

遗留代码之所以被吐槽,不是因为代码差,而是因为编写时的上下文已经消失了。

今天想分享我的经历:为什么遗留代码总会成为被责怪的对象,以及面对它时如何少受些伤。


什么是遗留代码?和旧代码不同吗

先明确一点:遗留代码不只是“旧代码”。

根据我的经验,标准只有一个:因为没有测试而不敢修改的代码

Michael Feathers 在《修改遗留代码的艺术》中将遗留代码定义为“没有测试的代码”。即使代码只写了一周,只要没有测试、每次修改都让人紧张,它就是遗留代码。

反过来,即使是 10 年前的代码,只要测试完善,也可以放心修改。

所以问题不在于年龄,关键在于你是否确信“改这里不会导致其他地方出问题”。


为什么遗留代码总是被吐槽

整理原因后,大致有三个。

1. 编写代码的人已经不在公司

没有人可以询问当初为什么要这样写。没有注释和文档时,剩下的只有代码和我的想象力。

2. 上下文消失了

奇怪地缠绕在一起的代码,大多都有故事:紧迫的期限、奇怪的需求,或是为了绕过特定 OS 版本的 bug。

当时可能是最佳方案,但那些背景不会留在代码里。留下的只有结果,所以现在看起来难以理解。

3. 别人的代码本来就显得奇怪

说实话,这是最大的原因。自己的代码,流程都在脑中;别人的代码,则必须从头跟一遍流程。

这种郁闷最后就会变成一句“为什么要这样写”。

来看看下面的代码。乍看之下,不知道为什么有这个条件,是典型的遗留代码痕迹。

// 没人知道为什么要减去 30
if user.type == "B" && amount > 0 {
    finalPrice = amount - 30 // 2019年份促销活动的遗留代码?
}

无法判断这个- 30现在是否仍然需要,还是旧活动留下的痕迹。这样的代码一行行累积起来,就成了遗留代码。


那么,该如何对待遗留代码

面对陌生的遗留代码,很容易产生“全部重写吧”的想法,但其实有更好的办法。

我现在遵守三个原则。

  1. 不要随便重写 — 能运行的代码中,包含了长期积累的各种 bug 修复。重新编写,就得从头再经历一遍。
  2. 修改前先补测试 — 用测试固定当前行为,修改后哪里坏了就能马上发现。
  3. 留下修改原因的记录 — 把理由写在提交信息或注释里,至少能让下一个人少怨你一些。

尤其是第三点很重要。这是唯一能避免把我现在的郁闷传给未来某个人的方法。


归根结底,今天的新代码也是明天的遗留代码

我用了 6 个月才明白一件有些无奈的事:现在精心编写的代码,几年后也会成为被某人吐槽的遗留代码。

接受这一点后,我轻松了许多。不再执着于完美,而是转向让下一个人少吃点苦

如果你现在正对着陌生的遗留代码叹气,请偶尔想想,编写它的人当时也已经尽了最大努力。然后安静地先补上测试吧。这似乎是让彼此少受伤的办法。