Things You Should Never Do, Part I
你永远不应该做的事情,第一部分

Netscape 6.0 is finally going into its first public beta. There never was a version 5.0. The last major release, version 4.0, was released almost three years ago. Three years is an awfully long time in the Internet world. During this time, Netscape sat by, helplessly, as their market share plummeted.
Netscape 6.0 终于要进入首个公开测试版了。从未有过 5.0 版。上一个主要版本,4.0 版,是在将近三年前发布的。在互联网世界里,三年真是漫长至极。在此期间,Netscape 只能无助地坐看自己的市场份额急剧下滑。

It’s a bit smarmy of me to criticize them for waiting so long between releases. They didn’t do it on purpose, now, did they?
我这样批评他们发布版本间隔太长,确实有点自以为是。他们并非故意这么做,对吧?

Well, yes. They did. They did it by making the single worst strategic mistake that any software company can make:
嗯,是的。他们确实故意这么做了。他们犯了软件公司可能犯的最糟糕的战略错误:

They decided to rewrite the code from scratch.
他们决定从头开始重写代码。

Netscape wasn’t the first company to make this mistake. Borland made the same mistake when they bought Arago and tried to make it into dBase for Windows, a doomed project that took so long that Microsoft Access ate their lunch, then they made it again in rewriting Quattro Pro from scratch and astonishing people with how few features it had. Microsoft almost made the same mistake, trying to rewrite Word for Windows from scratch in a doomed project called Pyramid which was shut down, thrown away, and swept under the rug. Lucky for Microsoft, they had never stopped working on the old code base, so they had something to ship, making it merely a financial disaster, not a strategic one.
Netscape 并不是第一个犯这种错误的公司。Borland 在收购 Arago 并试图将其转变为 Windows 版的 dBase 时犯了同样的错误,这是一个注定失败的项目,耗时太长,以至于被 Microsoft Access 抢去了市场。后来他们又一次从头开始重写 Quattro Pro,结果令人惊讶的是功能竟然如此之少。Microsoft 差点也犯同样的错误,试图从头开始重写 Windows 版的 Word,这是一个名为 Pyramid 的注定失败的项目,最终被终止、丢弃并被掩盖。幸运的是,Microsoft 从未停止过旧代码库的开发,因此他们还有产品可以发布,这只是一场财务灾难,而非战略灾难。

We’re programmers. Programmers are, in their hearts, architects, and the first thing they want to do when they get to a site is to bulldoze the place flat and build something grand. We’re not excited by incremental renovation: tinkering, improving, planting flower beds.
我们是程序员。程序员在心中都是建筑师,他们到达一个新地点首先想做的就是将现场夷为平地,然后建造一些宏伟的东西。我们对渐进式的翻新不感兴趣:调整、改进、种植花坛。

There’s a subtle reason that programmers always want to throw away the code and start over. The reason is that they think the old code is a mess. And here is the interesting observation: they are probably wrong. The reason that they think the old code is a mess is because of a cardinal, fundamental law of programming:
程序员总想丢弃旧代码并重新开始的一个微妙原因是,他们认为旧代码一团糟。有趣的观察是:他们可能是错的。他们认为旧代码一团糟的原因是因为编程的一个基本重要法则:

It’s harder to read code than to write it.
阅读代码比编写代码更难。

This is why code reuse is so hard. This is why everybody on your team has a different function they like to use for splitting strings into arrays of strings. They write their own function because it’s easier and more fun than figuring out how the old function works.
这就是为什么代码重用如此困难。这就是为什么你团队中的每个人都有他们喜欢用来将字符串分割成字符串数组的不同函数。他们编写自己的函数,因为这比弄清楚旧函数的工作原理更简单、更有趣。

As a corollary of this axiom, you can ask almost any programmer today about the code they are working on. “It’s a big hairy mess,” they will tell you. “I’d like nothing better than to throw it out and start over.”
作为这一公理的一个推论,你几乎可以问今天任何一个正在编写代码的程序员。他们会告诉你:“这是一团糟。”他们最希望的就是把它扔掉重新开始。

Why is it a mess?
为什么会一团糟?

“Well,” they say, “look at this function. It is two pages long! None of this stuff belongs in there! I don’t know what half of these API calls are for.”
“嗯,”他们说,“看看这个函数。它有两页那么长!这里面的东西都不该在这里!我都不知道这些 API 调用是做什么的。”

