The Cathedral and the Bazaar (1)

==========征求批评反馈,谢谢============

The Mail Must Get Through

Since 1993 I'd been running the technical side of a small free-access Internet service provider called Chester County InterLink (CCIL) in West Chester, Pennsylvania. I co-founded CCIL and wrote our unique multiuser bulletin-board software—you can check it out by telnetting to locke.ccil.org. Today it supports almost three thousand users on thirty lines. The job allowed me 24-hour-a-day access to the net through CCIL's 56K line—in fact, the job practically demanded it!

I had gotten quite used to instant Internet email. I found having to periodically telnet over to locke to check my mail annoying. What I wanted was for my mail to be delivered on snark (my home system) so that I would be notified when it arrived and could handle it using all my local tools.

The Internet's native mail forwarding protocol, SMTP (Simple Mail Transfer Protocol), wouldn't suit, because it works best when machines are connected full-time, while my personal machine isn't always on the Internet, and doesn't have a static IP address. What I needed was a program that would reach out over my intermittent dialup connection and pull across my mail to be delivered locally. I knew such things existed, and that most of them used a simple application protocol called POP (Post Office Protocol). POP is now widely supported by most common mail clients, but at the time, it wasn't built in to the mail reader I was using.

I needed a POP3 client. So I went out on the Internet and found one. Actually, I found three or four. I used one of them for a while, but it was missing what seemed an obvious feature, the ability to hack the addresses on fetched mail so replies would work properly.

The problem was this: suppose someone named `joe' on locke sent me mail. If I fetched the mail to snark and then tried to reply to it, my mailer would cheerfully try to ship it to a nonexistent `joe' on snark. Hand-editing reply addresses to tack on <@ccil.org> quickly got to be a serious pain.

This was clearly something the computer ought to be doing for me. But none of the existing POP clients knew how! And this brings us to the first lesson:

从1993年以来,我在负责宾州西切斯特的一家提供免费网络服务的小公司CCIL的技术工作。我协同创建了CCIL,并写了我们独家的多用户论坛软件——您可以用telnet连接locke.ccil.org来试一下。今天它在三十条线上支持近三千名用户。这份工作允许我通过CCIL的56K的线路每天二十四小时上网——其实,这份工作事实上要求这一点!
我已经习惯于使用即时的互联网邮件。我发现不时地要telnet登录上公司服务器“locke”检查邮件很烦人。我想要的是把我的邮件传送到我家里的机器“snark”上,这样我可以在邮件到达的时候得到通知,使用本地工具来处理它。

互联网的原装邮件输送协议SMTP不适用,因为它最好在机器全时在线的情况下使用,而我的个人机器并不总在网上,也没有一个静态的IP地址。我需要一个程序在我拨号上网的期间连到服务器上去,把我要下到本地的邮件取回来。我知道有这类东西存在,多数使用一个简单的应用协议POP。现在多数的常用客户端邮件软件都支持POP,但那个时候,它并不在我用的邮件阅读器里。

我需要一个POP3的客户端软件。所以我就跑到网上找了一个。事实上,我找到了三四个。其中的一个我用了一段时间,但它少了一个看起来很明显的功能:提取到达邮件的来信地址以便正确回信。
问题是这样的:假设“locke”上一个叫“乔”的人给我发了信。如果我把信取到“snark”上,然后试图回复,我的邮件程序会高高兴兴地努力把回信发送给“snark”上一个并不存在的“乔”。通过手工修改回信地址给邮件重新导向很快就成了很痛苦的事。

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

1. Every good work of software starts by scratching a developer's personal itch.

Perhaps this should have been obvious (it's long been proverbial that ``Necessity is the mother of invention'') but too often software developers spend their days grinding away for pay at programs they neither need nor love. But not in the Linux world—which may explain why the average quality of software originated in the Linux community is so high.

So, did I immediately launch into a furious whirl of coding up a brand-new POP3 client to compete with the existing ones? Not on your life! I looked carefully at the POP utilities I had in hand, asking myself ``Which one is closest to what I want?'' Because:

2. Good programmers know what to write. Great ones know what to rewrite (and reuse).

While I don't claim to be a great programmer, I try to imitate one. An important trait of the great ones is constructive laziness. They know that you get an A not for effort but for results, and that it's almost always easier to start from a good partial solution than from nothing at all.

1)每一个好的软件的起因都是挠到了开发者本人的痒处
这或许应该是很显然的(一直有箴言道是“需要是发明之母”),但软件开发人员太过经常地在那些他们既不需要也不喜欢的程序上消磨时日、换取工资。但在Linux世界不是这样子的——这或许解释了为什么Linux社区中产生的软件平均质量这么高。
那么,我立马儿投入到了一轮疯狂的编码来写一个和现有POP3客户竞争的软件了吗?打死你都不会!我仔细检查了我拿到手的那些POP程序,自问“哪一个离我要的最接近?”因为:

2)好的程序员知道写什么。伟大的程序员知道改写(和重复使用)什么。
虽然我不自封为伟大的程序员,但我努力模仿伟大的程序员。伟大者的一个重要特点是建设性的懒惰。他们知道你需要的是结果不是过程,而且从一个好的部分方案开始总比从零开始要容易得多。

Linus Torvalds, for example, didn't actually try to write Linux from scratch. Instead, he started by reusing code and ideas from Minix, a tiny Unix-like operating system for PC clones. Eventually all the Minix code went away or was completely rewritten—but while it was there, it provided scaffolding for the infant that would eventually become Linux.

In the same spirit, I went looking for an existing POP utility that was reasonably well coded, to use as a development base.

