Linux有一套令人感到吃惊的软件工程理论,为了验证这些理论,我专门在fetchmail项目中加以应用,效果之好让我感到惊讶。本文将讨论这些理论,并对比两种完全不同的开发模式:绝大多数商业公司所采用的“大教堂”模式和Linux世界采用的“集市”模式。两种模式的根本不同在于他们对软件排错有着完全对立的认识。我从Linux的经验出发,证实了这样一个命题:“只要眼睛多,bug容易捉”,这和那些由利己个体组成的自纠错系统有着异曲同工之妙。文末,我探讨了在这种观念的影响下,软件可能拥有的未来。
1
大教堂与集市
Linux是颠覆性的,就在5年前(译者注:此文最初版成形于1997年,后几经作者修订,2000年版本为最新版本。历经20余年,此文经受住了时间考验,文中所揭示的理论至今没有过时),谁能想到,几千名散布在全球各地的程序员,利用业余时间,仅仅通过Internet,就鬼斧神工般地造就一个世界级的操作系统?
我绝对想不到。1993年初,Linux进入我视野的时候,我在Unix和开源领域已经有10年开发经验了,我是1980年代中期GNU最早的贡献者之一,当时我已经在网上发布了一些开源软件,而且还正在开发或者合作开发一些程序(nethack、Emacs的VC和GUD模式、xlife等等),这些程序直到现在仍然被广泛的使用着,我并不是菜鸟。
Linux推翻了很多我以为我懂的东西,多年以来,我一直在宣扬“小工具”、“快速原型法”以及“演化式编程”等Unix信条。但我也相信,如果超过了一定的复杂度,更集中式的管理和更严格的流程是很有必要的。我相信大多数重要软件(操作系统和真正大型工具如Emacs编辑器)需要像建造大教堂那样,在与世隔绝的环境下,由天才式专家或几个行家里手精心打造,不成熟时绝不发布beta测试版。
Linus Torvalds的开发风格是:早发布、常发布、委托所有能委托的事、开放到几乎混乱的程度,这些都令人感到惊讶不已。在Linux社区,没有建筑大教堂那样的安静和虔诚,倒更像是一个乱糟糟的大集市,充满了各种不同的计划和方法(Linux的文件服务器就是个很好的例子,这里可以接受任何人的代码和文档提交),
然而,就在这样的环境下,居然诞生了一个稳定的操作系统,这真是奇迹中的奇迹。
事实上,集市模式真的管用,而且非常管用,这让所有人震惊。我开始以自己的方式去了解这种模式,除了在我的个人项目中努力探索外,我也试着去理解为什么Linux世界没有在混乱中四分五裂,反而以难以想象的速度变得越来越强。
1996年年中,我慢慢开始理解了,而且幸运地拥有了一个可以测试我的理论的机会,这个机会使我可以有意识地在集市模式下尝试一个开源项目,我这么做了,而且大获成功。
我要讲述的就是这个项目的故事,通过这个故事,我将引出一些在开源开发中很有用的理论,虽然对我来说,这些不都是从Linux中学到的,但我们可以看看Linux是怎样淋漓尽致地运用这些理论,如果我是对的,这些理论会帮助你准确地理解是什么让Linux社区能够源源不断地产生这么多好软件,还能帮助你成为一个富有成效的人。
2
邮件必达
“切斯特互联”(Chester County InterLink,CCIL)位于美国宾夕法尼亚州(Pennsylvania)的西切斯特郡(West Chester),这是一家小型的免费互联网服务提供商。1993年以来,作为联合创始人,我曾一直负责CCIL的技术部分,并编写了我们独创的多用户论坛程序——你可以通过telnet连到locke.ccil.org来试试看(译者注:别试了,这么多年了,早不在了)。时至今日,这个程序通过三十多条线路支持近三千名用户访问。这份工作使我能够使用CCIL的56K线路保持每天24小时连在网络上——当然,这是工作需要!
我已经习惯了使用电子邮件,但每过一会儿就telnet到locke上查一下邮件,是一件比较烦人的事。我很希望邮件能够自动地递送到snark(我家里的机器)上,这样,邮件来的时候就会通知我,然后我就能用本地工具来处理它。
互联网原生的邮件转发协议SMTP(Simple Mail Transfer Protocol,简单邮件传输协议)并不适用,它最适用于机器一直在线的情况,而我家里的机器并不总是在线,而且也没有一个静态IP地址。我需要这样一个程序,它可以在我时断时续的拨号上网期间,把我的邮件取到本地。我知道有这种软件,它们大多使用了应用层协议POP(Post Office Protocol,邮局协议)。现在绝大多数常见邮件客户端都支持POP,但在那个年代,我所用的邮件阅读器并不支持。
看来我需要一个POP3客户端。于是我便到网上找了一个(事实上我找到了三四个),使用了一段时间后,我发现它有个明显的缺陷:它不能正确地解析取回邮件的邮箱地址,导致我不能正确回复。
问题是这样的:比如locke上有个叫joe的人给我写信,我把信取到snark上并试图回复时,邮件程序会傻乎乎地想把它发给snark上并不存在的joe。所以我不得不每次把回复邮件地址修改为@ccil.org的样子,这着实有点烦人。
很明显这种事应该由计算机搞定,但没有任何一个现成的POP客户端能做到这点!这给我们上了第一课:
1. 好的软件作品,往往源自于开发者个人的痒处。
按说这是显而易见的(正如老话说“需要是发明之母”),但太多的软件开发人员并不需要也不热爱他们正在开发的软件,他们把编程当差事,为的只是拿薪水。Linux世界里可不是这样——也许这可以解释为什么Linux社区里原创软件的平均质量是如此之高。
那么,我是不是应该立即投入到疯狂的编程中,做出一个全新的POP3客户端和其他程序一较高下?那可不行!我把手头的POP程序看来看去,认真思索“哪个最接近我想要的?”,因为:
2.优秀的程序员知道写什么,卓越的程序员知道重用什么。
我不敢说自己是卓越的程序员,我只是模仿他们。卓越程序员们有个很重要的特征是“建设性懒惰”,他们知道人们要的是结果而不是勤奋,而从一个部分可行的方案开始,明显要比从零开始容易得多。
以Linus Torvalds为例,他并没有尝试从零开始写Linux,而是以重用Minix(一个用于PC机的迷你型UNIX类操作系统)的代码和理念作为开始,虽然Linux中所有Minix代码最终都被移除或重写,但它在Linux成长初期确实起到了脚手架的作用。
基于同样的理念,我试图找到一些代码写得还不错的POP程序,作为我开发的基础。
Unix世界共享源代码的传统使得代码重用变得很便利(这正是GNU为什么选择Unix作为基础OS的原因,且不论它对Unix本身的保留意见),Linux世界则把这个传统发挥到技术上的极限。相比其他地方,从Linux世界多达数T字节的开放源码中,找到一些他人写的“足够好”的代码要可行得多。
不出意外,连同上次找到的,我一共找到九个备选程序:fetchpop、PopTart、 get-mail、gwpop、pimp、pop-perl、popc、popmail和upop。我首先选择了Seung-Hong Oh写的fetchpop。我给程序加上了“邮件头重写”功能,并做了一些其他改进,这些改进被作者接受并在1.9版本中发布。
几周以后,我偶然发现了Carl Harris写的popclient代码,同时带来一个难题:尽管fetchpop有一些很好的创意(比如使用后台进程模式),但只能处理POP3协议,代码也略显业余(Seung-Hong Oh在那时是个聪明但缺乏经验的程序员,这两点都看得出来)。Carl Harris的代码要好一些,专业而稳健,但缺乏fetchpop中一些重要而精巧的特性(包括我写的那部分)。
继续完善fecthpop还是转换到popclient?如果转换,我写的那些代码就可惜了,但同时能换来一个更好的开发基础。
一个更实际的转换动机是popclient对多协议的支持。POP3是最常用的邮件服务器协议,但并不是唯一的。fetchpop以及其他备选程序并不支持诸如POP2、RPOP或AROP这些协议,而我还有点想加上对IMAP(Internet Message Access Protocol,互联网消息访问协议,这是最新设计、功能最强大的邮局协议,http://www.imap.org)的支持,那会更好玩一些。
另外,还有一个理论上的原因让我觉得转换是个好主意,这可是早在Linux之前我就知道的:
3. “计划好扔掉一个吧,迟早你会这么做的。”(Fred Brooks,《人月神话》第11章)
或者可以这么说:在你第一次把问题解决的时候,你往往并不了解这个问题,第二次你才可能知道怎么把事情做好。所以,如果你想做对事情,至少要再做一次。【注1】
好吧,我对自己说,改写fetchpop是我的第一次尝试,现在我可以换一个了。
1996年6月25日,我把自己对popclient所做的第一批补丁发给Carl Harris,之后发现他基本已经失去对popclient的兴趣。由于popclient代码有点陈旧,还有些小bug没有解决,很多地方都值得改进,我和Carl Harris很快达成一致:由我来接手这个程序。
项目在不经意间升级了,我不再是对现有POP客户端做一些小打小闹的补丁工作,而是开始维护整个程序。新想法不时冒出来,我意识到自己也许可以对程序做些大改动了。
在一个鼓励代码共享的软件文化中,这是一种很自然的项目演化方式。我见证了下面这条:
4.如果你有正确的态度,有趣的事情自然会找到你。
当然,Carl Harris的态度更重要,因为他明白:
5.当你对一个程序不再感兴趣时,你最后的责任就是把它交给一个可以胜任的接棒者。
尽管并没有明确提及,但Carl Harris和我都知道,我们的共同目标是做出最好的解决方案。唯一的问题是我能否证明自己是可靠的,一旦我做到这点,Carl Harris就优雅而利落地把程序交接给我。如果有一天轮到我时,希望我也能做的这么好。
3
拥有用户的重要性
于是我就这样继承了popclient,同样重要的是,我继承了popclient的用户群。拥有用户是一件很美好的事,这不仅表明你正在服务于某种需要,表明你做对了某些事,如果发展得当,他们还会成为你的开发合作者。
Unix的另一个传统强项也被Linux发挥到极致:很多用户本身就是黑客。因为可以拿到源代码,这些黑客能极为有效地缩短排错时间,只要给他们一点点鼓励,他们就会帮你查找问题、给出建议、并帮助改善代码,这些比你自己做要快得多!
6.把你的用户当成开发合作者对待,如果想让代码质量快速提升并有效排错,这是最省心的途径。
这种做法的效力很容易被低估,事实上,连我们这些在开源世界里的人,都极大低估了这种做法的效力,也就是用户越多就越能有效对抗系统的复杂性,直到Linus Torvalds向我们明白地展示了这一点。
我想,Linus最聪明和最有价值的成就其实不是构建出一个Linux内核,而是他发明的这种Linux开发模式。有次我当面向他表法了这个看法,他笑了,平静地重复了他常说的话:“我基本上是个很懒的人,别人做事,我得名誉。”像狐狸那样懒,或者像Robert Heinlein曾经描绘的一个很有名的角色,太懒以至于无所不能。
回顾以往,GNU Emacs Lisp库和Lisp代码资源库可能要算是Linux这种成功方法的先例,和Emacs用大教堂模式构建的C核心以及大多数GNU工具不同,Lisp代码池是不断更新的,并且在很大程度上是用户驱动的,大多数新想法和原型在达到最终稳定状态前,都会被重写3到4次,和Linux一样,其频繁的“松耦合”合作都是通过Internet实现的。
说实在的,在fetchmail之前我最成功的作品大概要数Emacs VC(版本控制)模式了,当时我通过邮件和其他三人采用了类似Linux的合作方式。
直到今天,我只和其中一人见过面(即Richard Stallman,Emacs的作者,自由软件基金会的创立人,参见http://www.fsf.org)。Emacs的VC模式提供了SCCS、RCS以及后来CVS的前端功能,使得用户可以完成“一键式”的版本控制操作。它是从某人写的一个简略而粗糙的sccs.el演化而来的,之所以能取得成功,是因为和Emacs自身不一样,Emacs的Lisp代码可以迅速地完成“发布/测试/改进”循环。
不只是Emacs,还有其他一些软件产品也使用了两层架构和两级用户群,内核使用大教堂模式开发,工具箱(toolbox)使用集市模式开发,比如数据分析和可视化展现的商业化工具MATLAB就是这样, MATLAB和其他类似产品的用户会发现:在产品的开放部分,总是创新、酝酿和行动最频繁发生的地方,而这部分的改进也总是由庞大而多样化的用户群完成。
4
早发布,常发布
尽早和尽量频繁发布是Linux开发模式中至关重要的一部分,绝大多数开发者(包括我)都习惯性地认为:除非是很小的项目,这么做有害无益,因为软件的早期版本几乎都是问题版本(buggy version),如果早早发布,恐怕会耗尽用户们的耐心。【编者评:Linux操作系统的用户可不是一般的用户,他们是在见证革命性的成果】
这种观念使人们更倾向于支持大教堂开发模式,但如果最重要的目标是给用户提供bug尽量少的软件,为什么你只是每六个月(或者更长间隔)才发布一个版本,并且在版本发布的间隔里忙得喘不过气来呢。Emacs用C写的内核是按照这种方式开发的,而Lisp库却不是,因为真正起作用的Lisp代码资源库并不在FSF的控制之下,在那里你可以找到新的和不断发展中的代码版本,而且它们都独立于Emacs的发布周期。【注2】
这里面最重要的要数俄亥俄州(Ohio)的Emacs Lisp代码资源库,该库早早就拥有了如今大规模Linux资源库所具备的精神和特性,但当时我们几乎没人去认真想想我们在做什么,或者想想资源库的这种存在,是否意味着FSF大教堂式开发模式多少有点问题。1992年左右我做过一次认真的尝试,我从这个代码库中下载了很多代码,并将其正式融入Emacs的官方Lisp库中,很快我遇到了政治上的麻烦,尝试非常不成功。
但是一年后,Linux越来越广为人知,它明显与众不同而且要健康的多。Linus开放式的开发策略简直就是和大教堂模式对着干,Linux的Internet资源库生机勃勃,多个不同版本同时流传,而这完全是由Linux内核那前所未闻的频繁发布所驱动的。
Linus把他的用户当作开发合作者一样看待,并以一种尽可能最有效的方式:
7.早发布,常发布,倾听用户的反馈。
Linus的创新之处,并不完全在于大量采纳用户反馈并快速发布系统版本(这也是Unix世界多年来的传统),而更多在于将这种做法强化到一种能和系统复杂度相匹配的强度。我们知道他在早期(1991年左右)发布内核的频率会超过一天一次!这要归功于他在发展合作开发群体方面的努力,Linus比其他任何人都更在意如何利用Internet杠杆促进合作,而且他真的做到了。
他是怎么做到的?我能否加以复制?还是说只有Linus Torvalds这样的天才才能驾驭?
我想不是。Linus无疑是一个顶级黑客,想想有多少人能从零开始建造一个完整的具有产品级质量的操作系统内核?但Linux并没有展现出多少令人赞叹的概念性突破。和Richard Stallman或者James Gosling(NeWS和Java的作者)相比,Linus不是(至少现在还不是)一个富有创造性的设计天才,他更像是一个工程实施上的天才,他具备一种避免bug和防范开发走入死胡同的第六感,而且有一种能发现从A点到B点最省力路径的本事。
事实上,Linux的整个设计,都透露着这种特质,透露了Linus那种本质上保守而简洁的设计取向。
所以,如果快速发布和利用互联网杠杆效应不是碰巧而为,而是Linus慧眼发现的最省力路径,那么他最想利用的是什么?什么是他最想从这种开发机制中获取的好处?
这样一问,答案就显而易见了。Linus在持续不断地激励和回报着他的黑客/用户,用自我满足感激励他们,用持续改进(甚至每天都有改进)回报他们。
Linus的直接目标就是将投入排错和开发的“人时”(person-hour)最大化,即便这样做可能导致代码不稳定,或者可能因为一些难以消除的严重Bug导致用户群流失。Linus也在所不惜,他相信:
8. 如果有足够多的beta测试者和合作开发者,几乎所有问题都会很快显现,然后自然有人会把它解决。
或者说得更通俗一些:“只要眼睛多,bug容易捉”,我把它称为“Linus定律”。
最初我的表达是“每个问题都会有人弄明白”。Linus提出异议,他认为那个弄明白并修复问题的人往往不是也没有必要是那个首先发现问题的人,“有人发现问题,”他说,“另有人搞定问题,我可以公开地说,发现问题更具挑战性。”这个改正很重要。我们会在下一节仔细考查排错过程到底是怎样的,但关键在于,Linux模式下排错的两个部分(发现问题和修复问题)通常都很快。
Linus定律道出了大教堂模式和集市模式最关键的区别:在大教堂建筑者看来,bug是棘手的、难以发现的,隐藏在深处的,要经过几个人数月的全心投入和仔细检查,才能有点信心说已经剔除了所有错误。而发布间隔越长,倘若等待已久的发布版本并不完美,人们的失望就越发不可避免。
对集市模式而言则完全不同,在上千名合作开发者热切钻研每个新发布版本的情况下,你可以假定bug是浅显易找的,或者至少可以很快变得浅显易找。所以你会频繁发布以获取更多的修正,其副作用是良性的:即便发布中有些小问题,你也不会损失太多。
就是这样,这就足够了。如果Linus定律是错的,那么任何一个像Linux内核这么复杂的系统,经过如此多黑客的改动,在无法预见的不良交互影响以及难以发现的“深度隐藏”bug的重压下,应该已然在某个时刻轰然倒塌了。如果Linus定律是对的,它可以很好解释为什么Linux的bug相对较少,且连续运行时间能够超过数月甚至数年。
也许人们不该为这个定律而惊讶,社会学家早在多年前就发现,一群专家(或一群无知的家伙)的平均观点要比一个随机选择的人的观点更有预见性,这就是“德尔菲效应”(Delphi effect)。看来Linus的做法表明这个理论甚至也适用于操作系统排错——“德尔菲效应”可以驯服软件开发的复杂性,甚至是操作系统内核开发这样的复杂性。【注3】
Linux对“德尔菲效应”提供支持的一个特别之处在于,给定任何一个Linux软件项目,其成员都是自发选择参与的,早前有读者指出,对Linux做出贡献的人并不是没有规律的,他们是这样的个体:他们很有大的兴趣使用软件、了解其工作原理、尝试解决遇到的问题、并实际给出一个明显合理的解决办法。具备这些特点的人很有可能贡献出有价值的东西。
Linus定律也可被表述为“排错可以并行”,尽管调试人员在排错时需要协调开发人员并与之交流,但调试人员之间并不怎么需要协调,也就是说,增加调试人员并不会带来增加开发人员那样的二次方复杂性和管理成本。
理论上,并行排错会由于重复劳动导致效率损失,但从Linux世界的实践来看,这似乎从来不是一个问题。“早发布、常发布”策略的一个效果就是快速传播反馈回来的修复,从而使重复劳动最小化。【注4】
Brooks(《人月神话》的作者)曾经非正式地说过:“对于一个被广泛使用的软件,其维护成本通常是开发成本的40%或者更多。令人惊奇的是,这个成本受到用户数的严重影响,用户越多,bug就会被越多地发现。”
“用户越多,bug越多”是因为增加用户就会增加测试的方式。当用户是合作开发者时,这种效应会被放大,每个着手去发现bug的人,都会有不同的视角,并使用各自不同的捕捉方法和分析工具。“德尔菲效应”似乎就是因为这种差异而变得有效。在排错这个特定场合下,差异也使得重复工作倾向于变少。
从开发者角度来看,增加更多的beta测试者似乎并不能减少当前“隐藏最深”bug的复杂度,但这种做法会使bug发现的概率变大:某人的那套环境正好匹配某个问题,使得那个bug容易被他发现。
为防范严重bug给用户带来的影响,Linus有这么一招:在Linux内核版本号上加以标识(译者注:可以从版本号看出系统是否稳定),潜在用户要么选择上一个被标识为“稳定”的版本,要么冒着有bug的风险使用最新版本以获取新特性。这种策略还没有被Linux黑客们系统性地加以模仿,也许他们以后会这样做;事实上,给用户以选择使得两种版本都更具吸引力。【注5】
5
多少只眼睛才能驯服复杂性
从宏观上观察到集市模式能极大加速代码排错和演化是一回事,但从微观上,结合开发者和测试者的日常行为,完全理解这是怎样做到的以及为什么会这样,就另是一回事了。本节(在本文首版的三年后写就,采纳了阅读本文首版并对照了他们自身行为的开发者们的观点)我们将仔细查看一下其真正机制。对技术不感兴趣的读者可以直接跳到下一节。
理解的一个关键在于要弄清楚这个现象:如果报告bug的用户对源码不关心,则其报告通常不会很有用。对源码不关心的用户,往往报告的都是表面症状,他们把自己的运行环境当成是理所当然的,他们不仅省略了重要的背景数据,而且很少给出重现bug的可靠方法。
这里隐含的问题是开发者和测试者对程序有着不匹配的思维模式,测试者是从外往内看,程序员是从内往外看,对于不开放源码的软件开发,他们都被固定在自己的角色里,往往倾向于各说各话,都对对方倍感沮丧。
开源开发打破了这种困境,由于大家都有真实的源码,开发者和测试者很容易发展出一个共享的表达模式并进行有效的交流。事实上,一个仅描述外部可见症状的bug报告,和一个直接关联到源码的分析型bug报告,对开发者而言简直是天壤之别
只要能有一个对出错条件在源码级别上的提示性描述(即便不完整),大多数bug都很容易被抓住。如果你的beta测试人员中能有人指出,“在第n行有一个边界问题”,或者仅仅是“在条件X、Y和Z下,这个变量会溢出”,这时你扫一眼那部分代码,往往很快就能准确找到错误并得出修正办法。
所以,如果beta测试人员和开发人员都能意识到源代码的作用,就能极大增强双方沟通和合作的效果。即便在合作者很多的情况下,核心开发人员的时间也会被节省很多。
开源方法之所以能节省开发者时间,另一个原因是开源项目所常采用的沟通模式,以前我习惯使用“核心开发人员”这个术语,主要想表明项目核心人员(通常很少,一个人是最常见的,典型情况是一到三人)和外围人员的区分,外围人员通常由beta测试者和潜在的贡献者组成(通常会达到数百人)。
传统软件开发在组织结构上的根本问题由Brooks定律一语道破:“在一个已经延期的项目上增加人手,只会让项目更加延期”,更为一般地讲,Brooks定律指出,随着开发人员数目的增长,项目复杂度和沟通成本按照人数的平方增加,而工作成果只会线性增长。
Brooks定律是建立在经验基础上的,人们发现,bug很容易集中在不同人写的代码的交互接口上,沟通/协调的开销会随开发者间接口数增加而增多,也就是说,问题规模和开发人员间沟通路径数相关,也即和人数的平方相关(更精确地讲,应该是N*(N-1)/2,N代表开发者数目)。
Brooks定律(以及随之而来对开发团队规模的恐惧)建立在这样的假设上:项目的沟通结构是一个完全图,也即人人之间都沟通。但在开源项目中,外围开发者们实际工作在分散而并行的子任务上,他们之间几乎不交流;代码修改和bug报告都会流经核心团队,只有在那个小的核心团队里才会有Brooks开销。【注6】
源码级bug报告非常有用的理由还有很多,但都围绕着这个事实:一个错误可能会有多种症状,具体症状因用户使用方式和环境不同而有不同表现。这种错误往往正是那种复杂而难缠的Bug(比如动态内存管理错误或者非确定中断窗口的产物),这些bug很难重现,也很难通过静态分析找到根源,导致软件中存在一些长期难以解决的问题。
如果测试者能给出一个源码级别的bug报告(这个bug可能会引起多种症状),尽管只是一个不确定的试探性描述(比如“看上去第1250行有一个信号处理窗口”或者“你在什么地方把这个buffer清零的?”),也会帮助开发人员找到解决那些多症状(症状看上去也许并不相关)问题的关键线索,要知道开发人员往往离代码太近而不能发现问题。这种情况下,要想精确说出是哪个bug导致了哪个外部可见问题,通常很难甚至不可能,但如果经常发布的话,就没有必要去知道了,其他合作者会很快去查看他们发现的bug是否被解决了。很多情况下,人们会关心导致问题消失的源码级bug报告,但很少关心是哪次补丁修复了它。
对于复杂的多症状错误,要想从表面症状追踪到实际bug,往往有多种路径,开发者或测试者追踪时经由何种途径,取决于千差万别的个人运行环境,并且该环境会随时间变化产生不确定的变化。实际上,每个开发者和测试者在寻找病状症结的时候,都是在“半随机”(semi-random)的变量集合上对程序状态空间进行采样。越是隐蔽和复杂的bug,就越难从技能上保证采样的对症性。
对于简单和容易重现的bug,重点要放在“半”而非“随机”上,此时,调试技能以及对代码和架构的熟悉程度能大显身手。对于复杂的bug,重点就要放在“随机”上了,这种情况下多人共同追踪bug远比少数几个人循序追踪要有效得多——即便这几个人的平均技能要高很多。
当从表面症状追踪到bug的难度不一且难以预测时,并行纠错的这种效果会更加显著。一个开发人员会循序选取追踪路径,可能一开始就选了一条困难的路径,当然也可能是容易的路径。而在快速发布模式下,如果多人同时尝试对bug进行追踪,很可能某人立刻就发现了最简单路径,然后在比别人短得多的时间内逮住bug。项目维护人员看到后会发布一个新版本,这样在其他更难路径上追踪该bug的人就可以停下来,以免浪费更多的时间。【注7】
6
何时名不再符实
在研究了Linus的做法并得出他为什么成功的理论后,我决定也在我的新项目(当然没有Linux那么复杂和艰巨)里测试一下这个理论。
我首先要做的一件事,是大幅度重组和简化popclient,Carl Harris的实现很好,但表现出了一种不必要的复杂性,这在C程序员中很常见。他把代码作为最重要部分,而将数据结构置于辅助地位。结果就是,代码很漂亮,但数据结构设计得有点随意和潦草(至少从一个LISP老手的标准来看)。
除了提升代码和数据结构的质量之外,我重写的另一个目的是想把它弄成一个我能完全理解的东西。如果你对一个程序不能了如指掌,而又要负责他的bug修复,那可不是闹着玩的。
最初一个月左右,我只是继续遵循Cral Harris的基本设计。对程序所做的第一个重大改变是对IMAP支持的添加,我把协议处理部分重新组织成一个通用的驱动和三个方法表(POP2、POP3和IMAP)。这次改动(以及先前的)再次说明了一个程序员应该铭记在心的总体原则(尤其对于C这种并不天然支持动态类型的语言):
9. 聪明的数据结构配上愚笨的代码,远比反过来要好得多。
Brooks在《人月神话》的第9章里说:“让我看你的流程图但不让我看表,我会仍然搞不明白。给我看你的表,一般我就不再需要你的流程图了,表能让人一目了然。”历经30年来的术语/文化变迁,这个道理依旧没变。
这个时候(1996年9月初,也即从零开始的六周后),我开始考虑给软件换个名字,毕竟它已不再只是一个POP客户端。但我有点犹豫,因为在设计上还没有做出什么真正新的东西,popclient还需要有点我自己的东西。
当popclient学会如何把取来的邮件转发到SMTP端口后,软件就有了根本上的变化,一会再谈这个。先说说我是怎么样验证集市模式理论的,有这么几个办法:
我尽早发布并频繁发布(几乎从来没有低于10天一次的频率,在高强度开发阶段会一天一次)。
我把每一个因fetchmail联系我的人都加到beta列表(译者注:是指beta测试人员邮件列表)中。
每次发布新版本时,我都向beta列表发送朋友对话般的通知,鼓励他们参与。
我听取beta测试者们的意见,征求他们关于设计决策的看法,当他们发来补丁和反馈时给他们以热情回应。
这些简单措施立刻收到了回报。从项目一开始,我就收到一些质量高到让程序员们垂涎欲滴的那种bug报告,而且还常常附带很不错的修复方法;我还收到经过深思熟虑的批评;收到粉丝来信;收到很有智慧的软件特性建议。这一切都表明:
10. 如果你把beta测试者当做最珍贵的资源对待,他们就会成为你最珍贵的资源。
衡量fetchmail有多成功的一个有趣指标是beta列表(fetchmail-friends列表)的规模,在本文最新一版时(2000年11月),列表成员达到了287名之多,并且每周还增加2到3名。
实际上,列表成员最多时接近300名,1997年5月底我修订这篇文章时发现成员开始流失。一些人要求我把他们从邮件列表中去掉,而原因很有趣:他们觉得fetchmail已经足够好了,他们不想再看到这个列表中的邮件!对于一个成熟的集市模式项目,也许这是其正常生命周期的一部分吧。
7
popclient变成了fetchmail
这个项目真正的转折点是在Harry Hochheiser发来了他的代码,看完这段将邮件转发到客户端机器SMTP端口的代码,我立刻意识到,如果能可靠地实现这个特性,其他的邮件投递模式都将可以废弃了。
曾经有好几周,我都在一步步对fetchmail进行微调,我觉得fetchmail的界面设计虽然可用但有点乱,不够优雅,选项琐碎且遍布各处,尤其是那个将已收取邮件导出为邮箱文件或打到标准输出上的选项让我感到很烦,虽然我也说不出为什么。
(如果你不关心互联网邮件的技术细节,尽可以跳过下面两段。)
当考虑SMTP转发的时候,我发现popclient想做的事太多了。它被设计为既是一个邮件发送代理(MTA)又是一个本地的邮件投递代理(MDA),有了SMTP转发,就应该把MDA去掉而成为一个纯MTA,由它将邮件再发给其他诸如sendmail之类的本地投递工具。
在所有支持TCP/IP的平台上都已保证25号端口缺省打开的情况下,为什么还要折腾复杂的邮件投递代理配置或者去设置邮箱的“加锁并添加”(lock-and-append)选项?而采用SMTP转发带来的另一个特别好处是:取回的邮件看上去就像原发的SMTP邮件一样,这可正是我们想要的。
(返回到非细节层面。。。。。。)
即便你没有读上面那些技术细节,下面还是给你准备了一些重要经验。我特意模仿Linus方法后所得到的最大收获是“SMTP转发”概念,是用户给了我这个极妙的想法——我所做的只是去理解其意义。
11.仅次于拥有好主意的是,识别来自用户的好主意,有时后者会更好。
很有趣的是,如果你发自内心地谦逊,并承认你欠别人很多,你将很快发现世界会这样对待你:他们认为是你发明了整个软件,而且你对自己的天赋有着得体的谦虚。我们可以看到这一点在Linus身上体现得有多好!
(当我1997年8月在Perl大会上第一次说出这些的时候,黑客泰斗Larry Wall在我前一排,我说出上面那句话的时候,他以一种宗教复兴般的状态大声喊道“继续!继续!兄弟!”(Tell it, tell it, brother!)所有的听众都笑了,因为他们知道这一点也适用在Perl发明人(Larry Wall)身上。)
我以这样的精神将项目运行几周后,开始收到同样的赞扬之词,不仅仅来自于用户,也来自一些对此有所耳闻的人。我把这些邮件收藏了起来,如果什么时候我开始怀疑人生,我就把它们拿出来看看:-)。
接下来是两个更基础的、非政治性的经验,适用于所有类型的设计。
12.通常,那些最有突破性和最有创新力的解决方案来自于你认识到你对问题的基本观念是错的。
我曾尝试解决错误的问题,那时我总是想把popclient做成一个MTA和MDA的结合体,并支持各种各样古怪的本地投递模式。而事实上,应该彻底重新思考Fetchmail的设计,它应该是一个纯粹的MTA,成为Internet邮件常规SMTP对话路径的一个部分。
当你发现自己在开发中碰壁时,当你发现自己苦思冥想也很难做出下一个补丁时,通常你不该问自己是否找到了正确答案,而是该问你是否提出了正确的问题,因为也许问题本身需要被重新定义。
于是,我重新定义了我的问题。显然,正确的做法应该是:(1)将SMTP转发做到通用驱动里面;(2)将它设为默认模式;(3)最后,将所有其他投递模式都扔掉,尤其是投递到文件(deliver-to-file)和投递到标准输出(deliver-to-standard-output)的选项。
对第3步我犹豫了一段时间,主要是害怕影响那些依赖其他投递模式的popclient老用户们。理论上讲,他们可以立刻使用.forward文件(译者注:如果使用sendmail)或者其他非sendmail软件的类似功能来获取同样的效果,但在实际操作中,这个转换可能会让人有点头大。
但当我这样做了以后,好处非常明显,驱动代码中最让人厌烦的部分不见了。配置得到根本上的简化——不再需要低声下气地围绕MDA和用户邮箱打转了,也不再担心底层的OS是否支持文件加锁。
并且,信件丢失的唯一途径也不见了——如果你让程序投递到文件而磁盘满了,信件就会丢失。使用SMTP转发就不会有这种问题,因为SMTP监听程序只在信件被正常投递或者至少被缓存后,才会返回确认消息。
性能也得到了提升(尽管你不是运行一次就能感觉到的)。另一个不太明显的好处是,用户手册也更简洁了。
后来,为了处理一些涉及到动态SLIP的棘手问题,我不得不加入了对“通过用户指定本地MDA投递”的支持,但这个做起来容易多了。
这件事寓意何在?在不损失效能的前提下,不要犹豫,扔掉那些过时的特性吧。Antoine de Saint-Exupéry(在不写经典儿童读物的时候,他是一名飞行员和飞行器设计师。译者注:此人即《小王子》的作者。)说过:
13. “设计上的完美不是没有东西可以再加,而是没有东西可以再减。”
当你的代码变得既好又简单,你就知道你对了,在这个过程中,fetchmail有了自己的特点,和它的前身popclient不再一样了。
现在是时候改名字了。和老的popclient相比,新的设计看上去更像是sendmail的搭档,两个都是MTA,sendmail是先“推”(push)后投递,新的popclient先“拉”(pull)后投递。所以,在开工两个月后,我把它重命名为fetchmail。
这个故事还告诉我们一个更通用的道理,不仅是排错过程可以并行,开发和设计也可以并行(而且能达到让人惊讶的程度)。如果你采用快速迭代开发模式,开发和改进过程就可能成为排错过程的一个特例——修复软件原先在功能或概念上的“疏漏型bug”(bug of omission)。
即便是高层次的设计,如果能有很多合作开发者在你产品的设计空间周围探索,也是很有价值的。想象一滩雨水是怎么找到下水口的,或者说蚂蚁是怎么发现食物的。探索在本质上是分散行动,并通过一种可扩展的通信机制来协调整体行为。这很有效,就像Harry Hochheiser和我,一个外围的游走者可能会在你旁边发现宝藏,而你可能有点太专注而没能发现。
8
fetchmail长大了
现在我有了一个简洁和新颖的设计,由于我自己每天都用,我知道代码还不错,并且有了一个不断繁荣的beta列表,我明白我不是仅仅在做一些微不足道的个人编程,做出来的东西也不只是对少数几个人有用。我现在做的程序,是每一个使用Unix和SLIP/PPP收发邮件的黑客都需要的。
有了SMTP转发功能,它远远地走在了其他竞争对手的前面,并逐渐成为这个领域内的杀手应用,由于它在同类程序中如此优秀,以至于其它对手不仅被抛弃,而且几乎都被遗忘了。
不过,记着,你不要一开始就设定这样的目标和结果。你必须要有一个非常强大的设计创意并完全投入,以至于这个结果就像是不可避免、自然而然和预先设定的。要做到这一点,唯一的途径是你有很多创意——或者有一种采纳别人好主意的工程上的决策力,并将这些创意发展到超越其作者所能想像的地步。
Andrew Tanenbaum写了一个简单的用于IBM PC的原生Unix,其原意是将其用做教学工具(他称之为Minix)。Linus Torvalds将Minix的概念发展到Andrew可能无法想象的地步——并成长成为让人赞叹不已的产物。同样地,尽管规模较小,我吸收并努力推进Carl Harris和Harry Hochheiser的创意。我们都不是那种有浪漫原创精神的天才式人物,但是,大多数科学、工程以及软件开发都不是天才完成的,在青史上留名的往往是黑客。
取得这样的结果真是让人感觉太好了——事实上,这正是黑客们所追求的成功!这意味着我要把标准设置得更高一些。现在看来,为了让fetchmail有更好的发展,我不应该只是为了自己的需求而写程序,而应该加入和支持一些他人需要的特性,同时还要让程序保持它的简单性和健壮性。
意识到这点以后,我发现首先要实现的最为重要的特性是对集体邮箱(multidrop)的支持-也即有能力从集体邮箱(这里保存着一组用户的邮件)中把邮件取出来,然后将其路由到相应的收件人那里。
我之所以决定增加集体邮箱支持,部分原因是一些用户一直在强烈要求,但更主要的原因是,这可以强迫我以一种完全通用的方式处理邮件地址,从而借此机会清除掉单邮箱实现中的一些bug,事实上这的确奏效了。弄明白RFC 822(http://info.internet.isi.edu:80/in-notes/rfc/files/rfc822.txt)中描述的邮件地址解析规则着实花了我很长时间,不是因为其中有什么地方很难懂,而是里面牵扯了太多相互关联而又繁琐的细节。
从结果看,对集体邮箱的支持是一个很英明的决定。因为:
14. 任何工具都应具备预期内的功能,但一个伟大的工具能给你带来你预期外的功能。
fetchmail的集体邮箱模式就有一个用户预期外的功能:它能在客户端(译者注:指连往ISP邮件服务器的终端)上保存地址列表并实现别名扩展,这意味着用户只要有一台个人电脑和一个ISP账号,就能够维护一个邮件列表,而无需总是读写ISP端的别名文件。
我的beta测试者们要求的另一个重要改动是支持8位MIME(多用途Internet邮件扩展)操作。这很容易做到,因为我已经很小心地保持着第8位的纯洁(也就是说,没有染指ASCII字符集中没用的第8位去让它携带程序信息),并不是我预先想到会有人提这个需求,而是我遵从了另一个规则:
15.写网关类软件时,尽可能不要干扰数据流,而且绝不要扔掉信息,除非接收方强迫你这么做。
如果我没有遵循这条规则,对8位MIME的支持就会变得困难且容易出错。现在,我要做的只是阅读MIME标准(RFC 1652, http://info.internet.isi.edu:80/in-notes/rfc/ files/rfc1652.txt),并稍稍增加一些邮件头部生成的逻辑。
一些欧洲用户一直要求我增加一个选项限制每次连接取回的邮件数(以便他们控制昂贵的拨号上网费用)。我抵制了很长时间,而且直到现在对此也不太开心。但如果你是为大家写程序,你就不得不倾听用户的意见——虽然他们并不付钱给你。
9
从fetchmail学到的其他经验
在回到一般性的软件工程话题前,还有几个fetchmail的特定经验值得思索。对技术细节不关心的读者完全可以跳过这一节。
rc控制文件(译者注:fetchmail的配置文件)的语法包括了一些不会被解析的“噪声”关键字,相比传统配置文件只剩下简洁的“关键字-值”配对,fetchmail这种类似英语的语法使文件更易读。
这个想法来自于某个深夜,当时我注意到rc文件的声明越来越像一个微型指令式语言(这也是为什么我把原先popclient中的“server”关键字换成了“poll”)。
在我看来,如果把一个微型指令式语言弄得像英语的话,会更方便人们使用。虽然我很崇尚“让它像语言那样”的设计哲学(正如Emacs、HTML以及一些数据库引擎),但我并不痴迷于“让它像英语那样”。
传统程序员倾向于喜欢那种非常简洁、紧凑和没有一点冗余的控制语法。这是计算资源昂贵年代的文化遗留,在当时看来,解析过程应尽可能简单和节省资源。英语大约有50%的冗余度,很不适宜作为控制语法的模型。
我并不是因此不喜欢英语语法,相反,提及它正是为了打破传统观念。有了更便宜的计算资源,简洁就不该成为最终目标。对现如今的计算机语言来说,是否便于人类使用要比是否节省计算资源更重要。
然而这并不容易:一方面,解析过程有着复杂性成本——你当然不想让它复杂到容易出错的地步;另一方面,试图让语言拥有类似英语的语法,往往使这个所谓的“英语”严重走形,以至于这种对自然语言的表面模仿并不比传统语法让人更易懂一些(你可以在很多所谓“第四代语言”和商业数据库查询语言中看到恶果)。
fetchmail的控制语法看来不会有这些问题,因为它的语言空间非常有限,它还远远不是一个通用功能的语言,它所描述的东西并不复杂,所以在这样一个英语的微小子集和实际控制语言上,应该不会让人们产生理解上的困惑。我认为,在大多数情况下:
16.当你的语言还远不是图灵完备(Turing-complete)的时候,语法糖会让你受益良多。
【译者注:语法糖(Syntactic Sugar,或译为语法糖衣)是英国计算机科学家Peter J. Landin发明的术语。是指为计算机语言添加某种不会影响语言功能的成分,但却使其更易用一些,目的是增强代码可读性,避免出错的机会。】
下面是一个关于信息隐藏的话题。一些fetchmail用户要求我改软件,使rc文件的密码能够以加密形式保存,这样能防范一个窥探者轻易看到密码。
我没有答应,因为实际上这并不能增强安全性。任何人如果获取了你的rc文件的读权限,都有能力以你的身份运行fetchmail。此外,如果他们想要你的密码,他们能从fetchmail代码中剥离出一个解码器,然后获取密码。
【编者评,eric此言差矣,密码加密,至少可以阻挡99%不会编码的人偷窥,安全不应该采用“有或全无”思维,而应该采用深度防御思维。】
给.fetchmailrc中的密码加密,只会给那些没有认真思考的人一种安全假象,一般而言:
17. 系统的安全性只取决于它所拥有的秘密。谨防虚假的秘密。
10
集市模式的必要条件
这篇文章早期读者和评论者一直不断提出这样的问题,即集市模式成功的前提是什么,包括项目领导人应该具备什么资格,项目首次发布并建立合作开发社区的时候,代码应该达到什么状态等等。
显然,你不可能从零开始实施集市模式。【注8】可以用集市模式测试、排错和完善项目,但以集市模式从零开始一个项目是非常困难的。Linus没有这么试过,我也没有。开发者社区从成立伊始,就需要一个可以运行和测试的东西。
当开始建设社区的时候,你需要拿出一个像样的承诺。程序此时并不需要特别好,它可以简陋、有错、不完整,文档可以少得可怜。但它至少要做到
(a)能运行,
(b)让潜在的合作开发者相信,这个软件在可预见的未来,能演变成一个非常棒的东西。
Linux和fetchmail在首次露面时,都有着很强和很吸引人的设计。很多人都已正确意识到这点非常重要,并进而得出结论:项目领导人必须要有高度的设计直觉和聪明才智。
但linus的设计来自于Unix,我的最初设计则来自于popclient(虽然后来做了很多改动,而且改动比例要远大于Linux)。所以,一个尝试集市模式的项目领导人或协调人,是否真的需要他本人是一个超群的设计天才,抑或他能借力于其他人的天才设计?
我想,一个协调者是否拥有卓越的原创设计能力,并不是项目成败的决定性因素,但他是否能识别出别人的优秀创意,则一定是最关键的。
Linux和fetchmail都证实了这一点。Linus虽不是一个让人惊叹的原创设计者(前面说过),但他表现出了能识别优秀设计并将其集成入Linux内核的出色才能。而我也介绍过,fetchmail中最强大的设计(SMTP转发)来自他人。
这篇文章的早期读者曾经很抬举地指出,我之所以低估集市模式的设计原创性,是因为我自身有很多原创,所以视之为理所当然。这可能有点道理,相对编码或调试而言,设计的确是我的强项。
问题是,在软件设计上表现得聪明而有原创性,容易养成一个习惯——在应该保持软件健壮性和简单性的时候,你往往下意识把它弄得既华丽又复杂。我曾经就因为这样的错误把项目搞砸,所以在fetchmail中,我尽量避免再犯同样的错误。
fetchmail项目之所以能成功,相信部分原因是我限制了表现自己聪明的倾向。这(至少)反驳了设计原创性是集市模式项目成功关键的论点。再来看看Linux,如果Linus Torvalds在开发过程中努力尝试在操作系统设计上表现出基础性创新,那做出来的内核还能像现在这样稳定和成功吗?
当然,一定水准的设计和编码能力还是需要的。但我认为,如果一个人真的想要启动一个集市项目,那么他的能力应该已在最低水准以上。开源社区内在的声誉评价机制会给人们施加微妙的压力,使那些不能胜任项目发展的人,不会去发起一个开发项目。至少到目前为止,这个机制非常有效。
还有一种技能,人们通常不会把它和软件开发联系在一起,但我认为,在集市项目中它和设计才能一样重要——甚至更重要:集市项目的协调人或领导人必须要有很好的人际交往和沟通能力。
这应该是显而易见的,为了建立一个开发社区,你需要吸引人们,让他们对你做的事感兴趣,让他们乐于看到自己的贡献。一些技巧可能有助于实现这些,但远远不是全部,你的人格魅力也很重要。
Linus是个好人,人们都喜欢他并愿意帮助他,这(和他的项目成功)不是巧合。我精力充沛、性格外向、乐于社交、有一些脱口秀演员般的说话风格和临场反应,这也不是巧合。为了让集市模式运转,哪怕有一点点的人格魅力,都会对你大有裨益。
11
开源软件的社会语境
此言不虚:最好的程序一开始只是作者对自己每天遭遇问题的个人解决方案,程序流传开来则是因为作者遇到的问题成了一大类用户的典型问题。这将我们带回规则1,并以一种可能更有用的方式来重申:
18.想要解决一个有趣的问题,先去找一个让你感兴趣的问题。
Cral Harris和先前的popclient是这样,我和fetchmail也是这样。这个道理已经早为人知,而Linux和fetchmail的发展历史让我们关注到更有趣的一点,那就是下一阶段——由用户和共同开发者们组成庞大而活跃的社区,共同促进软件的进化。
在《人月神话》中,Fred Brooks发现程序员的时间是不可替代的,增加开发者进入一个已经延迟的软件项目,只会让项目更加延迟。像我们前面看到的那样,他指出,项目复杂度和沟通成本与开发人员数目的平方成正比,与此同时,工作完成量只会随人数线性增长。Brooks定律已经被广泛地视为真理,但在本文中我们已经通过多种方式论证了开源软件的开发过程不满足这个定律背后的一些假设——并且从实践上看,如果Brooks定律普适于所有开发项目,Linux是不可能完成的。
作为一种后见之明,Gerald Weinberg在经典之作《计算机编程心理学》(The Psychology of Computer Programming,有译《程序开发心理学》)中提出了对Brooks定律的重要修正。在他关于“无私编程”(egoless programming)的讨论中,Weinberg观察到,在某些工作场所,开发人员不将代码看作是自己的“领土”,而是鼓励别人发现其中的bug和潜在改进点,这些场所中软件改善速度之快,是别处不能比拟的。(最近,Kent Beck在其“极限编程”(extreme programming)技术中提出的结对编程—两个程序员肩并肩共同完成编程—可以看作是一种仿效。)
也许是Weinberg在用语选择上的问题,导致他的分析未能获得应有的认可——用“无私”来形容互联网上的黑客,这可能会让某些人感到可笑。但我认为他的论点在今天看起来比以往任何时候都更有信服力。
集市模式,运用“无私编程”的能量,强有力地化解了Brooks定律的影响。Brooks定律背后的原理没有失效,但如果有一个大规模的开发群体和一个低成本的沟通机制,Brooks定律的效果将会被其他非线性因素带来的效果淹没,而后者是大教堂模式下看不到的。这很像是物理学上牛顿理论和爱因斯坦理论的关系——在低能量条件下,老的系统仍然有效,但如果把质量和速度推进到足够大的地步,你就会震惊于核爆炸,Linux就是核爆炸。
Unix历史为我们从Linux中获取经验早已做下了铺垫(为验证其有效性,我专门在一个较小规模的项目上拷贝Linus的方法【注9】),那就是,当编码在本质上仍然是个体行为时,真正了不起的作品来自于对整个社区注意力及脑力的有效利用。一个在封闭项目中只靠自己的开发者,将远远落后于这种开发者:他们知道如何创建一个开放的、有改进能力的环境,在这个环境中,上百人(甚至上千人)反馈并提供设计空间拓展、代码贡献、bug定位以及软件的其他改进。
传统的Unix世界中,有一些因素阻止了把这种方法推进到极致。一方面是各种许可证(license)的法律限制、商业秘密和市场利益,另一方面(现在看来)是当时的Internet还不够好。
在互联网变得便宜之前,有一些地域性的协作社区,他们在文化上鼓励Weinberg的“无私编程”,开发人员可以很容易地吸引到很多高水平的评论者和合作开发者。如Bell实验室、MIT的AI实验室和LCS实验室、UC Berkeley大学——这些地方都是创新的乐土,它们充满传奇并依然强劲有力。
Linux是第一个有意识并成功将整个世界作为其人才库的项目。Linux孕育之时万维网(World Wide Web)刚刚诞生,Linux蹒跚学步之时(1993-1994)ISP产业开始起飞,与此同时,主流对Internet的兴趣也开始爆发,我认为这都不是巧合,Internet普及之后,Linus是学会如何运用新规则的第一人。
廉价的Internet是Linux模式得以发展的必要条件,但我认为它还不足以成为充分条件。另一个重要因素是领导风格的成熟和合作习惯的建立,这是吸引合作开发者加入项目的关键,也是充分利用互联网的关键。
但应该是什么样的领导风格和合作习惯呢?他们不应建立在权力关系上——即便可以这样,强制型的领导风格也无法产生我们今天所能见到的成果。
Weinberg引用了19世纪俄国无政府主义者Pyotr Alexeyvich Kropotkin所著《一位革命家的回忆》(Memoirs of a Revolutionist)中的一段,很好地诠释了这个问题:
“我成长于一个农奴主家庭,在投入积极生活之时,像那个年代所有年轻人一样,我非常相信命令、指示、斥责、惩罚等等行为的必要性。但当我早期不得不管理重要事业并和(自由)人打交道时,在任何错误都会立刻导致严重后果时,我开始感悟到按“命令与纪律原则”行事和按“共识原则”行事之间的重要区别。前者在军队检阅时的作用令人钦佩,但在真实生活中却一文不值,想要达到目标,必须要靠众人的齐心协力。”
“齐心协力”正是Linux这种项目所需要的——对Internet上(可以看成是无政府主义者的天堂)志愿者们使用“命令原则”是根本行不通的。如果某个黑客想领导一个协作项目,想要项目有效地运作和竞赛,他就不得不学会如何施行Kropotkin所简单提出的“共识原则”,招募和激励有兴趣的成员形成有效社区。他还必须学会如何使用Linus定律。【注10】
前面我提到“德尔菲效应”也许可以解释Linus定律。但我发现,生物学和经济学中的自适应系统是更好的类比,Linux世界的运转,在很多方面像一个自由市场,或者像一个由很多利己个体组成的生态系统,系统中每个个体都追求自身效用的最大化,在其共生的过程中,能够自然建立起一种具备自我纠错能力的秩序,这种秩序比任何集中式规划都要精妙和高效。这里,正是“共识原则”达成的地方。
Linux黑客们致力于最大化的“效用函数”,其目的并不是经典意义上的经济价值,而是自我满足和黑客声望这些无形的东西。(有人把这种动机称为“利他”,但他们忽视了一个事实,即“利他”本身是“利他者”自我满足的外在表现。)按这种方式运转的志愿者文化其实很常见,除了黑客圈,我还长期参与在科幻迷圈子中,不像黑客,科幻迷们早就清楚认识到“egoboo”(个人在团体中声望的提升)是志愿者活动背后的基本驱动力。
【译者注:“egoboo”是ego boosting的口语化简称,是指参与志愿工作得到公共认可而获得的快乐,这个术语大约出现在1947年,最早用于科幻迷圈子。egoboo原本是描述人们看到自己名字出现在出版物上的感觉,由于做到这点比较可行的方式是做一些值得被别人提及的事情,该概念很快被用到了志愿者活动中。】
linus成功地将自己置于项目看门人的地位:大多数开发工作是他人完成的,他不断培养大家对项目的兴趣直到它能够自我维持下去,这表现出他对Kropotkin“共识原则”的敏锐领会。用这种“准经济”(quasi-economic)视角来观察Linux世界,有助于我们理解“共识原则”是如何应用的。
可以把Linus方法看成是创造一个有效率的“egoboo”市场:把一个个黑客的利己动机尽可能牢靠地牵系到一个艰巨的任务目标上,而这个目标只有在众人持续的合作之下能达成。正如我在fetchmail项目上所展示的(虽然项目小了点),Linus方法可以被复制并取得很好效果,我做得只是更有意识和更有计划一些。
很多人(尤其是那些在意识形态上不相信自由市场的人)把个人导向为主的利己主义文化看成是碎片化的、本位主义的、浪费资源的、不共享和不友善的,这里仅给出一例,就能很有力地证伪这个认识:那就是Linux文档有着令人震惊的广度、深度和质量。程序员痛恨写文档似乎已经成为一个不争的事实,那为什么Linux黑客们还要写出这么多文档?很明显,Linux自由的“egoboo”市场比那些有重金投资的商业软件公司,能够产生更有道德、更利他的行为。
fetchmail和Linux核心项目都表明,如果对参与者的“自我”做适当奖赏,一个优秀的开发者或协调者可以利用Internet获取多开发者的好处,而不会让项目陷入混乱不堪。所以对Brooks定律,我有如下的对立意见:
19.如果开发协调者有一个至少像Internet这样好的沟通媒介,并且知道如何不靠强制来领导,那么多人合作必然强于单兵作战。
我认为开源软件的未来会越来越属于那些懂得如何玩转Linus定律的人,属于那些离开大教堂并拥抱集市的人。这不是说个人眼光和远大志向不再重要,相反,冲在开源软件最前沿的人,正是凭借自己的眼光和才华而发起项目,并通过建设一个有效的志愿者社区将之越做越大。
可能这不只是开源软件的未来。但没有任何闭源开发者可以发动像Linux社区那样庞大的人才库来解决一个问题,也很少有人能雇得起对fetchmail做出贡献的那200多人(1999:600,2000:800)!
可能最终导致开源软件取得胜利的,不是因为“合作是道德正确的”或“软件闭锁是道德错误的”(也许你相信后者,但Linus和我不这样认为),而是简单由于闭源世界不能赢得一场与开源社区之间的不断演化的军备竞赛,因为后者可以在一个问题上投入比前者多几个数量级的熟练技术工时。
12
关于管理与马其诺防线
1997年首版的本文结束于上面这个展望:由程序员和无政府主义者组成的快乐的网络部落,战胜和压到了等级森严的传统闭源软件世界。
然而,很多怀疑者并不信服,应该对他们的疑问给予公允的回应。大多数对集市模式的异议都归结到这一点:集市模式支持者低估了传统管理方式带来的生产率乘数效应。
抱有传统观念的软件开发管理者经常会反驳说,开源世界中项目团队形成、变动和解散的随意性,极大抵消了开源社区在人数上相对闭源开发者的明显优势。他们说,软件开发真正需要的是持久的努力和客户预期在产品上持续投资的程度,而不是到底有多少人在锅中扔入一块骨头然后让它慢慢地炖着。
这并不是没有道理,事实上,我在“魔法锅”(The Magic Cauldron)一文中提出了这样的观点:未来软件产业的经济关键是服务价值。
反对者的这个论点暗藏了这样的假设:开源开发不能提供“持续的努力”。事实上,有一些开源项目长期保持着连贯的方向和有效的社区,而没有任何传统管理认为不可或缺的奖励体制或管控机构。GNU Emacs编辑器是一个极端的、有启发性的例子,尽管该项目的人员流动率很高,从始至今持续起作用的只有一人(Emacs的作者),但15年来,仍然有数百名贡献者投入努力,他们合作造就了一个统一的架构体系,还没有哪个闭源编辑器能匹敌这样的长寿记录。
这倒是给了我们一个质疑传统开发管理有什么优势的理由(与大教堂与集市模式的争议无关)。GNU Emacs能够在15年内保持一致的架构体系,像Linux这样的操作系统在硬件和平台技术不断变化的8年来也做到了这一点,很多设计优秀的开源项目发展都超过了5年(事实上确实如此)——我们当然有权利怀疑,传统开发管理的巨大花费,究竟给我们带来了什么。
不管是什么,它肯定不是这三个目标的达成:最后期限、预算、需求书中的所有功能。能达到其中一个目标,就已经是很少见的管得不错的项目,更不用说三个全达到了。它也不是在项目生命周期内适应科技和经济变化的能力,这方面,开源社区已被证明远远更为有效(这很容易被核实,比如说,比较Internet至今30年的历史和专有网络技术很短的半衰期;或者比较微软将Windows从16位过渡到32位的成本以及同时期Linux完成同样升级的毫不费力——不仅仅是在Intel产品线,还包括64位Alpha处理器在内的十多类硬件平台)。
一些人认为购买传统模式产品会带来这样的保障:如果项目出错,会有人负责,并为可能的损失买单。但这只是一个幻觉,大多数软件许可证连对商品的保证都没有,更不用履行责任了——因软件质量差而成功获得赔偿的案例几乎没有。即便很常见,也不要因为可以起诉某人就觉得心安,你想要的不是官司,你想要的是能用的软件。
那么所有这些管理开销能带来什么?
为弄明白这点,我们需要了解软件开发管理者是如何看待自己工作的,我有位朋友看上去在这方面做得很好,她说软件管理有五个功能:
明确目标并让大家朝同一个方向努力。
监督并确保关键细节不被遗漏。
激励人们去做那些乏味但必要的“体力活”。
组织人员部署并获得最佳生产力。
调配项目所需的资源。
显然所有这些目标都是有价值的,但在开源模式及其所在的社会语境中,人们会惊奇地发现这些目标毫无意义,我们按颠过来的顺序分析:
朋友告诉我,很多资源调配基本上都是防守性的:一旦你拥有人、机器和办公空间,你就不得不防备同级管理人员对资源的竞争,以及上级对有限资源中最有效部分的调用。
但开源开发者是志愿者,是因为兴趣和能力(能否对项目有所贡献)自主选择的(即便他们因开源工作领取薪水,这仍然适用),志愿者倾向于自发去解决资源问题,他们会把自己的资源带到工作中,这里几乎没有传统意义上“防守”的必要。
不论如何,在一个廉价PC和快速Internet连接的世界里,我们发现真正有限的资源是技术人员的关注,开源项目如果失败了,根本不会是因为机器、网络或办公场地,它们死掉的唯一原因就是开发者们不再感兴趣了。
这种情况下,黑客的“自组织”形式格外重要:志愿者选择项目,社会则选择能力。我那个朋友对开源世界和大型封闭项目都比较熟悉,她相信开源之所以成功,部分原因是开源只接受编程人员中那最有才华的5%。她将自己的大部分时间都花在了组织其他的95%,并因而第一手见证到那广为人知的差异:最有才华的程序员和那些刚刚及格的程序员之间,生产率能相差100倍。
人们常常会因为这种差异提出一个棘手的问题:对单个项目或者整个行业来说,撤离出那50%能力较差的程序员会不会更好一些?思考已久的管理者们早就明白,如果传统软件管理的目的仅仅是把能力最差那部分人的净损耗转变成微弱盈余的话,那问题就简单多了。
开源社区的成功使得这个问题更加尖锐,强有力的证据表明,从互联网上招募自主选择的志愿者,通常更便宜更有效。而传统方式管理的那整栋整栋楼里的人,其中有很多人宁愿去干点别的。
这很直接把我们带到“动机”问题上,一个经常听到的说法和我朋友的观点一致:传统开发管理是对缺乏激励的程序员们的必要补充,否则他们不会干得很好。
这个答案常常伴随着这样一种观点:开源社区只会去做那些很吸引人或者技术上很好玩的东西,其他“无聊”部分则会被丢在一边(或半途而废),等那些受金钱激励的坐在隔间里的苦工们在管理者的严厉鞭策下,机械地将其生产出来。我将从心理学和社会学方面,在“开垦心智层”(Homesteading the Noosphere)一文中对这种观点进行质疑。
如果传统、闭源、严格管理模式的软件开发真的想靠这种由“无聊”部分组成的马其诺防线来防御,那么它之所以在某个应用领域能继续生存下去,只是因为还没人发现这些问题是真正有趣的,并且还没人发现迂回包抄的路径。一旦有开源力量介入这些些领域,用户就会发现终于有人是因为问题自身的魅力而去解决它的,就像其他所有需要创造力的工作,若论激励效果,问题自身的魅力比单纯的金钱要有效得多。
单纯为解决动机问题而设立一个传统的管理架构,战术也许不错,但战略是错误的,短期看也许有效,但长远来说一定失败。
目前看来,传统的开发管理相对于开源,至少在两方面(资源调配和组织)都没有胜算,而且似乎在第三点上(动机)也难以为继。可怜的传统管理者,现在是四面楚歌,在“监管”这个话题上也无法获取一丝安慰,开源社区最强大的一个长项就是非中心化的同行评审,所有致力于细节不被疏漏的传统方法,都无法和它相比。
那么,“明确目标”的作用是否可以作为传统软件项目管理值得存在的正当理由?也许是,但是,比起开源世界由项目领导人和部落长老决定目标的方式,我们需要有好的理由相信管理委员会和公司路线图所定义的目标在价值上和接受度上能做得更成功。
我们很难相信这点。并不是因为开源这边(Emacs经久不衰,Linus Torvalds号召大量开发者们“统领世界”)表现得太优秀,而是传统机制在定义项目目标方面,做得实在太糟。
【译者注:Linus Torvalds于1999年在"The Linux Edge"一文中提到:“Linux现在有数百万用户、数千名开发者和正在增长的市场,Linux被用在嵌入式系统中,用在机器人系统中,用在航天飞机上,我想说我早知道这些都会发生,这些都是统领世界计划的一部分”。】
软件工程中最广为人知的一条大众定理是:传统软件项目中的60%到70%,要么从未被完成,要么被他们的用户拒绝。如果这个比例还算靠谱的话(我还没见过任何一个有经验的项目管理者对此提出过异议),那么大多数项目把目标设定得要么太不现实,要么完全错误。
这正是如今软件工程领域中,一听到所谓“管委会”就让人后背发凉的原因——即便(或尤其)听者是一名管理者。以前仅仅是程序员抱怨这种模式,现在,呆伯特玩偶已经出现在主管的办公桌上。
【译者注:呆伯特(Dilbert)是美国作家和漫画家Scott Adams创造的广为流行的职场卡通人物。呆伯特是一名计算机工程师,热爱科技、待人友善、憨厚老实,但很不成功,在公司里人微言轻,常常被主管过份要求和利用。】
所以,我们对传统软件开发管理者的答复就很简单了——如果开源社区真的低估了传统管理的价值,那为什么你们中这么多人都表现了对你们自己流程的不屑?
又一次,开源社区的例子把这个问题变得更为尖锐——我们做这些是为了乐趣。我们创造性的游戏已经在技术上、市场占有率上、观念认同上以令人震惊的速度获得了增长,我们不仅证明了我们可以做出更好的软件,而且证明了快乐也是一种资产。
本文第一版发布已经两年半了,我能提供用来作为结束语的最激进观点,已经不再是“开源统领软件世界”这样的愿景了,毕竟那些很严肃的西装革履的人,也认为这种观点有些道理了。
更进一步,我想给出一个更普遍的关于软件的经验 (可能适用于所有创造性或专业性工作),人类通常会从一种位于“最佳挑战区”的任务中获得乐趣,也即它不是太容易而让人无聊,也不是太困难而无法完成。一个快乐的程序员是一个既没有被浪费也没有被压垮(由于不适当的目标或过程中充满压力与冲突)的人,乐趣预示着效率。
如果你在工作过程中感到恐惧和厌恶(即便你以自嘲的形式来表达——比如悬挂呆伯特玩偶),就应该意识到过程已经出了问题。快乐、幽默和玩兴是真正的资产,前面我之所以写“快乐部落”(happy horde)并不是为了首字母押韵,而用一只憨态可掬的企鹅作为Linux吉祥物也绝不仅仅是为了搞笑。
现在看来,开源成功的一个最重要成果,就是告诉我们,“玩”是创造性活动中最具经济效能的工作模式。
13
后记:网景拥抱“集市模式”
感觉自己正在帮助创造历史的感觉实在很奇妙……
1998年1月22日,大约在我首次发布“大教堂与集市”七个月后,网景通信公司宣布了开放Netscape Communicator浏览器源代码的计划。此前,我一点消息也不知道。
很快,网景的执行副总裁和首席技术官Eric Hahn给我发了一封电子邮件:“我代表网景公司所有员工,感谢您帮助我们走到这一步,您的思考和写作,对我们的决定予以了至关重要的启发。”
接下来的一周,我受网景之邀飞抵硅谷,和他们的高管层以及技术人员开了一个长达一整天的战略会议(1998年2月4日),我们在会议上设计了网景源码的发布策略及许可声明。
几天后我写道:
“网景准备在商业世界中给我们提供一个大规模的、真实的集市模式的测试。开源文化现在面临一个危险:如果网景此举失败,那么开源概念将受到严重怀疑,商业世界将在未来十年中都不再碰它。
另一方面,这也是一个绝好的机会,华尔街以及其他一些机构,对这件事的初步反应是审慎乐观的。我们也获得了一个证明自己的机会,如果网景通过此举能够重新收复市场份额,那将会引发一场早该到来的软件产业革命。
接下来的一年将会非常有启发性,也会非常有意思。”
事实上确实如此。2000年年中我修订此文的时候,项目(后来被命名为Mozilla)发展的情况只能说勉强成功,它达到了网景的最初目标——阻止微软在浏览器市场上的垄断锁定。同时也取得了一些引人注目的成就(特别是下一代浏览器内核Gecko的发布)。
然而,开放浏览器源码还没能像Mozilla创立者最初希望的那样,聚拢大规模的来自网景外部的开发力量【编者评:聚拢粉丝何谈容易,程序员只愿意做他们愿意投入的事】。分析其原因,大约是,在很长一段时间内,Mozilla的发布实际上违反了集市模式的一条基本规则,也即它的发布缺少能让潜在贡献者可以轻易运行和查看效果的东西(发布后的一年多时间内,编译Mozilla源代码都需要Motif私有库的许可证)。
最消极的是(从外界来看),Mozilla组织在项目开始两年半内都没能发布一款商品级的浏览器。而且在1999年,一位项目核心成员的离职引发了不小的影响,他抱怨项目糟糕的管理和机会的错失,并正确的评论道:“开源并不能点石成金。”
现在(2000年11月)看来,比起Jamie Zawinski写离职信的那时, Mozilla的前景有了戏剧性的改善——最近几周的每夜版(nightly releases)已经终于在产品可用性上通过了关键性门槛。但Jamie没有说错,对于一个已有项目,走向开源不一定就能让项目免受目标错误、代码杂乱以及任何其他软件工程慢性病的困扰。Mozilla同时示例了如何让开源成功和如何让开源失败。
与此同时,开源理念在其他很多地方已经获得了成功和支持。自网景发布源码以来, 我们看到人们对开源模式的兴趣有爆发式的增长:这种趋势由Linux操作系统推动,并推动Liunx继续获得成功,Mozilla引发的潮流将继续加速前行。
注:
1.在《Programing Pearls》(编程珠玑)一书中,著名计算机科学家Jon Bentley对Brooks这个观点的评论是:“如果你计划抛弃一个,你会抛弃第二个。”基本上他说的是对的,Brooks和Bentley不只是说你对第一次尝试失败要有所预期,而且强调“用正确的办法重新来过”往往比整理一堆乱麻要有效得多。
2.在互联网井喷之前,就有开源集市开发模式的成功例子,而且和Unix及互联网传统并无关系,1990年至1992年间info-Zip(主要用于DOS系统的压缩工具,http://www.cdrom.com/pub/infozip/)的开发就是一例,另一例则是诞生于1983年的RBBS公告板系统(也是用于DOS的),它发展出足够强大的社区,尽管互联网邮件和文件分享相比本地BBS有着巨大的技术优势,但直到现在(1999年中后期),RBBS还有着相当规律的发布。info-Zip社区在一定程度上依赖互联网邮件,但RBBS的开发者文化实际上是建立在一个规模很大的RBBS在线社区之上,它完全独立于TCP/IP基础设施。
3.透明性和同行评审对控制操作系统开发的复杂性很有价值,这并不是新观点,1965年,在分时操作系统发展的早期,Multics操作系统的两位设计者Corbató和Vyssotsky写道:“Multics系统将在大规模试用后再发布……这样做出于两点考虑:第一,系统要经得起公众审视和有兴趣读者的批评;第二,在系统日益复杂的时代,现在和未来的系统设计者有义务让操作系统内部尽可能清晰易懂,以便揭示系统的基本问题。”
4.关于重复劳动不一定会拖累开源开发,John Hasler给出了一个有趣的解释,我把它称为“Hasler定律”:重复劳动的代价通常和团队成员数成“次二次方”(sub-quadratically)关系——也就是说,重复劳动的成本比计划和管理成本增长得慢得多,后者更需要想办法消除。
实际上,这个说法和Brooks定律并不矛盾。复杂性成本和Bug带来的脆弱性和团队成员数成二次方关系大概是对的,但重复劳动的代价比较特殊,它随团队成员数的变化更慢,这并不难解释,因为人们容易认可这样的不争事实:划定不同开发者代码的功能界限可以避免重复劳动;相比之下,人们并不认为这样就能防范整个系统内各种非预期的不良交互(正是它们导致了大多数bug)。
将Linus定律和Hasler定律结合起来可以发现,软件项目的规模(可分为三种)很关键。对于小项目(我认为也就一到三个开发人员)而言,没有什么管理结构比好好找一个主力程序员更有效。对于规模稍微大一些的项目,由于传统管理成本相对较低,能避免重复劳动,虽然在跟踪错误方面差一些,但总体效果是好的。当项目规模大到一定程度,传统管理的成本和问题会比重复劳动的成本增长得快得多,集市模式虽然有自身问题,但可以利用“多眼球效应”(many-eyeballs effect),所以在确认Bug和易疏漏细节上比传统模式要管用得多。因此,对于大型项目,这些定律的组合效果,使得传统管理模式的净收益趋近于零。
5.Linux将实验版和稳定版分开的做法,还有一个与风险对冲相关但又截然不同的作用,那就是解决要命的deadline问题(the deadliness of deadlines)。程序员在需求列表不能调整和最后期限不能拖延的双重要求下,会完全顾不上质量,整个工作很可能会变成一团乱麻。感谢哈佛商学院的Marco Iansiti和Alan MacCormack,他们向我证明,放宽这两个限制的任意一个,都会使进度变得可行。
一种办法是保持最后期限不变而让需求列表灵活一些,允许某些到最后期限时仍未完成的需求被舍弃,这基本上就是“稳定版”核心采取的策略。Alan Cox(稳定版核心的维护人)以相当规律的时间间隔将核心发布,但并不保证某个特定bug何时被修复,也不保证实验版中的某个特性何时会搬到稳定版中。
另一个办法是设定好想要的需求列表,并在其完成时发布,这基本上是“实验版”核心的策略。De Marco和Lister引用研究结果,指出这个进度策略(即“好了告诉我” (wake me up when it's done))不仅能够保证最高质量,而且就平均而言,与“保守”或“激进”的进度安排相比,它的交付时间更短。
2000年初,我开始怀疑本文早期版本中我严重低估了“好了告诉我”这一反deadline策略对开源社区生产力和产品质量的重要性。GNOME 1.0在1999年的匆忙发布给我们上了一课:不成熟发布带来的负面影响,会抵消开源通常所带来的质量收益。
现在看来,开源提升产品质量的三架马车中,“好了告诉我”和开发者“自我选择”是两架,另一架是“过程透明"。
6.Brooks关于解决N平方复杂性问题给出的建议是建立“手术团队”型组织,有人将开源项目“核心+光环”(core plus halo)式组织看做是“手术团队”的互联网版本,这种类比很有意思,也不是完全不对,但有很大区别:Brooks设想团队首领周围有一群不同角色的专家(如“代码管理员”),事实上这些角色并不真的存在,一个技术较强的开发者,配上些工具(比Brooks那个年代的工具要强多了),就可以替代Brooks说的这些角色;而开源文化十分倚重的UNIX传统——模块化、API和信息隐藏——都不是Brooks处方上的元素。
7.在谈及bug定位难度时,有位读者曾向我指出,bug跟踪路径长短的差异很大,他推测,对于那种多症状bug,循迹难度将随症状数呈“指数分布”(我认为呈“高斯分布”或“泊松分布”更合理一些)。如果有可能通过实验获得该分布形状的数据,那将会很有价值。由于跟踪困难度远不是一个等概率平均分布,建议即便是单人开发者,也效仿一下集市策略,对每个症状设定一个循迹时间,过了这个时间还找不到,就换另一症状去查。坚持不懈也许并不总是对的......
8.关于能否使用集市模式从零开始一个项目,关键在于集市模式能否支持真正有创新性的工作。有人声称,如果缺少强有力的领导,集市只能克隆和改进已有最高水平的工程创意,但不能将其推向更高的水平。这也许是万圣节文件(两篇令微软尴尬的关于开源现象的内部备忘录)中最臭名昭著的说法,其作者将Linux这种Unix类操作系统的开发比作是“追逐尾灯”,并认为“(当项目达到最高水平时,)管理也要走在最前沿,而且要强大有力。”这种说法隐含着严重的事实性错误,比如万圣节文件的作者们后来自己也认识到:“通常......,相比其他平台,新的研究成果总是最先在Linux上得到实现和使用。”
Linux并不是开源世界里的新事物,从历史上看,开源社区并不是通过“追逐尾灯”(chasing taillights)和“强有力管理”(massively managed)发明的Emacs或万维网或互联网本身,而且目前开源方面的创新工作已经多得让开发者都不知道该选哪个好。随手举个例子,GNOME 项目正把GUI和对象技术推向最高水平,不仅在Linux社区,在计算机行业媒体中它也获得了强烈的关注。其他例子还有很多,随便哪天你访问一下Freshmeat(http://freshmeat.net/),都会很快证实这点。
有种错误的观点认为教堂模式(或集市模式,或任何其他形式的管理结构)在一定程度上能可靠的产出创意,这完全是无稽之谈。一帮人在一起,不会有什么突破性的创见——即便是集市中那些无政府主义者组成的志愿者团体,通常也不能有真正的创见,更不要说公司委员会中那些为生计着想的还活在过去年代的人了。远见源自个人,社会机器的最好做法,就是响应这些有突破性的远见——培育、奖励并测试新的创意,而不是压制创意。
有人认为这是对发明家独行特立个性的怀旧,其实不然,我并不是断言一群人不能开发和孵化一个突破性创意,事实上,从同行评审过程可知,正是这类团体开发了高质量的产品。我只是想说,每个这样的团体开发,都必然源自于某人头脑中的一个好创意。大教堂、集市和其他社会结构都可以捕捉这个闪光点并使它更完美,但这些闪光点可不是想要就能有的。
因此创新的根本问题(在软件或任何其他领域中)是如何不压制创意——但是,更为根本的是,如何先产生出一批有创见的人。
如果有人认为大教堂模式能够做到这点,而集市模式由于进入门槛低和过程不够稳定而不能做到这点,那就大错特错了。如果我们需要的是一个人和他的创意,那怎样的社会环境会更有利于这个创意的实现?一个能凭借创意迅速吸引成百上千合作者的环境,必然要好于任何这样的环境:创意发明者必须要向领导推销他的创意,否则就有自行其是触怒领导而被炒掉的风险。
事实上,如果查一下有多少软件创新是因为使用大教堂模型导致的,就很快会发现它非常罕见。大公司靠大学研究提供新创意(所以万圣节文件的作者们对Linux能更快吸收这些研究感到不安),或者是靠收购小公司来收购创意,这些都不是公司文化的原生创新。事实上,用这种方式移植的许多创新,都在万圣节文件作者们大力颂扬的“强有力管理”下悄然窒息了。
当然,这是个否定性结论,读者应该看到更具肯定性的结论。我建议:
选定一个你认为你能始终贯彻的对原创性认定的标准。如果你的定义是“看到了我就能判断”,那也没关系。
选择任何一个和Linux竞争的闭源操作系统,然后选一个最佳来源,用于统计该操作系统上的开发工作。
对此来源和Freshmeat进行为期一个月的观察。每天统计Freshmeat发布的公告中你认为有‘原创性’的工作,并使用同一标准统计其它操作系统上的公告。
30天后,分别对两组数字求和。
我写到这里的当天,Freshmeat发布了22条公告,其中有3个可能在某方面达到了最高水平。对Freshmeat而言这天的成绩并不算好,但是,如果任何读者能发现在任何闭源渠道里一个月内有3条类似的创新,我会十分惊讶。
9.现在,我们有了一个比fetchmail能更好对集市模式进行验证的系统:EGCS,http://egcs.cygnus.com/, 即实验性GNU编译系统。
1997年8月中旬,EGCS项目问世了,它是一个对“大教堂与集市”早期版本中的观点进行有意识尝试的项目。项目创始人觉得GCC(GNU的C编译器)开发已经停滞不前。之后20个月内,GCC和EGCS成为并行产品——二者均从互联网上吸纳开发人员,均源于相同的GCC源码库,均使用了几乎一样的Unix工具箱和开发环境。二者不同之处仅在于EGCS有意识地尝试运用我之前描述的集市策略;而GCC则保留一种更类似大教堂模式的组织结构,其开发团队封闭,而且不常发布新版本。
这很像是一个应要求而开展的对照实验,其结果很有戏剧性,数月之内,EGCS版本在一些特性上已经有了实质性领先,比如更好的优化,以及对FORTRAN和C++的更好支持。很多人发现EGCS的开发快照要比GCC的最新稳定版本更可靠,而主要的Linux发行版已经开始转向EGCS。
1999年4月,自由软件基金会(GCC的官方赞助商)解散了原有GCC开发小组,并正式将该项目控制权移交给EGCS指导小组。
10.当然,Kropotkin批判和Linus定律引发了人们对社会组织控制论的更广范思考。比如软件工程的一个通俗理论——Conway定律——常常被表述为“如果有四个小组致力于开发一个编译器,那么你将会得到一个四步(4-pass)编译器。”其原始陈述更具一般性:“如果一个系统由多个组织共同设计,那么其设计的系统的结构,就是这些组织间沟通结构的翻版。”我们可以更简洁地称之为“方法决定结果”,或者乃至“过程变成产品”(Process becomes product)。
值得注意的是,开源社区的组织形态和功能在很多层面上是匹配的。网络就是一切而且无处不在;不只是互联网,还包括在其上工作的人,这些人形成了一个分布式、松耦合以及点到点的网络,它很优雅地实现了多重冗余和去等级化。这两个网络中,一个节点只有在其他节点想要和它合作时才显得重要。
点到点结构是开源社区惊人生产力的关键。Kropotkin曾经对权力关系做出的评价被“SNAFU原则”进一步阐明:“只有平等个体之间才有真正的交流,因为下级向上级讲好听的谎话会比讲真话更能得到持续的奖励。”真正的交流是创造型团队必不可少的,而权力关系将极大制约这点。开源社区有效避免了这种权力关系,并通过对比告诉我们权力关系会带来多么糟糕的代价:大量的Bug、低下的生产力和机会的丧失。
【译者注:SNAFU,Situation Normal All Fucked Up的缩写,是指事态已经混乱不堪,但从管理上看一切正常。该用语源于军队,因为士兵向长官汇报时经常说“一切正常!”(Situation Normal)】
更进一步,“SNAFU原则”预测:在权力组织中,决策者和现实情况会越来越脱节,因为决策者会听到越来越多好听的谎言。在传统软件开发中很容易看到这一点,由于下级有强烈的动机去隐藏、忽略和最小化问题,当这个“过程变成产品”时,软件会成为一个灾难。
参考文献:
我引用了Frederick P. Brooks 经典之作“The Mythical Man-Month”中的一些内容,在很多方面,他的观点还需要改进。真心推荐由Addison-Wesley出版社发行的25周年纪念版,这版中新增了Brooks在1986年发表的“No Silver Bullet”。
新版中还有一篇非常有价值的Brooks的回顾,他在20年后对该书重新思考,并坦率承认原文中有几个观点没有经受得住时间的检验。我首次读到这篇回顾时(在本文首个公开版本大致完成时),惊讶地发现Brooks把集市类(bazaar-like)实践归功于微软!(事实上,这种归功后来被证实是错误的。1998年,我们从万圣节文件(http://www.opensource.org/halloween/)中了解到微软内部的开发社区是被严重分割的,他们甚至都没有集市模式所需要的共享源码库。)
Gerald M. Weinberg在“The Psychology Of Computer Programming ”(New York: Van Nostrand Reinhold, 1971)一书中介绍了 “无私编程”(egoless programming)的概念,虽然这个命名有点令人遗憾。早在他之前就有人认识到“命令原理”(principle of command)的无用性,但Weinberg可能是在软件开发领域最早意识到并提出这点的人。
Richard P. Gabriel对Unix文化进行了深入的思考(早在Linux时代之前),1989年他在“LISP: 好消息, 坏消息,如何成为大赢家”一文提出了一个简单的集市类模型,并不太情愿地论证了它的优越性:虽然这篇文章略显过时,但它仍然在LISP粉丝中(包括我)受到追捧。一个读者提醒我说“Worse Is Better”那节几乎是对Linux的预言。这篇文章可以在http://www.naggum.no/ worse-is-better.html 中找到。
De Marco和 Lister的著作“Peopleware: Productive Projects and Teams ”(New York: Dorset House, 1987) 是一篇被低估了的佳作,我很高兴看到Fred Brooks在他的回顾中引用了该文。尽管作者极力主张的观点并不能直接应用于Linux或开源社区,但其对创造性工作必要条件的洞见是敏锐的,对任何想要把集市模型优点融入商业环境的人来说,该书都值得一读。
最后,我必须承认我差点把本文命名为“The Cathedral and the Agora”, Agora在希腊语中是公开市场或公共聚会场所的意思。Mark Miller和Eric Drexler在多篇论文中提出了有开创性意义的“agoric systems”,描述了这种市场类型计算生态的突出特点,这使得在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) 指出了贡献者自我选择的重要性,并提出多流程开发可以修复“疏漏型bug”这个颇具意义的观点。Daniel Upper (upper@peak.org) 提出了关于这点的自然类比。非常感谢PLUG(费城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的意见很有帮助,他很早就对本文表示认可,这实在令人鼓舞。
翻译:卫剑钒