[Developing] 重写软件与Netscape6的失败

博客首页 » Developing 重写软件与Netscape6的失败

发布于 22 Nov 2015 14:55
标签 blog
如果Java 失宠于Oracle,那么未来会怎么样? 》中提到全面重写软件与Netscape6的失败。仔细看了一下,值得广播。

其中,全面重写有三个伪需求,需要警醒。

概要

大型商业软件的重写需要慎重,部分渐进性重构或许是更好的选择。

看起来不够简洁甚至不知所云的代码,实际上是长时间的实践中bug fix的沉淀,是代码在各种环境中健壮运行的保障。而轻易地重写成的新代码,反而还是脆弱稚嫩的,还需要再经历时间的历练才能达到旧代码的成熟度。而所有的这些都是需要大量的时间,特别是重写以后的时间。

有三个关于重写的伪需求:

架构上的问题 - 小规模重构

首先是架构上的问题。程序代码并没有被正确地安排。网络连线的程序代码会在莫名奇妙的地方自己显示对话盒;而这应该是由使用介面来处理才对。你可以小心的搬动程序代码,重构并修改介面,一次一个地解决这些问题。你可以找一个程序员小心处理好,再把所有修改一次放回版本管理系统,就不会影响到其他人。即使很重大的架构修改,都不必丟掉程序代码就可完成。我们花了好几个月重整Juno项目的架构:只是把东西搬来搬去,把程序代码清理干凈,建立合理的基础类别,并且在模组间建立明确的介面。不过我们非常小心的处理现有的程序代码库,结果没有产生新问题也不必把还能用的程序丟掉。

效率问题 - 针对问题点优化

程序员认为程序代码一团糟的第二个原因是效率不好。谣传Netscape的成像程序很慢。不过这只牵涉整个项目的一小部份,你可以最佳化甚至重写这一小部份,并不需要把所有程序都重写。在最佳化速度时,抓到1%的工作重点可以得到99%的效果。

旧代码丑 - 用编辑器批量处理

第三个理由是说程序代码他X的丑。某个我做过的案子真的有一个叫FuckedString的数据类型。另一个案子则是在开始时在成员变量名字前加底线'_',后来却改用比较标准的'm_'。结果一半的函数是用'_'开头而另一半是用'm_'开头,看起来很丑。坦白地说,这种问题用Emacs的宏功能五分钟就解决了,不需要从头开始。

译文

你绝对不应该做的事 之一 - Things You Should Never Do, Part One
http://blog.csdn.net/tiewen/article/details/8554765
2000年04月06日

The Joel on Software Translation Project:你绝对不应该做的事
From The Joel on Software Translation Project
你绝对不应该做的事 之一
作者:周思博 (Joel Spolsky)
译:Paul May 梅普华
Thursday, April 06, 2000
属于Joel on Software, http://www.joelonsoftware.com
Netscape 6.0第一个公开的beta版终于出来了。5.0版从来没出现过,最后一版重大改版是大约三年前发行的4.0版。在Internet世界里三年的时间长得可怕。就在这段时间中,Netscape只能无望地坐看市场占有率直线下降。

我这样批评他们在两个版本间等了很久,似乎有点惹人厌。他们并不是故意的这样的吧。真有人会故意这样做吗?

呃,没错,他们是故意的。他们做了一个每家软件公司都可能犯的一个最糟的策略错误:

他们决定把程序从头重写过。

Upper_West_Side_Brownstones_2.jpg

Netscape并不是第一家犯这种错的公司。Borland买下Arago,想把它变成Windows版的dBase时就犯了同样的错。这个注定失败的项目用了很长的时间开发,长到让它被微软的Access彻底打败。Borland后来又重蹈覆辙整个重写Quattro Pro,还想拿重写的新功能来吓人。微软几乎也做了相同的蠢事,想要在一个叫Pyramid的项目里重写Windows版的Word,不过这个案子已经结束,并且消失在尘土之间。微软很幸运,他们从未停止使用原有的程序代码库,所以一直有东西可以推出。因此这个错误只成为财务上的问题,而不是策略上的灾难。

我们都是程序员。而程序员在內心其实是个设计者,他们每到一个地方第一件事,就是先把一切铲平然后创造伟大的事物。我们对修补改进和种种花床的渐进式革新不会感觉兴奋。

程序员总想把旧程序丟掉重新开始,其中的原因很微妙。他们会认为旧的程序是一团乱,不过下面这有趣的观察指出他们可能是错的。他们会认为旧程序一团乱的直正原因是一个很基本的程序设计原理:

读程序比写程序困难。
这就是程序再使用如此困难的原因。这也说明为何团队中每个人都喜欢用不同的函数把字串切成字串数组。他们自己写自己的函数,因为这样比去弄懂旧程序更简单而有趣。

Columbus_Ave_Barber_Shop.jpg

依据这个原则推论,你可以询问任何一个现役程序员正在用的程序代码。几乎每一个人都会告诉你:「这真是一团乱,我真想把它丟掉重新开始。」

为什么会说是一团乱呢?

「嗯,」他们说:「看看这个函数。有两页那么长耶!这些东西都不属于这里的!我真不知道里头一半的API是叫来做啥的。」