The source-sharing tradition of the Unix world has always been friendly to code reuse (this is why the GNU project chose Unix as a base OS, in spite of serious reservations about the OS itself). The Linux world has taken this tradition nearly to its technological limit; it has terabytes of open sources generally available. So spending time looking for some else's almost-good-enough is more likely to give you good results in the Linux world than anywhere else.

And it did for me. With those I'd found earlier, my second search made up a total of nine candidates—fetchpop, PopTart, get-mail, gwpop, pimp, pop-perl, popc, popmail and upop. The one I first settled on was `fetchpop' by Seung-Hong Oh. I put my header-rewrite feature in it, and made various other improvements which the author accepted into his 1.9 release.

A few weeks later, though, I stumbled across the code for popclient by Carl Harris, and found I had a problem. Though fetchpop had some good original ideas in it (such as its background-daemon mode), it could only handle POP3 and was rather amateurishly coded (Seung-Hong was at that time a bright but inexperienced programmer, and both traits showed). Carl's code was better, quite professional and solid, but his program lacked several important and rather tricky-to-implement fetchpop features (including those I'd coded myself).

Stay or switch? If I switched, I'd be throwing away the coding I'd already done in exchange for a better development base.

A practical motive to switch was the presence of multiple-protocol support. POP3 is the most commonly used of the post-office server protocols, but not the only one. Fetchpop and the other competition didn't do POP2, RPOP, or APOP, and I was already having vague thoughts of perhaps adding IMAP (Internet Message Access Protocol, the most recently designed and most powerful post-office protocol) just for fun.

But I had a more theoretical reason to think switching might be as good an idea as well, something I learned long before Linux.

以林纳斯·托瓦兹为例,他实际上没有试图从头来写Linux。相反,他开始于再用Minix——一个小小的在PC机上的类UNIX系统——的代码和主意。最终所有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版本。

然而几个星期以后,我碰到了卡尔·哈里斯的“popclient”代码,发现我遇到了一个问题。尽管fetchpop有一些很好的新主意(例如它的后台daemon模式),它只能处理POP3协议,而且程序代码写的比较业余(松宏当时是个聪明但是缺少经验的程序员,这两个特点都有显示)。卡尔的代码好一些,很专业和稳固,但他的程序缺几个重要的而且难实现的fetchpop里的功能(包括我自己写的那些)。

继续用fetchpop还是转换到popclient上来?如果转换的话,我是扔掉我已经写好的那些代码来换取一个好一些的开发基础。

一个实用的转换动机是对多种协议的支持。POP3是服务器端POP协议中最常用的,但不是唯一的。fetchpop和那一个竞争对手都不支持POP2、RPOP或APOP,而我已经有了为了好玩添加IMAP(最新设计的、最强大的POP协议)的模糊想法。

但我还有一个更理论上的原因来认为转换也是个好主意。这是我远在Linux之前就学到的。

3. ``Plan to throw one away; you will, anyhow.'' (Fred Brooks, The Mythical Man-Month, Chapter 11)

Or, to put it another way, you often don't really understand the problem until after the first time you implement a solution. The second time, maybe you know enough to do it right. So if you want to get it right, be ready to start over at least once [JB].

Well (I told myself) the changes to fetchpop had been my first try. So I switched.

After I sent my first set of popclient patches to Carl Harris on 25 June 1996, I found out that he had basically lost interest in popclient some time before. The code was a bit dusty, with minor bugs hanging out. I had many changes to make, and we quickly agreed that the logical thing for me to do was take over the program.

Without my actually noticing, the project had escalated. No longer was I just contemplating minor patches to an existing POP client. I took on maintaining an entire one, and there were ideas bubbling in my head that I knew would probably lead to major changes.

In a software culture that encourages code-sharing, this is a natural way for a project to evolve. I was acting out this principle:

4. If you have the right attitude, interesting problems will find you.

But Carl Harris's attitude was even more important. He understood that

5. When you lose interest in a program, your last duty to it is to hand it off to a competent successor.

Without ever having to discuss it, Carl and I knew we had a common goal of having the best solution out there. The only question for either of us was whether I could establish that I was a safe pair of hands. Once I did that, he acted with grace and dispatch. I hope I will do as well when it comes my turn.

3)“计划扔掉一个;无论如何你都会扔掉一个的。”()
或者换句话说,直到你第一次实现一个方案之前,你常常并没有真正理解你的问题。第二次呢,或许你已经学到了如果把它做对。所以你要是想把事情做对的话,准备好至少重来一次[JB]。

好吧(我对自己说),对fetchpop做的修改算我的第一次吧。于是我转换了。

在1996年6月25日我给卡尔·哈里斯发送了我写的第一批popclient的补丁后,我发现他一段时间之前就基本上对这个项目失掉兴趣了。项目的源代码有些陈旧了,小臭虫们流连不去。我有很多要修改的东西;我们很快同意我把整个项目接手过来是理所当然了。

在我没有觉察的时候,这个项目升级了。我不再是试图给一个现有的POP客户端程序做点儿小补丁。我负责起了维护整个程序,而且我知道我脑子里冒着的新主意可能会导致一些主要的变动。

在一个鼓励代码共享的软件文化中,这是一个项目进化的自然方式。我在实践这一个原理:

4)如果你有正确的态度,有意思的问题会找到你。

卡尔·哈里斯的态度甚至更重要。他懂得:

5)当你对一个项目失去兴趣时,你的最后的职责是把它交给一个称职的继承者。

尽管卡尔和我从来没有必要讨论过这一点,我们知道我们的共同目标是作出一个目前最好的程序。我们唯一的问题是我能否证明我的可靠性。一旦我作到了,他优雅而迅速地作了交接。我希望当这一天轮到我的时候,我也能做得同样出色。


