Linux是颠覆性的。就是五年以前(1991),谁能想得到散布在全球各地的几千名开发者,仅靠细细的互联网连接,能够在业余时间魔术般地铸成一个世界级的操作系统呢?

反正我没想到。在1993年初Linux引起我的注意的时候,我已经在Unix和开放源代码开发领域做了十年了。我是80年代中期最早的GNU开发者之一,已经在网上发布了相当一部分软件,正在开发或协助开发好几个直到今天都在广泛使用的软件(nethack,Emacs的VC和GUD模式,xlife和其它)。我觉得我很懂行了。

Linux颠覆了许多我以为我懂的东西。当时,我已经宣扬小而专的工具、快速建模和演进式开发等Unix理念多年了。但我也相信项目到了一定复杂程度后就需要更集中地按事先计划管理。我相信最重要的软件(操作系统和Emacs之类的大型工具)需要像大教堂一样来搭建:遗世独立的圣人巨匠们牵尺引斤琢之磨之;时候不到beta版不出。

Linus Torvalds的开发风格(尽早尽多的发布,委托所有可以委托的事,对所有的改动和融合开放)令人惊奇地降临了。这里没有建造大教堂的安静和虔诚;Linux社区更像一个充满不同议程和方法的嘈杂的市集(Linux归档站点就是绝好的例子,任何人的作品都接收)。然而,一个统一稳定的系统就象奇迹一般从这个市集中产生了。

这种设计风格不但可行,而且工作得很好,对我无疑是一个巨大的震撼。在我的摸索过程中,我不仅效力与个别项目,而且努力去理解为什么Linux世界没有在混乱中分崩离析,而是以大教堂建造者们难以想像的速度茁壮成长。

到1996年中,我想我开始理解了。我有了一个测试我理论的完美机会,一个我可以有意识地用市集风格来运行的开源项目。我这样做了,结果非常成功。

这里讲述的就是这个项目的故事。我将借它来提出一些开源软件有效开发的精髓。它们并非全部源自Linux世界,但我们会看到它们如何在Linux世界中得到印证。如果我是正确的话,它们会帮助您准确理解是什么使Linux社区成为优秀软件的源泉——或许,它们还会帮助您变得更加高效。


邮件必须得通过

从1993年以来,我负责宾州西切斯特一家提供免费网络服务的小公司CCIL的技术工作。我协同创建了CCIL,并写了我们独家的多用户论坛软件——您可以用telnet连接locke.ccil.org来试一下。今天它在三十条线上支持近三千名用户。这份工作允许我通过CCIL的56K线路每天二十四小时上网——其实,这份工作事实上要求这一点!

那时,我已经习惯使用即时的互联网邮件。我发现不时地要telnet登录上公司服务器“locke”检查邮件很烦人。我想要的是把我的邮件传送到我家里的个人机器“snark”上,这样我可以在邮件到达的时候得到通知,并使用我自己的软件来处理它。

这里互联网的默认邮件输送协议SMTP不适用了。SMTP是为全时在线的机器设计的,而我的个人机器并不总在网上,也没有一个固定的IP地址。我需要一个程序在我拨号上网期间连到服务器上,把要下到本地的邮件取回来。我知道有这种工具存在,且多数使用一个简单的叫做POP的协议。现在常用的客户端邮件软件都支持POP,但那个时候,我的邮件阅读器不支持它。

我需要一个POP3的客户端软件,所以我就跑到网上找了一个。事实上,我找到了三四个。其中的一个我用了一段时间,但它少了一个看起来很明显的功能:修改到达邮件的来信地址以便正确回信。

问题是这样的:假设“locke”上一个叫“joe”的人给我发了信。如果我把信取到“snark”上,然后试图回复,我的邮件程序会高高兴兴地努力把回信发送给“snark”上一个并不存在的“joe”。通过手工修正邮件的回信地址很快就变成了一件很痛苦的事。

显然这该是电脑替我做的事。但是现有的POP客户端软件没有一个会做!这给我们带来了第一个教训:

  • 每一个好软件的起因都是挠到了开发者本人的痒处。
这或许应该是很显然的(一直有箴言道“需要是发明之母”),但软件开发人员太过经常地在那些他们既不需要也不喜欢的程序上消磨时日、换取工资。但在Linux世界不是这样子的——这或许解释了为什么Linux社区中产生的软件平均质量这么高。
那么,我立马儿投入到了一轮疯狂的编程中来写一个和现有POP3客户端竞争的软件了吗?不是!相反,我仔细检查了我拿到手的那些POP程序,自问“哪一个离我要的最接近?”因为:
  • 好的程序员知道写什么。伟大的程序员知道改写(和重复使用)什么。
虽然我不自封伟大,但我努力模仿伟大的程序员。伟大者的一个重要特点是建设性的懒惰。他们知道你需要的是结果而不是过程,而且从一个好的部分方案开始总比从零开始要容易得多。
以Linus Torvalds为例,他实际上没有试图从零开始写Linux。相反,他的代码和主意开始于PC机一个小小的类UNIX系统MINIX。最终所有Minix的代码都被拿掉或重写了——但在起步的阶段,Minix提供了那个最后成为Linux的新生儿成长的脚手架。
遵循同样的精神,我出发去寻找一个已有的、写得过得去的POP程序来作为开发的基础。
UNIX世界里的源代码共享传统一直对代码再用很友好(这也是为什么GNU项目尽管对

UNIX很有成见,还是选择了UNIX作为其基本操作系统)。Linux世界几乎把这种传统发挥到了技术上的极限;有上万亿字节的开放代码可供获取。所以花点时间在Linux世界里找个别人“差不多够好”的程序,比其它任何地方都更有可能找到。

我就找到了。加上我以前找到的,我的第二次搜索有了九个候选对象:fetchpop、PopTart、get-mail、gwpop、pimp、pop-perl、popc、popmail和upop。我第一个选用的是欧松宏(音,Seung-Hong Oh)的“fetchpop”。我把我改写邮件头的功能加了进去,并作了其它一些改进。松宏后来把这些加进了他的1.9版本。
然而几个星期以后,当我碰到了Carl Harris的“popclient”代码时,我发现我遇到了一个问题。尽管fetchpop有一些很好的新主意(例如它的后台daemon模式),它只能处理POP3协议,而且程序代码写得比较业余(松宏当时是个聪明但是缺少经验的程序员,这两个特点都有显示)。Carl的代码好一些,很专业和稳固,但他的程序缺几个重要的而且难实现的fetchpop里的功能(包括我自己写的那些)。
继续用fetchpop还是转换到popclient上来?如果转换的话,我得扔掉我已经写好的那些代码来换取一个好一些的开发基础。
一个实用的转换动机是对多种协议的支持。POP3是服务器端POP协议中最常用的,但不是唯一的。Fetchpop和那一个竞争对手都不支持POP2、RPOP或APOP,而且为了好玩,我那时已经有了添加IMAP(最新设计的、最强大的POP协议)的模糊想法。
但我还有一个更理论上的原因来认为转换也是个好主意。这是我远在Linux之前就学到的。
  • “计划扔掉一个;无论如何你都会扔掉一个的。”(Fred Brooks《人月神话》第11章)
或者换句话说,直到你第一次实现一个方案之前,你常常并没有真正理解你的问题。第二次呢,或许你已经学到了如何把它做对。所以,要想把事做对,你得准备至少重来一次[注:JB]。
[注:JB]在《编程珠玑(Programming Pearls)》中,知名的计算机科学大师JonBentley对Brooks的上述文字有如下评注:“如果你计划要扔掉一个,你也会扔掉第二个”。他说的完全正确,Brooks和Bently不仅仅指出第一次尝试往往会错,而且指出用新的方法重新开始往往比挽救一堆乱代码来得快捷。
好吧(我对自己说),对fetchpop做的修改算我的第一次吧。于是我转换了。
在1996年6月25日我给Carl Harris发送了我写的第一批popclient补丁后,我发现他一段时间之前就基本上对这个项目失掉兴趣了。项目的源代码有些陈旧了,小臭虫们流连不去。我有很多要修改的东西;我们很快同意:理所当然,我该把整个项目接手过来。
在我没有觉察的时候,这个项目升级了。我不再是试图给一个现有的POP客户端程序做些小补丁。我开始负责维护整个程序,而且我知道我脑子里冒着的新主意可能会导致一些主要的变动。
在一个鼓励代码共享的软件文化中,这是一个项目进化的自然方式。我在实践下面这个原理:
  • 如果你有正确的态度,有意思的问题会自动找上门。
Carl Harris的态度甚至更重要。他懂得:
  • 当你对一个项目失去兴趣时,你最后的职责是把它交给一个称职的继承者。
尽管Carl和我从来没有讨论过这一点,我们知道我们的共同目标是找出问题的一个最好解决方案。我们唯一的问题是我能否证明我的能力。一旦我作到了,他优雅而迅速地作了交接。我希望当这一天轮到我的时候,我也能做得同样出色。


用户的重要性

就这样,我继承了popclient。同样重要的是,我继承了popclient的用户群。拥有用户是件美好的事情。他们的存在不仅证实了你的工作正在满足一种需求,而且证实的你做的不错。通过适当的培养,他们还可能成为你的开发伙伴。

很多用户也是黑客,这是UNIX传统中的另一个强项,而Linux把它发展到了快乐极致。因为可以得到源代码,他们可以是有效的黑客。这一点对缩短调试时间会非常有帮助。给上一点点鼓励,他们会帮助诊断问题,提出建议和补丁,并以你一个人不可企及的速度帮助改进代码。

  • 把用户看作合作者是通往快速改进代码和有效调试的最佳通道。
