温馨提醒:系统正在进行全面升级。如需阅读更多小说,请访问备份站点。
尽量早尽量频繁的布是Linux开模式的一个重要部分,多数开人员(包括我)过去都相信这对大型工程来说是个不好的策略,因为早期版本都是些充满错误的版本,而你不想耗光用户的耐心。
这种信仰强化了建造大教堂开方式的必要性,如果目标是让用户尽可能少的见到错误,那你怎能不会仅仅每六个月布一次(或更不经常),而且在布之间象一只狗一样辛勤“捉虫”呢?em内核就是以这种方式开的,Lisp库,实际上却相反,因为有一些有FsF控制之外的Lisp库,在那里你可以独立于em布周期地找寻新的和开代码版本。
这其中最重要的是ohio州的e1isp库,预示了今天的巨大的Linux库的许多特征的精神,但是我们很少真正仔细考虑我们在做什么,或者这个库的存在指出了FsF建造教堂式开模式的什么问题,1992年我曾经做了一次严肃的尝试,想把ohio的大量代码正式合并到em的官方Lisp库中,结果我陷入了政治斗争中,彻底失败了。
但是一年之后,在Linux广泛应用之后,很清楚,一些不同的更加健康的东西诞生了,Linus的开模式正好与建造教堂方式相反nsite和tsx11的库开始成长,推动了许多布。所有这些都是闻所未闻的频繁的内核系统的布所推动的。
Linus以所有实际可能的方式把它的用户作为协作开人员。
7.早布、常布、听取客户的建议
Linus的创新并不是这个(这在unix世界中是一个长期传统),而是把它扩展到和他所开的东西的复杂程度相匹配的地步,在早期一天一次布对他来说都不是罕见的!而且因为他培育了他的协作开者基础,比其他任何人更努力地充分利用了Internet进行合作,所以这确实能行。
但是它是怎样进行的呢?它是我能模仿的吗?还是这依赖于Linus的独特天才?
我不这样想,我承认Linus是一个极好的黑客(我们有多少人能够做出一个完整的高质量的操作系统内核?),但是Linux并不是一个令人敬畏的概念上的飞跃,Linus不是(至少还不曾是)象Rirdsta11man或Jamesgos1ing一样的创新天才,在我看来,Lin象一个工程天才,具有避免错误和开失败的第六感觉,掌握了现从a点到B点代价最小的路径的决窍,确实,Linux的整个设计受益于这个特质,并反映出Linus的本质上保守和简化设计的方法。
如果快的布和充分利用Internet不是偶然而是Linus的对代价最小的路径的洞察力的工程天才的内在部分,那么他极大增强了什么?他创建了什么样的方法?
问题回答了它自己,Linus保持他的黑客用户经常受到激励和奖赏:被行动的自我满足的希望所激励,而奖赏则是经常(甚至每天)都看到工作在进步。
Linus直接瞄准了争取最多的投入调试和开的人时,甚至冒代码不稳定和一旦有非常棘手的错误而失去用户基础的险,Linus似乎相信下面这个:
8.如果有一个足够大的beta测试人员和协作开人员的基础,几乎所有的问题都可以被快的找出并被一些人纠正。
或者更不正式的讲:“如果有足够多的眼睛,所有的错误都是浅显的”(群众的眼睛是雪亮的),我把这称为“Linus定律”。
我最初的表述是每个问题“对某些人是透明的”,Linus反对说,理解和修订问题的那个人不一定非是甚至往往不是先现它的人,“某个人现了问题”,他说,“另一个理解它,我认为现它是个更大的挑战”,但是要点是所有事都趋向于生。
我认为这是建造教堂和集市模式的核心区别,在建造教堂模式的编程模式看来,错误和编程问题是狡猾的、阴险的、隐藏很深的现象,花费几个月的仔细检查,也不能给你多大确保把它们都挑出来的信心,因此很长的布周期,和在长期等待之后并没有得到完美的版本布所引起的失望都是不可避免的。
以市集模式观点来看,在另一方面,我们认为错误是浅显的现象,或者至少当暴露给上千个热切的协作开人员,让他们来对每个新布进行测试的时候,它们很快变得浅显了,所以我们经常布来获得更多的更正,作为一个有益的副作用,如果你偶尔做了一个笨拙的修改,也不会损失太多。也许我们本不应该这样的惊奇,社会学家在几年前已经现一群相同专业的(或相同无知的)观察者的平均观点比在其中随机挑选一个来得更加可靠,他们称此为“de1hpi效应”,Linus所显示的证明在调试一个操作系统时它也适用——de1phi效应甚至可以战胜操作系统内核一级的复杂度。
我受Jeffdutky()的启指出Linus定律可以重新表述为“调试可以并行”,Jeff观察到虽然调试工作需要调试人员和对应的开人员相交流,但它不需要在调试人员之间进行大量的协调,于是它就没有陷入开时遇到的平方复杂度和管理开销。
在实际中,由于重复劳动而导致的理论上的丧失效率的现象在Linux世界中并不是一个大问题,“早布、常布策略”的一个效果就是利用快的传播反馈修订来使重复劳动达到
Brooks甚至做了一个与Jeff相关的更精确的观察:“维护一个广泛使用的程序的成本一般是其开成本的4o%,奇怪的是这个成本受到用户个数的强烈影响,更多的用户现更多的错误”(我的强调)。
更多的用户现更多的错误是因为更多的用户提供了更多测试程序的方法,当用户是协作开人员时这个效果被放大了,每个找寻错误的人都有自己稍微不同的感觉和分析工具,从不同角度来看待问题。“de1phi效应”似乎因为这个变体工作变得更加精确,在调试的情况下,这个变体同时减小了重复劳动。
所以加入更多的beta测试人员虽不能从开人员的p.o.V中减小“最深”的错误的复杂度,但是它增加了这样一种可能性,即某个人的工具和问题正好匹配,而这个错误对这个人来说是浅显的。
Linus也做了一些改进,如果有一些严重的错误,Linux内核的版本在编号上做了些处理,让用户可以自己选择是运行上一个“稳定”的版本,还是冒遇到错误的险而得到新特征,这个战略还没被大多数Linux黑客所仿效,但它应该被仿效,存在两个选择的事实让二者都很吸引人。
五.什么时候玫瑰不是玫瑰?
在研究了Linus的行为和形成了为什么它成功的理论之后,我决定在我的工程(显然没有那么复杂和雄心勃勃)里有意识的测试这个理论。
但我先做的事是熟悉和简化的实现非常好,但是有一种对许多c程序来说没有必要的复杂性。他把代码当作核心而把数据结构当作对代码的支持,结果是代码非常漂亮但是数据结构设计得很特别,相当丑陋(至少对以这个老LIsp黑客的标准来看),然而除了提高代码和数据结构设计之外,重写它还有一个目的,就是要把它演化为我彻底理解的东西,对修改你不理解的程序中的错误负责可不是一件有趣的事。
第一个月我只是在领会car1‘s的基本设计的含义,我所做的第一个重大修改是加入了I支持,我把协议机重新组织为一个通用驱动程序和三个方法表(对应pop2、pop3和I),这个前面的修改指出一个需要程序员(特别是象c这种没有自然的动态类型支持的语言)记在脑中的一般原理:
9.聪明的数据结构和笨拙的代码要比相反的搭配工作的更好
FredBrooks也在他第11章中讲道:“让我看你的[代码],把你的[数据结构]隐藏起来,我还是会迷惑;让我看看你的[数据结构],那我就不需要你的[代码]了,它是显而易见的”。
实际上,他说的是“流程图”和“表”,但是在三十年的术语/文化演进之后,事情还是一样的。
此时(1996年9月初,在从零开始六个月后),我开始想接下来修改名字——毕竟,它已不仅仅是一个pop客户,但我犹豫了,因为还没有什么新的漂亮设计呢,我的popnett版本需要有自己的特色。
当fetehmai1学会怎样把取到的邮件转送到**Tp端口时,事情就完全改变了,但是先:上面我说过我决定使用这个工程来测试我关于LinusTorua1ds所做的行为的理论,(你可能会问)我怎样做到这点呢?以下面的方式:
1.我尽早尽量频繁的布(几乎从未少于每十天布一次;在密集开的时候是每天一次)。
2.我把每一个和我讨论fetchmai1的人加入一个beta表中。
3.每当我布我都向beta表中的人出通告,鼓励人们参与。
4.我听取beta测试员的意见,向他们询问设计决策,对他们寄来的补丁和反馈表示感谢。
这些简单的手段立即收到的回报,在工程的开始,我收到了一些错误报告,其质量足以使开者因此被杀掉,而且经常还附有补丁、我得到了理智的批评,有趣的邮件,和聪明的特征建议,这导致了:
1o.如果你象对待最宝贵的资源一样对待你的beta测试员,他们就会成为你最宝贵的资源。
六.popnett变成了Fetnetbsp; 这个工程的真正转折点是harry1eiser寄给我他写的代码草稿,他把邮件转到客户端机器的**Tp端口,我立即意识到这个特征的可靠实现将淘汰所有其他的递送模式。
几个星期以来我一直在修改而不是改进fetchmai1,因为我觉得界面设计虽然有用但是太笨拙琐碎了,到处充满了太多的粗陋的细小选项。
当我思考**Tp转时我现popnett试图做的事太多了,它被设计成既是一个邮件传输代理(mTa)也是一个本地递送代理(mda)。使用**Tp转,它就可以从mda的事务中解脱出来而成为一个纯mTa,而象sendmai1一样把邮件交给本地递送程序来处理。
既然端口25在所有支撑Tcp/Ip的平台上早已被预留,为什么还要为一个邮件传输代理的配置或为一个邮箱设置加锁的附加功能而操心呢?尤其是当这意味着抽取的邮件就象一个正常的送者出的**Tp邮件一样,而这就是我们需要的。
这里有几个教益:第一Tp转的想法是我有意识地模拟Linus的方法以来的最大的单个回报,一个用户告诉我这个非同寻常的想法——我所需做的只是理解它的含义。
11.想出好主意是好事,从你的用户那里现好主意也是好事,有时候后者更好。
很有趣的是,你很快将现,如果你完全承认你从其他人那里得到多少教益的话,整个世界将会认为所有的明都是你做出的,而你会对你的天才变得谦虚。我们可以看到这在Linus身上体现得多明显!(当我在1997年8月的per1会议上表这个论文时,Larrya11坐在前排,当我讲到上面的观点时,他激动的叫了出来:“对了!说对了!哥们!”所有的听众都哄堂大笑起来,因为他们知道同样的事情也生在per1的明者身上)。
于是在同样精神指导下工程进行了几个星期,我开始不光从我的用户那儿也从听说我的系统的人那儿得到类似的赞扬,我把一些这种邮件收藏起来,我将在我开始怀疑自己的生命是否有价值时重新读读这些信。:)
但是有两个更基本的,非政治性的对所有设计都有普遍意义的教益。
12.最重要和最有创新的解决方案常常来自于你认识到你对问题的概念是错误的。
一个衡量fetchmai1成功的有趣方式是工程的beta测试人员表(fegtchmai1的朋友们)的长度,在创立它的时候已经有249个成员了,而且每个星期增加两到三个。
实际上,当我在1997年5月校订它时,这张表开始因为一个有趣的原因而缩短了,有几个人请求我把他们从表中去掉,因为fetchmai1已经工作的如此之好,他们不需要看到这些邮件了!也许这是一个成熟的市集风格工程的生命周期的一部分。
我以前一直在解决错误的问题,把popnett当作mTa和具有许多本地递送模式的mda的结合物,Fetchmai1的设计需要从头考虑为一个纯的mTa,做为一个普通Internet邮件路径的一部分。
当你在开中碰了壁时(当你现自己很难想通下一步时),那通常不是要问自己是否找到正确答案,而是要问是否问了正确问题,也许需要重新构造问题。
于是,我重新构造了我的问题,很清楚,要做的正确的事是(1)把**Tp转支持放在通用驱动程序中,(2)把它做为缺省模式,(3)最终分离所有其他的递送模式,尤其是递送到文件和标准输出的选项。
我在第三步上犹豫了一下,担心会让popdiant的长期用户对新的递送方法感到烦心,在理论上,他们可以立即转而转文件或者他们的非sendmai1等价物来得到同样的效果,在实际中这种转换可能会很麻烦。
但是当我这么做之后,证明好处是巨大的,驱动程序代码的冗余的部分消失了,配置完全变得简单了——不用屈从于系统mda和用户的邮箱,也不用为下层os是否支持文件锁定而担心了。
而且,丢失邮件的唯一漏洞也被堵死了,如果你选择了递送到一个文件而磁盘已满,你的邮件就会丢失,这在**Tp转中不会生,因为**Tp侦听器不会返回ok的,除非邮件可以递送成功或至少被缓冲留待以后递送。
还有,性能也改善了(虽然在单次执行中你不会注意到),这个修改的另一个不可忽视的好处是手册变得大大简单了。
后来,为了允许处理一些罕见的情况,包括动态sLIp,我必须回到让用户定义本地mda递送上来,但是我现了一个更加简单的方法。
所有这些给了我们什么启呢?如果可以不损失效率,就要毫不犹豫抛弃陈旧的特性,antoninedesaintexupery(在他成为经典儿童书籍作家之前是一个飞行员和飞机设计师)曾说过:
13.“最好的设计不是再也没有什么东西可以添加了,而是再也没有什么东西可以去掉。”
当你的代码变得更好和更简单时,这就是你知道它是正确的时候了,而且在这个过程中,fetehmai1的设计具有了自己的特点,而区别于其前身popnetbsp; 现在是改名的时候了,这个新的设计看起来比老popnetdmai1的【创建和谐家园】品,它们都是mTa,但是senmai1是推然后递送,而新的popnett是拉然后递送。于是,在两个月之后,我把它重新命名为fetehmai1。
七.Fetnetbsp; 现在我有了一个简洁和富有创意的设计,工作得很好的代码,因为我每天都用它,和一直在增长的beta表,它让我渐渐明白我已经不是在从事只能对少数其他人有用的工我写了一个所有有一个unix邮箱和sLIp/邮件连接的人都真正需要的程序。
通过**Tp转功能,它成为一个潜在的“目录杀手”,远远领先于它的竞争者,这个程序如此能干以至于其他的程序不但被放弃简直被忘记了。
我知道你不可以真得瞄准或计划出这样的结果,你只能努力去设计这些强大的思想,以后这些结果就好象是不可避免的、自然的、注定了的,得到这种思想的唯一办法是获取许多思想,或者用工程化的思考其他人的好主意而过原来想到它的人的设想。
andreTanenbanm原来设想建造一个适合386的简单的unix用做教学,LinusTorva1e1s把andre的可能想到的minix可以做什么的概念推进了一步,成长为一个极好的东西,同样的(虽然规模较小),我接受了cardharris和harryeiser的想法,把它们变得更强大,我们都不是人们所浪漫幻想的天才的创始人,但是大多数科学和工程和软件开不是被天才的创始人完成的,这和流传的神话恰恰相反。
结果总是执着的原因——实际上,它是每个黑客为之生存的成功!而且它们意味着我必须把自己的标准定高一点,为了把fetchmai1变得和我所能设想的那样好,我必须不仅为我自己的需要写代码,而且也要包括对在我生活围主页外的人们的需求的支持,而且同时也要保证程序的简单和健壮。
在实现它之后我先写的最重要的特征是支持多投——从集中一组用户的邮件的邮箱中取出邮件,然后把它路由到每个人手中。
我之所以加上多投功能部分是因为有些用户一直在闹着要它,更是因为我想它可以从单投的代码中揭露出错误来,让我完全一般地处理寻址,而且这被证明了。正确解释RFc822花了我相当长的时间,不仅因为它的每个单独部分都很难,而且因为它有一大堆相互依赖的苛刻的细节。
但是多投寻址也成为一个极好的设计决策,由此我知道:
14.任何工具都应该能以预想的方式使用,但是一个伟大的工具提供你没料到的功能。
Fetnett多投功能的一个没有料到的用途是在sLIp/的客户端提供邮件列表、别名扩展。这意味着一个使用个人机器的人不必持续访问Isp的别名文件就能通过一个Isp帐户管理一个邮件列表。我的beta测试员提出的另一个重要的改变是支持8位mIme操作,这很容易做,因为我已经仔细的保证了8位代码的清晰,不仅因为我预见到了这个特性的需求,而且因为我忠实于另一准则:
15.当写任何种类的【创建和谐家园】型程序时,多费点力,尽量少干扰数据流,永远不要抛弃信息,除非接收方强迫这么作!
如果我不遵从这个准则,那么8位mIme支持将会变得困难和笨拙,现在我所需要做的,是只读一下RFc1652,在产生信头的逻辑加上一点而已。
一些欧洲用户要求我加上一个选项来限制每次会话取得消息数(这样他们就可以从昂贵的电话网中控制花费了),我很长一段时间拒绝这样做,而且我仍然对它不很高兴,但是如果你是为了世界而写代码,你必须听取顾客的意见——这并不随他们不付给你钱而改变。
八.从Fetchmai1得来的另一些教益
在他们回到一般的软件工程问题以前,还有几个从fetchmai1得到的教益需要思考。
rnetoise”关键字,它被扫描器完全忽略了,当你把它们全抽取出的时候,关键字/值对更具可读性。
当我注意到rc文件的声明在多大程度上开始象一个微型命令语言时,这是一个Latenight的体验(这也是我为什么把popnett原来的“server”关键字改成了“po11”)。
对我来说似乎把这个微型命令语言变得更象英语可能会使它更容易使用。现在,虽然我对经过em和hTmL及许多数据库引擎所证实的“把它做成一个语言”的设计方式确信不疑,但是我并不是一个通常的“类英语”语法的狂热拥护者。
传统程序员容易控制语法使它尽量精确和紧凑,完全没有冗余,这是计算机资源还很昂贵时遗留下的一种文化传统,所以扫描策略需要尽可能的廉价和简单,而具有5o%冗余度的英语,看来好象是一个非常不合适的模型。
这并不是我不用类英语语法的原因,我提到这一点是为了推翻它,在更廉价的时钟周期与核心的时代,简洁并没有走到尽头,今天对一个语言来说,对人更方便比对机器更廉价来的更加重要。
然而,有几个原因提醒我们小心一点,一个是扫描策略的复杂度开销——你并不想把它变成一个巨大的错误来源和让用户困惑,另一个是试图使语言表面上的类似可以和传统语言一样令人困惑(你可以在许多4gL和商业数据库查询语言上看到这一点)。
Fetchmai1的控制语法避免了这些问题,因为语言的领域是极其有限的。它一点也不象一个一般性的语言,它很简单地描述的东西并不复杂,所以很少可能在英语的一个小子集与实际的控制语言之间生混淆,我想这有一个更广泛的教益:
16.如果你的语言一点也不象是图灵完备的,严格的语【创建和谐家园】有好处。
另一个教益是关于安全的,一些fetchmai1用户要求我修改软件把口令加密存贮在rc文件里,这样觑探者就不能看到它们了。
我没有这样做,因为这实际上起不到任何保护作用,任何有权读取你的rc文件的人都可以以你的名义运行fetchmai1——如果他们要破你的口令,它们可以从fetchmai1的代码中找到制作解码器的方法。
所以fetchmai1口令的加密都会给那些不慎重思考的人一种安全的错觉,这里一般性的准则是:
17.一个安全系统只能和它的秘密一样安全,当心伪安全。
九.集市风格的必要的先决条件
本文的早期评审人员和测试人员坚持提出成功的市集模式开的先决条件,包括工程领导人的资格问题和在把项目公开和开始建造一个协作开人员的社团的时候代码的状态。
相当清楚,不能以一个市集模式从头开一个软件,我们可以以市集模式、测试、调试和改进,但是以市集模式从头开始一个项目将是非常困难的,Linus没有这样做,我也没有,初期的开人员的社团应该有一此可以运行和测试的东西来玩。
当你开始创建社团时,你需要演示的是一个诺言,你的程序不需要工作的很好,它可以很粗糙、很笨拙、不完整和缺少文档、它不能忽略的东西是要吸引哪些人卷入一个整洁的项目。
Linux和fetchmai1都是以一个吸引人的基本设计进入公共领域的,许多和我一样在思考市集模式的人已经正确的认为这是非常关键的,然后得出了一个结论,工程领导者的高度的设计直觉和聪颖是必不可少的。
但是Linus是从unix得到他的设计的,我最初是从先前的popmai1得到启的(虽然相对Linux而言,它最后改变巨大),所以市集风格的领导人/协调人需要有出众的设计才能,或者他可以利用别人的设计才能?
我认为能够提出卓越的原始设计思想对协调人来说不是最关键的,但是对他/她来说绝对关键的是要能把从他人那里得到的好的设计重新组织起来。
Linux和fetnetus(如同前面所说)并不是惊人的原始设计者,但他显示了现好的设计并把它集成到Linux内核中的强大决窍。还有我也描述了怎样从别人那里得到了fetchmai1中最强大的设计思想(**Tp转)。
本文的早期读者称赞我,说因为我做了许多关于原始设计的事,所以倾向于低估原始设计在市集项目中的价值,也许有些是对的吧,但是设计(而不是编码或调试)本来就是我最强的能力。
变得聪明和软件设计的原始创作的问题是它会变成一个习惯,当需要保持事物健壮和简洁的时候,你却开始把事情变得漂亮但却复杂。我曾经犯过错误,使得一些项目因我而崩溃了,但我努力不让它生在fetnetbsp; 所以我相信fetchmai1项目的成功部分是因为我抑制自己不要变得太聪明,这说明(至少)对市集模式而言原始设计并不是本质的,请考察一下Linux假设LinusTorva1ds在开时试图彻底革新操作系统设计,它还会象今天我们所拥有的内核那样稳定和成功吗?
当然基本的设计和编码技巧还是必需的,但我希望每个严肃考虑起一个市集计划的人都已至少具备这些能力,自由软件社团的内部市场对人们有某些微妙的压力,让他们不要起自由不能搞定的开,目前为止,这工作得仍然相当好。
对市集项目来说,我认为还有另一种通常与软件开无关的技能和设计能力同样重要——或者更加重要,市集项目的协调人或领导人必须有良好的人际和交流能力。
这是很显然的,为了建造一个开社团,你需要吸引人,你所做的东西要让他们感到有趣,而且要保持他们对他们正在做的工作感到有趣,而且要保持他们对他们正在做的工作感到高兴,技术方面对达成这些目标有一定帮助,但这远远不是全部,你的个人素质也有关系。