The Importance of Having Users

And so I inherited popclient. Just as importantly, I inherited popclient's user base. Users are wonderful things to have, and not just because they demonstrate that you're serving a need, that you've done something right. Properly cultivated, they can become co-developers.

Another strength of the Unix tradition, one that Linux pushes to a happy extreme, is that a lot of users are hackers too. Because source code is available, they can be effective hackers. This can be tremendously useful for shortening debugging time. Given a bit of encouragement, your users will diagnose problems, suggest fixes, and help improve the code far more quickly than you could unaided.

6. Treating your users as co-developers is your least-hassle route to rapid code improvement and effective debugging.

The power of this effect is easy to underestimate. In fact, pretty well all of us in the open-source world drastically underestimated how well it would scale up with number of users and against system complexity, until Linus Torvalds showed us differently.

In fact, I think Linus's cleverest and most consequential hack was not the construction of the Linux kernel itself, but rather his invention of the Linux development model. When I expressed this opinion in his presence once, he smiled and quietly repeated something he has often said: ``I'm basically a very lazy person who likes to get credit for things other people actually do.'' Lazy like a fox. Or, as Robert Heinlein famously wrote of one of his characters, too lazy to fail.

In retrospect, one precedent for the methods and success of Linux can be seen in the development of the GNU Emacs Lisp library and Lisp code archives. In contrast to the cathedral-building style of the Emacs C core and most other GNU tools, the evolution of the Lisp code pool was fluid and very user-driven. Ideas and prototype modes were often rewritten three or four times before reaching a stable final form. And loosely-coupled collaborations enabled by the Internet, a la Linux, were frequent.

Indeed, my own most successful single hack previous to fetchmail was probably Emacs VC (version control) mode, a Linux-like collaboration by email with three other people, only one of whom (Richard Stallman, the author of Emacs and founder of the Free Software Foundation) I have met to this day. It was a front-end for SCCS, RCS and later CVS from within Emacs that offered ``one-touch'' version control operations. It evolved from a tiny, crude sccs.el mode somebody else had written. And the development of VC succeeded because, unlike Emacs itself, Emacs Lisp code could go through release/test/improve generations very quickly.

The Emacs story is not unique. There have been other software products with a two-level architecture and a two-tier user community that combined a cathedral-mode core and a bazaar-mode toolbox. One such is MATLAB, a commercial data-analysis and visualization tool. Users of MATLAB and other products with a similar structure invariably report that the action, the ferment, the innovation mostly takes place in the open part of the tool where a large and varied community can tinker with it.

用户的重要性

就这样,我继承了popclient。同样重要的是,我继承了popclient的用户群。拥有用户是件美好的事情,不仅因为他们证实了你满足了一种需要,而且你把事情作对了。在适当培养下,他们可以成为共同开发者。
UNIX传统中的另一个强项,Linux把它发展到快乐极致的一个,是很多用户也是黑客。因为可以得到源代码,他们可以是有效的黑客。这一点对缩短调试时间会非常的有帮助。有一点点鼓励,你的用户们会诊断问题,提出建议和补丁,并以你一个人不可企及的速度帮助改进代码。

6)把用户像合作者来对待是通往快速改进代码和有效调试的最佳通道

这一点所蕴藏的能量很容易被低估。事实上,直到林纳斯·托瓦兹给我们演示了之前,我们开源世界里的几乎所有人都严重低估了它如何随用户数目而增长,不论系统多么复杂。

事实上,我认为林纳斯的最聪明、最有影响的手笔不是建设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 Lisp代码不象Emacs本身那样,可以快速地通过多轮“发行/测试/改进”的循环。

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


Release Early, Release Often

Early and frequent releases are a critical part of the Linux development model. Most developers (including me) used to believe this was bad policy for larger than trivial projects, because early versions are almost by definition buggy versions and you don't want to wear out the patience of your users.

This belief reinforced the general commitment to a cathedral-building style of development. If the overriding objective was for users to see as few bugs as possible, why then you'd only release a version every six months (or less often), and work like a dog on debugging between releases. The Emacs C core was developed this way. The Lisp library, in effect, was not—because there were active Lisp archives outside the FSF's control, where you could go to find new and development code versions independently of Emacs's release cycle [QR].

The most important of these, the Ohio State Emacs Lisp archive, anticipated the spirit and many of the features of today's big Linux archives. But few of us really thought very hard about what we were doing, or about what the very existence of that archive suggested about problems in the FSF's cathedral-building development model. I made one serious attempt around 1992 to get a lot of the Ohio code formally merged into the official Emacs Lisp library. I ran into political trouble and was largely unsuccessful.

But by a year later, as Linux became widely visible, it was clear that something different and much healthier was going on there. Linus's open development policy was the very opposite of cathedral-building. Linux's Internet archives were burgeoning, multiple distributions were being floated. And all of this was driven by an unheard-of frequency of core system releases.
早发布、常发布

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

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

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

但是到了一年以后,当Linux已经引起了广泛注意的时候,显然他们有什么不同的但是远远更为健康的东西。林纳斯的开放性开发政策正与建造大教堂的方式相反。Linux的互联网档案枝蔓繁衍,多个发行种类在坊间流传。而所有这些都由核心系统的前所未闻的发放频率而驱动。

Linus was treating his users as co-developers in the most effective possible way:

7. Release early. Release often. And listen to your customers.

Linus's innovation wasn't so much in doing quick-turnaround releases incorporating lots of user feedback (something like this had been Unix-world tradition for a long time), but in scaling it up to a level of intensity that matched the complexity of what he was developing. In those early times (around 1991) it wasn't unknown for him to release a new kernel more than once a day! Because he cultivated his base of co-developers and leveraged the Internet for collaboration harder than anyone else, this worked.