这一点所蕴藏的能量很容易被低估。事实上,直到Linus Torvalds给我们演示之前,开源世界里几乎所有人都严重低估了它如何随用户数目而增长潜能,如何随系统的复杂度增大而更显威力。
事实上,我认为Linus最聪明、最有影响的手笔不是Linux内核本身,而是发明了Linux的开发模式。有一次当我当面向他表达这个观点时,他微笑了,安静地重复了他经常说的一句话:“我基本上是一个很懒惰的人,喜欢在其实是别人做的事情上领取荣誉”。象狐狸一样懒惰,或者象Robert Heinlein[译注:著名科幻作家]笔下的一个著名角色:太懒惰而不会失败。

回头来看,Linux方法和成功的一个先例是GNU Emacs的Lisp库和Lisp代码档案。与Emacs C核心和大多数的其它GNU工具的大教堂建造风格相反,Lisp代码群的进化是活跃的、多由用户驱动的。点子和原型经常要重写三四次才能达到一个稳定的最终形式。象Linux那种通过互联网的松散协作也很频繁。

确实,我自己在fetchmail之前最成功的一次编程可能是Emacs的VC(版本控制)模式。那是类似Linux一样与其他三个合作者仅通过电子邮件交流的一次合作。三个人中我至今只见过一个(Richard Stallman,Emacs的作者、自由软件基金会的创始人)。VC是Emacs中SCCS,RCS和后来CVS模式的前台;Emacs借此提供“单击式”的版本控制操作。它是由一个别人写的小小的、粗糙的sccsl.el模式演进而来。VC开发的成功也是因为不象Emacs本身,Emacs Lisp代码可以快速地通过多轮“发行/测试/改进”的循环。

Emacs的故事不是唯一的。其它软件也有这种双层的构架和双层的用户群:核心用大教堂模式;工具箱用市集模式。其中的一个是MATLAB,一个用于数据分析和可视化的商业工具。MATLAB和其它类似架构产品的用户一致认为,产品的开放部分——有一个巨大多样的用户群可以对其推敲的地方——才是动力、热情和创新的所在。


早发布、常发布

早发布和频繁发布是Linux开发模式中关键的一个部分。以前多数开发者,包括我,都认为这对复杂项目来说是个坏办法,因为早期版本几乎是问题版本的同义词,而你不想这么早就消耗完用户的耐心。

这个观点也促使人们普遍采取建造大教堂式的开发。如果首要的目标是尽量让用户少遇到臭虫,那么你应该六个月甚至更久才发布一个版本,在两次发布之间象狗一样拼命去调试。Emacs的C核心就是这样开发的。Lisp库实际上不是——因为在自由软件基金会所辖之外还有其它活跃的Lisp存档,提供独立于Emacs发布周期的新版本和测试版本。

那时最重要的Lisp库——俄亥俄州立大学Emacs Lisp档案——已经超前具有了今天Linux大型档案的管理精髓和许多功能。但是我们中很少有人深考过我们在做什么,以及俄亥俄档案的存在本身说明了自由软件基金会大教堂开发模式的哪些问题。在1992前后,我曾努力要把一大批俄亥俄代码合并到Emacs Lisp的官方库,但遇上政治性的麻烦,结果非常不成功。

一年以后,Linux影响逐渐扩大。显然Linux的开发者拥有一些不同的但是远远更为健康的东西。Linus的开放性开发政策正与建造大教堂的方式相反。Linux的互联网档案枝蔓繁衍,多个发行版在坊间流传。而所有这些都是由Linux内核前所未闻的发布频率所驱动的。

Linus在以最有效的合作者方式来对待他的用户:

  • 早发布、常发布,听取用户的意见。

快速发布、采纳大量用户反馈,并不怎么算Linus的创新(Unix世界历来就有这种传统)。他的创新之处是把这个办法升级到了与所开发系统复杂性相匹配的规模和强度。在早期(1991年左右),我们不是没听说过他一天发布不止一个新的内核版本!因为他比任何人都努力地培养合作开发群体、促进网上合作。他的办法生效了。

但它是怎样生效的呢?难道只有Linus Torvalds的独特天才才能实现?

我想不是的。Linus当然是个骨灰级黑客。有几个人能从零开始开发出一个企业级操作系统的内核?但是Linux并不代表任何概念上的重大突破。Linus不是(至少还没有成为)象Richard Stallman或James Gosling(Java之父)那种设计和创新的天才。在我看来,Linus更象是工程和开发的天才,有着避开臭虫和死胡同的第六感官和找到从一点到另一点最快捷径的本领。确实,整个Linux内核透露着这种特质,反映了Linus本质上保守和一切从简的设计方法。

如果快速发布和淋漓尽致的利用互联网媒介不是偶然,而是Linus对最快捷径的天才工程洞察力的有机部分,那么他试图最大化的是什么?他试图从这个机制释放出一种什么样的力量?

这样一问,答案一目了然。Linus在不断地激励和奖掖他的黑客用户们——激励来自于在参与中得到的自我实现,奖掖来自于看到他们自己工作的持续(甚至每天)进步。

Linus直接瞄准了调试和开发力量的最大化,即使牺牲程序的稳定性或因某个修正不了的严重问题导致丧失用户也在所不惜。似乎Linus相信:

  • 足够多beta测试者和合作开发者会让任何问题快速显形并很快被解决。

或者通俗一点,“只要眼球足够多,所有臭虫都好捉”。我称之为“Linus法则”。

对上述法则,我最早的表述是每个问题“都会有某个人能解决”。Linus有异议:理解和解决问题的人不一定甚至一般不是第一个发现问题的人。“一个人发现问题”,他说,“另一个人把它搞明白,而且我会作证说发现问题这一步更困难一些。”这是个重要的纠正;在下一节具体研究实际调试时我们会看到为什么。但是关键一点是,发现和解决问题这两个步骤一般都会很快完成。

我认为Linus法则中包含有大教堂模式和市集模式的关键区别。在大教堂式的编程观念中,臭虫和开发上的问题是复杂、困难和深奥的,要几个人全心全力几个月的投入才有把握已经把它们清理干净的,所以需要很长的发布周期;一旦等候已久的版本不够完美,失望就在所难免。

恰恰相反,在市集式的观念中,你预设臭虫都是简单的问题——至少在上千个共同开发者热心地琢磨每一个新版本的情况下,它们会很快就变简单了。相应地,你频繁发布来得到更多的纠错。作为一个附加效应,偶尔出个大勺子的后果也没有那么严重了。

这就是了。这也就够了。如果“Linus法则”是错误的,那么象Linux内核这样复杂的系统,经过了那么多人的敲打,应该在某一时刻已经在不曾预见的恶性互动和深藏不露的问题的重压下崩溃了。如果它是正确的,它足以解释Linux相对较少的问题,和数月甚至数年以上的持续运行时间。

或许这不该是如此一个意外。社会学家们多年前就发现了一大群同样内行(或同样白痴)观察者的平均预测要比其中随机选择一个人的预测可靠得多。他们称之为“神庙效应”。看来Linus显示了这一点甚至适用于调试一个操作系统——甚至是内核级的复杂程度,“神庙效应”也可以简化开发。

Linux情形中对“神庙效应”有帮助的一点是,任何一个项目的参与者都是自我选择的。一个早期评论指出,对Linux的贡献不是来自于一个随机的人群;他们都有足够的兴趣来使用这些软件、研究其机理、并试图解决所遇到的问题,而且真正给出显然可行的解决办法。经过了这些筛选的人一般都会有可以贡献的真才实料。

Linus法则也可以表述为“调试是可并行的”。尽管调试者们需要一个人来通讯协调,调试者们之间并不需要多少的协调。添加开发人员所带来的平方级复杂度和管理成本在这里不适用。

理论上因为调试者重复做功而导致的效率损失在Linux世界中似乎从来都不是问题。“早发布、常发布”策略的一个后果就是通过快速公步反馈修补来把重复做功最小化。

Fred Brooks(《人月神话》作者)甚至作过一个相关的非正式评论:“一个广泛使用的程序的维护费用一般是它开发成本的40%以上。令人惊奇的是,这个费用受用户数强烈影响。用户越多,发现的问题也越多。”

用户越多、发现问题越多是因为检验程序的角度也越多。当用户同时是合作开发者时,这个效应放大了。在检测问题的过程中,每个人都有一些不同的观察方法和分析工具,从不同角度逼近同一问题。“神庙效应”似乎正是因为这种多样性而有效。在调试程序这个特定的环境下,这种多样性也利于减少重复做功。

所以从开发者的角度来讲,增加更多的beta测试者不见得会减少当前最大问题的复杂程度,但会增加某个人的工具箱正好适用于该问题的几率——这样对这个人来说,这个问题其实很简单。

Linus在此之外还留有一招。如果可能存在大的“臭虫”,Linux内核的版本编号允许潜在用户选用老一点的“稳定”版本,或冒“臭虫”之险以求“实验”版本的最新功能。多数Linux黑客还没有系统地模仿这一招;但他们或许应该去模仿。给出这个选择使得两种版本都更有吸引力。[注:HBS]

[注:HBS]Linux内核的稳定版和实验版之分除了分担风险目的之外,还可针对解决发布期限问题。事实表明,当开发人员同时面临死板的功能列表和发布期限时,软件的制作质量明显降低。哈彿商学院的Marco Iansiti和Alan MacCormack指出放松其中任何一个限制均可产生可行的计划,在此表示感谢。