Before Borland’s new spreadsheet for Windows shipped, Philippe Kahn, the colorful founder of Borland, was quoted a lot in the press bragging about how Quattro Pro would be much better than Microsoft Excel, because it was written from scratch. All new source code! As if source code rusted.
在 Borland 的新 Windows 电子表格发布之前,Borland 的多彩创始人 Philippe Kahn 在媒体上频繁吹嘘 Quattro Pro 会比 Microsoft Excel 好得多,因为它是从头开始编写的。全新的源代码!好像源代码会生锈似的。

The idea that new code is better than old is patently absurd. Old code has been used. It has been tested. Lots of bugs have been found, and they’ve been fixed. There’s nothing wrong with it. It doesn’t acquire bugs just by sitting around on your hard drive. Au contraire, baby! Is software supposed to be like an old Dodge Dart, that rusts just sitting in the garage? Is software like a teddy bear that’s kind of gross if it’s not made out of all new material?
认为新代码比旧代码好是完全荒谬的。旧代码已经被使用过。它已经过测试。发现了很多错误,并且已经修复了。它没有问题。它不会仅仅因为存放在你的硬盘上就获得错误。恰恰相反,宝贝!软件难道应该像旧款 Dodge Dart 一样,即使只是停在车库里也会生锈吗?软件难道像泰迪熊,如果不是用全新的材料制成就有点恶心吗?

Back to that two page function. Yes, I know, it’s just a simple function to display a window, but it has grown little hairs and stuff on it and nobody knows why. Well, I’ll tell you why: those are bug fixes. One of them fixes that bug that Nancy had when she tried to install the thing on a computer that didn’t have Internet Explorer. Another one fixes that bug that occurs in low memory conditions. Another one fixes that bug that occurred when the file is on a floppy disk and the user yanks out the disk in the middle. That LoadLibrary call is ugly but it makes the code work on old versions of Windows 95.
回到那个两页长的函数。是的,我知道,它只是一个简单的显示窗口的函数,但它已经长出了小毛发和其他东西,没人知道为什么。好吧,我来告诉你为什么:那些都是错误修复。其中一个修复了 Nancy 在没有安装 Internet Explorer 的计算机上尝试安装该程序时遇到的错误。另一个修复了在内存不足的情况下发生的错误。还有一个修复了当文件位于软盘上并且用户在中途拔出软盘时发生的错误。那个 LoadLibrary 调用很丑,但它使代码能在旧版本的 Windows 95 上工作。

Each of these bugs took weeks of real-world usage before they were found. The programmer might have spent a couple of days reproducing the bug in the lab and fixing it. If it’s like a lot of bugs, the fix might be one line of code, or it might even be a couple of characters, but a lot of work and time went into those two characters.
每个错误的发现都需要几周的实际使用时间。程序员可能需要花费几天时间在实验室复现并修复错误。如果像很多错误一样,修复可能只需要一行代码,或者甚至是几个字符,但这两个字符背后却投入了大量的工作和时间。

When you throw away code and start from scratch, you are throwing away all that knowledge. All those collected bug fixes. Years of programming work.
当你丢弃代码并从头开始时,你正在丢弃所有那些知识。所有那些积累的错误修复。多年的编程工作。

You are throwing away your market leadership. You are giving a gift of two or three years to your competitors, and believe me, that is a long time in software years.
你正在放弃你的市场领导地位。你实际上是在送给竞争对手两到三年的时间,相信我,这在软件行业里是很长的一段时间。

You are putting yourself in an extremely dangerous position where you will be shipping an old version of the code for several years, completely unable to make any strategic changes or react to new features that the market demands, because you don’t have shippable code. You might as well just close for business for the duration.
你正在把自己置于一个极其危险的位置,几年来你只能发布旧版本的代码,完全无法进行任何战略性调整或对市场需求的新功能做出反应,因为你没有可发布的代码。你还不如在这段时间内干脆停业。

You are wasting an outlandish amount of money writing code that already exists.
你在浪费大量的金钱编写已经存在的代码。

Is there an alternative? The consensus seems to be that the old Netscape code base was really bad. Well, it might have been bad, but, you know what? It worked pretty darn well on an awful lot of real world computer systems.
有没有替代方案?普遍的看法似乎是旧的 Netscape 代码库非常糟糕。嗯,它可能很糟,但你知道吗?它在很多真实的计算机系统上运行得相当不错。

When programmers say that their code is a holy mess (as they always do), there are three kinds of things that are wrong with it.
当程序员说他们的代码是一团糟(他们总是这么说)时,通常有三种问题。