在Borland新的Windows版试算表软件推出前,该公司有意思的创办人Philippe Kahnwas在媒体上到处吹噓,说些Quattro Pro是整个重写的,所以比微软Excel好上多少倍等等的鬼话。全新的源代码哦!好像源代码会生锈一样。

新程序代码比旧程序代码好的想法显然是很荒唐的。旧程序代码已经被用过也被测试过。很多问题都已被找出来并被修好。它并没有什么问题,不会因为在你的硬盘里放久了就生出新的问题。你错得离谱了,宝贝!软件应该要像旧宾士一样,光在放在车库里就会生锈吗?软件应该要像泰迪熊那样,不用全新的材料做就不好吗?

回到那个两页长的函数吧。是的,我了解这只是个显示某个视窗的简单函数,不过却多了很多怪东西而且没有人知道为什么。嗯,我会告诉你原因:它们是问题的修正。其中一个是南西在没有Internet Explorer的电脑上安装时写的。另一个是对付内存不足时的问题。还有一个是要应付文件放在软盘上,使用者却中途抽掉软盘的状况。LoadLibrary呼叫很难看,不过却能让程序在旧版Windows 95上也可以执行。

里面每个问题都是在真实世界使用好几个星期之后才发现的。而程序员可能也花了好几天才在实验室重现并予以修正。问题看起来很多,可是解决方法可能只有一行程序,甚至可能只有几个字符,可是光两个字符的背后有著许多的时间和心血。

当你把程序代码丟掉从头重写时,其实是把这所有的知识都丟掉了。这所有已修正的问题,好几年的写程序的成果。

你会让出市场领导地位。你会把两三年的时间当礼物送给竞争者。相信我,软件的一年可是很长的。

你会让自己陷入一个极端危险的位置,到时候会有很多年都只能发行旧版程序,完全无法因应市场需求的新功能而改变策略,因为你没有可以发行的程序。这段时期最好还是把公司收起来算了。

你会浪费大量的资金去撰写已有的程序。

Columbus_Ave.jpg

有代替的方案吗?大家都同意Netscape的旧程序似乎真的非常糟。嗯,或许它真的很糟,不过你知道吗?它还是能在世界上数不清的电脑系统上运作的还不错。

当程序员照他们一貫的作风,说他们的程序是团神圣的垃圾时,其实里头会包含三种错误的理由。

首先是架构上的问题。程序代码并没有被正确地安排。网络连线的程序代码会在莫名奇妙的地方自己显示对话盒;而这应该是由使用介面来处理才对。你可以小心的搬动程序代码,重构并修改介面,一次一个地解决这些问题。你可以找一个程序员小心处理好,再把所有修改一次放回版本管理系统,就不会影响到其他人。即使很重大的架构修改,都不必丟掉程序代码就可完成。我们花了好几个月重整Juno项目的架构:只是把东西搬来搬去,把程序代码清理干凈,建立合理的基础类别,并且在模组间建立明确的介面。不过我们非常小心的处理现有的程序代码库,结果没有产生新问题也不必把还能用的程序丟掉。

程序员认为程序代码一团糟的第二个原因是效率不好。谣传Netscape的成像程序很慢。不过这只牵涉整个项目的一小部份,你可以最佳化甚至重写这一小部份,并不需要把所有程序都重写。在最佳化速度时,抓到1%的工作重点可以得到99%的效果。

第三个理由是说程序代码他X的丑。某个我做过的案子真的有一个叫FuckedString的数据类型。另一个案子则是在开始时在成员变量名字前加底线'_',后来却改用比较标准的'm_'。结果一半的函数是用'_'开头而另一半是用'm_'开头,看起来很丑。坦白地说,这种问题用Emacs的宏功能五分钟就解决了,不需要从头开始。

你一定要记住,在要从头重新开始时,完全没有理由相信这次会做得比第一次好。首先你的程序团队根本不可能和当初相同,所以并不会真的有「更多的经验」。你其实只会把大部份的旧错重新再犯一次,另外再多加一些旧版本没有的新问题。

Lincoln_Center_Trees.jpg

在面对大型商业应用程序时,做了就丟掉是很危险的旧咒语。如果你只是写程序做做实验,想到更好的演算法时大可把上星期写的函数丟掉,这是很正常的。想藉重构让某个类别更容易使用,这也不会有任何问题,不过把整个程序都丟掉是个危险的愚行。如果Netscape真的运用软件业经验成熟地管理,就不会把自己害得这么惨了。

一些回馈意见 ,包括某位很资深的前Netscape工程师的回应。另外Seth Gordon写了一封电邮给我,针对阅读他人的源代码提供一些很好的技巧。

原文

Joel on Software
Things You Should Never Do, Part I
by Joel Spolsky
Thursday, April 06, 2000
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.

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.

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."

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.

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?

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.

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.

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.

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.

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.

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.


本页面的文字允许在知识共享 署名-相同方式共享 3.0协议和GNU自由文档许可证下修改和再使用,仅有一个特殊要求,请用链接方式注明文章引用出处及作者。请协助维护作者合法权益。


系列文章

文章列表

  • Developing 重写软件与Netscape6的失败

这篇文章对你有帮助吗,投个票吧?

rating: 0+x

留下你的评论

Add a New Comment