稳定版内核采用的是放松功能列表,但限制发布期限的策略。稳定版内核的维护者Alan Cox定期发布新的稳定版,但是不承诺何时必须解决哪个问题或加入哪个开发版新功能。

实验版内核刚好相反,采用的是放松发布期限,但固定功能列表(所谓“做完了再叫醒我”)的策略。De Marco和Lister引用的研究结果表明该策略不仅导致高质量的软件,并且平均比“保守”或“激进”开发计划都可带来更短的发布时间。

2000年初我开始怀疑我在本文先前的版本中低估了这种“做完了再叫醒我”的策略对提高开源项目生产力和质量的重要性。1999年GNOME项目为赶1.0版导致的负面影响表明,即便是开源项目,为赶进度而发布尚未成熟的代码也会严重影响到软件质量。

很有可能我们会发现,开发过程的透明性,连同“做完了再叫醒我”以及开发者的自我选择,可能是推动开源项目质量的三个同等重要的作用力。


要多少个眼球来驯服复杂度

在整体上观察市集风格很大地加速了调试和代码进化是一回事,在微观、日常的开发者和测试者行为上来准确理解怎样和为什么是另一回事。在这一节(写在原始文章的三年以后,采纳了读了本文、又对照了自身的很多开发者们的意见),我们来实打实地看一下其背后真正的机制。不喜欢技术的读者可以安全地跳到下一节。

理解这个问题的一个关键在于认识到以下重要的事实,那就是对源码知之甚少的用户所递交的问题报告往往并没有多少用处。这些用户一般只会报告表面症状;他们往往忽略了软件的运行环境,所以这些提交的报告不但会漏掉关键的背景数据,而且极少包括重现问题的步骤。

这里更深层的问题是测试者和开发者对程序的不同理解。测试者从外往里看,而开发者从里往外看。在封闭源码的开发模式中,他们都被卡在各自的这种角色里了,往往各说各的话,同时又觉得和对方交流非常困难。

开源开发打破了这种束缚,测试者和开发者基于源代码很容易建立起统一的模型,就之进行有效地交流。仅仅描述外观症状的问题报告和直接联系到基于源码抽象模型的报告对开发者的帮助是截然不同的。

如果能够在代码层给出一个对出错条件哪怕是不完整的提示性的描述,大多数臭虫在大多数情况下都是容易捉到的。当某个beta测试员指出“在某某行有一个边界问题”,或者只是“在某某条件下,这个变量溢出”,对这些代码的一个快速扫描常常足以锁定出错的准确模式并搞定一个修补办法。

所以,如果beta测试者和核心开发者都对源代码心里有数,双方的交流和合作会得到大大增强。这意味着核心开发人员的时间会节约下来,即便合作者人数众多。

开源方法另一个节约开发者时间之处来自于开源项目的典型通讯结构。我在上面用到了“核心开发者”一词;这反映了项目核心(一般很小;一个核心开发者很平常,一到三个很典型)和beta测试人员、补丁提供人员组成的项目外沿(经常上百人)的区别。

传统软件开发结构需要解决的根本问题是Brooks法则:“在延期的项目添加程序员只会延期更久”。普遍来讲,Brooks法则认为,随着开发人员数目的增加,项目的复杂程度和通讯成本按平方增加,而业绩仅以直线增加。

经验表明,臭虫大多集中在不同人写的代码的界面上;而一个项目的通讯协调成本一般按照人与人之间的交流渠道数量增加。这是Brooks法则的基础。也就是,问题随开发者之间通讯路径数目的增加而增加,而后者与开发者数目是平方关系(更准确地说,遵从公式N*(N-1)/2,这里N是开发者的数目)。

Brooks法则的分析(以及它引起的开发团体中对人数过多的恐惧)基于一个潜在的前提:项目的通讯结构必须是一个完整的图,每个人都与其他所有人交接。但是在开源项目中,外沿开发者做的实际上是平行分离的子项目,彼此交接甚少;代码变动和臭虫报告都流经项目的核心,只有在小小的核心团体中,才需要完整的Brooks通讯开销。

由于一个错误常常可以产生多个不同的症状,在用户使用习惯和环境细节不同时有不同的表现,这使得源代码层次上的问题报告往往非常有效。这类错误一般正是那些复杂和微妙的臭虫——那些最难重现并难以用静态分析捕捉的,并在软件中制造长期问题的祸根(比如动态内存管理错误或随机的中断窗口错误)。

一个测试者提供的对此类错误尝试性的源码级诊断(例如:“看起来第1250行的信号处理部分存在一个窗口”或者“你在哪里把缓冲区清零了?”)可能会成为对这些部分代码熟视无睹的开发者同时解决七八个不同症状的关键线索。此时,往往无法判定症状和臭虫的对应关系,但是多发布使得我们无须去一一了解。其他用户很快就会发现问题是否不再出现。很多情况下,源码级的问题报告使得症状无须明确被哪个补丁解决而自然消失。

复杂的多症状错误也常常会有从表面症状联系到内在臭虫的多个跟踪途径。一个特定的开发者或测试者所能追寻的跟踪途径可能取决于这个人的具体环境细节,也很可能随着时间的改变发生不便预测的变化。实际上,每一个开发者和测试者在寻找一个症状的病原时都是在检查该程序的状态空间的一个“半随机”集合。臭虫越微妙越复杂,此人技能和所追寻空间相关的保证就越小。

对于简单的容易重现的臭虫,那么,重音要放在“半”上面而不是“随机”上面;此时,调试技能和对代码、框架的熟悉程度是最重要的。但对于复杂的臭虫,重音就要放在“随机”上面。在这种情况下许多人同时追踪要比少数人串行追踪有效的多——即使这少数人的技能水平高的多。

要是从不同的表面症状挖掘到臭虫的跟踪途径难度不一、难以从观察症状来预测的话,并发追踪的效果就会非常之明显了。一个持续追踪这些路径的开发者在开始可能会遇到一个简单的路径,也同样可能会遇到一个复杂的路径。另一方面,试想有许多人在快速发布下平行地来检查这些追踪路径,那么其中某人很可能会碰上最容易的路径,在短的多的时间里解决这个问题。维护项目的人会看到这个,发行一个新版本;其他在更困难的路径上追踪同一个臭虫的人们就可以在花费太多时间之前停下来。[注:RJ]

注:RJ]给我提供不同难度跟踪途径的读者推测此类多表症问题跟踪的难易程度呈“指数”分布(我把其理解为高斯或泊松分布,且同意他的看法)。如果有实验数据可以给出类似的分布曲线,将会非常有价值。如果此曲线与等概率分布的平行线差别甚远,那么即使在一个开发者的情况下,也应该模仿市集模式,采取限定在一个表症上跟踪时间的策略。坚持有时不一定是件好事……


玫瑰何时不再是玫瑰

研究了Linus的作法并形成了一个它何以成功的理论后,我决定在我的新项目(当然没有Linux那么复杂和宏伟)里有意识地测试这个理论。

但我做的第一件事是把popclient重组和简化了许多。Carl Harris的代码实现得很好,但是有一种在C程序员中常见的多余的复杂。他把代码放在了中心位置,数据结构作为辅助。结果代码很漂亮,但是数据结构设计得潦草甚至丑陋(至少按我这个LISP老手的标准来看)。

然而,除了改进代码和数据结构设计以外,我的重写还有另一层目的,那就是把它进化成一个我完全理解的东西。要是你不完全理解一个程序,维护起来可不是好玩的。

于是在最初的一个月左右,我只是在按照Carl的章程做事。我作的第一个重要改变是添加了IMAP支持。我实现这点的方法是:把协议的具体部分做成插件形式,用一个通用的驱动来根据不同协议调用不同插件的方法表(分别针对POP2、POP3和IMAP)。这些变动都示范了下面这个程序员们应该记住的通用原则(尤其像C这种本身不支持动态数据类型的语言):

聪明的数据结构和愚蠢的代码要比反过来好的多。

Brooks的第九章:“给我看你的流程图而隐藏你的数据结构,我会继续糊涂着。给我看你的数据结构,我一般就不需要你的流程图了;它们将显而易见”。经过三十年的文化和术语的变迁,这个观点仍然正确。

这时(1996年9月初,大约开工后六个星期),我开始想这个程序大概该换个名字了——它毕竟不再仅仅是一个POP客户端软件。但是我在犹豫,因为在设计上还没有什么真正的新东西。我的popclient版本还需要发展出它自己的特征。

当popclient学会了怎样把取到的邮件再通过本机SMTP端口转发的时候,这一点迅速改变了。我过一会儿再细谈这个。但是首先:我说过我决定用这个项目来测试我关于Linus的成功理论。(您也会问)我是怎样做的呢?在以下方面:

  • 我早发布和常发布(几乎从未低于十天一次;高强度开发的时候,一天一次)。
  • 我把每个和我交流有关fetchmail的人加进了我的beta测试名单。
  • 每当我发布一个版本,我就给beta名单发送一个内容丰富的通告,鼓励大家参与。
  • 我听取beta测试者的意见,在设计上征求他们的看法,当他们送交补丁和反馈时给予鼓励。

这些简单的办法立杆见影。从项目一开始,我就收到很多那种多数开发者梦寐以求的高质量的臭虫报告,经常还附带了好的补丁。我收到过深思熟虑的评论、粉丝的邮件,还有高明的功能性建议。这说明:

  • 将你的beta测试者作为“最有价值资源”来对待,他们就会成为“最有价值资源”。