First, there are architectural problems. The code is not factored correctly. The networking code is popping up its own dialog boxes from the middle of nowhere; this should have been handled in the UI code. These problems can be solved, one at a time, by carefully moving code, refactoring, changing interfaces. They can be done by one programmer working carefully and checking in his changes all at once, so that nobody else is disrupted. Even fairly major architectural changes can be done without throwing away the code. On the Juno project we spent several months rearchitecting at one point: just moving things around, cleaning them up, creating base classes that made sense, and creating sharp interfaces between the modules. But we did it carefully, with our existing code base, and we didn’t introduce new bugs or throw away working code.
首先,存在架构问题。代码的分解不正确。网络代码在无处不在的地方弹出自己的对话框;这本应在 UI 代码中处理。这些问题可以一个接一个地解决,通过仔细地移动代码、重构、更改接口来实现。它们可以由一个程序员仔细工作并一次性检入他的更改来完成,这样就不会干扰其他人。即使是相当重大的架构更改也可以在不丢弃代码的情况下完成。在 Juno 项目中,我们曾经花了几个月的时间进行重新架构:只是移动东西,清理它们,创建有意义的基类,并在模块之间创建清晰的接口。但我们是小心翼翼地用我们现有的代码库做的,并且我们没有引入新的错误或丢弃有效的代码。

A second reason programmers think that their code is a mess is that it is inefficient. The rendering code in Netscape was rumored to be slow. But this only affects a small part of the project, which you can optimize or even rewrite. You don’t have to rewrite the whole thing. When optimizing for speed, 1% of the work gets you 99% of the bang.
程序员认为他们的代码是一团糟的第二个原因是它效率低下。Netscape 中的渲染代码据说很慢。但这只影响项目的一小部分,你可以优化甚至重写。你不必重写整个东西。在优化速度时,1%的工作可以带来 99%的效果。

Third, the code may be doggone ugly. One project I worked on actually had a data type called a FuckedString. Another project had started out using the convention of starting member variables with an underscore, but later switched to the more standard “m_”. So half the functions started with “_” and half with “m_”, which looked ugly. Frankly, this is the kind of thing you solve in five minutes with a macro in Emacs, not by starting from scratch.
第三,代码可能非常难看。我参与的一个项目实际上有一个叫做 FuckedString 的数据类型。另一个项目最初使用在成员变量前加下划线的约定,但后来改用更标准的“m_”。所以一半的函数以“_”开始,一半以“m_”开始,看起来很难看。坦白说,这种事情用 Emacs 中的宏五分钟就能解决,不需要从头开始。

It’s important to remember that when you start from scratch there is absolutely no reason to believe that you are going to do a better job than you did the first time. First of all, you probably don’t even have the same programming team that worked on version one, so you don’t actually have “more experience”. You’re just going to make most of the old mistakes again, and introduce some new problems that weren’t in the original version.
重要的是要记住,当你从头开始时,没有任何理由相信你能做得比第一次更好。首先,你可能连第一版的编程团队都没有了,所以你实际上并没有“更多经验”。你只是会重复大部分旧的错误,并引入一些原始版本中没有的新问题。

The old mantra build one to throw away is dangerous when applied to large scale commercial applications. If you are writing code experimentally, you may want to rip up the function you wrote last week when you think of a better algorithm. That’s fine. You may want to refactor a class to make it easier to use. That’s fine, too. But throwing away the whole program is a dangerous folly, and if Netscape actually had some adult supervision with software industry experience, they might not have shot themselves in the foot so badly.
旧的口头禅“建一个丢一个”在应用于大规模商业应用时是危险的。如果你在实验性地编写代码,你可能想在想到更好的算法时撕掉上周写的函数。这很好。你可能想重构一个类以使其更易于使用。这也很好。但是丢弃整个程序是危险的愚蠢行为,如果 Netscape 真的有一些具有软件行业经验的成年人监督,他们可能就不会这么糟糕地搬起石头砸自己的脚了。

About the author. 关于作者。

In 2000 I co-founded Fog Creek Software, where we created lots of cool things like the FogBugz bug tracker, Trello, and Glitch. I also worked with Jeff Atwood to create Stack Overflow and served as CEO of Stack Overflow from 2010-2019. Today I serve as the chairman of the board for Stack Overflow, Glitch, and HASH.
2000 年,我共同创立了 Fog Creek Software,在那里我们创造了许多酷炫的东西,如 FogBugz 错误跟踪器、Trello 和 Glitch。我还与 Jeff Atwood 合作创建了 Stack Overflow,并从 2010 年到 2019 年担任 Stack Overflow 的首席执行官。今天,我担任 Stack Overflow、Glitch 和 HASH 的董事会主席。