But how did it work? And was it something I could duplicate, or did it rely on some unique genius of Linus Torvalds?

I didn't think so. Granted, Linus is a damn fine hacker. How many of us could engineer an entire production-quality operating system kernel from scratch? But Linux didn't represent any awesome conceptual leap forward. Linus is not (or at least, not yet) an innovative genius of design in the way that, say, Richard Stallman or James Gosling (of NeWS and Java) are. Rather, Linus seems to me to be a genius of engineering and implementation, with a sixth sense for avoiding bugs and development dead-ends and a true knack for finding the minimum-effort path from point A to point B. Indeed, the whole design of Linux breathes this quality and mirrors Linus's essentially conservative and simplifying design approach.

So, if rapid releases and leveraging the Internet medium to the hilt were not accidents but integral parts of Linus's engineering-genius insight into the minimum-effort path, what was he maximizing? What was he cranking out of the machinery?

Put that way, the question answers itself. Linus was keeping his hacker/users constantly stimulated and rewarded—stimulated by the prospect of having an ego-satisfying piece of the action, rewarded by the sight of constant (even daily) improvement in their work.
林纳斯在以最可能的有效的方式以合作者来对待他的用户:
7)早发布。常发布。听取用户的意见。
快速发布、采纳大量用户反馈,并不怎么算林纳斯的创新(Unix世界很久以来就有这种传统)。他的创新之处是把这个办法升级到了与他开发的系统的复杂性相匹配的规模和强度。在早期的时候(1991左右),我们不是没听说过他一天发布不止一个新的内核版本!因为他比任何人都努力地培养合作开发群体、促进网上合作,他的办法生效了。
但是它怎样生效的呢?这是我能够仿制的,还是只有林纳斯。托瓦兹的独特天才才能实现的?
我想不是的。林纳斯当然是个骨灰级黑客。我们有几个人能从头建造一整个工业级的操作系统核心呢?但是林纳斯并没有作出巨大的概念性突破。林纳斯不是(至少还没有成为)象Richard Stallman或James Gosling (of NeWS and Java)那种设计创新的天才。在我看来,林纳斯更象是工程和执行的天才,有着避开臭虫和死胡同的第六感官、找到从A点到B点最快通道的真本事。确实,整个Linux透露着这种特质,反映了林纳斯本质上的简约的设计方法。
如果快速发布和淋漓尽致的利用互联网媒介不是偶然的,而是林纳斯对最快通道的工程天才洞察力的有机部分,那么他的资本是什么呢?他在这个机制中依靠的是什么呢?
这样一问,答案一目了然。林纳斯在不断地激励和奖掖他的黑客/用户们——激励来自于在参与中得到的自我实现,奖掖来自于看到他们自己的工作的持续(甚至每天)进步。

Linus was directly aiming to maximize the number of person-hours thrown at debugging and development, even at the possible cost of instability in the code and user-base burnout if any serious bug proved intractable. Linus was behaving as though he believed something like this:

8. Given a large enough beta-tester and co-developer base, almost every problem will be characterized quickly and the fix obvious to someone.

Or, less formally, ``Given enough eyeballs, all bugs are shallow.'' I dub this: ``Linus's Law''.

My original formulation was that every problem ``will be transparent to somebody''. Linus demurred that the person who understands and fixes the problem is not necessarily or even usually the person who first characterizes it. ``Somebody finds the problem,'' he says, ``and somebody else understands it. And I'll go on record as saying that finding it is the bigger challenge.'' That correction is important; we'll see how in the next section, when we examine the practice of debugging in more detail. But the key point is that both parts of the process (finding and fixing) tend to happen rapidly.

In Linus's Law, I think, lies the core difference underlying the cathedral-builder and bazaar styles. In the cathedral-builder view of programming, bugs and development problems are tricky, insidious, deep phenomena. It takes months of scrutiny by a dedicated few to develop confidence that you've winkled them all out. Thus the long release intervals, and the inevitable disappointment when long-awaited releases are not perfect.

In the bazaar view, on the other hand, you assume that bugs are generally shallow phenomena—or, at least, that they turn shallow pretty quickly when exposed to a thousand eager co-developers pounding on every single new release. Accordingly you release often in order to get more corrections, and as a beneficial side effect you have less to lose if an occasional botch gets out the door.

And that's it. That's enough. If ``Linus's Law'' is false, then any system as complex as the Linux kernel, being hacked over by as many hands as the that kernel was, should at some point have collapsed under the weight of unforseen bad interactions and undiscovered ``deep'' bugs. If it's true, on the other hand, it is sufficient to explain Linux's relative lack of bugginess and its continuous uptimes spanning months or even years.
林纳斯直接瞄准了调试和开发中人力的最大化,即使代价是程序的稳定性,甚而某个修正不了的严重问题会疏离用户。林纳斯的做法似乎像是他相信:
8)如果beta测试者和合作开发者的群体足够大的话,几乎每个问题都会快速显形,会有人轻而易举地把它解决。
或者通俗一点,“只要眼球足够多,所有问题都很小”。我称之为“林纳斯法则”。
我最早的表述是每个问题“都会有某个人搞明白”。林纳斯有异议:理解和解决问题的人不一定甚至一般不是第一个发现问题的人。“一个人发现问题”,他说,“另一个人把它搞明白。而且我会作证说发现问题更困难一些”。这是个重要的纠正;在下一节我们具体研究实际调试时会看到为什么。但是关键一点是,发现和解决问题这两个步骤一般都会很快完成。
我认为林纳斯法则中包含有大教堂模式和市集模式的关键区别。在大教堂式的编程观念中,臭虫和开发上的问题是复杂、困难和深度的。要几个人全身全力几个月的钻研才有把它们清理干净的信心。所以需要长长的发布周期;一旦等候已久的版本不够完美,失望是不可避免的。
另一方面,在市集式的观念中,你预设臭虫都是简单的问题——至少在上千个共同开发者热心地琢磨每一个新版本的情况下,它们会很快就变简单了。相应地,你频繁发布来得到更多的纠错。作为一个附加效应,偶尔出个大勺子的后果也没有那么严重了。

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