Fetchmail庞大的beta测试名单(fetchmail-friends)成为衡量其成功的一个有意义的指标。在我最近一次修订这篇文章的时候(2000年11月),它有287名成员,而且每个星期在增加两三名。

实际上,当我在1997年5月下旬改写的时候,我发现这个名单由于一个有意思的原因,从它近300的巅峰开始流失成员了。一些人要求我把他们从名单中去掉,因为fetchmail对他们来讲近乎完美,他们再也不需要阅读这个邮件列表了!或许这是一个成熟市集风格项目正常生命周期的一部分。


Popclient变成了Fetchmail

当Harry Hochheiser把他转发邮件到客户机SMTP端口的草稿程序发给我的时候,这个项目的真正转折点来临了。我几乎马上意识到,这个功能会让其它所有的邮件递送模式成为历史。

许多星期以来,我一直在按照原来的架构改进fetchmail,但总有些不舒服的感觉。我感觉目前的接口设计还可以用,但是不够干净漂亮,而且到处是微不足道的选项。把收取的邮件直接输出到一个邮箱文件或转到标准输出里的选项尤其让我心烦,但我想不出为什么。

(如果你对互联网邮件的技术细节不感兴趣,可以安全跳过下面的两个段落。)

受到SMTP转发的启发,我终于看清了。Popclient在试图做太多的事情。它被设计成了既是一个邮件传输工具(MTA),又是一个本地投递工具(MDA)。有了SMTP转发功能,它就可以摆脱MDA的负荷,像sendmail那样专心只作MTA,并把邮件的本地投递留给其它程序来完成。

几乎每一个支持TCP/IP的平台上都预留了25号端口,为什么还要去折腾MDA的复杂配置或邮箱的“锁定-添加”呢?更有甚者,通过SMTP转发意味着收到的邮件看起来几乎和正常的SMTP邮件一样。这正是我们想做到的。

(返回到高一层次上……)

即使读者没看懂上面的技术细节,这里也有几条重要的经验可以学习。首先,这个SMTP转发的点子是我有意模仿Linus方法的最大收获。一个用户给了我这个好点子——我需要做的仅仅是理解它的含义。

  • 自己拥有好主意是好事,认识到来自用户的好主意也是好事。有时候后者会更好。

很有意思的是,如果你谦虚地坦白别人的贡献很多,你很快就会发现外面的世界不会这么看。他们会认为是你创造了这一切,只不过是你太谦虚而已。Linus就是最生动的例子。

(当我在1997年的第一次Perl大会上发言时,黑客大亨Larry Wall正坐在前排上。当我讲到上面的那句话时,他以激动的口吻喊了起来,“说出来,说出来,哥们!”全场都笑了,因为他们知道这一点对Perl的发明者[译注:即Larry Wall]也不例外。)

在我发扬这种精神把项目运行了几个星期以后,我开始得到类似的赞扬——不仅来自我的用户,而且来自于其他有所耳闻的人们。我把其中一些邮件收藏了起来;要是什么时候我开始疑惑我生命的意义时,我就拿出来再看看 :-)。

但是有两条基本的、非政治性的经验对各种设计都适用。

  • 最有突破和创新的方案常常来自于意识到你把问题的模型弄错了。

我之前想继续把popclient做成一个支持五花八门的本地递送模式的MTA/MDA时,就是试图在解决错误的问题。Fetchmail应该重新被设计为一个纯粹的MTA,作为正常SMTP邮件传输路径的一部分。

当你在开发中碰到死胡同时——当你绞尽脑汁要超越下一个补丁的时候——一般来讲你这时该问的不是你的答案对不对,而是你的问题对不对。或许你的问题需要重新定义。

嗯……我重新定义了我的问题。显然,正确的路子是

  1. 加入SMTP转发支持,
  2. 把它设置为默认模式,
  3. 最终把其它的传递模式都去掉,尤其是传递到文件和标准输出这两种模式。

这第三步让我犹豫了一段时间,担心会影响那些依赖于此类模式的popclient老用户。理论上,他们可以马上用.forward文件或其它非sendmail方式的类似功能来获得相同的效果。但在实践中,这种转换可能会让人头大。

但事实证明,做完这三步后好处非常明显。驱动代码中毛病最多的地方消失了。配置选项也大大简化——不再需要围着系统MDA和用户信箱打转,也不再需要担心背后的操作系统是否支持文件锁定。

而且,唯一可能丢失邮件的情形不见了。以前,如果你指定递送到文件而磁盘满了的话,你的邮件就丢了,而这在SMTP转发中不会发生,因为除非邮件成功传送或至少缓存了,SMTP的聆听端不会给以确认。

同时,性能也提高了(尽管不是你运行一次就能感觉到的)。改变后另外一个不小的好处是说明手册简化了许多。

后来,我为了对付一些涉及到动态SLIP(Serial Line Internet Protocol,串行线互联网协议)的晦涩情形,不得不把递送到用户指定MDA的功能加回来,但做起来简单多了。

说明了什么道理?在不损失效率的情况下,不要犹豫把多余的功能扔掉。Antoine deSaint-Exupéry[译注:著名法国作家,著有儿童故事《小王子》等](他不在写作经典儿童图书的时候是个飞行员和飞机设计师)曾说过:

  • “设计达到完美的时候,不是增加得不能再增加了、而是减少得不能再减少了”。

代码变得既优良又简单的时候,标志着它上正轨了。在这个过程中,fetchmail有了它自己的设计特色,脱离了上一代的popclient。

到了该换名字的时候了。新的设计和老的popclient相比,更像是sendmail的对偶;二者都是MTA,但sendmail是往外投递,新的popclient是接过来再投递。所以在动工两个月后,我把它重命名为fetchmail。

在这个SMTP转发功能如何进入fetchmail的故事里,有一个更普遍的经验。那就是不仅调试是可并行的;开发和(在可能令人吃惊的程度上)搜索设计空间也是。当采用快速短周期的开发模式时,开发和添加新功能在某种意义上就成为调试改错的一个特例——改正软件原始设计中的“功能不足错误”。

即使在高一层次的设计上,有许多共同开发者在你产品的设计空间附近随机行走将会很有价值。想象一下:一滩水是怎样发现下水口的,或者更恰当一点,蚂蚁怎样发现食物的?本质上是分散、搜索,并通过一个可扩展的通讯机制来协调。这一点很管用,就像Herry和我一样,你们随行中的一个很可能会发现有一个宝藏就在附近,你只不过太专注了一点而没有看到。

大教堂与市集(续)

Fetchmail长大了

现在我有了一个整洁新颖的设计;我知道代码工作良好因为我每天使用;beta测试名单繁荣热闹。我慢慢明白了我不再是在做一个可能只对几个人有用的琐碎的个人编程——我在主持一个所有使用SLIP/PPP邮件接口的Unix用户都需要的程序。

带有SMTP转发功能的fetchmail在竞争对手面前表现强劲,并很可能成为那种在它的功能领域里鹤立鸡群的经典程序,那种让对手们不仅被放弃而且几乎被遗忘了的“领域杀手”。

我觉得这种结果不是你想达到就能达到的。你需要某种超级的设计构想,自然而然地、甚至命中注定地把你推到那里,而找到这种构想前提无非就是要有很多想法可以去尝试——或者有工程眼光把其他人的点子发挥到其原作者根本想象不到的地步。

Andy Tanenbaum最先想到了做一个运行于IBM PC机的简单Unix作为教学工具(他称之为minix)。Linus把Minix的概念推进到了Andy可能想都想不到的地步,使其变成一个如此神奇的东西。与此类似(不过是规模小些),我从Carl Harris和Harry Hochheiser那里借来主意并努力推进它们。我们都不是“原创”——那种人们浪漫想象中的天才。但是话说回来,多数科学、技术和软件的进展都不是由“原创”或者黑客神秘主义中的超级天才完成的。

这两个项目的结果都一致是那种很眩目的东西——那种每一个黑客毕生追求的成功!而且这意味着我将不得不把我的标准设得更高。为了让fetchmail达到我预想的目标,我不仅要为自己,而且还要为别人编程,同时保持程序简洁、健壮。

意识到这点之后,我所写的第一个也是绝对最重要的一个功能是集体收发(multidrop)——从一群用户的集体信箱里把累积的所有邮件取来,然后把每一封分发给单独的收信人。

我决定添加集体收发功能,一部分是因为用户们吵着要,但主要还是因为我觉得它会迫使我更全面地处理地址问题,从而甩掉单信发送模式中的臭虫。结果如我所愿。我花了很长的时间才把RFC822的地址解析搞定,不是因为它的哪一部分很难,而是因为它涉及了一堆相互关联的烦人细节。

然而集体收发也成为了一项优秀的设计决定。我是这样知道的:

  • 任何一个工具都应该达到预期的用处,但是一个真正优秀的工具会带来预期不到的用处。

集体收发一个不曾预期的功能是可以在网络连接的客户端建立邮件列表、管理列表成员和展开别名。这样,通过ISP上网的个人不必持续访问ISP方的别名扩展文件就可以管理一个邮件列表。

我的beta测试员们要求的另一个重要功能是支持8位的MIME操作。这个很容易,因为我已经很小心地保持了代码的8位兼容性(没有强迫ASCII字符集中没有使用的第8位比特去携带程序中的信息)。不是因为我预料到了这个功能要求,而是遵循了另一个原则:

  • 在写任何接口软件的时候,花点功夫尽可能不要干扰数据流——除非用户强迫你,永远不要扔掉任何信息!

