代码的兔子理论

encn 9年前

英文原文:The bunny theory of code

曾经和我一起共事的人都知道,我把源代码库的签入工作摆在非常高的位置。这样做的理由很简单:一旦代码被签入了,代码就有了它自己的生命。签入代码类似于你和其他人分享代码,一旦分享出去,就难以预测这些代码会发挥什么作用。很难,但不是不可能,因为有一种现象实际上是我保证要出现的。

多年来,我和朋友、客户分享过我所谓的、代码的兔子理论。这个理论是指,当你没有留意时,代码会繁殖,同样,当你没有留意时,兔子也会繁殖,二者没有什么不同。这不是说繁殖代码是好的,还是坏的——不管质量如何,这是所有代码的特点。使其优劣的是那些被繁殖的代码。

支撑代码的兔子理论的原因在于软件工程师的工作方式。我们很少,倘若有的话,从一个完全空白的文件开始写代码。我们通常从拷贝一个现有文件开始,随后修改以得到我们想要的结果。重申,这和好与坏无关,它仅仅是创建类似于其它代码的某种代码的、最有效方式。

那么,你从哪里去寻找能拷贝的已有代码呢?在同一个源代码库里。你的源代码库虚假的承诺是,它包含的每处代码都是“好的”。为了完成你的任务,就找到类似的代码、拷贝、修改,然后搞定。深入同一个代码库,貌似是代码质量的一种安全机制,但是实际上,这是无法保证的。

当你签入一个文件时,另一个相似文件的出现是不需要太长时间的。一旦出现了同样代码的两个例子,那么第三个文件出现的机会就增加了。一旦第三个出现了,代码就在你的代码库建立了基础,并被视作一种认可模式。毕竟,如果我们在很多地方都在用这种方法做着同样的事情,那么它一定是做这种事情的正确方法……对吧?

追溯到 2005 年,我找到一些代码,它们貌似符合我的任务。随着我高亮这部分代码以拷贝到我自己的文件,我注意到,我已经跳过了它前面的长注释。然而我不记得注释原话了,大意是说:

不要拷贝这段代码!我没搞清楚完成这个功能的其它方式,我们只是在一个地方这样做了,因此看起来是没事的。如果你觉得你需要在其它地方也这样做,那么你应该找到正确的方法。你绝对不要将这段代码拷贝到其它地方。

我笑了笑……然后开始痛心。你是说,我不得不搞清楚该怎样用其它方法来做同样的事情?这是不公平的。前任工程师知道他们没有妥善地解决这个问题,而将其作为地雷留给了其他人。当我踩到它上面时,它就这么发生了,现在我不能挪动我的脚,直到它被安全地拆除。

这就是把糟糕的代码签入代码控制系统所带来的问题:它增加了人们找到它并拷贝它的可能性。一旦它被拷贝了一次,也就增加了被再次拷贝的可能性,如此反复。在你明白之前,糟糕的代码已经渗透到了代码库的所有部分,难以摘除。

随着向同样代码库提交代码的人数增长,这个问题也在增长。当你有一个规模较大的团队时,对代码控制里该结束的代码的管理就显得尤为重要了,因为它很快就要繁殖了。同样,你想确保被签入的代码有着尽可能高的质量,也体现了你想让其他人要做到的标准。

为了保持代码库的理智,你首先要关注的是怎样阻止第一段糟糕代码进入代码控制。通过自动化的执行或拒绝对于这个结果是重要的。你越是能够自动化并在物理上阻止代码进入代码库,每个人就越是安全。当然,有一些模式是难以阻止的,尤其是它们之前从来没有遇见过。这就是代码审查的原因。和人们的眼睛比起来,没有什么奇怪的、更好的检测器了。

当然,某些模式不一定是“糟糕的”,你只是不想让其他人那样做。考虑一下第三方资源库的情况,比如 jQuery。假如你不想让团队成员使用 jQuery,因为你已经建立了 jQuery 所能完成的同样任务的模式。这时候,有人认为,使用 jQuery 会更好,因此加了进来。问题来了:如果 jQuery 加入了代码库,一定有其他人也要使用它。这样,你将做一些不在计划内的工作,这差不多是一件糟糕的事情,尤其在大型团队里。引入一种新资源库,意味着需要学习它的怪癖、bug、最佳实践等所有方面,并且总是没有时间去学习。

根据我在 Box 目前的角色,我因为挂在嘴边的一句话而知名,“没有意外的标准。”我们不接受“本该是那个样子”的一些东西,仅仅因为它们在很多地方流行。当我们看到出现这种情况时,我们就加以制止、讨论,或者把它定做“规则”或摒弃它。在错误情况扩大之前,我们就适当地更新代码。通过自动化、代码审查和代码研讨会【注 1】,我们可以密切注视代码,以确保我们保持一致。

用这种方式管理代码库貌似需要大量工作,但是,如果不这样做,实际上需要更多的工作。让代码在人工干预下增长,是对付大麻烦的良方。工程师尽量做正确的事情,他们是通过拷贝代码控制里的已有代码完成的。这样做是完全自然和符合期望的。这就是你为什么想确保被拷贝的代码代表了你想让他们去做的以及你准备好了有更多的代码拷贝出现的原因。

就像兔子,如果你准备繁殖了,就没有大问题。如果没有人注意到麻烦出现的苗头,繁殖却发生了,这就是问题产生的时候。