Maybe it shouldn't have been such a surprise, at that. Sociologists years ago discovered that the averaged opinion of a mass of equally expert (or equally ignorant) observers is quite a bit more reliable a predictor than the opinion of a single randomly-chosen one of the observers. They called this the Delphi effect. It appears that what Linus has shown is that this applies even to debugging an operating system—that the Delphi effect can tame development complexity even at the complexity level of an OS kernel. [CV]

One special feature of the Linux situation that clearly helps along the Delphi effect is the fact that the contributors for any given project are self-selected. An early respondent pointed out that contributions are received not from a random sample, but from people who are interested enough to use the software, learn about how it works, attempt to find solutions to problems they encounter, and actually produce an apparently reasonable fix. Anyone who passes all these filters is highly likely to have something useful to contribute.

Linus's Law can be rephrased as ``Debugging is parallelizable''. Although debugging requires debuggers to communicate with some coordinating developer, it doesn't require significant coordination between debuggers. Thus it doesn't fall prey to the same quadratic complexity and management costs that make adding developers problematic.

In practice, the theoretical loss of efficiency due to duplication of work by debuggers almost never seems to be an issue in the Linux world. One effect of a ``release early and often'' policy is to minimize such duplication by propagating fed-back fixes quickly [JH].
或许这不该是如此一个意外。社会学家们多年前就发现了一大群同样内行(或同样白痴)的观察者的平均预测要比其中随机选择的一个人的预测可靠得多。他们称之为“神庙效应”。看来林纳斯显示了这一点甚至适用于调试一个操作系统——甚至在一个操作系统内核的复杂程度上,“神庙效应”可以简化开发。
Linux情形中对“神庙效应”有帮助的特殊的一点是,任何一个项目的参与者都是自我选择的。一个早期评论指出,对Linux的贡献不是来自于一个随机的人群;他们都有足够的兴趣来使用这些软件、研究其机理、试图解决所遇到的问题,而且真正给出显然可行的解决办法。经过了这些筛选的人一般都会有可以贡献的真才实料。

林纳斯法则也可以表述为“调试是可并行的”。尽管调试者们需要一个人来通讯协调,调试者们之间并不需要多少的协调。添加开发人员带来的平方级的复杂度和管理成本在这里不适用。
理论上因为调试者重复做功而导致的效率损失在Linux世界的实践中似乎从来都不是一个问题。“早发布、常发布”策略的一个后果就是通过快速公布反馈修补来把重复做功最小化。

Brooks (the author of The Mythical Man-Month) even made an off-hand observation related to this: ``The total cost of maintaining a widely used program is typically 40 percent or more of the cost of developing it. Surprisingly this cost is strongly affected by the number of users. More users find more bugs.'' [emphasis added].

More users find more bugs because adding more users adds more different ways of stressing the program. This effect is amplified when the users are co-developers. Each one approaches the task of bug characterization with a slightly different perceptual set and analytical toolkit, a different angle on the problem. The ``Delphi effect'' seems to work precisely because of this variation. In the specific context of debugging, the variation also tends to reduce duplication of effort.

So adding more beta-testers may not reduce the complexity of the current ``deepest'' bug from the developer's point of view, but it increases the probability that someone's toolkit will be matched to the problem in such a way that the bug is shallow to that person.

Linus coppers his bets, too. In case there are serious bugs, Linux kernel version are numbered in such a way that potential users can make a choice either to run the last version designated ``stable'' or to ride the cutting edge and risk bugs in order to get new features. This tactic is not yet systematically imitated by most Linux hackers, but perhaps it should be; the fact that either choice is available makes both more attractive. [HBS]
布洛克甚至作过一个相关的非正式评论:“一个广泛使用的程序的维护费用一般是它的开发成本的40%以上。令人惊奇的是,这个费用受到用户数目的强烈影响。用户越多,发现问题越多。”[]

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

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

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


How Many Eyeballs Tame Complexity

It's one thing to observe in the large that the bazaar style greatly accelerates debugging and code evolution. It's another to understand exactly how and why it does so at the micro-level of day-to-day developer and tester behavior. In this section (written three years after the original paper, using insights by developers who read it and re-examined their own behavior) we'll take a hard look at the actual mechanisms. Non-technically inclined readers can safely skip to the next section.

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

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

One key to understanding is to realize exactly why it is that the kind of bug report non–source-aware users normally turn in tends not to be very useful. Non–source-aware users tend to report only surface symptoms; they take their environment for granted, so they (a) omit critical background data, and (b) seldom include a reliable recipe for reproducing the bug.

The underlying problem here is a mismatch between the tester's and the developer's mental models of the program; the tester, on the outside looking in, and the developer on the inside looking out. In closed-source development they're both stuck in these roles, and tend to talk past each other and find each other deeply frustrating.