要是我没有遵守这个规则,8位MIME支持会很困难且毛病不断。事实上,现在我所需要做的仅仅是读一下MIME标准(RFC1652),然后添加一条小小的文件头生成规则。

在一些欧洲用户的要求下,我添加了一个选项来限制每次连接能下载的邮件数目(这样他们可以控制他们昂贵的电话费)。我对这件事抵制了很长一段时间,直到现在也不是完全满意。但是如果你是给外边的世界写程序,你就不得不聆听你的顾客——就算他们不付你钱也是这个道理。


Fetchmail带来的其它几条经验

在回到更广义的软件工程问题之前,还有几条fetchmail经历中的经验值得细想。非技术性的读者可以安全地跳开这一节。

Fetchmail用户配置文件(rc)语法中包括了一些完全不解析的、可选的“噪音”关键词。它们所带来的类似英语的配置文件语法比把它们全部梳理掉之后所剩下的传统“关键词-对应值”语法要可读得多。

这开始于一个深夜实验——那时我注意到rc文件的定义看起来多么像一个微型的命令式语言。(这也是我把popclient原有的“server”关键词换成“poll”的原因。[译注:server是名词“服务器”,poll是动词“检查”,后面跟随的是邮件服务器名。改成poll使配置文件读起来更象句子。])

在我看来,努力把这个微型指令语言做得更像英语可能会使它更容易使用。那时,尽管我支持“把它做成一门语言”的设计流派,比如Emacs、HTML和许多数据库引擎设计的那样,我还不是特别热衷于“类似英语的”语法。

传统上,程序员们倾向于选用简洁紧凑、完全没有冗余的控制语法。这是计算资源昂贵时期的文化遗留。那时,解析过程不得不尽可能的廉价和简单,大概有50%冗余的英语明显是一个非常不合适的模型。

这不是我一般避免英语式语法的原因;我在这儿提起它正是为了打破这个看法。有了便宜的主频和处理器,简洁不应该为了简洁而简洁。现在一门语言对于人的方便比对于计算机处理的方便更重要。

然而我们还有需要小心的原因。其中之一是解析过程的复杂性成本不能被提高到富产臭虫和困惑用户的程度。另外,试图把一门语言的语法做得像英语经常迫使它的“英语”严重扭曲变形,以至于对自然语言的表面模仿变得像传统语法一样令人困惑。(你可以在许多所谓的“第四代”和商业数据库查询语言中看到这个坏效果。)

Fetchmail配置文件的语法似乎避免了这些问题,因为它的语言空间极为有限。它离一个通用的编程语言还很远;它需要表达的内容也很简单。所以在这里,由语言扭曲引起困惑的可能性很小。我觉得这里可能有一个更普适的经验:

  • 当你的语言离图灵完备还差得远的时候,不妨给语法加点“糖衣”包装。

另一条经验是关于隐藏和安全性的问题。一些fetchmail的用户要求我改一下软件来把储存在rc文件里的密码加密,这样入侵者就不会在无意中看到它们。

我没有照办,因为这实际上并不会添加保护。不管怎样,任何一个有权读你rc文件的人都可以像你一样来运行fetchmail打开你的信箱——如果他们真的来找你的密码,他们也可以从fetchmail的代码中剥离出必要的解码器来得手。

所以,在rc文件中使用加密的密码只不过是给那些不怎么用心思考的人一种虚假的安全感。这里的一般规则是:

  • 一个安全系统的安全性取决于其秘密的安全性。小心伪秘密。


市集风格的必要前提

这篇文章的早期审阅者和试验听众们不断希望了解市集开发风格的成功前提,包括项目领导人的素质和他开放项目和开始建立合作者社区时的程序代码状态。

很显然,市集风格不能帮助你从零开始编程[注:IN]。你可以使用市集风格测试、调试和提高你的代码,但是直接以市集模式来孕育一个项目会是很困难的。Linus没有这样试过,我也没有。你新生的开发者社区至少需要一个能运行和测试的东西。

[注:IN]另外一个和市集风格能否帮助你从零开始一个项目的话题是市集风格中能否产生创新。一些人声称市集风格缺乏强有力的领导,因此只能模仿或改进已有的工  程方法,但无法孕育创新。该观点最有代表的作品要属“万圣节档案”了。这是微软关  于开源现象的两篇内部备忘录,其作者认为,Linux只不过是追着Unix系统的尾巴跑,“(一旦追上了后者开始领跑),庞大的管理开销便会让其前进得非常缓慢”。

这个观点和事实完全不符。甚至万圣节文档的作者自己后来又指出“往往新点子首先在Linux中被实现,然后再被搬到其它平台。”

其实这也不是什么新现象。把上述论断中的“Linux”换成“开源项目”,我们可以发现来自开源社区的Emacs、万维网甚至英特网本身,不是追谁的尾巴跑出来的,也没有看到任何庞大的管理开销。现在开源项目不断创新给我们带来的是前所未有的广阔选择空间。随便举个例子,GNOME项目中关于图型界面和对象技术的创新已经受到大量的商业关注。其它例子举不胜举,随便那一天看一下Freshmeat.net就可证明。

该论断还包含的一个更根本的错误,即隐含地假设大教堂模型(或市集模型,或任何其它管理结构)可以有效的产生创新。这一点根本站不住脚。群体并没有更创造性的眼光。即便是市集模式中自愿组成的架构师团体往往也缺乏新点子,更不用说那些需要在权力平衡中考虑自身利益的公司委员会了。相反,创新来自个体。其周围的社会机制能做得最好的就是给予响应——去培育、奖励并严格的测试它们,而不是排挤它们。

所以,不论是软件还是其它任何领域,创新的关键在于如何去激发更多人提供新点子,以及如何不去排挤它们。

显然,假定大教堂开发模式有利于创新,而门槛低、流程通畅的市集模式不利于创新,是很荒谬的。如果创新的起点是一个人加一个点子,那么一个可以使该主意吸引成百上千合作人的环境将不可避免地优于一个为继续工作于该点子而不至于被解职,其主人不得不通过政治性的手腕将其推销到上级管理层的环境。事实是,那些使用大教堂方式机构的创新史表明,来自其自身的创新极为少见。大公司依赖大学研究成果作为其新点子(这也是“万圣节文档”作者对Linux有力地加速和吸收学术研究的不安),或收购那些基于某项创新而成立的小公司。这两种情况,创新均非来源于大教堂文化。恰恰相反,很多以类似方式买来的创新被“万圣节文档”作者所鼓吹“庞大的管理开销”所扼杀了。

上面讲的是负面的例子。这里更应该把一个正面的例子奉献给读者。我建议大家试试下面的方法:

  • 定下一个你可以严守的创新准则。比如“看到了我就知道”就满足这个测试的条件。
  • 再定下任何一个和Linux竞争的商业操作系统,和一个其开发工作进展的最好的消息渠道。同时观察该消息渠道和Freshmeat一个月,每天各自记下两者中你认为是创新的新点子数。三十天后,统计这两个数字。
我写这些文字这天,Freshmeat有22条软件发布信息,其中有3条看起来部分推进了现有技术。这只是Freshmeat上较差的一天。然而,如果哪个读者能在一个月中在某个商业渠道上找出类似的发现,我都会非常吃惊。

当你开始社区建设的时候,你要能够给出一个可行的承诺。你的程序不一定要工作得非常好。它可以是粗糙的、问题多多的、不完整的、缺少文档的,但它不可或缺的是

  1. 能运行
  2. 能说服潜在的合作者,它可以在可预见的将来进化成真正漂亮的东西。

Linux和fetchmail开放的时候都带有强劲、吸引人的基本设计。许多像我描述的那样来思考市集模式的人正确地认为这一点很关键;于是进而断定在项目领导人身上,高度的设计灵感和聪明不可或缺。

但是Linus的设计来自于Unix,我的最初设计来自于先前的popclient(尽管它后来变化很大,按比例来说比Linux的大的多),那么一个市集风格项目的领导人/主持人真的一定要有杰出的设计天才,还是只需掌握四两拨千斤的方法来利用大众的设计才能呢?

我认为项目主持人能否想出杰出灿烂的设计不是很关键,但绝对关键的是,他必须能够慧眼识别出他人的优秀设计或想法。

Linux和fetchmail项目都显示了这方面的证据。Linus,(像前面讨论过的)尽管不是一个特别有原创性的设计者,却展现了识别优秀设计并把它集成到Linux内核里强大才能。我也已经描述了在fetchmail里的最有力的一个设计思想(SMTP转发)怎样来自于另一个人。

这篇文章的早期读者捧我的场说我容易低估市集项目里原创设计的价值,因为我自己不缺创造性,因而就想当然的习惯了。这话大概有一点点的真实性在里面;设计(而不是编码或调试)确实是我的强项。

但是在软件设计里表现聪明和创造力的问题在于它会形成一种坏习惯——当你应该保持代码稳固和简单的时候,你开始放任地把它们搞得好玩和复杂。我曾经因为犯了这个错误把项目搞砸过,但是我在fetchmail里做到了避开这个错误。

所以我相信fetchmail项目的成功有一部分是因为我克制住了自作聪明的习惯;这(至少)反驳了设计的原创性是市集项目的成功关键。再想一下Linux,假设Linus在开发中试图整出操作系统设计的根本性创新,做出来的内核还会像我们现在的这么稳定和成功吗?

