说明:
本文的作者Eric Raymond是Open Source Software领域的领袖,这方面许多
新的思想正是从他那儿产生的,同时他也是UNIX上最流行的Email软件Fetchmail
的作者。
下面这篇文章有点儿长,然而它是值得你去耐心把它读完的。文章以Fetchmail
为例,讨论了Internet上集市风格的开发方式。
我们应该感谢HansB,是他把这篇长文章翻译成了中文。
Eric的主页地址在: [url]http://www.tuxedo.org/~esr/[/url]
-------------------------------------------------------------------------
一. 大教堂和市集
Linux的影响是非常巨大的。甚至在5年以前,有谁能够想象一个世界级的操
作系统能够仅仅用细细的Internet连接起来的散布在全球的几千个开发人员有以业
余时间来创造呢?
我当然不会这么想。在1993年早期我开始注意Linux时,我已经参与Unix
和自由软件开发达十年之久了。我是八十年代中期GNU最早的几个参与者之一。我
已经在网上发布了大量的自由软件,开发和协助开发了几个至今仍在广泛使用的
程序(Nethack,Emacs VC和GND模式,xlife等等)。我想我知道该怎样做。
Linux推翻了许多我认为自己明白的事情。我已经宣扬小工具、快速原型和演
进式开发的Unix福音多年了。但是我也相信某些重要的复杂的事情需要更集中化的,
严密的方法。我相信多数重要的软件(操作系统和象Emacs一样的真正大型的工具)
需要向建造大教堂一样来开发,需要一群于世隔绝的奇才的细心工作,在成功之前
没有beta版的发布。
Linus Torvalds的开发风格(尽早尽多的发布,委托所有可以委托的事,对所
有的改动和融合开放)令人惊奇的降临了。这里没有安静的、虔诚的大教堂的建造
工作——相反,Linux团体看起来像一个巨大的有各种不同议程和方法的乱哄哄的
集市(Linux归档站点接受任何人的建议和作品,并聪明的加以管理),一个一致
而稳定的系统就象奇迹一般从这个集市中产生了。
这种设计风格确实能工作,并且工作得很好,这个事实确实是一个冲击。在我
的研究过程中,我不仅在单个工程中努力工作,而且试图理解为什么Linux世界不
仅没有在一片混乱中分崩离析,反而以大教堂建造者们不可想象的速度变得越来越
强大。
到了1996年中,我想我开始理解了。我有一个极好的测试我的理论的机会,
以一个自由软件计划的形式,我有意识的是用了市集风格。我这样做了,并取得了
很大的成功。
在本文的余下部分,我将讲述这个计划的故事,我用它来明确一些自由软件高
效开发的格言。并不是所有这些都是从Linux世界中学到的,但我们将看到Linux世
界给予了它们一个什么样的位置。如果我是正确的,它们将使你理解是什么使Linux
团体成为好软件的源泉,帮助你变得更加高效。
二. 邮件必须得通过
1993年以前我在一个小的免费访问的名为Chester County InterLink的ISP
的做技术工作,它位于Pennsylvania的West Chester。(我协助建立了CCIL,并写了
我们独特的多用户BBS系统——你可以telnet到locke.ccil.org来检测一下。今天它
在十九条线上支持三千的用户)。这个工作使我可以一天二十四小时通过CCIL的56K
专线连在网上,实际上,它要求我这么做!
所以,我对Internet email很熟悉。因为复杂的原因,很难在我家里的机器
(snark.thyrsus.com)和CCIL之间用SLIP工作。最后我终于成功了,但我发现不
得不时常telnet到locke来检查我的邮件,这真是太烦了。我所需要的是我的邮件
发送到snark,这样biff(1)会在它到达时通知我。
简单地sendmail的转送功能是不够的,因为snark并不是总在网上而且没有一
个静态地址。我需要一个程序通过我的SLIP连接把我的本地发送的邮件拉过来。
我知道这种东西是存在的,它们大多使用一个简单的协议POP(Post Office
Protocol)。而且,locke的BSD/OS操作系统已经自带了一个POP3服务器。
我需要一个POP3客户。所以我到网上去找到了一个。实际上,我发现了三、
四个。我用了一会pop-perl,但它却少一个明显的特征:抽取收到的邮件的地址
以便正确回复。
问题是这样的:假设locke上一个叫“joe”的人向我发了一封邮件。如果我
把它取到snark上准备回复时,我的邮件程序会很高兴地把它发送给一个不存在的
snark上的“joe”。手工的在地址上加上“@ccil.org”变成了一个严酷的痛苦。
这显然应是计算机替我做的事。(实际上,依据RFC1123的5.2.18节,
sendmail应该做这件事)。但是没有一个现存的POP客户知道怎样做!于是这就给
我们上了第一课:
1.每个好的软件工作都开始于搔到了开发者本人的痒处。
也许这应该是显而易见的(“需要是发明之母”长久以来就被证明是正确的),
但是软件开发人员常常把他们的精力放在它们既不需要也不喜欢的程序,但在
Linux世界中却不是这样——这解释了为什么从Linux团体中产生的软件质量都如
此之高。
那么,我是否立即投入疯狂的工作中,要编出一个新的POP3客户与现存的那
些竞争呢?才不是哪!我仔细考察了手头上的POP工具,问自己“那一个最接近我
的需要?”因为:
2.好程序员知道该写什么,伟大的程序员知道该重写(和重用)什么。
我并没有声称自己是一个伟大的程序员,可是我试着效仿他们。伟大程序员
的一个重要特点是建设性的懒惰。他们知道你是因为成绩而不是努力得到奖赏,
而且从一个好的实际的解决方案开始总是要比从头干起容易。
例如,Linux并不是从头开始写Linux的。相反的它从重用Minix(一个386机
型上的类似Unix的微型操作系统)的代码和思想入手。最后所有的Minix代码都消
失或被彻底的重写了,但是当它们在的时候它为最终成为Linux的雏形做了铺垫。
秉承同样的精神,我去寻找良好编码的现成的POP工具,用来作为基础。
Unix世界中的代码共享传统一直对代码重用很友好(这正是为什么GNU计划不
管Unix本身有多么保守而选取它作为基础操作系统的原因)。Linux世界把这个传
统推向技术极限:它有几个T字节的源代码可以用。所以在Linux世界中花时间寻
找其他几乎足够好的东西,会比在别处带来更好的结果。
这也适合我。加上我先前发现的,第二次寻找找到了9个候选者——fetchPOP
,PopTart,get-mail,gwpop,pimp,pop-perl,popc,popmail 和 upop)。我
首先选定的是“fetchpop”。我加入了头标重写功能,并且做了一些被作者加入
他的1.9版中的改进。
但是几个星期之后,我偶然发现了Carl Harris写的“popclient”的代码,
然后发现有个问题,虽然fetchpop有一些好的原始思想(比如它的守护进程模式),
它只能处理pop3,而且编码的水平相当业余(Seung-Hong是个很聪明但是经验不足
的程序员),Carl的代码更好一些,相当专业和稳固,但他的程序缺少几个重要的
相当容易实现的fetchpop的特征(包括我自己写的那些)。
继续呢还是换一个? 如果换一个的话,作为得到一个更好开发基础的代价,
我就要扔掉我已经有的那些代码。
换一个的一个实际的动机是支持多协议,pop3是用的最广的邮局协议,但并
非唯一一个,Fetchpop和其余几个没有实现POP2.RPOP,或者APOP,而且我还有一
个为了兴趣加入IMAP(Internet Message Access Protocol,最近设计的最强大的
邮局协议)的模糊想法。
但是我有一个更加理论化的原因认为换一下会是一个好主意,这是我在Linux
很久以前学到的:
3.“计划好抛弃,无论如何,你会的”(Fred Brooks,《神秘的人月》第11章)
或者换句话说,你常常在第一次实现一个解决方案之后才能理解问题所在,
第二次你也许才足够清楚怎样做好它,因此如果你想做好,准备好推翻重来至少
一次。
好吧(我告诉自己),对fetchpop的尝试是我第一次的尝试,因此我换了一下。
当我在1996年6月25日把我第一套popclient的补丁程序寄给Carl Harris之
后,我发现一段时间以前他已经对popclient基本上失去了兴趣,这些代码有些陈
旧,有一些次要的错误,我有许多修改要做,我们很快达成一致,我来接手这个
程序。不知不觉的,这个计划扩大了,再也不是我原先打算的在已有的pop客户上
加几个次要的补丁而已了,我得维护整个的工程,而且我脑袋里涌动着一些念头
要引起一个大的变化。
在一个鼓励代码共享的软件文化里,这是一个工程进化的自然道路,我要指
出:
4. 如果你有正确的态度,有趣的问题会找上你的,但是Carl Harris的态度甚
至更加重要,他理解:
5.当你对一个程序失去兴趣时,你最后的责任就是把它传给一个能干的后继者。
甚至没有商量,Carl和我知道我们有一个共同目标就是找到最好的解决方
案,对我们来说唯一的问题是我能否证明我有一双坚强的手,他优雅而快速的写
出了程序,我希望轮到我时我也能做到。
三. 拥有用户的重要性
于是我继承了popclient,同样重要的是,我继承了popclient的用户基础,
用户是你所拥有的极好的东西,不仅仅是因为他们显示了你正在满足需要,你做
了正确的事情,如果加以适当的培养,他们可以成为合作开发者。
Unix传统另一有力之处是许多用户都是***,因为源优码是公开的,他们可
以成为高效的***,这一点在Linux世界中也被推向了令人高兴的极致,这对缩短
调试时间是极端重要的,在一点鼓励之下,你的用户会诊断问题,提出修订建
议,帮你以远比你期望快得多的速度的改进代码。
6. 把用户当做协作开发者是快速改进代码和高效调试的无可争辩的方式。
这种效果的力量很容易被低估,实际上,几乎所有我们自由软件世界中的人
都强烈低估了用户可以多么有效地对付系统复杂性,直到Linus让我们看到了这一
点。
实际上,我认为Linus最聪明最了不起的工作不是创建了Linux内核本身,而
是发明了Linux开发模式,当我有一次当着他的面表达这种观点时,他微笑了一
下,重复了一句他经常说的话:“我基本上是一个懒惰的人,依靠他人的工作来
获取成绩。”象狐狸一样懒惰,或者如Robert Heinlein所说,太懒了而不会失
败。
回顾起来,在GNU Emacs Lisp库和Lisp代码集中可以看到Linux方法的成功,
与Emacs的C内核和许多其他FSF的工具相比,Lisp代码库的演化是流动性的和用户
驱动的,思想和原型在达到最终的稳定形式之前往往要重写三或四次,而且经常
利用Internet的松散合作。
实际上,我自己在fetchmail之前最成功的作品要算Emacs VC模式,它是三个
其他的人通过电子邮件进行的类似Linux的合作,至今我只见过其中一个人
(Richard Stallman),它是SCCS、RCS和后来的CVS的前端,为Emacs提供“one-
touch”版本控制操作,它是从一个微型的、粗糙的别人写好的sccs.el模式开始
演化的,VC开发的成功不像Emacs本身,而是因为Emacs Lisp代码可以很快的通过
发布/测试/改进的过程。
(FSF的试图把代码放入GPL之下的策略有一个未曾预料到的副作用,它让FSF
难以采取市集模式,因为他们认为每个想贡献二十行以上代码的人都必须得到一
个授权,以使受到GPL的代码免受版权法的侵扰,具有BSD和MITX协会的授权的用
户不会有这个问题,因为他们并不试图保留那些会使人可能受到质询的权力)。
四. 早发布、常发布
尽量早尽量频繁的发布是Linux开发模式的一个重要部分,多数开发人员(包
括我)过去都相信这对大型工程来说是个不好的策略,因为早期版本都是些充满错
误的版本,而你不想耗光用户的耐心。
这种信仰强化了建造大教堂开发方式的必要性,如果目标是让用户尽可能少
的见到错误,那你怎能不会仅仅每六个月发布一次(或更不经常),而且在发布之
间象一只狗一样辛勤“捉虫”呢? Emacs C内核就是以这种方式开发的,Lisp库,
实际上却相反,因为有一些有FSF控制之外的Lisp库,在那里你可以独立于Emacs
发布周期地找寻新的和开发代码版本。
这其中最重要的是Ohio州的elisp库,预示了今天的巨大的Linux库的许多特
征的精神,但是我们很少真正仔细考虑我们在做什么,或者这个库的存在指出了
FSF建造教堂式开发模式的什么问题,1992年我曾经做了一次严肃的尝试,想把
Ohio的大量代码正式合并到Emacs的官方Lisp库中,结果我陷入了政治斗争中,彻
底失败了。
但是一年之后,在Linux广泛应用之后,很清楚,一些不同的更加健康的东西
诞生了,Linus的开发模式正好与建造教堂方式相反,Sunsite和tsx-11的库开始
成长,推动了许多发布。所有这些都是闻所未闻的频繁的内核系统的发布所推动
的。
Linus以所有实际可能的方式把它的用户作为协作开发人员。
7. 早发布、常发布、听取客户的建议
Linus的创新并不是这个(这在Unix世界中是一个长期传统),而是把它扩展到
和他所开发的东西的复杂程度相匹配的地步,在早期一天一次发布对他来说都不
是罕见的!而且因为他培育了他的协作开发者基础,比其他任何人更努力地充分利
用了Internet进行合作,所以这确实能行。
但是它是怎样进行的呢?它是我能模仿的吗?还是这依赖于Linus的独特天才?
我不这样想,我承认Linus是一个极好的***(我们有多少人能够做出一个完
整的高质量的操作系统内核?),但是Linux并不是一个令人敬畏的概念上的飞跃,
Linus不是(至少还不曾是)象Richard stallman或James Gosling一样的创新天
才,在我看来,Linus更象一个工程天才,具有避免错误和开发失败的第六感觉,
掌握了发现从A点到B点代价最小的路径的决窍,确实,Linux的整个设计受益于这
个特质,并反映出Linus的本质上保守和简化设计的方法。
如果快速的发布和充分利用Internet不是偶然而是Linus的对代价最小的路径
的洞察力的工程天才的内在部分,那么他极大增强了什么?他创建了什么样的方法?
问题回答了它自己,Linus保持他的***用户经常受到激励和奖赏:被行动的
自我满足的希望所激励,而奖赏则是经常(甚至每天)都看到工作在进步。
Linus直接瞄准了争取最多的投入调试和开发的人时,甚至冒代码不稳定和一
旦有非常棘手的错误而失去用户基础的险,Linus似乎相信下面这个:
8. 如果有一个足够大的beta测试人员和协作开发人员的基础,几乎所有的问题
都可以被快速的找出并被一些人纠正。
或者更不正式的讲:“如果有足够多的眼睛,所有的错误都是浅显的”(群众
的眼睛是雪亮的),我把这称为“Linus定律”。
我最初的表述是每个问题“对某些人是透明的”,Linus反对说,理解和修订
问题的那个人不一定非是甚至往往不是首先发现它的人,“某个人发现了问题”,
他说,“另一个理解它,我认为发现它是个更大的挑战”,但是要点是所有事都趋
向于迅速发生。
我认为这是建造教堂和集市模式的核心区别,在建造教堂模式的编程模式看
来,错误和编程问题是狡猾的、阴险的、隐藏很深的现象,花费几个月的仔细检
查,也不能给你多大确保把它们都挑出来的信心,因此很长的发布周期,和在长
期等待之后并没有得到完美的版本发布所引起的失望都是不可避免的。
以市集模式观点来看,在另一方面,我们认为错误是浅显的现象,或者至少
当暴露给上千个热切的协作开发人员,让他们来对每个新发布进行测试的时候,
它们很快变得浅显了,所以我们经常发布来获得更多的更正,作为一个有益的副
作用,如果你偶尔做了一个笨拙的修改,也不会损失太多。也许我们本不应该这
样的惊奇,社会学家在几年前已经发现一群相同专业的(或相同无知的)观察者的
平均观点比在其中随机挑选一个来得更加可靠,他们称此为“Delhpi效应”,
Linus所显示的证明在调试一个操作系统时它也适用——Delphi效应甚至可以战胜
操作系统内核一级的复杂度。
我受Jeff Dutky (dutky @ wam.umd.edu)的启发指出Linus定律可以重新表述
为“调试可以并行”,Jeff观察到虽然调试工作需要调试人员和对应的开发人员
相交流,但它不需要在调试人员之间进行大量的协调,于是它就没有陷入开发时
遇到的平方复杂度和管理开销。
在实际中,由于重复劳动而导致的理论上的丧失效率的现象在Linux世界中并
不是一个大问题,“早发布、常发布策略”的一个效果就是利用快速的传播反馈
修订来使重复劳动达到最小。
Brooks甚至做了一个与Jeff相关的更精确的观察:“维护一个广泛使用的程
序的成本一般是其开发成本的40%,奇怪的是这个成本受到用户个数的强烈影响,
更多的用户发现更多的错误”(我的强调)。
更多的用户发现更多的错误是因为更多的用户提供了更多测试程序的方法,
当用户是协作开发人员时这个效果被放大了,每个找寻错误的人都有自己稍微不
同的感觉和分析工具,从不同角度来看待问题。“Delphi效应”似乎因为这个变
体工作变得更加精确,在调试的情况下,这个变体同时减小了重复劳动。
所以加入更多的beta测试人员虽不能从开发人员的P.O.V中减小“最深”的错
误的复杂度,但是它增加了这样一种可能性,即某个人的工具和问题正好匹配,
而这个错误对这个人来说是浅显的。
Linus也做了一些改进,如果有一些严重的错误,Linux内核的版本在编号上
做了些处理,让用户可以自己选择是运行上一个“稳定”的版本,还是冒遇到错
误的险而得到新特征,这个战略还没被大多数Linux***所仿效,但它应该被仿
效,存在两个选择的事实让二者都很吸引 人。
五. 什么时候玫瑰不是玫瑰?
在研究了Linus的行为和形成了为什么它成功的理论之后,我决定在我的工程
(显然没有那么复杂和雄心勃勃)里有意识的测试这个理论。
但我首先做的事是熟悉和简化Popclient。 Carl Harris的实现非常好,但是
有一种对许多C程序来说没有必要的复杂性。他把代码当作核心而把数据结构当作
对代码的支持,结果是代码非常漂亮但是数据结构设计得很特别,相当丑陋(至少
对以这个老LISP***的标准来看),然而除了提高代码和数据结构设计之外,重写
它还有一个目的,就是要把它演化为我彻底理解的东西,对修改你不理解的程序
中的错误负责可不是一件有趣的事。
第一个月我只是在领会Carl's的基本设计的含义,我所做的第一个重大修改
是加入了IMAP支持,我把协议机重新组织为一个通用驱动程序和三个方法表(对应
POP2、POP3和IMAP),这个前面的修改指出一个需要程序员(特别是象C这种没有自
然的动态类型支持的语言)记在脑中的一般原理:
9. 聪明的数据结构和笨拙的代码要比相反的搭配工作的更好
Fred Brooks也在他第11章中讲道:“让我看你的[代码],把你的[数据结
构]隐藏起来,我还是会迷惑;让我看看你的[数据结构],那我就不需要你的[代
码]了,它是显而易见的”。
实际上,他说的是“流程图”和“表”,但是在三十年的术语/文化演进之
后,事情还是一样的。
此时(1996年9月初,在从零开始六个月后),我开始想接下来修改名字——毕
竟,它已不仅仅是一个POP客户,但我犹豫了,因为还没有什么新的漂亮设计呢,
我的popclient版本需要有自己的特色。
当fetehmail学会怎样把取到的邮件转送到SMTP端口时,事情就完全改变了,
但是首先:上面我说过我决定使用这个工程来测试我关于Linus Torualds所做的
行为的理论,(你可能会问)我怎样做到这点呢? 以下面的方式:
1. 我尽早尽量频繁的发布(几乎从未少于每十天发布一次;在密集开发的时候
是每天一次)。
2. 我把每一个和我讨论fetchmail的人加入一个beta表中。
3. 每当我发布我都向beta表中的人发出通告,鼓励人们参与。
4. 我听取beta测试员的意见,向他们询问设计决策,对他们寄来的补丁和反馈
表示感谢。
这些简单的手段立即收到的回报,在工程的开始,我收到了一些错误报告,
其质量足以使开发者因此被杀掉,而且经常还附有补丁、我得到了理智的批评,
有趣的邮件,和聪明的特征建议,这导致了:
10. 如果你象对待最宝贵的资源一样对待你的beta测试员,他们就会成为你最
宝贵的资源。
六. popclient变成了Fetchmail
这个工程的真正转折点是Harry Hochleiser寄给我他写的代码草稿,他把邮
件转发到客户端机器的SMTP端口,我立即意识到这个特征的可靠实现将淘汰所有
其他的递送模式。
几个星期以来我一直在修改而不是改进fetchmail,因为我觉得界面设计虽然
有用但是太笨拙琐碎了,到处充满了太多的粗陋的细小选项。
当我思考SMTP转发时我发现popclient试图做的事太多了,它被设计成既是一
个邮件传输代理(MTA)也是一个本地递送代理(MDA)。使用SMTP转发,它就可以从
MDA的事务中解脱出来而成为一个纯MTA,而象sendmail一样把邮件交给本地递送
程序来处理。
既然端口25在所有支撑TCP/IP的平台上早已被预留,为什么还要为一个邮件
传输代理的配置或为一个邮箱设置加锁的附加功能而操心呢?尤其是当这意味着抽
取的邮件就象一个正常的发送者发出的SMTP邮件一样,而这就是我们需要的。
这里有几个教益:第一,SMTP转发的想法是我有意识地模拟Linus的方法以来
的最大的单个回报,一个用户告诉我这个非同寻常的想法——我所需做的只是理
解它的含义。
11. 想出好主意是好事,从你的用户那里发现好主意也是好事,有时候后者更
好。
很有趣的是,你很快将发现,如果你完全承认你从其他人那里得到多少教益
的话,整个世界将会认为所有的发明都是你做出的,而你会对你的天才变得谦
虚。我们可以看到这在Linus身上体现得多明显!(当我在1997年8月的Perl会议上
发表这个论文时,Larry Wall坐在前排,当我讲到上面的观点时,他激动的叫了
出来:“对了!说对了!哥们!”所有的听众都哄堂大笑起来,因为他们知道同样的
事情也发生在Perl的发明者身上)。
于是在同样精神指导下工程进行了几个星期,我开始不光从我的用户那儿也
从听说我的系统的人那儿得到类似的赞扬,我把一些这种邮件收藏起来,我将在
我开始怀疑自己的生命是否有价值时重新读读这些信。:)
但是有两个更基本的,非政治性的对所有设计都有普遍意义的教益。
12. 最重要和最有创新的解决方案常常来自于你认识到你对问题的概念是错误
的。
一个衡量fetchmail成功的有趣方式是工程的beta测试人员表(fegtchmail的
朋友们)的长度,在创立它的时候已经有249个成员了,而且每个星期增加两到三
个。
实际上,当我在1997年5月校订它时,这张表开始因为一个有趣的原因而缩短
了,有几个人请求我把他们从表中去掉,因为fetchmail已经工作的如此之好,他
们不需要看到这些邮件了!也许这是一个成熟的市集风格工程的生命周期的一部分。
我以前一直在解决错误的问题,把popclient当作MTA和具有许多本地递送模
式的MDA的结合物,Fetchmail的设计需要从头考虑为一个纯的MTA,做为一个普通
Internet邮件路径的一部分。
当你在开发中碰了壁时(当你发现自己很难想通下一步时),那通常不是要问
自己是否找到正确答案,而是要问是否问了正确问题,也许需要重新构造问题。
于是,我重新构造了我的问题,很清楚,要做的正确的事是(1)把SMTP转发支
持放在通用驱动程序中,(2)把它做为缺省模式,(3)最终分离所有其他的递送模
式,尤其是递送到文件和标准输出的选项。
我在第三步上犹豫了一下,担心会让popdiant的长期用户对新的递送方法感
到烦心,在理论上,他们可以立即转而转发文件或者他们的非sendmail等价物来
得到同样的效果,在实际中这种转换可能会很麻烦。
但是当我这么做之后,证明好处是巨大的,驱动程序代码的冗余的部分消失
了,配置完全变得简单了——不用屈从于系统MDA和用户的邮箱,也不用为下层
OS是否支持文件锁定而担心了。
而且,丢失邮件的唯一漏洞也被堵死了,如果你选择了递送到一个文件而磁
盘已满,你的邮件就会丢失,这在SMTP转发中不会发生,因为SMTP侦听器不会返
回OK的,除非邮件可以递送成功或至少被缓冲留待以后递送。
还有,性能也改善了(虽然在单次执行中你不会注意到),这个修改的另一个
不可忽视的好处是手册变得大大简单了。
后来,为了允许处理一些罕见的情况,包括动态SLIP,我必须回到让用户定
义本地MDA递送上来,但是我发现了一个更加简单的方法。
所有这些给了我们什么启发呢?如果可以不损失效率,就要毫不犹豫抛弃陈旧
的特性,Antonine de Saint-Exupery(在他成为经典儿童书籍作家之前是一个飞
行员和飞机设计师)曾说过:
13. “最好的设计不是再也没有什么东西可以添加了,而是再也没有什么东西
可以去掉。”
当你的代码变得更好和更简单时,这就是你知道它是正确的时候了,而且在
这个过程中,fetehmail的设计具有了自己的特点,而区别于其前身popclient。
现在是改名的时候了,这个新的设计看起来比老popclient更象一个sendmail
的复制品,它们都是MTA,但是Senmail是推然后递送,而新的popclient是拉然后
递送。于是,在两个月之后,我把它重新命名为fetehmail。
七. Fetchmail成长起来
现在我有了一个简洁和富有创意的设计,工作得很好的代码,因为我每天都
用它,和一直在增长的beta表,它让我渐渐明白我已经不是在从事只能对少数其
他人有用的工作中,我写了一个所有有一个Unix邮箱和SLIP/PPP邮件连接的人都
真正需要的程序。
通过SMTP转发功能,它成为一个潜在的“目录杀手”,远远领先于它的竞争
者,这个程序如此能干以至于其他的程序不但被放弃简直被忘记了。
我知道你不可以真得瞄准或计划出这样的结果,你只能努力去设计这些强大
的思想,以后这些结果就好象是不可避免的、自然的、注定了的,得到这种思想
的唯一办法是获取许多思想,或者用工程化的思考其他人的好主意而超过原来想
到它的人的设想。
Andrew Tanenbanm原来设想建造一个适合386的简单的Unix用做教学,Linus
Torvalels把Andrew的可能想到的Minix可以做什么的概念推进了一步,成长为一
个极好的东西,同样的(虽然规模较小),我接受了Card Harris和Harry
Hochheiser的想法,把它们变得更强大,我们都不是人们所浪漫幻想的天才的创
始人,但是大多数科学和工程和软件开发不是被天才的创始人完成的,这和流传
的神话恰恰相反。
结果总是执着的原因——实际上,它是每个***为之生存的成功!而且它们意
味着我必须把自己的标准定高一点,为了把fetchmail变得和我所能设想的那样
好,我必须不仅为我自己的需要写代码,而且也要包括对在我生活围主页外的人
们的需求的支持,而且同时也要保证程序的简单和健壮。
在实现它之后我首先写的最重要的特征是支持多投——从集中一组用户的邮
件的邮箱中取出邮件,然后把它路由到每个人手中。
我之所以加上多投功能部分是因为有些用户一直在闹着要它,更是因为我想
它可以从单投的代码中揭露出错误来,让我完全一般地处理寻址,而且这被证明
了。正确解释RFC822花了我相当长的时间,不仅因为它的每个单独部分都很难,
而且因为它有一大堆相互依赖的苛刻的细节。
但是多投寻址也成为一个极好的设计决策,由此我知道:
14. 任何工具都应该能以预想的方式使用,但是一个伟大的工具提供你没料到
的功能。
Fetchmant多投功能的一个没有料到的用途是在SLIP/PPP的客户端提供邮件
列表、别名扩展。这意味着一个使用个人机器的人不必持续访问ISP的别名文件就
能通过一个ISP帐户管理一个邮件列表。我的beta测试员提出的另一个重要的改变
是支持8位MIME操作,这很容易做,因为我已经仔细的保证了8位代码的清晰,不
仅因为我预见到了这个特性的需求,而且因为我忠实于另一准则:
15. 当写任何种类的网关型程序时,多费点力,尽量少干扰数据流,永远不要
抛弃信息,除非接收方强迫这么作!
如果我不遵从这个准则,那么8位MIME支持将会变得困难和笨拙,现在我所需
要做的,是只读一下RFC 1652,在产生信头的逻辑加上一点而已。
一些欧洲用户要求我加上一个选项来限制每次会话取得消息数(这样他们就可
以从昂贵的电话网中控制花费了),我很长一段时间拒绝这样做,而且我仍然对它
不很高兴,但是如果你是为了世界而写代码,你必须听取顾客的意见——这并不
随他们不付给你钱而改变。
八. 从Fetchmail得来的另一些教益
在他们回到一般的软件工程问题以前,还有几个从fetchmail得到的教益需要
思考。
rc文件语法包括可选的“noise”关键字,它被扫描器完全忽略了,当你把它
们全抽取出的时候,关键字/值对更具可读性。
当我注意到rc文件的声明在多大程度上开始象一个微型命令语言时,这是一个
Late-night的体验(这也是我为什么把popclient原来的“server”关键字改成了
“poll”)。
对我来说似乎把这个微型命令语言变得更象英语可能会使它更容易使用。现在,
虽然我对经过Emacs和HTML及许多数据库引擎所证实的“把它做成一个语言”的设计
方式确信不疑,但是我并不是一个通常的“类英语”语法的狂热拥护者。
传统程序员容易控制语法使它尽量精确和紧凑,完全没有冗余,这是计算机资
源还很昂贵时遗留下的一种文化传统,所以扫描策略需要尽可能的廉价和简单,而
具有50%冗余度的英语,看来好象是一个非常不合适的模型。
这并不是我不用类英语语法的原因,我提到这一点是为了推翻它,在更廉价的
时钟周期与核心的时代,简洁并没有走到尽头,今天对一个语言来说,对人更方便
比对机器更廉价来的更加重要。
然而,有几个原因提醒我们小心一点,一个是扫描策略的复杂度开销——你并
不想把它变成一个巨大的错误来源和让用户困惑,另一个是试图使语言表面上的类
似可以和传统语言一样令人困惑(你可以在许多4GL和商业数据库查询语言上看到这
一点)。
Fetchmail的控制语法避免了这些问题,因为语言的领域是极其有限的。它一
点也不象一个一般性的语言,它很简单地描述的东西并不复杂,所以很少可能在英
语的一个小子集与实际的控制语言之间发生混淆,我想这有一个更广泛的教益:
16. 如果你的语言一点也不象是图灵完备的,严格的语法会有好处。
另一个教益是关于安全的,一些fetchmail用户要求我修改软件把口令加密存
贮在rc文件里,这样觑探者就不能看到它们了。
我没有这样做,因为这实际上起不到任何保护作用,任何有权读取你的rc文件
的人都可以以你的名义运行fetchmail——如果他们要破你的口令,它们可以从
fetchmail的代码中找到制作×××的方法。
所以fetchmail口令的加密都会给那些不慎重思考的人一种安全的错觉,这里
一般性的准则是:
17. 一个安全系统只能和它的秘密一样安全,当心伪安全。
九. 集市风格的必要的先决条件
本文的早期评审人员和测试人员坚持提出成功的市集模式开发的先决条件,
包括工程领导人的资格问题和在把项目公开和开始建造一个协作开发人员的社团
的时候代码的状态。
相当清楚,不能以一个市集模式从头开发一个软件,我们可以以市集模式、
测试、调试和改进,但是以市集模式从头开始一个项目将是非常困难的,Linus
没有这样做,我也没有,初期的开发人员的社团应该有一此可以运行和测试的
东西来玩。
当你开始创建社团时,你需要演示的是一个诺言,你的程序不需要工作的
很好,它可以很粗糙、很笨拙、不完整和缺少文档、它不能忽略的东西是要吸
引哪些人卷入一个整洁的项目。
Linux和fetchmail都是以一个吸引人的基本设计进入公共领域的,许多和
我一样在思考市集模式的人已经正确的认为这是非常关键的,然后得出了一个
结论,工程领导者的高度的设计直觉和聪颖是必不可少的。
但是Linus是从Unix得到他的设计的,我最初是从先前的popmail得到启发的
(虽然相对Linux而言,它最后改变巨大),所以市集风格的领导人/协调人需要有
出众的设计才能,或者他可以利用别人的设计才能?
我认为能够提出卓越的原始设计思想对协调人来说不是最关键的,但是对
他/她来说绝对关键的是要能把从他人那里得到的好的设计重新组织起来。
Linux和fetchmail项目都显示了这些证据,Linus(如同前面所说)并不是惊人
的原始设计者,但他显示了发现好的设计并把它集成到Linux内核中的强大决窍。
还有我也描述了怎样从别人那里得到了fetchmail中最强大的设计思想(SMTP转发)。
本文的早期读者称赞我,说因为我做了许多关于原始设计的事,所以倾向于
低估原始设计在市集项目中的价值,也许有些是对的吧,但是设计(而不是编码或
调试)本来就是我最强的能力。
变得聪明和软件设计的原始创作的问题是它会变成一个习惯,当需要保持事
物健壮和简洁的时候,你却开始把事情变得漂亮但却复杂。我曾经犯过错误,使
得一些项目因我而崩溃了,但我努力不让它发生在fetchmail身上。
所以我相信fetchmail项目的成功部分是因为我抑制自己不要变得太聪明,这
说明(至少)对市集模式而言原始设计并不是本质的,请考察一下Linux假设Linus
Torvalds在开发时试图彻底革新操作系统设计,它还会象今天我们所拥有的内核
那样稳定和成功吗?
当然基本的设计和编码技巧还是必需的,但我希望每个严肃考虑发起一个市
集计划的人都已至少具备这些能力,自由软件社团的内部市场对人们有某些微妙
的压力,让他们不要发起自由不能搞定的开发,目前为止,这工作得仍然相当好。
对市集项目来说,我认为还有另一种通常与软件开发无关的技能和设计能力
同样重要——或者更加重要,市集项目的协调人或领导人必须有良好的人际和交
流能力。
这是很显然的,为了建造一个开发社团,你需要吸引人,你所做的东西要让
他们感到有趣,而且要保持他们对他们正在做的工作感到有趣,而且要保持他们
对他们正在做的工作感到高兴,技术方面对达成这些目标有一定帮助,但这远远
不是全部,你的个人素质也有关系。
并不是说Linus是一个好小伙子,让人们喜爱并乐于帮助他,也并不是说我是
个积极外向的,喜欢扎堆儿工作,有出众的幽默感的人,对市集模式的工作而
言,至少有一点吸引人的技巧是非常有帮助的。
十. 自由软件的社会学语境
下述如实:最好的开发是从作者解决每天工作中的个人问题开始的,因为它
对一大类用户来说是一个典型问题,所以它就推广开来了,这把我们带回到准则1,
也许是用一个更有用的方式来描述:
18. 要解决一个有趣的问题,请从发现让你感兴趣的问题开始。
这是Carl Harris和原先的popclient的情形,也是我和fetchmail的情形,但
这已在很长一段时间被大家知晓了,Linux和fetchmail的历史要求我们注意的有
趣之处是下一个阶段——软件在一个庞大的活跃的用户和协作开发人员的社团中
的进化。
在《神秘的人月》一书中,Fred Brooks观察到程序员的工作时间是不可替代
的:在一个误了工期的软件项目中增加开发人员只会让它拖得更久,他声称项目
的复杂度和通讯开销以开发人员的平方增长,而工作成绩只是以线性增长,这个
说法被称为“Brooks定律”,被普遍当作真理,但如果Brooks定律就是全部,那
Linux就不可能成功。
几年之后,Gerald Weinbeng的经典之作“The Psychology Of Computer
Progromming”为我们更正了Brooks的看法,在他的“忘我(egoless)的编程”中,
Weinberg观察到在开发人员不顽固保守自己的代码,鼓励其他人寻找错误和发展
潜力的地方,软件的改进的速度会比其他地方有戏剧性的提高。
Weinberg的用词可阻止了他的分析得到应有的接受,人们对把Internet***
称为“忘我”的想法微笑,但是我想今天他的想法比以往任何时候都要引人注目。
Unix的历史已经为我们准备好了我们正在从Linux学到的(和我在更小规模上
模仿Linus的方法所验证的)东西,这就是,虽然编码仍是一个人干的活,真正伟
大的工作来自于利用整个社团的注意和脑力,在一个封闭的项目中只利用他自己
的脑力的人会落在知道怎样创建一个开放的、进化的,成百上千的人在其中查找
错误和进行修改的环境的开发人员之后。
但是Unix的传统中有几个因素阻止把这种方法推到极致。一个是各种授权的
法律约束、商业机密和商业利益,另一个(事后来看)是Internet还不够好。
在Internet变得便宜之前,有一些在地理上紧密的社团,
本文的作者Eric Raymond是Open Source Software领域的领袖,这方面许多
新的思想正是从他那儿产生的,同时他也是UNIX上最流行的Email软件Fetchmail
的作者。
下面这篇文章有点儿长,然而它是值得你去耐心把它读完的。文章以Fetchmail
为例,讨论了Internet上集市风格的开发方式。
我们应该感谢HansB,是他把这篇长文章翻译成了中文。
Eric的主页地址在: [url]http://www.tuxedo.org/~esr/[/url]
-------------------------------------------------------------------------
一. 大教堂和市集
Linux的影响是非常巨大的。甚至在5年以前,有谁能够想象一个世界级的操
作系统能够仅仅用细细的Internet连接起来的散布在全球的几千个开发人员有以业
余时间来创造呢?
我当然不会这么想。在1993年早期我开始注意Linux时,我已经参与Unix
和自由软件开发达十年之久了。我是八十年代中期GNU最早的几个参与者之一。我
已经在网上发布了大量的自由软件,开发和协助开发了几个至今仍在广泛使用的
程序(Nethack,Emacs VC和GND模式,xlife等等)。我想我知道该怎样做。
Linux推翻了许多我认为自己明白的事情。我已经宣扬小工具、快速原型和演
进式开发的Unix福音多年了。但是我也相信某些重要的复杂的事情需要更集中化的,
严密的方法。我相信多数重要的软件(操作系统和象Emacs一样的真正大型的工具)
需要向建造大教堂一样来开发,需要一群于世隔绝的奇才的细心工作,在成功之前
没有beta版的发布。
Linus Torvalds的开发风格(尽早尽多的发布,委托所有可以委托的事,对所
有的改动和融合开放)令人惊奇的降临了。这里没有安静的、虔诚的大教堂的建造
工作——相反,Linux团体看起来像一个巨大的有各种不同议程和方法的乱哄哄的
集市(Linux归档站点接受任何人的建议和作品,并聪明的加以管理),一个一致
而稳定的系统就象奇迹一般从这个集市中产生了。
这种设计风格确实能工作,并且工作得很好,这个事实确实是一个冲击。在我
的研究过程中,我不仅在单个工程中努力工作,而且试图理解为什么Linux世界不
仅没有在一片混乱中分崩离析,反而以大教堂建造者们不可想象的速度变得越来越
强大。
到了1996年中,我想我开始理解了。我有一个极好的测试我的理论的机会,
以一个自由软件计划的形式,我有意识的是用了市集风格。我这样做了,并取得了
很大的成功。
在本文的余下部分,我将讲述这个计划的故事,我用它来明确一些自由软件高
效开发的格言。并不是所有这些都是从Linux世界中学到的,但我们将看到Linux世
界给予了它们一个什么样的位置。如果我是正确的,它们将使你理解是什么使Linux
团体成为好软件的源泉,帮助你变得更加高效。
二. 邮件必须得通过
1993年以前我在一个小的免费访问的名为Chester County InterLink的ISP
的做技术工作,它位于Pennsylvania的West Chester。(我协助建立了CCIL,并写了
我们独特的多用户BBS系统——你可以telnet到locke.ccil.org来检测一下。今天它
在十九条线上支持三千的用户)。这个工作使我可以一天二十四小时通过CCIL的56K
专线连在网上,实际上,它要求我这么做!
所以,我对Internet email很熟悉。因为复杂的原因,很难在我家里的机器
(snark.thyrsus.com)和CCIL之间用SLIP工作。最后我终于成功了,但我发现不
得不时常telnet到locke来检查我的邮件,这真是太烦了。我所需要的是我的邮件
发送到snark,这样biff(1)会在它到达时通知我。
简单地sendmail的转送功能是不够的,因为snark并不是总在网上而且没有一
个静态地址。我需要一个程序通过我的SLIP连接把我的本地发送的邮件拉过来。
我知道这种东西是存在的,它们大多使用一个简单的协议POP(Post Office
Protocol)。而且,locke的BSD/OS操作系统已经自带了一个POP3服务器。
我需要一个POP3客户。所以我到网上去找到了一个。实际上,我发现了三、
四个。我用了一会pop-perl,但它却少一个明显的特征:抽取收到的邮件的地址
以便正确回复。
问题是这样的:假设locke上一个叫“joe”的人向我发了一封邮件。如果我
把它取到snark上准备回复时,我的邮件程序会很高兴地把它发送给一个不存在的
snark上的“joe”。手工的在地址上加上“@ccil.org”变成了一个严酷的痛苦。
这显然应是计算机替我做的事。(实际上,依据RFC1123的5.2.18节,
sendmail应该做这件事)。但是没有一个现存的POP客户知道怎样做!于是这就给
我们上了第一课:
1.每个好的软件工作都开始于搔到了开发者本人的痒处。
也许这应该是显而易见的(“需要是发明之母”长久以来就被证明是正确的),
但是软件开发人员常常把他们的精力放在它们既不需要也不喜欢的程序,但在
Linux世界中却不是这样——这解释了为什么从Linux团体中产生的软件质量都如
此之高。
那么,我是否立即投入疯狂的工作中,要编出一个新的POP3客户与现存的那
些竞争呢?才不是哪!我仔细考察了手头上的POP工具,问自己“那一个最接近我
的需要?”因为:
2.好程序员知道该写什么,伟大的程序员知道该重写(和重用)什么。
我并没有声称自己是一个伟大的程序员,可是我试着效仿他们。伟大程序员
的一个重要特点是建设性的懒惰。他们知道你是因为成绩而不是努力得到奖赏,
而且从一个好的实际的解决方案开始总是要比从头干起容易。
例如,Linux并不是从头开始写Linux的。相反的它从重用Minix(一个386机
型上的类似Unix的微型操作系统)的代码和思想入手。最后所有的Minix代码都消
失或被彻底的重写了,但是当它们在的时候它为最终成为Linux的雏形做了铺垫。
秉承同样的精神,我去寻找良好编码的现成的POP工具,用来作为基础。
Unix世界中的代码共享传统一直对代码重用很友好(这正是为什么GNU计划不
管Unix本身有多么保守而选取它作为基础操作系统的原因)。Linux世界把这个传
统推向技术极限:它有几个T字节的源代码可以用。所以在Linux世界中花时间寻
找其他几乎足够好的东西,会比在别处带来更好的结果。
这也适合我。加上我先前发现的,第二次寻找找到了9个候选者——fetchPOP
,PopTart,get-mail,gwpop,pimp,pop-perl,popc,popmail 和 upop)。我
首先选定的是“fetchpop”。我加入了头标重写功能,并且做了一些被作者加入
他的1.9版中的改进。
但是几个星期之后,我偶然发现了Carl Harris写的“popclient”的代码,
然后发现有个问题,虽然fetchpop有一些好的原始思想(比如它的守护进程模式),
它只能处理pop3,而且编码的水平相当业余(Seung-Hong是个很聪明但是经验不足
的程序员),Carl的代码更好一些,相当专业和稳固,但他的程序缺少几个重要的
相当容易实现的fetchpop的特征(包括我自己写的那些)。
继续呢还是换一个? 如果换一个的话,作为得到一个更好开发基础的代价,
我就要扔掉我已经有的那些代码。
换一个的一个实际的动机是支持多协议,pop3是用的最广的邮局协议,但并
非唯一一个,Fetchpop和其余几个没有实现POP2.RPOP,或者APOP,而且我还有一
个为了兴趣加入IMAP(Internet Message Access Protocol,最近设计的最强大的
邮局协议)的模糊想法。
但是我有一个更加理论化的原因认为换一下会是一个好主意,这是我在Linux
很久以前学到的:
3.“计划好抛弃,无论如何,你会的”(Fred Brooks,《神秘的人月》第11章)
或者换句话说,你常常在第一次实现一个解决方案之后才能理解问题所在,
第二次你也许才足够清楚怎样做好它,因此如果你想做好,准备好推翻重来至少
一次。
好吧(我告诉自己),对fetchpop的尝试是我第一次的尝试,因此我换了一下。
当我在1996年6月25日把我第一套popclient的补丁程序寄给Carl Harris之
后,我发现一段时间以前他已经对popclient基本上失去了兴趣,这些代码有些陈
旧,有一些次要的错误,我有许多修改要做,我们很快达成一致,我来接手这个
程序。不知不觉的,这个计划扩大了,再也不是我原先打算的在已有的pop客户上
加几个次要的补丁而已了,我得维护整个的工程,而且我脑袋里涌动着一些念头
要引起一个大的变化。
在一个鼓励代码共享的软件文化里,这是一个工程进化的自然道路,我要指
出:
4. 如果你有正确的态度,有趣的问题会找上你的,但是Carl Harris的态度甚
至更加重要,他理解:
5.当你对一个程序失去兴趣时,你最后的责任就是把它传给一个能干的后继者。
甚至没有商量,Carl和我知道我们有一个共同目标就是找到最好的解决方
案,对我们来说唯一的问题是我能否证明我有一双坚强的手,他优雅而快速的写
出了程序,我希望轮到我时我也能做到。
三. 拥有用户的重要性
于是我继承了popclient,同样重要的是,我继承了popclient的用户基础,
用户是你所拥有的极好的东西,不仅仅是因为他们显示了你正在满足需要,你做
了正确的事情,如果加以适当的培养,他们可以成为合作开发者。
Unix传统另一有力之处是许多用户都是***,因为源优码是公开的,他们可
以成为高效的***,这一点在Linux世界中也被推向了令人高兴的极致,这对缩短
调试时间是极端重要的,在一点鼓励之下,你的用户会诊断问题,提出修订建
议,帮你以远比你期望快得多的速度的改进代码。
6. 把用户当做协作开发者是快速改进代码和高效调试的无可争辩的方式。
这种效果的力量很容易被低估,实际上,几乎所有我们自由软件世界中的人
都强烈低估了用户可以多么有效地对付系统复杂性,直到Linus让我们看到了这一
点。
实际上,我认为Linus最聪明最了不起的工作不是创建了Linux内核本身,而
是发明了Linux开发模式,当我有一次当着他的面表达这种观点时,他微笑了一
下,重复了一句他经常说的话:“我基本上是一个懒惰的人,依靠他人的工作来
获取成绩。”象狐狸一样懒惰,或者如Robert Heinlein所说,太懒了而不会失
败。
回顾起来,在GNU Emacs Lisp库和Lisp代码集中可以看到Linux方法的成功,
与Emacs的C内核和许多其他FSF的工具相比,Lisp代码库的演化是流动性的和用户
驱动的,思想和原型在达到最终的稳定形式之前往往要重写三或四次,而且经常
利用Internet的松散合作。
实际上,我自己在fetchmail之前最成功的作品要算Emacs VC模式,它是三个
其他的人通过电子邮件进行的类似Linux的合作,至今我只见过其中一个人
(Richard Stallman),它是SCCS、RCS和后来的CVS的前端,为Emacs提供“one-
touch”版本控制操作,它是从一个微型的、粗糙的别人写好的sccs.el模式开始
演化的,VC开发的成功不像Emacs本身,而是因为Emacs Lisp代码可以很快的通过
发布/测试/改进的过程。
(FSF的试图把代码放入GPL之下的策略有一个未曾预料到的副作用,它让FSF
难以采取市集模式,因为他们认为每个想贡献二十行以上代码的人都必须得到一
个授权,以使受到GPL的代码免受版权法的侵扰,具有BSD和MITX协会的授权的用
户不会有这个问题,因为他们并不试图保留那些会使人可能受到质询的权力)。
四. 早发布、常发布
尽量早尽量频繁的发布是Linux开发模式的一个重要部分,多数开发人员(包
括我)过去都相信这对大型工程来说是个不好的策略,因为早期版本都是些充满错
误的版本,而你不想耗光用户的耐心。
这种信仰强化了建造大教堂开发方式的必要性,如果目标是让用户尽可能少
的见到错误,那你怎能不会仅仅每六个月发布一次(或更不经常),而且在发布之
间象一只狗一样辛勤“捉虫”呢? Emacs C内核就是以这种方式开发的,Lisp库,
实际上却相反,因为有一些有FSF控制之外的Lisp库,在那里你可以独立于Emacs
发布周期地找寻新的和开发代码版本。
这其中最重要的是Ohio州的elisp库,预示了今天的巨大的Linux库的许多特
征的精神,但是我们很少真正仔细考虑我们在做什么,或者这个库的存在指出了
FSF建造教堂式开发模式的什么问题,1992年我曾经做了一次严肃的尝试,想把
Ohio的大量代码正式合并到Emacs的官方Lisp库中,结果我陷入了政治斗争中,彻
底失败了。
但是一年之后,在Linux广泛应用之后,很清楚,一些不同的更加健康的东西
诞生了,Linus的开发模式正好与建造教堂方式相反,Sunsite和tsx-11的库开始
成长,推动了许多发布。所有这些都是闻所未闻的频繁的内核系统的发布所推动
的。
Linus以所有实际可能的方式把它的用户作为协作开发人员。
7. 早发布、常发布、听取客户的建议
Linus的创新并不是这个(这在Unix世界中是一个长期传统),而是把它扩展到
和他所开发的东西的复杂程度相匹配的地步,在早期一天一次发布对他来说都不
是罕见的!而且因为他培育了他的协作开发者基础,比其他任何人更努力地充分利
用了Internet进行合作,所以这确实能行。
但是它是怎样进行的呢?它是我能模仿的吗?还是这依赖于Linus的独特天才?
我不这样想,我承认Linus是一个极好的***(我们有多少人能够做出一个完
整的高质量的操作系统内核?),但是Linux并不是一个令人敬畏的概念上的飞跃,
Linus不是(至少还不曾是)象Richard stallman或James Gosling一样的创新天
才,在我看来,Linus更象一个工程天才,具有避免错误和开发失败的第六感觉,
掌握了发现从A点到B点代价最小的路径的决窍,确实,Linux的整个设计受益于这
个特质,并反映出Linus的本质上保守和简化设计的方法。
如果快速的发布和充分利用Internet不是偶然而是Linus的对代价最小的路径
的洞察力的工程天才的内在部分,那么他极大增强了什么?他创建了什么样的方法?
问题回答了它自己,Linus保持他的***用户经常受到激励和奖赏:被行动的
自我满足的希望所激励,而奖赏则是经常(甚至每天)都看到工作在进步。
Linus直接瞄准了争取最多的投入调试和开发的人时,甚至冒代码不稳定和一
旦有非常棘手的错误而失去用户基础的险,Linus似乎相信下面这个:
8. 如果有一个足够大的beta测试人员和协作开发人员的基础,几乎所有的问题
都可以被快速的找出并被一些人纠正。
或者更不正式的讲:“如果有足够多的眼睛,所有的错误都是浅显的”(群众
的眼睛是雪亮的),我把这称为“Linus定律”。
我最初的表述是每个问题“对某些人是透明的”,Linus反对说,理解和修订
问题的那个人不一定非是甚至往往不是首先发现它的人,“某个人发现了问题”,
他说,“另一个理解它,我认为发现它是个更大的挑战”,但是要点是所有事都趋
向于迅速发生。
我认为这是建造教堂和集市模式的核心区别,在建造教堂模式的编程模式看
来,错误和编程问题是狡猾的、阴险的、隐藏很深的现象,花费几个月的仔细检
查,也不能给你多大确保把它们都挑出来的信心,因此很长的发布周期,和在长
期等待之后并没有得到完美的版本发布所引起的失望都是不可避免的。
以市集模式观点来看,在另一方面,我们认为错误是浅显的现象,或者至少
当暴露给上千个热切的协作开发人员,让他们来对每个新发布进行测试的时候,
它们很快变得浅显了,所以我们经常发布来获得更多的更正,作为一个有益的副
作用,如果你偶尔做了一个笨拙的修改,也不会损失太多。也许我们本不应该这
样的惊奇,社会学家在几年前已经发现一群相同专业的(或相同无知的)观察者的
平均观点比在其中随机挑选一个来得更加可靠,他们称此为“Delhpi效应”,
Linus所显示的证明在调试一个操作系统时它也适用——Delphi效应甚至可以战胜
操作系统内核一级的复杂度。
我受Jeff Dutky (dutky @ wam.umd.edu)的启发指出Linus定律可以重新表述
为“调试可以并行”,Jeff观察到虽然调试工作需要调试人员和对应的开发人员
相交流,但它不需要在调试人员之间进行大量的协调,于是它就没有陷入开发时
遇到的平方复杂度和管理开销。
在实际中,由于重复劳动而导致的理论上的丧失效率的现象在Linux世界中并
不是一个大问题,“早发布、常发布策略”的一个效果就是利用快速的传播反馈
修订来使重复劳动达到最小。
Brooks甚至做了一个与Jeff相关的更精确的观察:“维护一个广泛使用的程
序的成本一般是其开发成本的40%,奇怪的是这个成本受到用户个数的强烈影响,
更多的用户发现更多的错误”(我的强调)。
更多的用户发现更多的错误是因为更多的用户提供了更多测试程序的方法,
当用户是协作开发人员时这个效果被放大了,每个找寻错误的人都有自己稍微不
同的感觉和分析工具,从不同角度来看待问题。“Delphi效应”似乎因为这个变
体工作变得更加精确,在调试的情况下,这个变体同时减小了重复劳动。
所以加入更多的beta测试人员虽不能从开发人员的P.O.V中减小“最深”的错
误的复杂度,但是它增加了这样一种可能性,即某个人的工具和问题正好匹配,
而这个错误对这个人来说是浅显的。
Linus也做了一些改进,如果有一些严重的错误,Linux内核的版本在编号上
做了些处理,让用户可以自己选择是运行上一个“稳定”的版本,还是冒遇到错
误的险而得到新特征,这个战略还没被大多数Linux***所仿效,但它应该被仿
效,存在两个选择的事实让二者都很吸引 人。
五. 什么时候玫瑰不是玫瑰?
在研究了Linus的行为和形成了为什么它成功的理论之后,我决定在我的工程
(显然没有那么复杂和雄心勃勃)里有意识的测试这个理论。
但我首先做的事是熟悉和简化Popclient。 Carl Harris的实现非常好,但是
有一种对许多C程序来说没有必要的复杂性。他把代码当作核心而把数据结构当作
对代码的支持,结果是代码非常漂亮但是数据结构设计得很特别,相当丑陋(至少
对以这个老LISP***的标准来看),然而除了提高代码和数据结构设计之外,重写
它还有一个目的,就是要把它演化为我彻底理解的东西,对修改你不理解的程序
中的错误负责可不是一件有趣的事。
第一个月我只是在领会Carl's的基本设计的含义,我所做的第一个重大修改
是加入了IMAP支持,我把协议机重新组织为一个通用驱动程序和三个方法表(对应
POP2、POP3和IMAP),这个前面的修改指出一个需要程序员(特别是象C这种没有自
然的动态类型支持的语言)记在脑中的一般原理:
9. 聪明的数据结构和笨拙的代码要比相反的搭配工作的更好
Fred Brooks也在他第11章中讲道:“让我看你的[代码],把你的[数据结
构]隐藏起来,我还是会迷惑;让我看看你的[数据结构],那我就不需要你的[代
码]了,它是显而易见的”。
实际上,他说的是“流程图”和“表”,但是在三十年的术语/文化演进之
后,事情还是一样的。
此时(1996年9月初,在从零开始六个月后),我开始想接下来修改名字——毕
竟,它已不仅仅是一个POP客户,但我犹豫了,因为还没有什么新的漂亮设计呢,
我的popclient版本需要有自己的特色。
当fetehmail学会怎样把取到的邮件转送到SMTP端口时,事情就完全改变了,
但是首先:上面我说过我决定使用这个工程来测试我关于Linus Torualds所做的
行为的理论,(你可能会问)我怎样做到这点呢? 以下面的方式:
1. 我尽早尽量频繁的发布(几乎从未少于每十天发布一次;在密集开发的时候
是每天一次)。
2. 我把每一个和我讨论fetchmail的人加入一个beta表中。
3. 每当我发布我都向beta表中的人发出通告,鼓励人们参与。
4. 我听取beta测试员的意见,向他们询问设计决策,对他们寄来的补丁和反馈
表示感谢。
这些简单的手段立即收到的回报,在工程的开始,我收到了一些错误报告,
其质量足以使开发者因此被杀掉,而且经常还附有补丁、我得到了理智的批评,
有趣的邮件,和聪明的特征建议,这导致了:
10. 如果你象对待最宝贵的资源一样对待你的beta测试员,他们就会成为你最
宝贵的资源。
六. popclient变成了Fetchmail
这个工程的真正转折点是Harry Hochleiser寄给我他写的代码草稿,他把邮
件转发到客户端机器的SMTP端口,我立即意识到这个特征的可靠实现将淘汰所有
其他的递送模式。
几个星期以来我一直在修改而不是改进fetchmail,因为我觉得界面设计虽然
有用但是太笨拙琐碎了,到处充满了太多的粗陋的细小选项。
当我思考SMTP转发时我发现popclient试图做的事太多了,它被设计成既是一
个邮件传输代理(MTA)也是一个本地递送代理(MDA)。使用SMTP转发,它就可以从
MDA的事务中解脱出来而成为一个纯MTA,而象sendmail一样把邮件交给本地递送
程序来处理。
既然端口25在所有支撑TCP/IP的平台上早已被预留,为什么还要为一个邮件
传输代理的配置或为一个邮箱设置加锁的附加功能而操心呢?尤其是当这意味着抽
取的邮件就象一个正常的发送者发出的SMTP邮件一样,而这就是我们需要的。
这里有几个教益:第一,SMTP转发的想法是我有意识地模拟Linus的方法以来
的最大的单个回报,一个用户告诉我这个非同寻常的想法——我所需做的只是理
解它的含义。
11. 想出好主意是好事,从你的用户那里发现好主意也是好事,有时候后者更
好。
很有趣的是,你很快将发现,如果你完全承认你从其他人那里得到多少教益
的话,整个世界将会认为所有的发明都是你做出的,而你会对你的天才变得谦
虚。我们可以看到这在Linus身上体现得多明显!(当我在1997年8月的Perl会议上
发表这个论文时,Larry Wall坐在前排,当我讲到上面的观点时,他激动的叫了
出来:“对了!说对了!哥们!”所有的听众都哄堂大笑起来,因为他们知道同样的
事情也发生在Perl的发明者身上)。
于是在同样精神指导下工程进行了几个星期,我开始不光从我的用户那儿也
从听说我的系统的人那儿得到类似的赞扬,我把一些这种邮件收藏起来,我将在
我开始怀疑自己的生命是否有价值时重新读读这些信。:)
但是有两个更基本的,非政治性的对所有设计都有普遍意义的教益。
12. 最重要和最有创新的解决方案常常来自于你认识到你对问题的概念是错误
的。
一个衡量fetchmail成功的有趣方式是工程的beta测试人员表(fegtchmail的
朋友们)的长度,在创立它的时候已经有249个成员了,而且每个星期增加两到三
个。
实际上,当我在1997年5月校订它时,这张表开始因为一个有趣的原因而缩短
了,有几个人请求我把他们从表中去掉,因为fetchmail已经工作的如此之好,他
们不需要看到这些邮件了!也许这是一个成熟的市集风格工程的生命周期的一部分。
我以前一直在解决错误的问题,把popclient当作MTA和具有许多本地递送模
式的MDA的结合物,Fetchmail的设计需要从头考虑为一个纯的MTA,做为一个普通
Internet邮件路径的一部分。
当你在开发中碰了壁时(当你发现自己很难想通下一步时),那通常不是要问
自己是否找到正确答案,而是要问是否问了正确问题,也许需要重新构造问题。
于是,我重新构造了我的问题,很清楚,要做的正确的事是(1)把SMTP转发支
持放在通用驱动程序中,(2)把它做为缺省模式,(3)最终分离所有其他的递送模
式,尤其是递送到文件和标准输出的选项。
我在第三步上犹豫了一下,担心会让popdiant的长期用户对新的递送方法感
到烦心,在理论上,他们可以立即转而转发文件或者他们的非sendmail等价物来
得到同样的效果,在实际中这种转换可能会很麻烦。
但是当我这么做之后,证明好处是巨大的,驱动程序代码的冗余的部分消失
了,配置完全变得简单了——不用屈从于系统MDA和用户的邮箱,也不用为下层
OS是否支持文件锁定而担心了。
而且,丢失邮件的唯一漏洞也被堵死了,如果你选择了递送到一个文件而磁
盘已满,你的邮件就会丢失,这在SMTP转发中不会发生,因为SMTP侦听器不会返
回OK的,除非邮件可以递送成功或至少被缓冲留待以后递送。
还有,性能也改善了(虽然在单次执行中你不会注意到),这个修改的另一个
不可忽视的好处是手册变得大大简单了。
后来,为了允许处理一些罕见的情况,包括动态SLIP,我必须回到让用户定
义本地MDA递送上来,但是我发现了一个更加简单的方法。
所有这些给了我们什么启发呢?如果可以不损失效率,就要毫不犹豫抛弃陈旧
的特性,Antonine de Saint-Exupery(在他成为经典儿童书籍作家之前是一个飞
行员和飞机设计师)曾说过:
13. “最好的设计不是再也没有什么东西可以添加了,而是再也没有什么东西
可以去掉。”
当你的代码变得更好和更简单时,这就是你知道它是正确的时候了,而且在
这个过程中,fetehmail的设计具有了自己的特点,而区别于其前身popclient。
现在是改名的时候了,这个新的设计看起来比老popclient更象一个sendmail
的复制品,它们都是MTA,但是Senmail是推然后递送,而新的popclient是拉然后
递送。于是,在两个月之后,我把它重新命名为fetehmail。
七. Fetchmail成长起来
现在我有了一个简洁和富有创意的设计,工作得很好的代码,因为我每天都
用它,和一直在增长的beta表,它让我渐渐明白我已经不是在从事只能对少数其
他人有用的工作中,我写了一个所有有一个Unix邮箱和SLIP/PPP邮件连接的人都
真正需要的程序。
通过SMTP转发功能,它成为一个潜在的“目录杀手”,远远领先于它的竞争
者,这个程序如此能干以至于其他的程序不但被放弃简直被忘记了。
我知道你不可以真得瞄准或计划出这样的结果,你只能努力去设计这些强大
的思想,以后这些结果就好象是不可避免的、自然的、注定了的,得到这种思想
的唯一办法是获取许多思想,或者用工程化的思考其他人的好主意而超过原来想
到它的人的设想。
Andrew Tanenbanm原来设想建造一个适合386的简单的Unix用做教学,Linus
Torvalels把Andrew的可能想到的Minix可以做什么的概念推进了一步,成长为一
个极好的东西,同样的(虽然规模较小),我接受了Card Harris和Harry
Hochheiser的想法,把它们变得更强大,我们都不是人们所浪漫幻想的天才的创
始人,但是大多数科学和工程和软件开发不是被天才的创始人完成的,这和流传
的神话恰恰相反。
结果总是执着的原因——实际上,它是每个***为之生存的成功!而且它们意
味着我必须把自己的标准定高一点,为了把fetchmail变得和我所能设想的那样
好,我必须不仅为我自己的需要写代码,而且也要包括对在我生活围主页外的人
们的需求的支持,而且同时也要保证程序的简单和健壮。
在实现它之后我首先写的最重要的特征是支持多投——从集中一组用户的邮
件的邮箱中取出邮件,然后把它路由到每个人手中。
我之所以加上多投功能部分是因为有些用户一直在闹着要它,更是因为我想
它可以从单投的代码中揭露出错误来,让我完全一般地处理寻址,而且这被证明
了。正确解释RFC822花了我相当长的时间,不仅因为它的每个单独部分都很难,
而且因为它有一大堆相互依赖的苛刻的细节。
但是多投寻址也成为一个极好的设计决策,由此我知道:
14. 任何工具都应该能以预想的方式使用,但是一个伟大的工具提供你没料到
的功能。
Fetchmant多投功能的一个没有料到的用途是在SLIP/PPP的客户端提供邮件
列表、别名扩展。这意味着一个使用个人机器的人不必持续访问ISP的别名文件就
能通过一个ISP帐户管理一个邮件列表。我的beta测试员提出的另一个重要的改变
是支持8位MIME操作,这很容易做,因为我已经仔细的保证了8位代码的清晰,不
仅因为我预见到了这个特性的需求,而且因为我忠实于另一准则:
15. 当写任何种类的网关型程序时,多费点力,尽量少干扰数据流,永远不要
抛弃信息,除非接收方强迫这么作!
如果我不遵从这个准则,那么8位MIME支持将会变得困难和笨拙,现在我所需
要做的,是只读一下RFC 1652,在产生信头的逻辑加上一点而已。
一些欧洲用户要求我加上一个选项来限制每次会话取得消息数(这样他们就可
以从昂贵的电话网中控制花费了),我很长一段时间拒绝这样做,而且我仍然对它
不很高兴,但是如果你是为了世界而写代码,你必须听取顾客的意见——这并不
随他们不付给你钱而改变。
八. 从Fetchmail得来的另一些教益
在他们回到一般的软件工程问题以前,还有几个从fetchmail得到的教益需要
思考。
rc文件语法包括可选的“noise”关键字,它被扫描器完全忽略了,当你把它
们全抽取出的时候,关键字/值对更具可读性。
当我注意到rc文件的声明在多大程度上开始象一个微型命令语言时,这是一个
Late-night的体验(这也是我为什么把popclient原来的“server”关键字改成了
“poll”)。
对我来说似乎把这个微型命令语言变得更象英语可能会使它更容易使用。现在,
虽然我对经过Emacs和HTML及许多数据库引擎所证实的“把它做成一个语言”的设计
方式确信不疑,但是我并不是一个通常的“类英语”语法的狂热拥护者。
传统程序员容易控制语法使它尽量精确和紧凑,完全没有冗余,这是计算机资
源还很昂贵时遗留下的一种文化传统,所以扫描策略需要尽可能的廉价和简单,而
具有50%冗余度的英语,看来好象是一个非常不合适的模型。
这并不是我不用类英语语法的原因,我提到这一点是为了推翻它,在更廉价的
时钟周期与核心的时代,简洁并没有走到尽头,今天对一个语言来说,对人更方便
比对机器更廉价来的更加重要。
然而,有几个原因提醒我们小心一点,一个是扫描策略的复杂度开销——你并
不想把它变成一个巨大的错误来源和让用户困惑,另一个是试图使语言表面上的类
似可以和传统语言一样令人困惑(你可以在许多4GL和商业数据库查询语言上看到这
一点)。
Fetchmail的控制语法避免了这些问题,因为语言的领域是极其有限的。它一
点也不象一个一般性的语言,它很简单地描述的东西并不复杂,所以很少可能在英
语的一个小子集与实际的控制语言之间发生混淆,我想这有一个更广泛的教益:
16. 如果你的语言一点也不象是图灵完备的,严格的语法会有好处。
另一个教益是关于安全的,一些fetchmail用户要求我修改软件把口令加密存
贮在rc文件里,这样觑探者就不能看到它们了。
我没有这样做,因为这实际上起不到任何保护作用,任何有权读取你的rc文件
的人都可以以你的名义运行fetchmail——如果他们要破你的口令,它们可以从
fetchmail的代码中找到制作×××的方法。
所以fetchmail口令的加密都会给那些不慎重思考的人一种安全的错觉,这里
一般性的准则是:
17. 一个安全系统只能和它的秘密一样安全,当心伪安全。
九. 集市风格的必要的先决条件
本文的早期评审人员和测试人员坚持提出成功的市集模式开发的先决条件,
包括工程领导人的资格问题和在把项目公开和开始建造一个协作开发人员的社团
的时候代码的状态。
相当清楚,不能以一个市集模式从头开发一个软件,我们可以以市集模式、
测试、调试和改进,但是以市集模式从头开始一个项目将是非常困难的,Linus
没有这样做,我也没有,初期的开发人员的社团应该有一此可以运行和测试的
东西来玩。
当你开始创建社团时,你需要演示的是一个诺言,你的程序不需要工作的
很好,它可以很粗糙、很笨拙、不完整和缺少文档、它不能忽略的东西是要吸
引哪些人卷入一个整洁的项目。
Linux和fetchmail都是以一个吸引人的基本设计进入公共领域的,许多和
我一样在思考市集模式的人已经正确的认为这是非常关键的,然后得出了一个
结论,工程领导者的高度的设计直觉和聪颖是必不可少的。
但是Linus是从Unix得到他的设计的,我最初是从先前的popmail得到启发的
(虽然相对Linux而言,它最后改变巨大),所以市集风格的领导人/协调人需要有
出众的设计才能,或者他可以利用别人的设计才能?
我认为能够提出卓越的原始设计思想对协调人来说不是最关键的,但是对
他/她来说绝对关键的是要能把从他人那里得到的好的设计重新组织起来。
Linux和fetchmail项目都显示了这些证据,Linus(如同前面所说)并不是惊人
的原始设计者,但他显示了发现好的设计并把它集成到Linux内核中的强大决窍。
还有我也描述了怎样从别人那里得到了fetchmail中最强大的设计思想(SMTP转发)。
本文的早期读者称赞我,说因为我做了许多关于原始设计的事,所以倾向于
低估原始设计在市集项目中的价值,也许有些是对的吧,但是设计(而不是编码或
调试)本来就是我最强的能力。
变得聪明和软件设计的原始创作的问题是它会变成一个习惯,当需要保持事
物健壮和简洁的时候,你却开始把事情变得漂亮但却复杂。我曾经犯过错误,使
得一些项目因我而崩溃了,但我努力不让它发生在fetchmail身上。
所以我相信fetchmail项目的成功部分是因为我抑制自己不要变得太聪明,这
说明(至少)对市集模式而言原始设计并不是本质的,请考察一下Linux假设Linus
Torvalds在开发时试图彻底革新操作系统设计,它还会象今天我们所拥有的内核
那样稳定和成功吗?
当然基本的设计和编码技巧还是必需的,但我希望每个严肃考虑发起一个市
集计划的人都已至少具备这些能力,自由软件社团的内部市场对人们有某些微妙
的压力,让他们不要发起自由不能搞定的开发,目前为止,这工作得仍然相当好。
对市集项目来说,我认为还有另一种通常与软件开发无关的技能和设计能力
同样重要——或者更加重要,市集项目的协调人或领导人必须有良好的人际和交
流能力。
这是很显然的,为了建造一个开发社团,你需要吸引人,你所做的东西要让
他们感到有趣,而且要保持他们对他们正在做的工作感到有趣,而且要保持他们
对他们正在做的工作感到高兴,技术方面对达成这些目标有一定帮助,但这远远
不是全部,你的个人素质也有关系。
并不是说Linus是一个好小伙子,让人们喜爱并乐于帮助他,也并不是说我是
个积极外向的,喜欢扎堆儿工作,有出众的幽默感的人,对市集模式的工作而
言,至少有一点吸引人的技巧是非常有帮助的。
十. 自由软件的社会学语境
下述如实:最好的开发是从作者解决每天工作中的个人问题开始的,因为它
对一大类用户来说是一个典型问题,所以它就推广开来了,这把我们带回到准则1,
也许是用一个更有用的方式来描述:
18. 要解决一个有趣的问题,请从发现让你感兴趣的问题开始。
这是Carl Harris和原先的popclient的情形,也是我和fetchmail的情形,但
这已在很长一段时间被大家知晓了,Linux和fetchmail的历史要求我们注意的有
趣之处是下一个阶段——软件在一个庞大的活跃的用户和协作开发人员的社团中
的进化。
在《神秘的人月》一书中,Fred Brooks观察到程序员的工作时间是不可替代
的:在一个误了工期的软件项目中增加开发人员只会让它拖得更久,他声称项目
的复杂度和通讯开销以开发人员的平方增长,而工作成绩只是以线性增长,这个
说法被称为“Brooks定律”,被普遍当作真理,但如果Brooks定律就是全部,那
Linux就不可能成功。
几年之后,Gerald Weinbeng的经典之作“The Psychology Of Computer
Progromming”为我们更正了Brooks的看法,在他的“忘我(egoless)的编程”中,
Weinberg观察到在开发人员不顽固保守自己的代码,鼓励其他人寻找错误和发展
潜力的地方,软件的改进的速度会比其他地方有戏剧性的提高。
Weinberg的用词可阻止了他的分析得到应有的接受,人们对把Internet***
称为“忘我”的想法微笑,但是我想今天他的想法比以往任何时候都要引人注目。
Unix的历史已经为我们准备好了我们正在从Linux学到的(和我在更小规模上
模仿Linus的方法所验证的)东西,这就是,虽然编码仍是一个人干的活,真正伟
大的工作来自于利用整个社团的注意和脑力,在一个封闭的项目中只利用他自己
的脑力的人会落在知道怎样创建一个开放的、进化的,成百上千的人在其中查找
错误和进行修改的环境的开发人员之后。
但是Unix的传统中有几个因素阻止把这种方法推到极致。一个是各种授权的
法律约束、商业机密和商业利益,另一个(事后来看)是Internet还不够好。
在Internet变得便宜之前,有一些在地理上紧密的社团,
——摘自:
[url]http://www.tuxedo.org/~esr[/url]