Open-source development breaks this bind, making it far easier for tester and developer to develop a shared representation grounded in the actual source code and to communicate effectively about it. Practically, there is a huge difference in leverage for the developer between the kind of bug report that just reports externally-visible symptoms and the kind that hooks directly to the developer's source-code–based mental representation of the program.
理解存在差别的关键在于,认为对源代码知之甚少的用户所递交的Bug报告没有多少用处。这些用户一般只会报告表面症状;他们把运行环境当作理所当然的了,所以这些提交的报告(一)漏掉了关键的背景数据,(二)极少包括能再现Bug的必要步骤。
这里深层的问题是测试者和开发者脑中对程序的模型的不匹配;测试者从外往里看,而开发者从里往外看。在源代码封闭的开发模式中,他们都被卡在各自的这种角色里了,往往个说个的话,觉得对方相当恼火。
开源开发打破了这种束缚,使得在实在的源代码的基础上建立一个共享的模型、就之进行有效的交流对测试者和开发者容易的多。在实践中,那种仅仅描述外观症状的臭虫报告和直接联系到建立在开发者的代码上的抽象程序模型的报告,给予开发者的帮助是大不相同的。

Most bugs, most of the time, are easily nailed given even an incomplete but suggestive characterization of their error conditions at source-code level. When someone among your beta-testers can point out, "there's a boundary problem in line nnn", or even just "under conditions X, Y, and Z, this variable rolls over", a quick look at the offending code often suffices to pin down the exact mode of failure and generate a fix.

Thus, source-code awareness by both parties greatly enhances both good communication and the synergy between what a beta-tester reports and what the core developer(s) know. In turn, this means that the core developers' time tends to be well conserved, even with many collaborators.

Another characteristic of the open-source method that conserves developer time is the communication structure of typical open-source projects. Above I used the term "core developer"; this reflects a distinction between the project core (typically quite small; a single core developer is common, and one to three is typical) and the project halo of beta-testers and available contributors (which often numbers in the hundreds).

The fundamental problem that traditional software-development organization addresses is Brook's Law: ``Adding more programmers to a late project makes it later.'' More generally, Brooks's Law predicts that the complexity and communication costs of a project rise with the square of the number of developers, while work done only rises linearly.

Brooks's Law is founded on experience that bugs tend strongly to cluster at the interfaces between code written by different people, and that communications/coordination overhead on a project tends to rise with the number of interfaces between human beings. Thus, problems scale with the number of communications paths between developers, which scales as the square of the humber of developers (more precisely, according to the formula N*(N - 1)/2 where N is the number of developers).

The Brooks's Law analysis (and the resulting fear of large numbers in development groups) rests on a hidden assummption: that the communications structure of the project is necessarily a complete graph, that everybody talks to everybody else. But on open-source projects, the halo developers work on what are in effect separable parallel subtasks and interact with each other very little; code changes and bug reports stream through the core group, and only within that small core group do we pay the full Brooksian overhead. [SU]

There are are still more reasons that source-code–level bug reporting tends to be very efficient. They center around the fact that a single error can often have multiple possible symptoms, manifesting differently depending on details of the user's usage pattern and environment. Such errors tend to be exactly the sort of complex and subtle bugs (such as dynamic-memory-management errors or nondeterministic interrupt-window artifacts) that are hardest to reproduce at will or to pin down by static analysis, and which do the most to create long-term problems in software.

A tester who sends in a tentative source-code–level characterization of such a multi-symptom bug (e.g. "It looks to me like there's a window in the signal handling near line 1250" or "Where are you zeroing that buffer?") may give a developer, otherwise too close to the code to see it, the critical clue to a half-dozen disparate symptoms. In cases like this, it may be hard or even impossible to know which externally-visible misbehaviour was caused by precisely which bug—but with frequent releases, it's unnecessary to know. Other collaborators will be likely to find out quickly whether their bug has been fixed or not. In many cases, source-level bug reports will cause misbehaviours to drop out without ever having been attributed to any specific fix.
如果有一个在代码层的对出错条件的描述,甚至不必完整,只要有所指向,大多数臭虫在大多数时间都是容易捉到的。当你的beta测试人员中某个人能指出,“在第nnn行有一个边界问题”,或者只是“在XYZ条件下,这个变量溢出”,对问题代码的一个快速扫描常常足以锁定出错的准确模式、搞定一个修补办法。
所以,如果beta测试者和核心开发者都对源代码心里有数,双方的交流和合作会得到大大增强。结果,这意味着核心开发人员的时间会节约下来,即使合作者人数很多。

开源方法另一个节约开发者时间的特点是典型的开源项目的通讯结构。我在上面用到了“核心开发者”一词;这反映了项目核心(一般很小;一个核心开发者很平常,一到三个很典型)和beta测试人员、协助人员组成的项目外沿(经常上百人)的区别。
传统上软件开发的组织结构的基本问题是布洛克法则:“在延期的项目添加程序员只会延期更久”。普遍来讲,布洛克法则认为,随着开发人员数目的增加,项目的复杂程度和通讯成本按平方增加,而业绩仅以直线增加。

经验表明,臭虫大多集中在不同人写的代码的界面上;而一个项目的通讯协调的成本一般按照人的界面的数量增加。这是布洛克法则的基础。也就是,问题随开发者之间通讯路径的数目增加,而后者与开发者数目是平方关系(更准确地说,遵从公式N*(N - 1)/2,这里N是开发者的数目)。
布洛克法则的分析(以及它引起的开发团体中对人数过多的恐惧)是基于一个潜在的前提:项目的通讯结构必须是一个完整的图、每个人都与其他所有人交接。但是在开源项目中,外沿的开发者做的实际上是平行分离的子项目,彼此交接甚少;代码变动和臭虫报告都流经项目的核心,只有在小小的核心团体中全面的布洛克成本才有效。