当然一定的设计和编码水准还是必要的,但是我认为几乎每个认真考虑发起一个市集型项目的人已经超出了这个基本要求。开源社区内部的声望机制给人们一种微妙的压力,就是不要发起自己不能坚持下去并搞好的开发项目。迄今为止,这一点似乎工作得很有效。

另外有一个和编程能力无关的技能,我认为对于市集型项目来讲和设计才能一样的重要——甚至可能更重要,那就是一个市集项目的主持人或领导者必须有良好的人际交流技能。

这应该是显而易见的。要建设一个开发社区,你需要吸引人群,让他们对你所做的感兴趣,并且让他们对自己的工作量舒心。要做到这一点,高超的专业技能会起很大的作用,但远远不是故事的全部,你所展现的人格也很重要。

Linus是一个平易的人,让人们喜欢他、想帮助他——这不是巧合。我是个活泼外向的人,喜欢和人群打交道,有着一些现场喜剧演员的直觉和本事——这不是巧合。要使市集模式运行起来,你最好还能有些让别人喜欢你的本领。


开源软件的社会语境

这句话写到了实处:最好的程序因作者日常问题的个人解决方案而开始,因一大批人正好都有这个问题而流行。这把我们带回了第一条经验的内容,用一种或许更有用的方式来表达是:

  • 要解决一个有意思的问题,首先找到一个你觉得有意思的问题。

Carl Harris和先前的popclient如此,我和fetchmail也是如此。但是这点大家已经明白很久了。Linux和fetchmail的历史看来要求我们关心的是另外一个有意义的话题,即在下一个阶段——在用户和合作者形成了庞大活跃的社区时的软件的进化。

在《人月神话》中,Fred Brooks表述了程序员的时间是不能简单进行叠加的;添加开发人员的做法只能使得已经延期的软件项目更为延期。像我们前面提到的,他论述了项目的复杂程度和通讯成本按开发人员数目的平方增加,而业绩仅以直线增加。Brooks法则被广泛的认同为真理。但在这篇文章里,我们已经探讨了开源开发过程在好几处破除了Brooks规则的前提假设——而且事实证明,如果Brooks法则统领一切,Linux就不可能发生。

以事后之明来看,Gerald Weinberg的经典《计算机编程的心理学》对Brooks法则作出了一个关键的修正。在他对“无私编程”的讨论里,Weinberg注意到一些地方的开发人员不对自己的源码画地为牢,而是鼓励他人在其中寻找错误和指出改进的余地——在这些地方,改进比别处进展得明显快很多。(最近,Kent Beck的“极度编程”技术——把编程者配对让他们互相监督——或许可以看作是强制这一效果的尝试。)

Weinberg的用词可能让该结论未获得应有的认可——把网络黑客说成毫无私心未免让人莞尔。但是我认为他的结论在今天看起来比以往任何时候都更让人信服。

市集模式,借助“无私编程”效果的极致动力,有力减弱了Brooks法则的效果。Brooks法则背后的原理没有被推翻,但是庞大的开发者群体和廉价的通讯所带来的前所未有的准线性可扩展性,开始将其效果淹没。这就像牛顿式的和爱因斯坦式的物理之间的关系——旧的系统在低能量下仍然有效,但当质量和速度变得足够大的时候,就得到了如同核爆炸或Linux那样的惊奇。

Unix的历史应该使得我们对研究Linux的结果(和我在小规模上有意拷贝Linus的方法所实验确认的结果)有了心理准备。这是说,虽然编程基本上仍是一种个人封闭的活动,真正高超的程序来自于借助整个社区的注意力和脑力。一个在封闭的项目中只使用自己脑力的开发者,将会输给一个知道怎样创造一个开放和进化式环境的开发者、一个知道从中吸收成千上万人的探索设计空间的反馈、编码贡献、臭虫检测和其它改进的开发者。

但是有几个因素阻止了传统的Unix世界把这个方法发挥到极致。一个是各种软件许可、贸易秘密和商业利益的法律限制。另一个(回头来看)是互联网还不够好。

在便宜的互联网普及之前有过一些地域性的紧密团体,在文化上鼓励Weinberg的“无私编程”,使得一个开发者可以容易地吸引到一批有水平的“军师”和合作者。贝尔实验室、麻省理工的人工智能和计算机实验室、伯克利加州大学——这些成为了传奇性的和依然强劲的发明家园。

Linux是第一个有意识地并成功地把全世界当作智囊库使用的项目。我不认为Linux的孕育期与互联网的诞生重叠是一个巧合。Linux在1993-1994之间网络服务业起步和对互联网的主流兴趣爆发的同期脱离了它的婴儿时代也不是巧合。Linus第一个学会了如何运作普及的网络连接所促成的新规则。

虽然便宜的互联网是Linux模式进化出来的必要条件,我觉得它还没有构成充分条件。另一个关键的因素是一种领导风格和一套合作制度的建立——使得开发者可以吸引合作者并在这个媒介中获取最大程度的收益。

但什么是这种领导风格、什么是这些制度呢?它们不可能是基于权力关系的——就算是可能,强制性的领导不会产生我们所看到的成果。在这个题目上,Weinberg很恰当地引用了19世纪俄罗斯无政府主义者Pyotr Alexeyvich Kropotkin的自传《一个革命者的回忆录》:

成长于一个农奴主的家庭,我进入社会后,像我那个时候所有的年轻人一样,很是相信领导、命令、训斥、惩罚等等的必要性。但是在早期我不得不管理重要的事业和对付[自由的]人们的时候,在每个错误都会立刻导致严重后果的时候,我开始领悟到按指令的原则行事与按共同理解的原则行事之间的区别。前者在阅兵式中运行得令人崇敬,然而就真实的生活而言,它却一文不值;而且目标只有通过许多共同意志的竭诚努力才能实现。

这个“许多共同意志的竭诚努力”正是Linux这种项目所要求的;在这个我们叫作互联网的无政府主义者天堂里,对志愿者们行使“指令的原则”事实上是不可能的。要有效地运作和竞争,想要领导协作性项目的黑客们不得不学会怎样按照Kropotkin的“共同理解的原则”里模糊地提出的模式,招募和激励活动中的相关社区。他们必须学会使用Linus法则。[注:SP]

[注:SP]除了Kropotkin对“指令的原则”的批判和Linus法则,关于社会组织的内在机制问题还存在更广泛的讨论。其中包括另一个众所周知的软件工程定理——Conway定理,其通俗地表述就是“如果分四个小组去开发一个编译器,得到的会是个四遍编译器”。其最初的描述更为一般化:“软件产品的体系结构必然是其开发机构内在通讯结构的缩影”。简单说来就是:“方法决定结果”,或者“过程演变为产品”。

同样有必要指出的是开源社区存在多层与其功能吻合的组织结构,网络无处不在。除了英特网本身,成员间还存在一个分布式、松耦合的点对点网络,具有多重冗余性和可降级。在这两个网络中,节点的重要性只取决于外界愿意和他合作的程度。

其中的点对点网络对于开源社区惊人的生产力至关重要。以下的SNAFU法则又进一步发展了Kropotkin解释权力关系的尝试:“真正的交流只能在平等的个体间存在;下级从上级得到更多回报的可靠方式是通过顺耳的谎言而非事实真相。”团体项目的创新最终依赖于真正平等的交流,因此,会受到权力关系的严重阻碍。开源群体不存在权力关系的事实从反面告诉了我们权力关系导致的修正错误的可怕代价、生产力的底下和机会的丧失。

更进一步,SNAFU法则预测在基于权力的机构中,随着流入决策层的顺耳谎言越来越多,决策者和现实之间的脱节将越来越严重。这个结果在传统软件开发中扮演的角色显而易见,就是下级极力掩饰、无视及淡化问题,做出的软件将成为灾难。

我早先引用了“神庙效应”作为Linus法则的一个可行的解释。但是不可避免自我呈现出的一个更有力的类比是生物学和经济学中的自适应系统。Linux世界在很多方面都接近自由市场或生态系统:其中的自私个体都试图将自身的利益最大化,但在这个过程中形成了一个自我纠正的自发秩序,其周密度和有效性不管多少中央计划都无法与之媲美。那么,这里就是寻找“共同理解的原则”的地方。

Linux黑客们最大化的这个“利益函数”不是经典经济学上的,而是他们自我的满足和在其他黑客中的声望这些摸不到的东西。(有人或许可以把他们的动机称为“利他的”,但这忽略了利他主义自身对利他主义者就是一种自我满足这一事实。)这样运作的自愿者文化其实也很常见;我长期参与的另一个就是科幻粉丝族。不像黑客族,他们早就明白地认识到了“自我彰显”(ego-boosting,或在其他粉丝中增强个人的声望)是志愿者活动背后的基本动力。

Linus,通过成功地把自己定位为一个主要由其他人来开发的项目的看门人,以及培养对这个项目的兴趣直到它可以自我维持,表现了对Kropotkin“共同理解的原则”的敏锐把握。上述对Linux世界的类经济学视角使得我们能够看到这种理解是如何应用的。

Linus方法其实就是利用“自我彰显”来创造有效的市场。是“自我彰显”把单个黑客的自我利益最大化行为紧密地和那些只有通过持续合作才能达到的困难目标绑在一起。通过fetchmail项目,我证明(尽管在小规模上)可以通过复制他的方法产生出好结果。或许我甚至做得比他更有意识和更系统一点。

很多人(尤其是在政治上不相信自由市场的那些)会以为自我驱动的个人主义者们形成的文化会是支离破碎、占山为王、低效浪费、秘密诡异和充满敌意的。但是这个设想显然被(只举一个例子)Linux文档的惊人的广度、深度和质量所证伪。既然程序员痛恨写文档是众所周知的,上述事实简直是奇迹。Linux黑客们是怎样生产出这么多文档的呢?显然,Linus自我彰显的自由市场在产出优良的、协同的行为上优于商业软件厂商的大笔资金驱动的文档工厂。

Fetchmail项目和Linux内核项目都表明,通过适当地表彰众多其他黑客的成就,一个有力的开发/协调者可以使用互联网来收获拥有许多合作者的好处,而不至于让项目陷入嘈杂的混乱。所以针对Brooks法则,我反过来建议下面的一条:

  • 如果开发的协调者有一个至少和互联网一样好的通讯媒介,而且懂得如何不通过强迫来领导,那么多个头脑不可避免地优于一个头脑。

我认为开源软件的未来会更多地属于那些懂得如何运行Linus规则的人们,属于那些告别大教堂来拥抱市集的人们。这不是说个人的远见和才华不再重要;而是,就我看来开源软件的前沿会属于那些开始于个人的远见和才华,然后通过有效地建设相关志愿者社区来扩展放大的人们。

或许这不仅是开源软件的未来。要对付一个问题,没有闭源的开发者可以比得上Linux社区所能驱动的才能之众。极少有人甚至能雇得起那些对fetchmail作出了贡献的200(1999:600, 2000: 800)多人!

也许,开源文化最终胜利的原因不是因为合作在道德上正确或软件“劳役”在道德上错误(假设你相信后者,Linus和我都不),而只是因为开源社区可以在一个问题上投入多几个数量级的技术工时。闭源世界无法赢得这场进化式的军备竞争。


关于管理和马其诺防线

原始于1997年的《大教堂和市集》文章以上述预见结束——程序员/无政府主义者的幸福网络群体胜出并压倒了传统闭源软件的阶层化世界。

然而,很多怀疑者并不信服;他们提出的问题值得我在这里做出回应。多数对市集模式的反对归结到以下观点:市集模型的鼓吹者们低估了传统管理促进生产率的效果。

老脑筋的软件开发经理经常指责开源世界里项目组创建-变动-解散的随意性大大抵消了开源社区对单个闭源开发机构在人数上的明显优势。他们会指出对软件开发真正重要的是长时间里不懈的努力和多大程度上顾客可以预期对产品的持续投资,而不仅仅是多少人往锅里扔一块骨头让它炖着。

没有疑问,这条争论有一定道理;实际上,我在“魔法大熔炉(The Magic Cauldron)”一文中就已经说明预期的未来服务价值是软件产业经济的关键。

但是这个论点隐藏有一个严重的问题:它暗中假设开源开发不能形成持续的努力。事实上,有的开源项目在很长的时间段里保持了一致的方向和有效的维护团体,而不需要传统管理必不可少的那些奖励机制或制度性的控制。GNU Emacs编辑器的开发是一个极端的、说明问题的例子:尽管人事变换频繁、一贯持续下来的只有一个人(它的作者),它在超过15年的时间里吸取了成百上千贡献者的劳动、形成了一个统一的结构设计。没有哪个闭源的编辑器或曾比得上这个长寿记录。

这建议了一个质疑传统管理模式下软件开发优势的理由(与其它关于大教堂和市集模式的争议不相干)。如果GNU Emacs可以在15年里表述一个一致的框架设计,如果Linux操作系统在8年多快速变化的硬件和平台技术中作到了同一点,如果(事实的确如此)存在许多设计优良的开源项目超出了5年的历史——那么我们有权发问传统管理开发的庞大开销到底给我们买来了什么——如果有的话。

不管是什么,它显然不包括按期、按预算和按指定功能完成预定计划的可靠管理运营手段;能满足这三个目标中仅仅一条就是一个罕见的“管理好”的项目了,更不用说全部了。它看来也不包括在项目进行过程中适应技术和经济环境变化的能力;在这点上,开源社区已证明其远远来得更为有效(来简单确认这点,比方说,可以比较互联网30年的历史和私有网络技术短短的半衰期;或者比较微软视窗从16位转换为32位的成本和Linux同一时期几乎毫不费力的升级——不仅是围绕英特尔系列,而且还包括含64位Alpha芯片在内的十多个其它硬件平台)。

很多人觉得从传统模式中购买到的一件东西是有人负法律责任:如果事情出了问题可以找赔偿。但这是一个幻觉;大多数软件协议甚至免除可商品化的保证,更不用说性能了——而且由于软件不工作而索赔成功的案例少得近于虚幻。退一步说,即便成功案例很多,因为有打官司的对象而觉得心安是搞错了要点。您不想打官司;您要的是能工作的软件。

那么这些管理开销都买了什么呢?

要理解这个问题,我们需要理解管理软件开发的经理们是怎么想的。我认识的一个似乎很优秀的女经理指出,软件项目管理有以下五项功能:

  1. 明确目标并保持大家向同一个方向努力(目标定义)
  2. 监督并确保关键的细节不被漏掉(监督细节)
  3. 动员人们做枯燥但是必要的苦力活儿(驱动力)
  4. 组织人员分配来达到最佳生产力(组织结构)
  5. 监护项目持续所需要的资源(资源监护)

显然是有价值的目标,所有这些都是;但是在开源模式下,并且在它周围的社会语境中,这些功能会变得出奇地不相干。我们来按逆序讨论这几条。

我的朋友报告说许多“资源监护”基本是防卫性的;一旦你有了你的人员、机器和办公空间,你不得不防卫其他经理竞争相同的资源,和防卫上级调用有限资源中最高效的部分。

但是开源开发者是志愿的、在兴趣和对所参与项目的贡献能力上自我挑选的(甚至在他们领了薪水为开源项目编码的情况下这条也一般适用)。志愿者的特点会自动解决资源监护的“攻击方”;人们把自己的资源带到桌面上来,而且对管理者来说,没有或几乎没有必要来作传统意义上的“防卫”。

不管怎样,在一个有便宜电脑和快速互联网连接的世界里,我们很一致地发现项目真正唯一稀缺的资源是来自技术人才的关注。开源项目本质上从不会为了争夺机器或网络或办公空间而成立;它们只在开发者自己失掉兴趣的时候消亡。

在这点之外,加倍重要的是开源黑客们通过自我选择产生的“组织结构”来达到最大生产率——社会环境也无情地对能力作选择。我的朋友对开源世界和大型闭源项目都熟悉,她认为开源的成功部分归功于它的文化只接受编程人员中最有才华的5%左右。她花费了她大部分时间来组织部署其他的95%,并第一手观察到了那著名的事实,即最优秀的和仅仅及格的程序员之间上百倍的效率差别。

这个巨大的差别程度总是引发一个尴尬的问题:不管单个的项目还是整个行业,甩脱了那50%最差的是不是会更好一些?肯动脑的管理者很久以来就懂得,如果传统软件管理的唯一功能是把最差的一帮人从净损失转为微盈利,这事儿恐怕就不值得折腾。

开源社区的成功提供了硬性证据显示从互联网上招募自我选择的志愿者经常要比管理一整栋楼的“身在曹营心在汉”的人们要便宜和有效的多。这在相当程度上尖锐化了上述问题。

这恰好把我们带到“驱动力”的问题上。对我朋友观点的一个等同的、常有耳闻的转述是:传统开发管理是对缺乏动力的程序员的必要补充,不然他们做不好工作。

这个回答一般携带着一个说法:只能指望开源社区做那种“眩目”的或技术上好玩的工作;任何其它的会被拉下(或敷衍其事)——只有金钱驱动的坐隔间的人在经理们的鞭策下才能把这些给搅出来。我在“开拓智域(Homesteading the Noosphere)”里从心理学和社会学角度论述了我对这个说法的怀疑。然而就当前的目的,假定它正确而来看看其衍生出的推论会更有意思一些。

如果传统的、闭源的、冗肿管理的软件开发方式的是为了对付一堆马其诺防线般的枯燥问题,那么它在每一个应用领域里的寿命就只有指望没有人发现这些问题真正有意思,而且没有人发现绕道而行的方法。因为一旦一种“枯燥”的软件出现了开源的竞争者,顾客们会知道终于有人因为关注这个问题本身而选择来解决它了——对软件业,这一点像对其它任何的创造性工作一样,是比单独的金钱远为有效的驱动力。

仅仅为了驱动力来要一个传统的管理结构,或许是一个好的战术、坏的战略:可以获得短期的胜利,但长期下去必将失败。

说到这里,传统式开发管理和开源相比,现在在两点(资源监护,组织结构)上看起来不是明智之选,而且在第三点(驱动力)上朝不保夕。可怜的受困的传统项目经理也不会在“监督细节”一项上得到任何帮助;开源社区最强大的一个优势就是其非集中式的同行评议在试图保证细节不被忽略上胜出了所有的传统方法。

我们可以把“目标定义”留下来作为接受传统软件项目管理开支的理由吗?可能吧;但是这样的话,我们需要好的理由来相信管理委员会们和公司的远景规划比开源世界里的扮演类似角色的项目领导和部落长者们在定义有价值的、被广泛接受的目标上更为成功。

就面上来看,这很难讲得通的。困难没有多少是来自于对峙的开源一方(Emacs的长寿,或Linus以“统领世界”的说辞动员大群开发者的能力),而是来自于传统机制在定义软件项目目标上表现出来的尴尬。