还有其它的原因使得源代码层次上的臭虫报告往往更有效。一个核心问题是单独的错误常常可以产生多个不同的症状,在用户使用习惯和环境的细节不同时有不同显示。这类错误一般正是那些复杂和微妙的臭虫——那些最难故意复制或用静态分析捕捉的、那些在软件中制造长期问题的祸根(比如动态内存管理错误或窗口随机干预后果等)。

Complex multi-symptom errors also tend to have multiple trace paths from surface symptoms back to the actual bug. Which of the trace paths a given developer or tester can chase may depend on subtleties of that person's environment, and may well change in a not obviously deterministic way over time. In effect, each developer and tester samples a semi-random set of the program's state space when looking for the etiology of a symptom. The more subtle and complex the bug, the less likely that skill will be able to guarantee the relevance of that sample.

For simple and easily reproducible bugs, then, the accent will be on the "semi" rather than the "random"; debugging skill and intimacy with the code and its architecture will matter a lot. But for complex bugs, the accent will be on the "random". Under these circumstances many people running traces will be much more effective than a few people running traces sequentially—even if the few have a much higher average skill level.

This effect will be greatly amplified if the difficulty of following trace paths from different surface symptoms back to a bug varies significantly in a way that can't be predicted by looking at the symptoms. A single developer sampling those paths sequentially will be as likely to pick a difficult trace path on the first try as an easy one. On the other hand, suppose many people are trying trace paths in parallel while doing rapid releases. Then it is likely one of them will find the easiest path immediately, and nail the bug in a much shorter time. The project maintainer will see that, ship a new release, and the other people running traces on the same bug will be able to stop before having spent too much time on their more difficult traces [RJ].
复杂的多症状错误也常常会有多个从表面症状联系到内在臭虫的跟踪途径。一个特定的开发者或测试者所能追寻的跟踪途径可能取决于这个人的具体环境细节,也很可能随着时间的改变发生不便预测的变化。实际上,每一个开发者和测试者在寻找一个症状的病原的时候都是在检查该程序的状态空间的一个“半随机”的集合。臭虫越微妙越复杂,单靠技能就越难保证找到那个相关的集合。
对于简单的容易复制的臭虫,那么,重音要放在“半”上面而不是“随机”上面;调试的技能和对代码、框架的熟悉是最重要的。但对于复杂的臭虫,重音就要放在“随机”上面。在这种情况下许多人同时追踪要比少数人持续追踪有效的多——即使这少数人的技能水平高的多。
要是从不同的表面症状挖掘到臭虫的跟踪途径难度不一、难以从观察症状来预测的话,这一效果就会非常之明显了。一个持续追踪这些路径的开发者一开始可能会遇到一个简单的路径也同样可能遇到一个复杂的路径。另一方面,试想有许多人在快速发布下平行地来检查这些追踪路径。那么其中的某一个人可能会马上发现最容易的路径,在短的多的时间里搞定这个臭虫。维护项目的人会看到这个,发行一个新版本;其他在更困难的路径上追踪同一个臭虫的人们就可以在花费太多的时间之前停下来。


When Is a Rose Not a Rose?

Having studied Linus's behavior and formed a theory about why it was successful, I made a conscious decision to test this theory on my new (admittedly much less complex and ambitious) project.

But the first thing I did was reorganize and simplify popclient a lot. Carl Harris's implementation was very sound, but exhibited a kind of unnecessary complexity common to many C programmers. He treated the code as central and the data structures as support for the code. As a result, the code was beautiful but the data structure design ad-hoc and rather ugly (at least by the high standards of this veteran LISP hacker).

I had another purpose for rewriting besides improving the code and the data structure design, however. That was to evolve it into something I understood completely. It's no fun to be responsible for fixing bugs in a program you don't understand.

研究了林纳斯的作法后我形成了一个它何以成功的理论;我有意识地决定在我的新项目(当然没有Linux那么复杂和宏伟)里测试这个理论。
但我做的第一件事是把popclient重组和简化了许多。卡尔。哈里斯的代码实现的很好,但是有一种在C程序员中常见的多余的复杂。他把代码放在了中心位置,数据结构作为辅助。结果代码很漂亮,但是数据结构设计得潦草甚至丑陋(至少根据我这个LISP老手的标准来看)。
然而,除了改进代码和数据结构设计以外,我的重写还有另一层目的。那是把它进化成一个我完全理解的东西。要是你不完全理解一个程序,维护起来可就不好玩了。

For the first month or so, then, I was simply following out the implications of Carl's basic design. The first serious change I made was to add IMAP support. I did this by reorganizing the protocol machines into a generic driver and three method tables (for POP2, POP3, and IMAP). This and the previous changes illustrate a general principle that's good for programmers to keep in mind, especially in languages like C that don't naturally do dynamic typing:

9. Smart data structures and dumb code works a lot better than the other way around.

Brooks, Chapter 9: ``Show me your flowchart and conceal your tables, and I shall continue to be mystified. Show me your tables, and I won't usually need your flowchart; it'll be obvious.'' Allowing for thirty years of terminological/cultural shift, it's the same point.

At this point (early September 1996, about six weeks from zero) I started thinking that a name change might be in order—after all, it wasn't just a POP client any more. But I hesitated, because there was as yet nothing genuinely new in the design. My version of popclient had yet to develop an identity of its own.

That changed, radically, when popclient learned how to forward fetched mail to the SMTP port. I'll get to that in a moment. But first: I said earlier that I'd decided to use this project to test my theory about what Linus Torvalds had done right. How (you may well ask) did I do that? In these ways:

于是在最初的一个月左右,我只是在按照卡尔的章程做事。我作的第一个重要改变是添加了IMAP支持。我实现这点的方法是:把协议部分的机制重组成了一个通用的驱动和三个方法表单(分别针对POP2、POP3和IMAP)。这和以前的变动都示范了一个程序员们应该记住的通用原则,尤其对于像C这种本身不支持动态数据类型的语言:
9)聪明的数据结构和愚蠢的代码要不反过来好的多。
布洛克的第九章:“给我看你的流程图而隐藏你的表单,我会继续糊涂着。给我看你的表单,我一般就不需要你的流程图了;事情该是明显的了”。经过三十年的文化和术语的变迁,这是同一个道理。
这时(1996年9月初,大约开工后六个星期),我开始想这个程序大概该换个名字了-它毕竟不再仅仅是一个POP客户端软件。但是我在犹豫,因为在设计上还没有什么真正的新东西。我的popclient版本还需要发展出它自己的特征。
当popclient学会了怎样把取到的邮件转发到SMTP端口的时候,这一点迅速改变了。我过一会儿再细谈这个。但是首先:我说过我决定用这个项目来测试我对林纳斯。托瓦兹的成功之处的理论。(您也会问)我是怎样做的呢?在以下方面:

* I released early and often (almost never less often than every ten days; during periods of intense development, once a day).
* I grew my beta list by adding to it everyone who contacted me about fetchmail.
* I sent chatty announcements to the beta list whenever I released, encouraging people to participate.
* And I listened to my beta-testers, polling them about design decisions and stroking them whenever they sent in patches and feedback.

The payoff from these simple measures was immediate. From the beginning of the project, I got bug reports of a quality most developers would kill for, often with good fixes attached. I got thoughtful criticism, I got fan mail, I got intelligent feature suggestions. Which leads to:

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

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

10. If you treat your beta-testers as if they're your most valuable resource, they will respond by becoming your most valuable resource.

One interesting measure of fetchmail's success is the sheer size of the project beta list, fetchmail-friends. At the time of latest revision of this paper (November 2000) it has 287 members and is adding two or three a week.

Actually, when I revised in late May 1997 I found the list was beginning to lose members from its high of close to 300 for an interesting reason. Several people have asked me to unsubscribe them because fetchmail is working so well for them that they no longer need to see the list traffic! Perhaps this is part of the normal life-cycle of a mature bazaar-style project.

10) 如果你以“最有价值资源”来对待你的beta测试者,他们会以成为“最有价值资源”来回应。
fetchmail的成功的一个有意思的方面是项目的beta测试名单(fetchmail-friends)的庞大。在这篇文章的最后一稿的时候(2000年11月),它有287名成员,而且每个星期在增加两三名。
实际上,当我在1997年5月下旬改写的时候,我发现这个名单由于一个有意思的原因,从它近300的巅峰开始流失成员了。一些人要求我把他们从名单中去掉,因为fetchmail对他们来讲运行完美、他们再也不需要阅读这个邮件列表了!或许这是一个成熟的市集风格的项目的正常生命周期的一部分。


About Brook"The Mythical Man-Month: Essays on Software Engineer"

Man-Month这里该是人头X工作时间的意思,先译作“工时”吧。
下面是一篇Amazon.com的书评。


Reviewer: A. Imran "a87" (Irvine, CA United States)

If you have managed some software projects or have worked on some non-trivial software systems, undoubtedly you have faced many difficulties and challenges that you thought were unique to your circumstance. But after reading this book, you will realize that many of the things you experienced, and thought were unique problems, are NOT unique to you but are common systemic problems of developing non-trivial software systems. These problems appear repeatedly and even predictably, in project after project, in company after company, regardless of year, whether it's 1967 or 2007.

You will realize that long before maybe you were even born, other people working at places like IBM had already experienced those problems and quandries. And found working solutions to them which are as valid today as they were 30 years ago.

The suggestions in this book will help you think better and better manage yourself, and be more productive and less wasteful with your time and energy. In short, you will do more with less.

Some of Brooks insights and generalizations are:

The Mythical Man-Month:
Assigning more programmers to a project running behind schedule, may make it even more late.

The Second-System Effect:
The second system an engineer designs is the most bloated system she will EVER design.

Conceptual Integrity:
To retain conceptual integrity and thereby user-friendliness, a system must have a single architect (or a small system architecture team), completely separate from the implementation team.

The Manual:
The chief architect should produce detailed written specifications for the system in the form of the manual, which leaves no ambiguities about any part of the system and completely specifies the external spcifications of the system i.e. what the user sees.

Pilot Plant:
When designing a new kind of system, a team should factor in the fact that they will have to throw away the first system that is built since this first system will teach them how to build the system. The system will then be completely redesigned using the newly acquired insights during building of the first system. This second system will be smarter and should be the one delivered to the customer.

Formal Documents:
Every project manager must create a roadmap in the form of formal documents which specifies milestones precisely and things like who is going to do what and when and at what cost.

Communication:
In order to avoid disaster, all the teams working on a project, such as the architecture and implementation teams, should stay in contact with each other in as many ways as possible and not guess or assume anything about the other. Ask whenever there's a doubt. NEVER assume anything.

Code Freeze and System Versioning:
No customer ever fully knows what she wants from the system she wants you to build. As the system begins to come to life, and the customer interacts with it, he understands more and more what he really wants from the system and consequently asks for changes. These changes should of course be accomodated but only upto a certain date, after which the code is frozen. All requests for more changes will have to wait until the NEXT version of the system. If you keep making changes to the system endlessly, it may NEVER get finished.

Specialized Tools:
Every team should have a designated tool maker who makes tools for the entire team, instead of all individuals developing and using their private tools that no one else understands.

No silver bullet:
There is no single strategy, technique or trick that will exponentially raise the productivity of programmers.