软件工程里一个出名的大众定理是60%到75%的传统软件项目要么从没完成过,要么被目标用户否决了。要是这个数字真的和事实沾边(我从没有遇到过一个有经验的管理者否定过这点),那么占多数的项目都瞄向了

  • 现实里达不到的或
  • 错得离谱的目标。

上述事实使得在今天的软件工程世界里,“管理委员会”这个词会让听者背上直冒冷气——甚至(或者尤其)当听者是管理者的时候。那些只有程序员们咒骂这一现象的日子早已过去了;Dilbert卡通如今挂上了管理层的案头[译注:呆伯特是美国著名卡通系列的人物;该系列的主题是技术人员对管理层的揶揄]。

我们对传统软件开发经理的答复也就很简单——如果开源社区真的低估了传统管理的价值,为什么你们这么多人表现了对你们自己开发过程的轻蔑?

开源社区的例子再次把这个问题尖锐化了——因为我们做事乐在其中。我们创新的游戏已在技术、市场占有和观念的成功上以惊人的速率得分晋级。我们在证明不仅我们可以开发更好的软件,而且欢乐是一种宝贵财产。

在这篇文章第一版的两年半后,一个开源统领的软件世界不再是我能用来结尾的最激进的观点;毕竟,今天很多穿西服套装的人都已认同这个结局的可能性。

相反,我想提出一个对软件业或许更广泛的教训(或许也是对于任何一种创造性的或专业性的工作)。人们一般在一项任务处于一种适当难度范围的时候享有乐趣;不要太简单了至于无聊,不要太难了无法完成。一个快乐的程序员是一个既没有被浪费也没有被错误制定的目标和烦人过程摩擦所压倒的人。乐趣决定效率。

以畏惧和厌恶来谈论你自己的工作过程本身(即使通过悬挂Dilbert卡通这种改头换面的讽刺性方式)应该被看作一个过程失败了的信号。欢乐、幽默,和趣味是真正的财富;我在上面写的关于“快乐的一群”主要不是为了押韵,Linux的吉祥物是一个可亲的、稚气犹存的企鹅也不仅仅是玩笑。

也许,开源的成功所带来的最重要的影响是教育我们,乐趣才是创造性工作经济上最有效的模式。


后记:网景欢迎市集

与历史同行,那是一种奇特的感觉……

1998年1月22日,大概在我发表“大教堂和市集”七个月之后,网景通讯公司宣布了开放网景浏览器源代码的计划,事先我一点都不知道。

之后不久,网景的执行副总和首席技术官Eric Hahn发给我这样一封电邮:“我希望代表网景的每一个人感谢您带头帮助我们走到了这一步。您的思考和文字给了这个决定关键性的启迪。”

接下来的那周我接受网景的邀请飞到硅谷,和他们的高层管理和技术人员进行了一整天的战略性会议(1998年2月4日)。我们一起制定了网景的代码开发计划和发放执照。

几天后我写道:

网景将要给我们提供一个商业世界里的对市集模式的大型的、现实的尝试。开源文化现在正面临着一个危险;如果网景此举失败,开放源代码的概念会信用扫地,商界在之后的十年内都不会再碰它。
另一方面,这也是一个绝好的机会。华尔街和其它地方的初步反应是谨慎的赞成。我们也得到一个证明自己的机会。如果网景通过此举夺回一定的市场份额,或许会触发一场软件业等待已久的革命。
接下来的一年将会很有指导意义,也将会十分有趣。

确实是这样。2000年中期我修订此文之际,后来命名为Mozilla的开发项目只算是及格的成功。它达到了网景的最初目标——阻止微软在浏览器市场的垄断锁定。它也达到了一些显著的成功(尤其是下一代Gecko转换引擎的发布)。

然而,它还没有召集到来自网景之外的、Mozilla创办者们起初所期冀的那种开发规模。这里的问题似乎是,在很长的一段时间里,Mozilla的发布实际上破坏了市集模式的一条基本规则;它没有发放一个潜在的参与者可以轻易运行和眼观其效的东西。(直到发布后一年多,编译Mozilla需要一个专有的Motif库许可。)

最消极的是(从外部世界的角度来看),Mozilla团队在项目开始后两年半里没有发布出一个具有工业质量的浏览器——而且在1999年,一个项目骨干的辞职引起了不小的影响。他抱怨管理不力,错失良机。“开源”,他正确地评论道,“不能点石成金”。

确实不能。现在(2000年11月)Mozilla项目经过长期恢复,比起当初Jamie Zawinski辞职时看起来有了戏剧性提高——最近几个星期的日末发布终于跨过了生产性使用的关键门坎。但是Jamie的观点完全正确。走开源路线并不一定会挽救一个目标错乱、或编码堆面条、或患有其它软件工程慢性病的已有项目。Mozilla成了一个同时展示开源如何成功和如何失败的案例。

然而与此同时,开源的理念已经在其它地方获得了成功和支持。自从网景的计划公布以来,我们目睹了对开源开发模式的兴趣的爆炸式增长——Linux操作系统的持续成功既是驱动方也是收益方。这个由Mozilla触发的潮流正在加速前进。

[译者按]尽管网景后来难敌微软垄断性的重压,几年后从Mozilla中浴火重生的Firefox再次证明了开源社区的能量。Thomas Friedman在他2005年的畅销书《The Worldis Flat》中把网景列为全球化的十大动力之一,因为网景为互联网的普及作出了奠基性的贡献。


参考文献

我多次引用了Frederick P. Brooks的经典《人月神话(The Mythical Man-Month)》。在很多层面,他的观点到目前为止仍然有效。我全心推荐收录了其1986年文章“不存在银弹(No Silver Bullet)”的25周年纪念版(Addison-Wesley出版社,ISBN 0-201-83595-9)。

这个版本还包含了非常珍贵的一份Brooks在20年以后对文中极少数没有经得住时间考验的论点的回顾。在本文第一个公开版本几近完工时,我第一次阅读了这份回顾,并惊讶的发现Brooks把市集模式归功于微软。事实证明这是不正确的。1998年我们通过“万圣节文档”了解到,微软内部开发团队之间帮派严重,根本不可能真正存在市集模式所必须的绝对源码共享。

Gerald M. Weinberg的《计算机编程的心理学(The Psychology Of Computer Programming)》(纽约,Van Nostrand Reinhold出版社,1971年)引入了(可惜命名地不太好的)“无私编程”的概念。他虽然远不是意识到“命令的原则”不实用性的第一人,但他可能是第一个将此观点和软件工程联系起来的人。

Richard P. Gabriel在其1989年的文章“LISP:好消息、坏消息及如何做大(LISP: GoodNews, Bad News, and How To Win Big)”中勉强地阐述了一个准市集模型的优越性。尽管在一些方面有些过时,此文仍然受不少LISP迷(包括我)的推崇。一位读者提醒我题为“更坏即是更好(Worse Is Better)”的小节读起来更象是对Linux出现的预言。该文的网址为:http://www.naggum.no/worse-is-better.html

De Marco和Lister的《人件:高产的项目和团队(Peopleware: Productive Projectsand Teams)》(纽约,Dorset House出版社,1987,ISBN 0-932633-05-6)是一个被低估了的好作品。我很高兴看到Brooks在其回顾中引用了此书。虽然文中所述极少可被直接应用于Linux和开源社区,此书作者对产生创造性工作先决条件的精辟论断值得每个希望将市集模式精华移植到商业领域中的人参考。

最后,我必须承认我差点将“The Cathedral and the Agora”作为本文的题目。Agora特指古希腊、罗马的露天市集或公众聚会场所。Mark Miller和Eric Drexler关于“agoricsystems”的系列开创性文章描绘了类似自由市场的计算机生态学。此文帮助我在5年后领悟了Linux开源文化中的类似现象。相关文章的网址为: http://www.agorics.com/agorpapers.html.


致谢

此文质量的提高得益于很多人与我交流并提供修改建议。特别感谢Jeff Dutky<dutky@wam.umd.edu>提出“并行改错”的观点并帮助完成其后的分析。感谢Nancy Lebovitz<nancyl@universe.digex.net>建议我模仿Weinberg来引用Kropotkin。General Technics邮件列表的Joan Eslinger <wombat@kilimanjaro.engr.sgi.com>和Marty Franz <marty@net-link.net>提供了关于可读性的批评。Glen Vandenburg <glv@vanderburg.org>指出贡献者人群自我选择的重要性,并提出了开发新功能即改正“功能不足错误”的富有成效的观点。Daniel Upper <upper@peak.org>指出了自然界中的类似现象。感谢费城Linux用户组作为本文第一个公开版本的第一批测试读者。Paula Matuszek <matusp00@mh.us.sbphrd.com>提供了关于软件管理的实践知识。Phil Hudson <phil.hudson@iname.com>指出黑客的社会结构映射出了其软件结构,反之亦然。John Buck <johnbuck@sea.ece.umassd.edu>指出MATLAB和Emacs的有益类比.。Russell Johnston <russjj@mail.com>让我意识到“要多少个眼球来驯服复杂度”中讨论的一些内在机制。最后,Linus Torvalds提供了有用的建议和对本文很早的公开支持。

来源: http://www.ebanpo.com/roamingo/esr/catb.txt

原文版本:2000年9月11日1.57版

参考译文:

habpi, http://www.rockiestech.com/rl/files/cathedral_RL_v1.1.pdf
HansB, http://www.linuxforum.net/books/c&b.html

翻译整理:管旭东 <roamingo@gmail.com> 

Logo

更多推荐