出版社:电子工业出版社
作者: Eric S. Raymond/ 姜宏/ 何源/ 蔡晓骏
定价:59.00
 
 

   本书主要介绍了 Unix 系统领域中的设计和开发哲学、思想文化体系、原则与经验,由公认的 Unix 编程大师、开源运动领袖人物之一 Eric S. Raymond 倾力多年写作而成。包括 Unix 设计者在内的多位领域专家也为本书贡献了宝贵的内容。本书内容涉及社群文化、软件开发设计与实现,覆盖面广、内容深邃,完全展现了作者极其深厚的经验积累和领域智慧。

 

第一章

哲学

Philosopy: Philosophy Matters

Those who do not understand Unix are condemned to reinvent it, poorly.

不懂 Unix 的人注定最终还要重复发明一个蹩脚的 Unix 。

Usenet 签名 , 1987 11

—— Henry Spencer

1 .1 文化?什么文化?

  这是一本讲 Unix 编程的书,然而在这本书里,我们将反复提到“文化”、“艺术”以及“哲学”这些字眼。如果你不是程序员,或者对 Unix 涉水未深,这可能让你感觉很奇怪。但是 Unix 确实有它自己的文化;有独特的编程艺术;有一套影响深远的设计哲学。理解这些传统,会使你写出更好的软件,即使你是在非 Unix 平台上开发。

  工程和设计的每个分支都有自己的技术文化。在大多数工程领域中,就一个专业人员的素养组成来说,有些不成文的行业素养具有与标准手册及教科书同等重要的地位(并且随着专业人员经验的日积月累,这些经验常常会比书本更重要)。资深工程师们在工作中会积累大量的隐性知识,他们用类似禅宗“教外别传” [ 译注 1 ] 的方式,通过言传身教传授给后辈 。

  软件工程算是此规则的一个例外:技术变革如此之快,软件环境日新月异,软件技术文化暂如朝露。然而,例外之中也有例外。确有极少数软件技术被证明经久耐用,足以演进为强势的技术文化、有鲜明特色的艺术和世代相传的设计哲学。

  Unix 文化便是其一。互联网文化又是其一 —— 或者,这两者在 21 世纪无可争议地合二为一。其实,从 1980 年代早期开始, Unix 和互联网便越来越难以分割,本书也无意强求区分。

  1.2 Unix 的生命力

  Unix 诞生于 1969 年,此后便一直应用于生产领域。按照计算机工业的标准,那已经是好几个地质纪年前的事了 —— 比 PC 机、工作站、微处理器甚至视频显示终端都要早,与第一块半导体存储器是同一时代的古物。在现今所有分时系统中,也只有 IBM 的 VM/CMS 敢说它比 Unix 资格更老,但是 Unix 机器的服务时间却是 VM/CMS 的几十万倍;事实上,在 Unix 平台上完成的计算量可能比所有其它分时系统加起来的总和还要多。

  Unix 比其它任何操作系统都更广泛地应用在各种机型上。从超级计算机到手持计算机到嵌入式网络设备,从工作站到服务器到 PC 机到微型计算机。 Unix 所能支持的机器架构和奇特硬件可能比你随便抓取任何其它三种操作系统所能支持的总和还要多。

  Unix 应用范围之广简直令人难以置信。没有哪一种操作系统能像 Unix 那样,能同时在作为研究工具、定制技术应用的友好宿主机、商用成品软件平台和互联网技术的重要部分等各个领域都大放异彩。

  从 Unix 诞生之日起,各种信誓旦旦的预言就伴随着它,说 Unix 必将衰败,或者被其它操作系统挤出市场。可是在今天,化身为 Linux 、 BSD 、 Solaris 、 MacOS X 以及好几个其它变种的 Unix ,却显得前所未有的强大。

  Robert Metcalf[ 以太网络的发明者 ] 曾说过:如果将来有什么技术来取代以太网,那么这个取代物的名字还会叫“以太网”。因此以太网是永远不会消亡的 (注 1 。 Unix 也多次经历了类似的转变。

—Ken Thompson


  至少, Unix 的一个核心技术 ——C 语言 —— 已经在其它系统中植根。事实上,如果没有无处不在的 C 语言这个通用语言,还如何奢谈系统级软件工程。 Unix 还引入了如今广泛采用的带目录节点的树形文件名字空间以及 用于 程序间通信的管道机制。

  Unix 的生命力和适应力委实令人称奇。尽管其它技术如蜉蝣般生生灭灭,计算机性能成千倍增长,语言历经嬗变,业界规范多次变革 —— 然而 Unix 依然巍然屹立,仍在运行,仍在创造价值,仍然能赢得这个星球上无数最优秀、最聪明的软件技术人员的忠诚。

  性能—时间的指数曲线对软件开发过程所引发的结果,就是每过 18 个月,就有一半的知识会过时。 Unix 并不承诺使你免遭此劫,只是使你的知识投资更趋稳定。因为不变的东西有很多:语言、系统调用、工具用法——它们积年不变,甚至可以用上数十载。而在其它操作系统中则无法预判什么东西会持久不变,有时候甚至整个操作系统都会被淘汰。在 Unix 中,持久性知识和短期性知识有着明显的区别,人们在一开始学习的时候,就能提前判断(命中率约有九成)要学的知识属于哪一类。这些便是 Unix 有众多忠实拥趸的原因。

  Unix 的稳定和成功在很大程度上归功于它与生俱来的内在优势,归功于 Ken Thompson, Dennis Ritchie, Brian Kernighan, Doug McIroy, Rob Pike 和其他早期 Unix 开发者一开始就作出的设计决策。这些决策,连同设计哲学、编程艺术、技术文化一起,从 Unix 的婴儿期到今天的成长路程中,已经被反复证明是健康可靠的,而 Unix 才得以有今天的成功。

  1.3 反对学习 Unix 文化的理由

  Unix 的耐用性及其技术文化对于喜爱 Unix 的人们、以及技术史家来说肯定颇为有趣。但是, Unix 的本源用途——作为大中型计算机的通用分时系统,由于受到个人工作站的围剿,正迅速地退出舞台,隐入历史的迷雾之中。因而 Unix 究竟能否在目前被 Microsoft 主宰的主流商务桌面市场上取得成功,人们自然也存在着一定的疑问。

  外行常常把 Unix 当作是教学用的玩具或者是黑客的沙盒而不屑一顾。有一本著名的抨击 Unix 的书——《 Unix 反对者手册》( Unix Hater's Handbook ) [Garfinkel) ,几乎从 Unix 诞生时就一直奉行反对路线,将 Unix 的追随者描写成一群信奉邪教的怪人


  和失败者。 AT&T 、 Sun 、 Novell ,以及其他一些大型商业销售商和标准联盟在 Unix 定位和市场推广方面不断铸下的大错也已经成为经典笑柄。

  即使在 Unix 世界里, Unix 的通用性也一直受到怀疑,摇摆在危崖边。在持怀疑态度的外行人眼中, Unix 很有用,不会消亡,只是登不了大雅之堂;注定只能是个小众的操作系统。

  挫败这些怀疑者的不是别的,正是 Linux 和其它开源 Unix (如现代 BSD 各个变种)的崛起。 Unix 文化是如此的有生命力,即使十几年的管理不善也丝毫未箝制它的勃勃生机。现在 Unix 社区自身已经重新控制了技术和市场,正快速而有效地解决着 Unix 的问题(第 20 章将有详述)。

  1.4 Unix 之失

  对于一个始于 1969 年的设计来说,在 Unix 设计中居然很难找到硬伤,这着实令人称奇。其它的选择不是没有,但是每一个这样的选择同样面临争论,无论是 Unix 爱好者,还是操作系统设计社群的人们。

  Unix 文件在字节层次以上再无结构可言。文件删除了就没法恢复。 Unix 的安全模型公认地太过原始。作业控制有欠精致。命名方式非常混乱。或许拥有文件系统本身就是一个错误。我们将在第 20 章讨论这些技术问题。

  但是,也许 Unix 最持久的异议恰恰来自 Unix 哲学的一个特性,这一条特性是 X window 设计者首先明确提出的。 X 致力于提供 一套“机制,而不是策略”,以支持一套极端通用的图形操作,从而把使用工具箱和界面的“观感”(策略)推后到应用层。 Unix 其它系统级的服务也有类似的倾向:行为的最终逻辑被尽可能推后到使用端。 Unix 用户可以在多种 shell 中进行选择。而 Unix 应用程序通常会提供很多的行为选项和令人眼花缭乱的定制功能。

  这种倾向也反映出 Unix 的遗风:原本是为技术人员设计的操作系统;同时也表明设计的信念:最终用户永远比操作系统设计人员更清楚他们究竟需要什么。


  贝尔实验室的 Dick Hamming 2 在 1950 年代便树立了此信条:尽管计算机稀缺昂贵,但是开放式的计算模式,即客户可以为系统写出自己的应用程序,这一点势在必行,因为 “ 用错误的方式解决正确的问题总比用正确的方法解决错误的问题好 ” 。

—— Doug McIlroy

  然而这种选择机制而不是策略的代价是:当用户“ 可以 ”自己设置策略时,他们其实是“必须”自己设置策略。非技术型的终端用户常常会被 Unix 丰富的选项和接口风格搞得晕头转向,于是转而选择那些伪称能够给他们提供简洁性的操作系统。

  只看眼前的话, Unix 的这种自由放纵主义风格会让它失去很多非技术型用户。但从长远考虑,最终你会发觉这个“错误”换来至关重要的优势:策略相对短寿,而机制才会长存。现今流行的界面观感常常会变成明日进化的死胡同(去问问那些使用已经过时的 X 工具包的用户,他们会有一肚子苦水倒给你!)。说来说去,只提供机制不提供方针的哲学能使 Unix 长久保鲜;而那些被束缚在一套方针或界面风格内的操作系统,也许早就从人们的视线中消失了。 3

  1.5 Unix 之得

  最近 Linux 爆炸式的发展和 Internet 技术重要性的渐增,都给我们充足的理由来否定怀疑者的论断。其实,退一步说,就算怀疑者的断言正确, Unix 文化也同样值得研习,因为在有些方面, Unix 及其外围文化明显比任何竞争对手都出色。

  1.5.1 开源软件

  尽管“开源”这个术语和开源定义( the Open Source Definition )直到 1998 年才出现,但是自由共享源码的同僚严格复审的开发方式打从 Unix 诞生起就是其文化最具特色的部分。


  最初十年中的 AT&T 原始 Unix ,及其后来的主要变种 Berkeley Unix ,通常都随源代码一起发布。下文要提到的 Unix 的优势,大多数也由此而来。

  1.5.2 跨平台可移植性和开放标准

  Unix 仍是唯一一个在不同种类的计算机、众多厂商、各种专用硬件上提供了一个一致的、文档齐全的应用程序接口( API )的操作系统。 Unix 也是唯一一个从嵌入式芯片、手持设备到桌面机,从服务器到专门用于数值计算的怪兽级计算机以及数据库后端都腾挪有余的操作系统。

  Unix API 几乎就可以作为编写真正可移植软件的硬件无关标准。难怪最初 IEEE 称之为 “可移植操作系统标准”( Portable Operating System Standard )的 POS 很快就被大家加了后缀变成了“ POSIX ” [ 译注:缩写为 POSIX 是为了读音更像 Unix] 。 确实,只有称之为 Unix API 的等价物才能算是这种标准比较可信 的模型。

  其它操作系统只提供二进制代码的应用程序,并随其诞生环境的消亡而消亡,而 Unix 源码却是永生的。至少,永生在数十年不断维护翻修它们的 Unix 技术文化之中。

  1.5.3 Internet 和万维网

  美国国防部将第一版 TCP/IP 协议栈的开发合同交给一个 Unix 研发组就是因为考虑到 Unix 大部分是开放源码。除了 TCP/IP 之外 , Unix 也已成为互联网服务提供商 (Internet Service Provider) 行业不可或缺的核心技术之一。甚至在 1980 年代中期 TOPS 系列操作系统消亡之际 , 大部分互联网服务器 ( 实际上 PC 以上所有级别的机器 ) 都依赖于 Unix 。

  在 Internet 市场上, Unix 甚至面对 Microsoft 可怕的行销大锤也毫发无伤。 虽然成型于 TOPS-10 的 TCP/IP 标准(互联网的基础) 在理论上可以与 Unix 分开 , 但当应用在其它操作系统上时, 一直都饱受兼容性差、不稳定、 bug 太多等问题的困扰。实际上,理论和规格说明人人都可以获取 , 但是只有 Unix 世界中你才见得到这些稳固可靠的现实成果。 4


  互联网技术文化和 Unix 文化在 1980 年代早期开始汇合,现在已经共生共存,难以分割。万维网的设计——也就是互联网的现代面孔,从其祖先 ARPANET 所得到的,不比从 Unix 得到的更多。实际上 , 统一资源定位符 URL(Uniform Resource Locator) 作为 Web 的核心概念,也是 Unix 中无处不在的统一文件名字空间概念的泛化。要作为一个有效的网络专家,对 Unix 及其文化的理解绝对是必不可少的。

  1.5.4 开源社区

  伴随早期 Unix 源码发布而形成的社群从未消亡——在 1990 年代早期互联网技术的爆炸式发展之后,这个社群新造就了整整一代的使用家用机的狂热黑客。

  今天, Unix 社区是各种软件开发的强大支持组。 高质量的开源开发工具在 Unix 世界极为丰富 ( 在本书中我们会讲到很多 ) 。开源的 Unix 应用程序已经达到、或者超越它们专属同侪的高度 [Fuzz] 。整个 Unix 操作系统连同完整的工具包、基本的应用套件,都可以在互联网上免费获取。既然能够改编、重用、再造,节省自己 90% 的工作量,为什么还要从零开始编码呢 ?

  通过协作开发与代码复用路上艰辛的探索,才耕耘出代码共享的传统。不是在理论上,而是通过大量工程实践,才有了这些并非显而易见的设计规则:程序得以形成严丝合缝的工具套装,而不是应景的解决对策。本书的一个主要目的就是阐明这些原则。

  今天 , 方兴未艾的开源运动给 Unix 传统注入了新的血液、新的技术方法,同时也带来了新一代年轻而有才华的程序员。包括 Linux 操作系统以及共生的应用程序如 Apache 、 Mozilla 等开源项目已经使 Unix 传统在主流世界空前亮眼与成功。如今,在争相对未来计算基础设施进行定义的这场竞争中,开源运动似乎已经站在了胜利的边缘——新架构的核心正是运行在互联网上的 Unix 机器。

  1.5.5 从头到脚的灵活性

  许多操作系统自诩比起 Unix 来有多么的“现代”,用户界面又是多么的 “ 友好 ” 。 它们漂亮外表的背后,却是以貌似精巧实则脆弱狭隘难用的编程接口,把用户和开发者禁锢在单一的界面方针下。在这样的操作系统中,完成设计者(指操作系统)预见的任务


  很容易,但如果要完成设计者没有预料到的任务,用户不是无计可施就是痛苦不堪。

  相反, Unix 具有非常彻底的灵活性。 Unix 提供众多的程序粘合手段,这意味着 Unix 基本工具箱的各种组件连纵开合后,将收到单个工具设计者无法想象的功效。

  Unix 支持多种风格的程序界面(通常也因为给终端用户增加了明显的系统复杂度而被视为 Unix 的一个缺点),从而增加了它的灵活性;只管简单数据处理的程序而无需背上精巧图形界面的担子。

  Unix 传统将重点放在尽力使各个程序接口相对小巧、简洁和正交——这也是另一个提高灵活性的方面。整个 Unix 系统,容易的事还是那么容易,困难的事呢,至少是有可能做到的。

  1.5.6 Unix Hack 之趣

  那些夸夸其谈 Unix 技术优越性的家伙一般不会提到 Unix 的终极法宝、它赖以成功的原因: Unix Hack 的趣味。

  一些 Unix 的玩家有时羞于认同这一点,似乎这会破坏他们的正统形象。但是,确实如此,同 Unix 打交道,搞开发就是好玩;现在是,且一向如是。

  并没有多少操作系统会被人们用“好玩”来描述。实际上,在其它操作系统下搞开发的摩擦和艰辛,就像是有人比喻的“把一头搁浅的死鲸推下海” 5 一样费力不讨好;或者,最客气的也就是“尚可容忍”、“不是太痛苦”之类形容词。与之成鲜明对比的是,在 Unix 世界里,操作系统以成就感而不是挫折感来回报人们的努力。 Unix 下的程序员通常会把 Unix 当作一个积极有效的帮手,而不是把操作系统当作一个对手还非得用蛮力逼迫它干活。

  这一点有着实实在在的重要经济意义。趣味性在 Unix 早期的历史中开启了一个良性循环。正是因为人们喜爱 Unix, 所以编制了更多的程序让它用起来更好, 而如今,连编制一个完整商用产品级的开源 Unix 操作系统都成了一项爱好。如果想知道这是多么惊人的伟绩,想想看你什么时候听说过谁为了好玩来临摹 OS/360 或者 VAX VMS 或者 Microsoft Windows 就行了。

  从设计角度来说,趣味性也绝非无足轻重。对于程序员和开发人员来说,如果完成某项任务所需要付出的努力对他们是个挑战却又恰好还在力所能及的范围内,他们就会觉得很有乐趣。因此,趣味性是一个峰值效率的标志。充满痛苦的开发环境只会浪费劳动力和创造力;这样的环境会在无形之中耗费大量时间、资金,还有机会。

  就算 Unix 在其它各个方面都一无是处, Unix 的工程文化仍然值得学习,它使得开发过程充满乐趣。乐趣是一个符号,意味着效能、效率和高产。

  1.5.7 Unix 的经验别处也可适用

  在探索开发那些我们如今已经觉得理所当然的操作系统特性的过程中, Unix 程序员已经积累了几十年的经验。哪怕是非 Unix 的程序员也能够从这些经验中获益。好的设计原则和开发方法在 Unix 上实施相对容易,所以 Unix 是一个学习这些原则和方法的良好平台。

  在其它操作系统下,要做到良好实践通常要相对困难一些,但是尽管如此, Unix 文化中的有益经验仍然可以借鉴。多数 Unix 代码 ( 包括所有的过滤器、主要脚本语言和大多数代码生成器 ) 都可以直接移植到任何只要支持 ANSI C 的操作系统中去 ( 原因在于 C 语言本身就是 Unix 的一项发明,而 ANSI C 程序库表述了相当大一部分的 Unix 服务 ) 。

  1.6 Unix 哲学基础

  Unix 哲学起源于 Ken Thompson 早期关于如何设计一个服务接口简洁、小巧精干的操作系统的思考,随着 Unix 文化在学习如何尽可能发掘 Thompson 设计思想的过程中不断成长,同时一路上还从其它许多地方博采众长。

  Unix 哲学说来不算是一种正规设计方法。它并不打算从计算机科学的理论高度来产生理论上完美的软件。那些毫无动力、松松垮垮而且薪水微薄的程序员们,能在短短期限内,如同神灵附体般造出稳定而新颖的软件——这只不过是经理人永远的梦呓罢了。

  Unix 哲学(同其它工程领域的民间传统一样)是自下而上的,而不是自上而下的。 Unix 哲学注重实效,立足于丰富的经验。你不会在正规方法学和标准中找到它,它更接近于隐性的半本能的知识,即 Unix 文化所传播的 专业经验 。它鼓励那种分清轻重缓急的感觉,以及怀疑一切的态度,并鼓励你以幽默达观的态度对待这些。

  Unix 管道的发明人、 Unix 传统的奠基人之一 Doug McIlroy 在 [McIlroy78] 中曾经说过:


  ( i )让每个程序就做好一件事。如果有新任务,就重新开始,不要往原程序中加入新功能而搞得复杂。

  ( ii )假定每个程序的输出都会成为另一个程序的输入,哪怕那个程序还是未知的。输出中不要有无关的信息干扰。避免使用严格的分栏格式和二进制格式输入。不要坚持使用交互式输入。

  ( ii )尽可能早地将设计和编译的软件投入试用 , 哪怕是操作系统也不例外,理想情况下 , 应该是在几星期内。对拙劣的代码别犹豫,扔掉重写。

  ( iv )优先使用工具而不是拙劣的帮助来减轻编程任务的负担。工欲善其事,必先利其器。

  后来他这样总结道(引自《 Unix 的四分之一世纪》( A Quarter Century of Unix [Salus] )):

  Unix 哲学是这样的:一个程序只做一件事,并做好。程序要能协作。程序要能处理文本流,因为这是最通用的接口。

  Rob Pike, 最伟大的 C 语言大师之一 , 在《 Notes on C Programming 》中从另一个稍微不同的角度表述了 Unix 的哲学 [Pike] :

  原则 1: 你无法断定程序会在什么地方耗费运行时间。瓶颈经常出现在想不到的地方,所以别急于胡乱找个地方改代码,除非你已经证实那儿就是瓶颈所在。

  原则 2 :估量。在你没对代码进行估量,特别是没找到最耗时的那部分之前,别去优化速度。

  原则 3: 花哨的算法在 n 很小时通常很慢,而 n 通常很小。花哨算法的常数复杂度很大。除非你确定 n 总是很大,否则不要用花哨算法(即使 n 很大,也优先考虑原则 2 )。

  原则 4 :花哨的算法比简单算法更容易出 bug 、更难实现。尽量使用简单的算法配合简单的数据结构。

  原则 5 :数据压倒一切。如果已经选择了正确的数据结构并且把一切都组织得井井有条,正确的算法也就不言自明。编程的核心是数据结构,而不是算法 6


  原则 6 :没有原则 6 。

  Ken Thompson —— Unix 最初版本的设计者和实现者,禅宗偈语般地对 Pike 的原则 4 作了强调:

  拿不准就穷举。

  Unix 哲学中更多的内容不是这些先哲们口头表述出来的,而是由他们所作的一切和 Unix 本身所作出的榜样体现出来的。从整体上来说,可以概括为以下几点:

•  模块原则:使用简洁的接口拼合简单的部件。

•  清晰原则:清晰胜于机巧。

•  组合原则:设计时考虑拼接组合。

•  分离原则:策略同机制分离,接口同引擎分离。

•  简洁原则:设计要简洁,复杂度能低则低。

•  吝啬原则:除非确无它法,不要编写庞大的程序。

•  透明性原则:设计要可见,以便审查和调试。

•  健壮原则:健壮源于透明与简洁。

•  表示原则:把知识叠入数据以求逻辑质朴而健壮。

•  通俗原则:接口设计避免标新立异。

•  缄默原则:如果一个程序没什么好说的,就沉默。

•  补救原则:出现异常时,马上退出并给出足够错误信息。

•  经济原则:宁花机器一分,不花程序员一秒。

•  生成原则:避免手工 hack ,尽量编写程序去生成程序。


•  优化原则:雕琢前先要有原型,跑之前先学会走。

•  多样原则:决不相信所谓 “ 不二法门 ” 的断言。

•  扩展原则:设计着眼未来,未来总比预想来得快。

  如果刚开始接触 Unix ,这些原则值得好好体味一番。谈软件工程的文章常常会推荐大部分的这些原则,但是大多数其它操作系统缺乏恰当的工具和传统将这些准则付诸实践,所以,多数的程序员还不能自始至终地贯彻这些原则。蹩脚的工具、糟糕的设计、过度的劳作和臃肿的代码对他们已经是家常便饭了;他们奇怪, Unix 的玩家有什么好烦的呢。

  1.6.1 模块原则:使用简洁的接口拼合简单的部件

  正如 Brian Kernighan 曾经说过的:“计算机编程的本质就是控制复杂度” [Kernighan-Plauger] 。排错占用了大部分的开发时间,弄出一个拿得出手的可用系统,通常与其说出自才华横溢的设计成果,还不如说是跌跌撞撞的结果。

  汇编语言、编译语言、流程图、过程化编程、结构化编程、所谓的人工智能、第四代编程语言、面向对象、以及软件开发的方法论,不计其数的解决之道被抛售者吹得神乎其神。但实际上这些都用处不大,原因恰恰在于它们“成功”地将程序的复杂度提升到了人脑几乎不能处理的地步。就像 Fred Brooks 的一句名言 [Brooks] :没有万能药。

  要编制复杂软件而又不至于一败涂地的唯一方法就是降低其整体复杂度——用清晰的接口把若干简单的模块组合成一个复杂软件。如此一来,多数问题只会局限于某个局部,那么就还有希望对局部进行改进而不至牵动全身。

  1.6.2 清晰原则 : 清晰胜于机巧

  维护如此重要而成本如此高昂;在写程序时,要想到你不是写给执行代码的计算机看的,而是给人——将来阅读维护源码的人,包括你自己——看的。

  在 Unix 传统中,这个建议不仅意味着代码注释。良好的 Unix 实践同样信奉在选择


  算法和实现时就应该考虑到将来的可扩展性。而为了取得程序一丁点的性能提升就大幅度增加技术的复杂性和晦涩性,这个买卖做不得——这不仅仅是因为复杂的代码容易滋生 bug ,也因为它会使日后的阅读和维护工作更加艰难。

  相反,优雅而清晰的代码不仅不容易崩溃 ―― 而且更易于让后来的修改者立刻明白理解。这点非常重要,尤其是说不定若干年后回过头来修改这些代码的人可能恰恰就是你自己。

  永远不要去吃力地解读一段晦涩的代码三次。第一次也许侥幸成功,但如果发现必须重新解读一遍 ―― 离第一次太久了,具体细节无从回想 ―― 那么你该注释代码了,这样第三次就相对不会那么痛苦了。

  —Henry Spencer

  1.6.3 组合原则:设计时考虑拼接组合

  如果程序彼此之间不能有效通信,那么软件就难免会陷入复杂度的泥淖。

  在输入输出方面, Unix 传统极力提倡采用简单、文本化、面向流、设备无关的格式。在经典的 Unix 下,多数程序都尽可能采用简单过滤器的形式,即将一个输入的简单文本流处理为一个简单的文本流输出。

  抛开世俗眼光, Unix 程序员偏爱这种做法并不是因为他们仇视图形用户界面,而是因为如果程序不采用简单的文本输入输出流,它们就极难衔接。

  Unix 中,文本流之于工具,就如同在面向对象环境中的消息之于对象。文本流界面的简洁性加强了工具的封装性。而许多精致的进程间通讯方法,比如远程过程调用,都存在牵扯过多各程序间内部状态的倾向。

  要想让程序具有组合性,就要使程序彼此独立。在文本流这一端的程序应该尽可能不要考虑文本流另一端的程序。将一端的程序替换为另一个截然不同的程序,而完全不惊扰另一端应该很容易做到。

  GUI 可以是个好东西。有时竭尽所能也不可避免复杂的二进制数据格式。但是,在做一个 GUI 前,最好还是应该想想可不可以把复杂的交互程序跟干粗活的算法程序分离开,每个部分单独成为一块,然后用一个简单的命令流或者是应用协议将其组合在一起。


  在构思精巧的数据传输格式前,有必要实地考察一下,是否能利用简单的文本数据格式;以一点点格式解析的代价,换得可以使用通用工具来构造或解读数据流的好处是值得的。

  当程序无法自然地使用序列化、协议形式的接口时,正确的 Unix 设计至少是,把尽可能多的编程元素组织为一套定义良好的 API 。这样,至少你可以通过链接调用应用程序,或者可以根据不同任务的需求粘合使用不同的接口。

  (我们将在第 7 章详细讨论这些问题。)

  1.6.4 分离原则 : 策略同机制分离,接口同引擎分离。

  在 Unix 之失的讨论中,我们谈到过 X 系统的设计者在设计中的基本抉择是实行 “ 机制,而不是策略 ” 这种做法 ―― 使 X 成为一个通用图形引擎,而将用户界面风格留给工具包或者系统的其它层次来决定。这一点得以证明是正确的,因为策略和机制是按照不同的时间尺度变化的,策略的变化要远远快于机制。 GUI 工具包的观感时尚来去匆匆,而光栅操作和组合却是永恒的。

  所以,把策略同机制揉成一团有两个负面影响:一来会使策略变得死板,难以适应用户需求的改变,二来也意味着任何策略的改变都极有可能动摇机制。

  相反,将两者剥离,就有可能在探索新策略的时候不足以打破机制。另外,我们也可以更容易为机制写出较好的测试(因为策略太短命,不值得花太多精力在这上面)。

  这条设计准则在 GUI 环境之外也被广泛应用。总而言之,这条准则告诉我们应该设法将接口和引擎剥离开来。

  实现这种剥离的一个方法是,比如,将应用按照一个库来编写,这个库包含许多由内嵌脚本语言驱动的 C 服务程序,而至于整个应用的控制流程则用脚本来撰写而不是用 C 语言。这种模式的经典例子就是 Emacs 编辑器,它使用内嵌的脚本语言 Lisp 解释器来控制用 C 编写的编辑原语操作。我们会在第 11 章讨论这种设计风格。

  另一个方法是将应用程序分成可以协作的前端和后端进程,通过套接字上层的专用应用协议进行通讯;我们会在第 5 章和第 7 章讨论这种设计。前端实现策略,后端实现


  机制。比起仅用单个进程的整体实现方式来说,这种双端设计方式大大降低了整体复杂度, bug 有望减少,从而降低程序的寿命周期成本。

  1.6.5 简洁原则:设计要简洁,复杂度能低则低

  来自多方面的压力常常会让程序变得复杂(由此代价更高, bug 更多),其中一种压力就是来自技术上的虚荣心理。程序员们都很聪明,常常以能玩转复杂东西和耍弄抽象概念的能力为傲,这一点也无可厚非。但正因如此,他们常常会与同行们比试,看看谁能够鼓捣出最错综复杂的美妙事物。正如我们经常所见,他们的设计能力大大超出他们的实现和排错能力,结果便是代价高昂的废品。

  “错综复杂的美妙事物”听来自相矛盾。 Unix 程序员相互比的是谁能够做到“简洁而漂亮”并以此为荣,这一点虽然只是隐含在这些规则之中,但还是很值得公开提出来强调一下。

  —Doug McIlroy

  更为常见的是 ( 至少在商业软件领域里 ) ,过度的复杂性往往来自于项目的要求,而这些要求常常基于当月的推销热点,而不是基于顾客的需求和软件实际能够提供的功能。许多优秀的设计被市场推销需要的大堆大堆“特性清单”扼杀 ―― 实际上,这些特性功能几乎从未用过。然后,恶性循环开始了:比别人花哨的方法就是把自己变得更花哨。很快,庞大臃肿变成了业界标准,每个人都在使用臃肿不堪、 bug 极多的软件,连软件开发人员也不敢敝帚自珍。

  无论以上哪种方式,最后每个人都是失败者。

  要避免这些陷阱,唯一的方法就是鼓励另一种软件文化,以简洁为美,人人对庞大复杂的东西群起攻之——这是一个非常看重简单解决方案的工程传统,总是设法将程序系统分解为几个能够协作的小部分,并本能地抵制任何用过多噱头来粉饰程序的企图。

  这就有点 Unix 文化的意味了。


  1.6.6 吝啬原则 : 除非确无它法,不要编写庞大的程序。

  “大”有两重含义:体积大,复杂程度高。程序大了,维护起来就困难。由于人们对花费了大量精力才做出来的东西难以割舍,结果导致在庞大的程序中把投资浪费在注定要失败或者并非最佳的方案上。

  (我们会在第 13 章就软件的最佳大小进行更多的详细讨论。)

  1.6.7 透明性原则:设计要可见,以便审查和调试

  因为调试通常会占用四分之三甚至更多的开发时间,所以一开始就多做点工作以减少日后调试的工作量会很划算。一个特别有效的减少调试工作量的方法就是设计时充分考虑透明性和显见性。

  软件系统的透明性是指你一眼就能够看出软件是在做什么以及怎样做的。显见性指程序带有监视和显示内部状态的功能,这样程序不仅能够运行良好,而且还可以看得出它以何种方式运行。

  设计时如果充分考虑到这些要求会给整个项目全过程都带来好处。至少,调试选项的设置应该尽量不要在事后,而应该在设计之初便考虑进去。这是考虑到程序不但应该能够展示其正确性,也应该能够把原开发者解决问题的思维模型告诉后来者。

  程序如果要展示其正确性,应该使用足够简单的输入输出格式,这样才能保证很容易地检验有效输入和正确输出之间的关系是否正确。

  出于充分考虑透明性和显见性的目的,还应该提倡接口简洁,以方便其它程序对其进行操作 ―― 尤其是测试监视工具和调试脚本。

  1.6.8 健壮原则 : 健壮源于透明与简洁。

  软件的健壮性指软件不仅能在正常情况下运行良好,而且在超出设计者设想的意外条件下也能够运行良好。

  大多数软件禁不起磕碰,毛病很多,就是因为过于复杂,很难通盘考虑。如果不能够正确理解一个程序的逻辑,就不能确信其是否正确,也就不能在出错的时候修复它。


  这也就带来了让程序健壮的方法,就是让程序的内部逻辑更易于理解。要做到这一点主要有两种方法:透明化和简洁化。

  就健壮性而言,设计时要考虑到能承受极端大量的输入,这一点也很重要。这时牢记组合原则会很有益处;经不起其它一些程序产生的输入(例如,原始的 Unix C 编译器据说需要一些小小的升级才能处理好 Yacc 的输出)。当然,这其中涉及的一些形式对人类来说往往看起来没什么实际用处。比如,接受空的列表 / 字符串等等,即使在人们很少或者根本就不提供空字符串的地方也得如此,这可以避免在用机器生成输入时需要对这种情况进行特殊处理。

  —Henry Spencer

  在有异常输入的情况下,保证软件健壮性的一个相当重要的策略就是避免在代码中出现特例。 bug 通常隐藏在处理特例的代码以及处理不同特殊情况的交互操作部分的代码中。

  上面我们曾说过,软件的透明性就是指一眼就能够看出来是怎么回事。如果“怎么回事”不算复杂,即人们不需要绞尽脑汁就能够推断出所有可能的情况,那么这个程序就是简洁的。程序越简洁,越透明,也就越健壮 .

  模块性(代码简朴,接口简洁)是组织程序以达到更简洁目的的一个方法。另外也有其它的方法可以得到简洁。接下来就是另一个。

  1.6.9 表示原则 : 把知识叠入数据以求逻辑质朴而健壮

  即使最简单的程序逻辑让人类来验证也很困难,但是就算是很复杂的数据,对人类来说,还是相对容易地就能够推导和建模的。不信可以试试比较一下,是五十个节点的指针树,还是五十行代码的流程图更清楚明了;或者,比较一下究竟用一个数组初始化器来表示转换表,还是用 switch 语句更清楚明了呢?可以看出,不同的方式在透明性和清晰性方面具有非常显著的差别。参见 Rob Pike 的 原则 5 。

  数据要比编程逻辑更容易驾驭。所以接下来,如果要在复杂数据和复杂代码中选择一个,宁愿选择前者。更进一步:在设计中,你应该主动将代码的复杂度转移到数据之中去。

  此种考量并非 Unix 社区的原创,但是许多 Unix 代码都显示受其影响。特别是 C 语言对指针使用控制的功能,促进了在内核以上各个编码层面上对动态修改引用结构。在结构中用非常简单的指针操作就能够完成的任务,在其它语言中,往往不得不用更复杂的过程才能完成。

  (我们将在第 9 章再讨论这些技术。)

  1.6.10 通俗原则:接口设计避免标新立异

  (也就是众所周知的“最少惊奇原则”。)

  最易用的程序就是用户需要学习新东西最少的程序——或者,换句话说,最易用的程序就是最切合用户已有知识的程序。

  因此,接口设计应该避免毫无来由的标新立异和自作聪明。如果你编制一个计算器程序,‘+'应该永远表示加法。而设计接口的时候,尽量按照用户最可能熟悉的同样功能接口和相似应用程序来进行建模。

  关注目标受众。他们也许是最终用户,也许是其他程序员,也许是系统管理员。对于这些不同的人群,最少惊奇的意义也不同。

  关注传统惯例。 Unix 世界形成了一套系统的惯例,比如配置和运行控制文件的格式,命令行开关等等。这些惯例的存在有个极好的理由:缓和学习曲线。应该学会并使用这些惯例。

  (我们将在第 5 章和第 10 章讨论这些传统惯例。)

  最小立异原则的另一面是避免表象相似而实际却略有不同。这会极端危险,因为表象相似往往导致人们产生错误的假定。所以最好让不同事物有明显区别,而不要看起来几乎一模一样。

  —Henry Spencer

  1.6.11 缄默原则:如果一个程序没什么好说的,就保持沉默

  Unix 中最古老最持久的设计原则之一就是:若程序没有什么特别之处可讲,就保持沉默。行为良好的程序应该默默工作,决不唠唠叨叨,碍手碍脚。沉默是金。

  “沉默是金”这个原则的起始是源于 Unix 诞生时还没有视频显示器。在 1969 年的缓慢的打印终端,每一行多余的输出都会严重消耗用户的宝贵时间。现在,这种情况已不复存在,一切从简的这个优良传统流传至今。

  我认为简洁是 Unix 程序的核心风格。一旦程序的输出成为另一个程序的输入,就很容易把需要的数据挑出来。站在人的角度上来说 ―― 重要信息不应该混杂在冗长的程序内部行为信息中。如果显示的信息都是重要的,那就不用找了。

  —Ken Arnold

  设计良好的程序将用户的注意力视为有限的宝贵资源,只有在必要时才要求使用。

  (我们将在第 11 章末尾进一步讨论缄默原则及其理由。)

  1.6.12 补救原则 : 出现异常时,马上退出并给出足量错误信息

  软件在发生错误的时候也应该与在正常操作的情况下一样,有透明的逻辑。最理想的情况当然是软件能够适应和应付非正常操作;而如果补救措施明明没有成功,却悄无声息地埋下崩溃的隐患,直到很久以后才显现出来,这就是最坏的一种情况。

  因此,软件要尽可能从容地应付各种错误输入和自身的运行错误。但是,如果做不到这一点,就让程序尽可能以一种容易诊断错误的方式终止。

  同时也请注意 Postel 的规定 7 :“宽容地收,谨慎地发”。 Postel 谈的是网络服务程序,但是其含义可以广为适用。就算输入的数据很不规范,一个设计良好的程序也会尽量领会其中的意义,以尽量与别的程序协作;然后,要么响亮地倒塌,要么为工作链下一环的程序输出一个严谨干净正确的数据。

  然而,也请注意这条警告:

  最初 HTML 文档推荐“宽容地接受数据”,结果因为每一种浏览器都只接受规范中一个不同的超集,使我们一直倍感无奈。要宽容的应该是规范而不是它们的解释工具。

  —Doug McIlroy


  McIlroy 要求我们在设计时要考虑宽容性,而不是用过分纵容的实现来补救标准的不足。否则,正如他所指出的一样,一不留神你会死得很难看。

  1.6.13 经济原则 : 宁花机器一分,不花程序员一秒

  在 Unix 早期的小型机时代,这一条观点还是相当激进的(那时机器要比现在慢得多也贵得多)。如今,随着技术的发展,开发公司和大多数用户(那些需要对核爆炸进行建模或处理三维电影动画的除外)都能够得到廉价的机器,所以这一准则的合理性就显然不用多说啦!

  但不知何故,实践似乎还没完全跟上现实的步伐。如果我们在整个软件开发中很严格的遵循这条原则的话,大多数的应用场合都应该使用高一级的语言,如 Perl 、 Tcl 、 Python 、 Java 、 Lisp ,甚至 shell―― 这些语言可以将程序员从自行管理内存的负担中解放出来(参见 [Ravenbrook] )。

  这种做法在 Unix 世界中已经开始施行,尽管 Unix 之外的大多数软件商仍坚持采用旧 Unix 学派的 C( 或 C++) 编码方法。本书会在后面详细讨论这个策略及其利弊权衡。

  另一个可以显著节约程序员时间的方法是:教会机器如何做更多低层次的编程工作,这就引出了……

  1.6.14 生成原则 : 避免手工 hack ,尽量编写程序去生成程序

  众所周知,人类很不善于干辛苦的细节工作。因此,程序中的任何手工 hacking 都是滋生错误和延误的温床。程序规格越简单越抽象,设计者就越容易做对。由程序生成代码几乎 ( 在 各个 层次 ) 总是比手写代码廉价并且更值得信赖。

  我们都知道确实如此(毕竟这就是为什么会有编译器、解释器的原因),但我们却常常不去考虑其潜在的含义。对于代码生成器来说,需要手写的重复而麻木的高级语言代码,与机器码一样是可以批量生产的。当代码生成器能够提升抽象度时 —— 即当生成器的说明性语句要比生成码简单时,使用代码生成器会很合算,而生成代码后就根本无需再费力地去手工处理了。


  在 Unix 传统中,人们大量使用代码生成器使易于出错的细节工作自动化。 Parser/Lexer 生成器就是其中的经典例子,而 makefile 生成器和 GUI 界面式的构建器( interface builder )则是新一代的例子。

  (我们会在第 9 章讨论这些技术。)

  1.6.15 优化原则 : 雕琢前先得有原型,跑之前先学会走

  原型设计最基本的原则最初来自于 Kernighan 和 Plauger 所说的“ 90% 的功能现在能实现,比 100% 的功能永远实现不了强”。做好原型设计可以帮助你避免为蝇头小利而投入过多的时间。

  由于略微不同的一些原因, Donald Knuth (程序设计领域中屈指可数的经典著作之一《计算机程序设计艺术》的作者)广为传播普及了这样的观点:“过早优化是万恶之源” 8 。他是对的。

  还不知道瓶颈所在就匆忙进行优化,这可能是唯一一个比乱加功能更损害设计的错误。从畸形的代码到杂乱无章的数据布局,牺牲透明性和简洁性而片面追求速度、内存或者磁盘使用的后果随处可见。滋生无数 bug ,耗费以百万计的人时——这点芝麻大的好处,远不能抵消后续排错所付出的代价。

  经常令人不安的是,过早的局部优化实际上会妨碍全局优化(从而降低整体性能)。在整体设计中可以带来更多效益的修改常常会受到一个过早局部优化的干扰,结果,出来的产品既性能低劣又代码过于复杂。

  在 Unix 世界里,有一个非常明确的悠久传统(例证之一是 Rob Pike 以上的评论, 另一个是 Ken Thompson 关于穷举法的格言): 先制作原型,再精雕细琢 。 优化之前先确保能用 。或者:先能走,再学跑。“极限编程”宗师 Kent Beck 从另一种不同的文化将这一点有效地扩展为:先求运行,再求正确,最后求快。

  所有这些话的实质其实是一个意思:先给你的设计做个未优化的、运行缓慢、很耗内存但是正确的实现,然后进行系统地调整,寻找那些可以通过牺牲最小的局部简洁性而获得较大性能提升的地方。


  制作原型对于系统设计和优化同样重要——比起阅读一个冗长的规格说明,判断一个原型究竟是不是符合设想要容易得多。我记得 Bellcore 有一位开发经理,他在人们还没有谈论 “ 快速原型化 ” 和 “ 敏捷开发 ” 前好几年就反对所谓的 “ 需求 ” 文化。他从不提交冗长的规格说明,而是把一些 shell 脚本和 awk 代码结合在一起,使其基本能够完成所需要的任务,然后告诉客户派几个职员来使用这些原型,问他们是否喜欢。如果喜欢,他就会说“在多少多少个月之后,花多少多少的钱就可以获得一个商业版本”。他的估计往往很精确,但由于当时的文化,他还是输给了那些相信需求分析应该主导一切的同行。

  —Mike Lesk

  借助原型化找出哪些功能不必实现,有助于对性能进行优化;那些不用写的代码显然无需优化。目前,最强大的优化工具恐怕就是 delete 键了。

  我最有成效的一天就是扔掉了 1000 行代码。

  —Ken Thompson

  (我们将在第 12 章对相关内容进行深一步讨论。)

  1.6.16 多样原则 : 决不相信所谓 “ 不二法门 ” 的断言。

  即使最出色的软件也常常会受限于设计者的想象力。没有人能聪明到把所有东西都最优化,也不可能预想到软件所有可能的用途。设计一个僵化、封闭、不愿与外界沟通的软件,简直就是一种病态的傲慢。

  因此 , 对于软件设计和实现来说, Unix 传统有一点很好,即从不相信任何所谓的“不二法门”。 Unix 奉行的是广泛采用多种语言、开放的可扩展系统和用户定制机制。

  1.6.17 扩展原则 : 设计着眼未来,未来总比预想快。

  如果说相信别人所宣称的“不二法门”是不明智的话,那么坚信自己的设计是“不二法门”简直就是愚蠢了。决不要认为自己找到了最终答案。因此,要为数据格式和代


  码留下扩展的空间,否则,就会发现自己常常被原先的不明智选择捆住了手脚,因为你无法既要改变它们又要维持对原来的兼容性。

  设计协议或是文件格式时,应使其具有充分的自描述性以便可以扩展。一直,总是,要么包含进一个版本号,要么采用独立、自描述的语句,按照可以随时插入新的、换掉旧的而不会搞乱格式读取代码的方法组织格式。 Unix 经验告诉我们:稍微增加一点让数据部署具有自描述性的开销,就可以在无需破坏整体的情况下进行扩展,你的付出也就得到了成千倍的回报。

  设计代码时,要有很好的组织,让将来的开发者增加新功能时无需拆毁或重建整个架构。当然这个原则并不是说你能随意增加根本用不上的功能,而是建议在编写代码时要考虑到将来的需要,使以后增加功能比较容易。程序接合部要灵活 , 在代码中加入“如果你需要……”的注释。有义务给之后使用和维护自己编写的代码的人做点好事。

  也许将来就是你自己来维护代码,而在最近项目的压力之下你很可能把这些代码都遗忘了一半。所以,设计为将来着眼,节省的有可能就是自己的精力。

  1.7 Unix 哲学之一言以蔽之

  所有的 Unix 哲学浓缩为一条铁律,那就是各地编程大师们奉为圭臬的“ KISS ”原则:

  Unix 提供了一个应用 KISS 原则的良好环境。本书的剩余部分将帮助你学习如何应用这个原则。

  1.8 应用 Unix 哲学

  这些富有哲理的原则决不是模糊笼统的泛泛之谈。在 Unix 世界中,这些原则都直接来自于实践,并形成了具体的规定,我们已经在上文中阐述了一些。以下列举的只是部分内容:

  •  只要可行,一切都应该做成与来源和目标无关的过滤器。

  •  数据流应尽可能文本化(这样可以使用标准工具来查看和过滤)。

  •  数据库部署和应用协议应尽可能文本化(让人可以阅读和编辑)。

  •  复杂的前端(用户界面)和后端应该泾渭分明。

  •  如果可能,用 C 编写前,先用解释性语言搭建原型。

  •  当且仅当只用一门语言编程会提高程序复杂度时,混用语言编程才比单一语言编程来得好。

  •  宽收严发(对接收的东西要包容,对输出的东西要严格)。

  •  过滤时,不需要丢弃的信息决不丢。

  •  小就是美。在确保完成任务的基础上,程序功能尽可能少。

  在本书的余下部分,我们会看到这些 Unix 的设计原则及其衍生的设计规则被反复运用于实践。毫不奇怪,这些往往与其它传统中最优秀的软件工程实践思想不谋而合。 9

  1.9 态度也要紧

  看到该做的就去做——短期来看似乎是多做了,但从长期来看,这才是最佳捷径。如果不能确定什么是对的,那么就只做最少量的工作,确保任务完成就行,至少直到明白什么是对的。


  要良好的运用 Unix 哲学,你就应该不断追求卓越。你必须相信,软件设计是一门技艺,值得你付出所有的智慧、创造力和激情。否则,你的视线就不会超越那些简单、老套的设计和实现;你就会在应该思考的时候急急忙忙跑去编程。你就会在该无情删繁就简的时候反而把问题复杂化 — —然后你还会反过来奇怪你的代码怎么会那么臃肿、那么难以调试。

  要良好地运用 Unix 哲学,你应该珍惜你的时间决不浪费。一旦某人已经解决了某个问题,就直接拿来利用,不要让骄傲或偏见拽住你又去重做一遍。永远不要蛮干;要多用巧劲,省下力气到需要的时候再用,好钢用在刀刃上。善用工具,尽可能将一切都自动化。

  软件设计和实现应该是一门充满快乐的艺术,一种高水平的游戏。如果这种态度对你来说听起来有些荒谬,或者令你隐约感到有些困窘,那么请停下来,想一想,问问自己是不是已经把什么给遗忘了。如果只是为了赚钱或是打发时间,你为什么要搞软件设计而不是别的什么呢?你肯定曾经也认为软件设计值得你付出激情……

  要良好地运用 Unix 哲学,你需要具备(或者找回)这种态度。你需要用心。你需要去游戏。你需要乐于探索。

  我们希望你能带着这种态度来阅读本书的其它部分。或者,至少,我们希望本书能帮助你重拾这种态度。

1 教外别传 。禅宗用语。不依文字、语言,直悟佛陀所悟之境界,即称为教外别传。又称单传。故禅宗又作别传宗,系教外别传宗之略称。据《祖庭事苑卷五怀禅师前》录载,禅宗传法诸祖亦以三藏教乘接引弟子,至达摩祖师时,始单传心印,破执显宗,即所谓教外别传,不立文字,直指人心,见性成佛。后四句英文为 “A special transmission independent of the scriptures. Not founded on words or letters. By directly pointing to the mind. One's nature is seen, enlightenment is attained”.

1 事实上,以太网已经两次被不同的技术所取代,只是名字没有变。第一次是双绞线取代了同轴电缆,第二次是千兆以太网的出现。

2 对,就是创立 “ 汉明距离 ” 和 “ 汉明码 ” 的那位汉明( Hamming )。

3 注: X 的架构者之一 Jim Gettys (也为本书撰写了部分内容)鞭辟入里地揭示了 X 的自由放纵主义才使得它有如此成就。无论就其专门建议,还是对 Unix 理念的表述,这篇小文都极其值得一读。

4 别的操作系统通常已经复制或者沿袭了 Unix TCP/IP 的实现, 但是很遗憾,他们没学到 Unix 实现代码幕后的同僚复审这个强力传统 , 看看 RFC1025( TCP and IP Bake Off — —“ TCP/IP 不同实现大比拼” ) 就知道我是什么意思了。

5 语出 Stephen C. Johnson 对 IBM MVS TSO 机制发的牢骚,此人是 yacc 的作者。

6 Pike 的原稿在这里补充了 “ (参考 Brooks p. 102. ) ” 。引用是来自于 The Mythical Man - Month 【 Brooks 】早期的版本;引语为 “ 给我看流程图而不让我看(数据)表,我仍会茫然不解;如果给我看(数据)表,通常就不需要流程图了;数据表是够说明问题了。 ”

7 Jonathan Postel 是第一个互联网 RFC 系列标准的编纂者,也是互联网的主要架构者之一。网上有一个由 Postel 实验网络中心( Postel Center for Experimental Networking )维护的纪念网页 <http://www.postel.org/postel.html> 。

8 完整的句子是这样的: “97% 的时间里,我们不应考虑蝇头小利的效率提升:过早优化是万恶之源 ” 。 Knuth 自称这一观点来自 C. A. R. Hoare 。

9 我在本书准备工作的后期发现一个值得注意的例子就是 Butler Lampson 的《 Hints for Computer System Design 》 [lampson] 。这本书不仅通过显然是独立发现的形式表达了一系列的 Unix 格言,甚至还使用了许多同样的结语来进行阐述。

 

第二章
历史:——双流记
History: A Tale of Two Cultures
Those who cannot remember the past are condemned to repeat it.
忘记过去的人,注定要重蹈覆辙。
(The Life of Reason) (1905) 《理性生活》(1905年)
—George Santayana

前事不忘,后事之师。Unix的历史悠久而且丰富多彩,许多内容仍然以坊间传说、猜想,以及(更常见的是)Unix程序员集体记忆中的战争创伤等形式鲜活地留存着。本章我们将通过回顾Unix的历史来阐明2003年如今的Unix文化为什么会呈现当前这样一种状态。
2.1 Unix的起源及历史,1969-1995
  小型实验原型系统的后继开发产品往往备受臭名昭著令人讨厌的“第二系统版效应”折磨。由于迫切希望把所有第一次首次开发时来不及做的都添加进去,往往导致设计十分庞大、过于复杂。其实,还有一个因不常遇到而鲜为人知的“第三系统效应”“第三版效应”:有时候,在第二系统不堪自身重负而崩溃之后,然有机会有可能返璞归真,走上正道。
  最初的Unix就是一个第三系统。Unix的祖父祖辈是又小又而简单的兼容分时系统(CTSS, Compatible Time-Sharing System),也算曾经实施过的分时系统的第一代或者第二代了(取决于不同的定义,具体我们在此坚决略过不作讨论)分时系统。Unix的父亲父辈是颇具开拓性的Multics项目,该项目试图建立一个具备众多功能的“信息功用体/应用工具(information utility)”,能够很漂亮地支持大群用户对大型计算机的交互式分时使用。Multics,唉,Multics最后确因不堪自身重负而崩溃了。但Unix却却正是从它的废墟中破壳而出能力。
2.1.1 创世纪:1969-—1971
  Unix于1969年诞生于贝尔实验室的计算机科学家Ken Thompson的头脑中。Thompson曾经是Multics项目的研究人员,饱受当时几乎作为铁律而到处应用的原始批量计算的困扰。但是然而在1960六十年代晚期,分时系统还是个新鲜玩意儿。计算机科学家John McCarthy(Lisp语言的发明者 )几乎是在十年前才首次发表了分时系统的构思,而直到Unix诞生前七年的1962年才第一次真正部署使用,因此当时的分时系统尚处实验性阶段,像喜怒无常的野兽,性能极不稳定。
  那个时代的计算机硬件非常的原始程度,即使当时的亲历者现在恐怕亲历者现在也很难以记清有多么原始。那时最强大的机器所拥有的计算能力和内存还不如现在一个普通的手机。 视频显示终端才还处于起步阶段刚刚起步,直到六年以后才得到广泛应用。最早的分时系统的标准交互设备就是ASR-33电传打字机——一个缓慢、嘈杂又慢又响的设备,只能在大卷的黄色纸张上打印大写字母。于是乎,ASR-33就成了催生Unix命令简洁、应答稀疏少说多作这一的Unix传统的天然母体正是从ASR-33开始的。
  当贝尔实验室(Bell Labs)从Multics研究联盟中退出时,Ken Thompson带着从Multics激发的灵感——如何创建一个文件系统——留了下来。他甚至没能留下一台机器来玩自己编写的“星际旅行”游戏,,这是个科幻游戏,——主要是模拟驾驶一艘火箭在太阳系中遨游。Unix就在一台废弃的PDP-7小型机 上诞生问世了。这台PDP-7成为了“星际旅行”的游戏平台和Thompson关于操作系统设计思路的试验地场。
  Unix的完整起源故事可参见[Ritchie79],这是从Thompson第一个合作者Dennis Ritchie的角度讲述的。Dennis Ritchie后来以Unix的合作发明者和C语言的发明者而闻名于世。Dennis Ritchie、Doug McIlroy和其他一些同事,已经习惯了Multics环境下的交互计算方式,并且也不愿意放弃这一能力。Thompson的PDP-7操作系统给了他们一条救生绳。


  Ritchie评述道:“我们希望保留的不仅仅是一个良好的编程环境,还包括一种能够形成伙伴关系的系统。经验告诉我们,远程访问(remote-access)和分时系统支持的公用计算,的其本质不是用终端机代替打孔机来输入程序,而是鼓励密切的交流。”计算机不光应仅被视为一种逻辑设备而更应视为社群的立足点,这种主旋律四处流传观念深入人心。ARPANET(现今Internet的直系祖先)也发明于1969年。“伙伴关系”这一旋律将一直鸣奏在Unix的后继历史中。
  Thompson 和Ritchie“星际旅行”的实现引起了关注。起先,PDP-7的软件不得不在通用电气公司(GE)的大型机上交叉编译。Thompson和Ritchie为了支持游戏开发而在PDP-7上编制的实用程序成为了Unix的核心——虽然直到1970年才产生Unix这个名字。最初的缩写是“UNICS”(单路信息与计算服务,Uniplexed Information and Computing Service),Ritchie后来称之为“一个有点反叛Multics味道的双关语”,因为Multics是多路信息与计算服务(MULTiplexed Information and Computing Service)的英文缩写。
  即使在最早期的时候,PDP-7 Unix已经拥有现今Unix的诸多共性,提供的编程环境也比当

   时插读卡式批处理大型机的环境要舒服得多。Unix几乎可以称得上第一个能让程序员直接坐在机器旁,飞快捕获稍纵即逝的灵感,并能一边编写一边测试的系统。Unix的整个发展进程中都能吸引那些不堪忍受其它操作系统局限性的程序员自愿为它自愿进行开发,这也一直是Unix不断拓展其能力的模式。这种模式早在贝尔实验室中时就已确立了。
  Unix的轻装开发和方法上不拘一格的传统自和Unix诞生之日起也同时诞生了与生俱来。Multics是项庞大的工程,硬件开发出来前必须编写几千页的技术规格说明书,而第一份跑起来的Unix代码只是由三个人头脑风暴了一下一把,然后由Ken Thompson花了两天时间来实现罢了——还是在一台破烂的机器上完成的,而那个机器本来只是作为一台“真正”计算机的图形终端!
  Unix的第一功,是1971年为贝尔实验室的专利部门进行“文字处理”的支持工作;第一。首个Unix应用程序是nroff(1)文本格式化程序的前身。这个项目也让他们名正言顺地购买了一台功能更强大得多的PDP-11微型机小型机。万幸的是,当时管理层还未意识到Thompson和他的其同事所编写的字处理系统就快孵化出一个操作系统。操作系统并不在贝尔实验室并没有开发操作系统的计划中——AT&T加入Multics联盟正是为了避免自行开发一个操作系统。不管怎样,整个系统还是取得了令人振奋的成功。它使Unix变成在贝尔实验室的计算群落中一个的重要而永久的部分地位由此确立,并且开创了Unix历史的下一个主旋律——与文档格式化、排版和通讯工具的紧密关系结合。1972年版的手册宣称装机量达10台。
  Doug McIlroy[McIlroy91]后来这样描述这个时代:“外界的压力和纯粹出于对技艺的荣誉感,促使人们在有了更好更基本的想法多的初步思路后,去重写或抛开已有的大量代码。从来没听说什么职业竞争和势力范围保护:好东西太多了,没有人需要把这些创新占为己有。”但是直到四分之一世纪后,人们才真正体会到他的话的含义。
  2.1.2 出埃及记:1971-1980
  最初的Unix用汇编语言写成,应用程序用汇编语言和解释性型语言B混和编写。B语言的优点在于小巧,能在PDP-7上运行,但是作为系统编程语言还不够强大,所以Dennis Ritchie给它增加了数据类型和结构。1971年起,C语言从1971年起自B语言进化而来;1973年,Thompson和Ritchie成功地用新语言重写了整个Unix系统。这是一个大胆的举动;——那时,为了最大程度地利用硬件性能,系统编程都通过汇编器来完成,。与此同时,可移植操作系统的概念几乎在任何一个人的眼里都只是一闪而过鲜为人知。1979年,Ritchie终于可以这么写了:“很肯定,Unix的成

  功很大程度上源自其使用以高级语言作为表述方式所带来的可读性、可改性和可移植性”,虽然理想与现实此时尚有一线距离。
  1974年在《美国计算机通信》(Communications of the ACM)上发表的一篇论文中[Ritchie-Thompson]第一次公开展示了Unix。文中作者描述了Unix前所未有的简洁设计,并报告了600多例Unix应用——这些都是安装在即便按照那个年代的标准,性能都算很低的机器上,但是(正如Ritchie和Thompson所写,)“性能的局限不仅鼓励提倡了经济性,而且鼓励了设计的简约”。
  CACM论文发表后,全球各个研究实验室和大学都吵吵嚷着要自己尝试亲身体验Unix。根据1958年为解决反托拉斯案例达成的1958年和解协议,AT&T(贝尔实验室的母公司)被禁止进入计算机相关的商业领域。所以,Unix不能够成为一种商品;。实际上,根据和解协议的规定,贝尔实验室必须将非电话业务的技术许可给任何提出要求的人。Ken Thompson开始默默回应那些请求,将磁带和磁盘一包包的地寄送出去——据传说,每包里都有一张字条,写着“love,ken”(爱你的,ken)。
  这是在离个人机出现的多年前还有些年。那时候,不仅运行Unix所必须的硬件设备价格超出个人的承受范围,而且也没人敢奢望这种情况会在可预见的未来会改变。因此,只有预算充足的大机构才用得起Unix机器:公司、高校、政府机构等。但是,对这些小型机的使用管制要比那些大型机少得多,因此,Unix的发展迅速笼罩了一层反传统文化的气氛氛围。在上世纪70年代早期,最早搞Unix编程的通常都是头发蓬乱的嬉皮和准嬉皮们。摆弄操作系统的乐趣对他们来说不仅意味着可以在计算机科学的前沿上纵情挥洒,而且在于可以去推翻伴随“大计算”的所有技术假定和商业实践:卡式打孔机、COBOL、商务套装、IBM批处理大型机都成了看不上眼的过时事物;Unix黑客们沉浸在同时编织未来和编写系统的狂欢中。
  那些日子的兴奋从Douglas Comer的话语中可见一斑:“许多大学都对Unix作出过贡献。多伦多大学计算机系发明了200dpi的打印机/绘图仪,并且开发了用打印机模拟照相排版机的软件。;耶鲁大学的计算机专家和学生们改进了Unix的Shellshell。;普渡大学的电子工程系对Unix的性能作了重要改进,推出了支持大量用户的Unix版本。;普度大学还开发出了最早的Unix计算机网络之一。;加州大学伯克利分校的学生开发了新shell和许多小型实用工具。1970年代后期贝尔实验室发布Unix V7版本时,很显然,该系统解决了许多部门的运算问题,也综合了许多高校的创意。最终诞生了一个更强大的系统诞生了。思

  想潮流开始了新一轮循环,从学术界流向工业实验室,然后又回到学术界,最后流向了不断增加的商业用户。”[Comer]

  1972年在PDP-11旁的Ken(坐)和Dennis(站)
  现代Unix程序员公认的第一个完全意义上的Unix版本是1979年发布的V7版本。 第一代Unix用户群一年前就已形成。此时,Unix已被终用于支撑贝尔系统(Bell System)的大部分业务所有操作[Hauben],并且传播到高校中,甚至漂到了远至澳大利亚——在那里,John Lions对V6版源码的注释[Lions]成了Unix内核的第一个正式文档。许多资深的Unix黑客仍然珍藏着一份拷贝。
  Lions的书是地下出版界轰动一时的大事。由于侵犯版权或等诸如此类的问题,该书不能在美国出版,所以大家就你拷给我、我拷给你。我也有一份拷贝,至少是第六手了。在那个时代,若没有Lions的书,你就当不成内核黑客。
  - Ken Arnold

  Unix产业也初露端倪。1978年,第一个Unix公司(the Santa Cruz Operation,SCO)成立,同年售出第一个商业商用C编译器(Whitesmiths)。1980年,西雅图一家鲜为人知还不起眼的软件公司(——微软)也加入到Unix游戏中,他们把AT&T版本移植到微机上,以取名为XENIX命名来销售。但是微软把Unix作为一个产品的热情并没有持续多久(尽管直到1990年左右,微软的大部分内部开发工作都一直用的是Unix)。
  2.1.3 TCP/IP 和Unix内战:1980-1990
  在Unix的发展过程中,加州大学伯克利分校很早就成为唯一最重要的学术热点。伯克利分校早在1974年就开始了对Unix的研究,而Ken Thompson利用1975-1976的年休在此教学,更对Unix的研究注入了强劲活力。1977年,当时还默默无闻的伯克利毕业生Bill Joy管理的实验室发布了第一版BSD。到1980年,伯克利分校成了为他们这个Unix变种积极作贡献的高校子网的核心。有关伯克利 Unix(包括vi(1)编辑器)的创意和代码不断从伯克利反馈到贝尔实验室。
  1980年,国防部高级研究计划局(DARPA,Defense Advanced Research Projects Agency)需要一个小组请人在Unix环境下的VAX机上实现全新的TCP/IP协议栈。那时,运行ARPANET的PDP-10已垂垂老矣处耆耆之年,而数据设备公司(DEC)可能被迫放弃PDP-10以支持VAX的种种迹象也空穴来风。DARPA曾考虑和DEC公司签订实现TCP/IP的合同,但是因为担心DEC可能不太同意乐意改动他们的专有VAX/VMS操作系统[Libes-Ressler]而打消了这个念头。最后,DARPA选择了伯克利Unix作为平台——显然因为可以毫无阻碍地拿到它的源码[Leonard]。
  伯克利计算机科学研究组当时拥有天时地利,还有最强大的开发工具;而这毫DARPA的合同无疑问地成为Unix历史上自诞生以来最关键的转折点。
  在1983年TCP/IP实现随Berkeley4.2版发布之前,Unix对网络的支持一直是最薄弱的。早期的以太网实验不尽人意。贝尔实验室开发了一个虽然难看但还能用的工具UUCP(Unix to Unix Copy Program),可在传统普通电话线上通过调制解调器来传送软件。 UUCP可以在分布很广的机器之间转信发邮件,并且(在1981年Usenet发明后)支持Usenet:——一个分布式的电子公告牌系统,允许用户能把文本信息传播到任何拥有电话线和Unix系统的机器上。

  尽管如此,已经意识到ARPANET光明前景的少数Unix用户感觉自己似乎陷在一潭死水中。没有FTP,没有telnet,只有限制重重的远程作业执行和慢得要死的连接。在TCP/IP诞生之前,Unix和互联网Internet文化尚未融合。Dennis Ritchie将计算机视为“鼓励密切交流”的工具这一设想还只是围绕单机分时系统或同一计算中心的学术社群,并没有扩展到自1970年代中期开始ARPA用户群逐渐形成的一个分布全美的“网络国家”。早期ARPANET的用户对着自己蹩脚的硬件时,也只能想:凑合着用Unix吧。
  有了TCP/IP,一切都变了。ARPANET和Unix文化自边缘开始融合,这种发展最终使两者都免遭灭亡。但是不过,首先还得经过炼狱,原因起因是两个毫不相干的灾难:微软的兴起和AT&T的拆分。
  1981年,微软同IBM就新型IBM个人机 PC达成了历史性交易。比尔·盖茨从西雅图计算机产品公司(SCP,Seattle Computer Products)买下了QDOS(Quick and Dirty Operating System)。QDOS是SCP公司的Tim Paterson花六个星期凑出来的CP/M翻版。盖茨对Paterson和SCP公司隐瞒了同IBM的交易,以五万美元的价格买下了所有权利。后来,盖茨又说服了IBM公司允许微软将MS-DOS从硬件中剥离出来单独出售。接下来的十年中,盖茨利用这个非他所写的程序变成了超级亿万富翁,而比首笔交易更加精明的商业策略更是让微软垄断了桌面计算机市场。作为产品的XENIX很快就废弃弃而不用了,最终卖给了SCO公司。
  那时,没什么人能看出微软会多么成功(或有多大破坏性)。因为IBM PC-1硬件条件不足以来运行Unix,所以Unix人群几乎没注意这个产品(尽管,具有讽刺意味的是,DOS 2.0光芒能盖过CP/M,主要因为微软的合创者Paul Allen在DOS 2.0中融入了一些Unix的特征,包括子目录和管道等)。看起来更为还有更有趣的一些事也正在发生呢——比如说1982年SUN微系统公司的诞生出世。
  SUN微系统公司的创立者Bill Joy、Andreas Bechtolsheim和Vinod Khosla打算制造出一种内置网络功能的Unix梦幻机器。他们综合了斯坦福大学设计的硬件和伯克利分校开发的Unix,取得了辉煌的成功,开创了工作站产业。随着Sun公司越来越像一个传统的商家而不再像一个无拘无束的新公司时,Unix大树上一的这根分支的源码来源的树枝正在逐渐干涸枯萎,然而当时并没有人在意这一点。伯克利分校仍然随同源码一起销售BSD。一份System III源码许可证的官方价格为4万美元;贝尔实验室对非法流传贝尔Unix源码磁带的行为还是睁只眼闭只眼,各个高校也依然同贝尔实验室交换代码,看起来Sun公司对Unix的商业化似乎对它再好不过了。
  C语言也在1982年显露出作有望被选为Unix世界外的系统编程语言之选的迹象。仅仅只用了五年左右

   的时间,C语言就几乎让机器码汇编语言完全失去了作用。到了1990九十年代早期,C和C++不仅成为统治了系统编程的主流领域,而且成为应用编程的主流;。到1990九十年代晚期,其他所有传统编译语言实际上都已经被废弃过时了。
  1983年,当在DEC公司取消PDP-10的后继机型的“木星”(Jupiter)的开发计划后,运行Unix的VAX机器开始逐渐代之成为主流的互联网机器,直到被Sun工作站所取代。到1985年,尽管DEC极力抵抗,还是有25%左右的VAX用上了Unix。但是取消Jupiter木星计划的长期效应并不显见;。更主要的是,MIT人工智能实验室以PDP-10为中心的黑客文化的消亡激发了Richard StallMan开始编制GNU,——一个完全自由的Unix克隆版本。
  到1983年,IBM个人机 PC可使用不下六种的Unix通用操作系统:uNETix、Venix、Coherent、QNX、Idris和运行在Sritexk PC子板上的移植版本。但是System V和BSD版本仍然没有Unix移植;——两个群体都悲观地认为8086微处理器不够强大,根本就没打算做这件事这么作。IBM PC上的这些Unix通用操作系统无一取得显著的商业成功,但表明了市场迫切需求运行Unix的低价硬件,而主要厂商并不供应。个人用户谁也买不起,更何况源码许可证上还挂着4万美元的价签呢。
  1983年,当美国司法部对在针对AT&T的第二件起反托拉斯案例诉讼中获胜,并拆分了贝尔系统。这的时候,Sun公司(及其效仿者!)已经取得了成功。这次判决将AT&T从1958年的禁止将Unix产品化的和解协议中解脱了出来。AT&T马上忙不迭地将Unix System V商业化——这一举措差点几乎扼杀了Unix的一步。
  确实如此。但他们的市场营销策略却将Unix推向了全球。
  —Ken Thompson
   大多数Unix支持者都认为AT&T的拆分是个好消息。我们原以为,在拆分后的AT&T、Sun公司及效仿Sun的小型公司中,我们看到了一个健康的Unix产业核心——利用基于低廉的68000芯片组的工作站,——这样一个产业能够挑战并最终打破压迫笼罩在计算机行业上的压迫性垄断者——IBM。
  那时,没有人意识到,Unix的产业化会破坏Unix源码的自由交流,而恰是源码后者的自由交流滋养了Unix系统早期的活力。AT&T只知道用保密从软件中获利,只会用集中控制模式开发商业产品,AT&T对源码散发严加防护。因为唯恐官司上身,非法交易的Unix源码也越来越乏人问津。来自高校的贡献随之开始枯竭。

  雪上加霜更糟的是:刚刚进入Unix市场的几家大公司立马犯下了重大的战略性错误,其中之一就是试图通过产品分化差异化来寻求有利地位——这个策略导致了各种Unix接口的分歧,这样就它抛弃了Unix的跨平台兼容性,造成了Unix市场分分割。
  另一个更隐微微妙的错误就是以为个人计算机和微软与不关Unix前景的前景无关事。Sun微系统公司未能意识到,日用品化的个人机最终会无可避免地动摇其工作站市场的根基。AT&T公司为了成为计算机行业执牛耳者,针对小型机和大型机采取了不同的策略,结果两个摊子都砸了。几间家小公司试图在PC机上支持Unix,但都资金不足,仅专注于将产品出售给开发者和工程师,从未关注商用和家庭——微软所瞄准的商用和家庭两块市场。
  事实上,AT&T拆分后的数年内,Unix社区却在忙着Unix大战的第一阶段——System V Unix和BSD Unix之间的内部争论争吵。争论争吵分成不同的层次层面,有些属于技术方面层面(socket对stream,BSD tty对System V termio),有些则属于文化方面层面。分歧可以大致划分为长发派和短发派。程序员和技术人员往往与伯克利和BSD站在同一战线一边,而以商业为目标的人则倾向AT&T和System V。长发派,重唱着十年前Unix早期的主题,喜欢把自己看作是自我标榜为企业帝国的反抗叛逆者,比如一家小公司贴了张的海报那样,上面画着一个标着“BSD”的X翼星际战机快速飞离巨大的AT&T死星,它后者在熊熊烈火中粉身碎骨。就这样,罗马在燃烧时,而我们还在拉着小提琴消磨时光。
  但是,AT&T拆分那一年当年发生的另一件事对Unix产生了更深远的影响。一位程序员兼语言学家Larry Wall发明了patch(1)实用程序。Patch程序是一个将diff(1)生成的修改记录(changebar)写入基础文件的简单工具,这意味着Unix开发人员之间可通过传送补丁——代码的渐增变化——进行协作,而不是不必传送整个代码文件。这一点非常重要,不仅因为补丁要比整个文件小,更因为即使基础文件和补丁制作者拿到的版本之间变化很大,仍然可以很干净地应用补丁。运用这个工具,基于同一个共有源码库的开发流可以分流分开、并行、最后合流合拢。patch程序比其它任何单一工具都更能促进Internet上的协作开发——这种方式在1990年代年后让Unix获得新生。
  1985年,Intel的第一枚386芯片下线,。它具有用平面地址空间寻址来提供4G内存的寻址能力。笨拙的8086和286的段寻址旋即废弃。这是条大新闻,因为这意味着占据主导地位的Intel家族终于有了一款无需作出痛苦妥协就能运行Unix的微处理器。对Sun公司和其它工作站厂商来说,这真是不祥之兆,可惜它们并未觉察到。

  同样在1985年,Richard Stallman发表了GNU宣言(the GNU manifesto) [Stallman],并发起了自由软件基金会(Free Software Foundation)。没有谁把他和他的GNU当回事,结果证明这是个大错误。同年,另一个与之无关在一项与此不相干的开发行动中,X window系统的创始人发布了X window的源码,而无需版税、约束和授权。这项决策的直接结果就是X window成为不同的不同Unix厂商之间合作的安全中立区,并挫败了专属的竞争对手,成为了Unix的图形引擎。
  以调解System V和Berkeley API为目标的严肃的标准化工作始于1983年,产生了/usr/group标准。这随后成之为1985年IEEE支援支持的POSIX标准。这些标准描述了BSD和SVR3(System V Release 3)调用的交集,以综合了伯克利出色的伯克利信号处理和作业控制搭配,以及SVR3的终端控制。所有后续的Unix标准其核心都以加入了POSIX为核心,后续开发的各种Unix版本也紧密严格遵循这个标准。后来的现代Unix核心API唯一增加主要的补充就是BSD套接字。
  1986年,前面提到的发明patch(1)的Larry Wall开始开发Perl语言,这后者是最先、也是最广泛使用的开源脚本语言。1987年年初,GNU C编译器的第一版问世,到1987年年底,GNU工具包的核心部分——编辑器、编译器、调试器以及其它基本的开发工具——都已就位。同时,X window系统也开始在相对低廉的工作站上露面了。这些因素都为20世纪90年代的Unix开源发展提供了利器。
  同样是在1986年,PC技术挣脱了IBM的掌控。IBM,因为仍然试图在产品系列上维持高价格性能比,更青睐高利润的大型机市场,所以在新的PS/2系列产品上拒用386而选择了更较弱的286。PS/2系列,为了杜绝仿冒而围绕一个专有总线结构进行设计,变成结果成了代价一个高昂代价的大败笔。 康柏(Compaq),最积极进取的效仿者康柏(Compaq),发布了第一款386机器,靠这张牌打败了IBM。虽然主频只有16MHz,但是386也算能跑起来Unix了。这是第一款可以叫Unix机器的PC。
  这会儿已经能够想象Stallman的GNU项目可以和386机器配合而制造出Unix工作站,这将它比当时任何方案都要便宜一个数量级。奇怪的是,没人想到这步棋。来自小型机和工作站世界的大多数Unix程序员,依然鄙视廉价的80x86芯片,而青睐钟情基于68000的高雅设计。尽管许多程序员都为GNU工程做出了贡献,但在Unix人群中,这个GNU

  项目仍然被视为一个唐吉诃德式的狂想,短期内还无法实用。
  Unix社区从未丢掉丢弃叛逆气质。但是回头看来,我们几乎和IBM或者AT&T一样,对迫近我们的未来毫无所知。即使是数年前就开始对专有软件开展精神讨伐的Richard Stallman也未能真正理解Unix的产品化会对其周围所在社区有多大的破坏力;他关心的是更抽象的长期论题。其余的人还一直企盼企业规则能有些精明的变化,从此市场分割、营销不利和战略漂移漂忽不定等问题不复存在,救赎回Unix拆分之前的世界。但是祸不单行。
  很多人都知道Ken Olsen(DEC的CEO)在1988年将Unix描绘成“蛇油”(骗人的万灵油)。从1982年起,DEC就一直在销售自己其开发的用于PDP-11的Unix变种,但真正希望的却是将业务回到自己专有的VMS操作系统上来。DEC和其它小型机厂商碰到了大麻烦,陷入Sun微系统公司和其它工作站厂商功能强劲、价格低廉的机器重重包围中。这些工作站大多运行的是Unix。
  但是Unix产业自身的问题却更为严峻。1988年,AT&T持有了Sun公司20%的股份。作为Unix市场领军的这两家公司,终于开始清醒地认识到PC、IBM和微软构成的威胁,也终于认识到过去五年的争斗令他们几无所获。AT&T和Sun的联盟以及以POSIX为核心的技术标准的发展,最终抹去弥合了System V和BSD Unix之间的杯葛裂痕。但是,当二线商家(IBM、DEC、HP等)创建开放软件基金会(Open Software Foundation)并结成盟友和以“Unix 国际”为代表的“AT&T/Sun轴心”(以Unix International为代表)对抗时,Unix内战的第二阶段开始了。更多回合的Unix与Unix三家的内战战斗随而展开爆发。
  这段时间中,微软从家庭和小型商用市场创造赚了数十亿美元的财富钱,而内战争战不休的Unix各方却从未决意涉足这些市场。1990年,Windows 3.0的发布——来自来自微软总部Redmond发布了第一个成功的图形操作系统——巩固了微软的统治地位,为微软在1990九十年代扫平荡平并最终垄断桌面应用领域并最终垄断其市场创造了条件。
  1989年到1993年是Unix的中世纪。当时,似乎Unix社群所有的梦想都破灭了。两败俱伤相互争斗的战事已使专有Unix产业衰落得像个吵闹的肉店,无力振起挑战微软的雄心。大多数Unix编程者青睐的优雅的Motorola芯片也已经输给了Intel丑陋但廉价的处理器。GNU项目没能开发出自由的Unix内核,尽管从1985年GNU就不断就此作此承诺,狼过了几年还没来其信用令人质疑。PC技术被无情地商业化了。1970年代的Unix hacker黑客先锋们人近中年,步履开始蹒跚。硬件便宜了,但Unix还是太贵。我们幡然醒悟地太晚了:过去的IBM垄断换成了让位于现在

  的微软垄断,而微软设计糟糕的软件像浊流一样,绕围着我们越涨越高。
2.1.4 反击帝国反击:1991-1995
  黑暗中第一缕曙光是1990年,William Jolitz把BSD移植到了386机器上,这是黑暗中的第一缕曙光。1991年起一系列杂志文章对此进行了报道。向386移植BSD的移植之所以可能,是由于伯克利黑客Keith Bostic功不可没,他一定程度上受Stallman影响,早在1988年他就开始努力从BSD码中清除AT&T专有代码。但是,Jolitz在1991年年底退出此386-BSD项目,并毁掉了自己的成果,386BSD使该项目遭到受到了严重打击。对于此事原因说法不一的起因众说纷纭,不过普遍认同公认的一点是Jolitz希望将其代码以源码形式无限制地源码形式发布,因此当项目的企业赞助商选择了更专有的授权模式时,他火了。
  1991年8月,当时默默无闻的芬兰大学生Linus Torvalds宣布了Linux项目。据称Torvalds最主要的动机激励是学校里用的Sun Unix太贵了。Torvalds还说,要是早知道有BSD项目,他就会加入BSD组而不是自己做一个。但是386BSD直到1992年年初早些时候才下线,而此时Linux第一版已经发布好几个月了。
  不回头看,人们无法发现这两个项目的重要性。那时,即使在Internet hacker黑客文化内部也没有多少人关注它们,遑论更广大的Unix社区,。当时Unix社区还在盯着比PC机性能更强大的机器,仍试图把Unix的特有品质与软件业的常规专有模式扯到一起。
  又过了两年,经过经历了1993-1994年的互联网大爆炸,Linux和开源BSD的真正重要性才为整个Unix世界所了解。但不幸的是对BSD人支持者来说,AT&T对BSDI(赞助Jolitz移植的创业公司)的诉讼消耗了大量的时间,使一些关键的Berkeley开发者转向了Linux。
  代码抄袭和窃取商业秘密的行为从未被证实。他们花了两年的时间也没找到确凿的侵权代码。要不是Novell从AT&T买下了USL、并达成协议,这个这场官司还会拖得更久。结果是从发布包中18000个组成文件中删掉了三个,对其它文件作了一些小修改。另外,伯克利大学也同意为约70个文件增加USL版权,但同时约定这些文件仍然可以自由重新分发。
—Marshall Kirk McKusick

  这项和解为开创了从专有控制下解放获取一个自由而完整可用的Unix的开创了先河,但对BSD本身自身的影响却是灾难性的。当伯克利的计算机科学研究组于1992-1994年间被关闭时,情况更糟了;随后,BSD社区内的派系斗争又将BSD开发分割成三个方向间的竞争。结果,BSD这一脉在关键时刻落后了Linux,Unix社区的领先地位失给了Linux拱手让人。
  与此前各种版本的Unix开发相比,Linux和BSD的开发相当不同。它们植根于互联网的方式和此前各种版本的Unix开发均不同。他们,依赖分布式开发和Larry Wall的patch(1)工具,通过email和Usenet新闻组招募开发者。因此,当互联网服务提供商(ISP)的业务于1993年因通信技术的变革和Internet主干骨干网的私有化(超出Unix历史部分范围,不详述)而扩展时,Linux和BSD的发展也得到了巨大的推进推动力。但对廉价互联网的需求却是由另一件事创造的:1991年万维网(WWW)的发明。万维网是互联网中最讨人喜欢的“杀手级应用”,图形用户界面技术对大量的非技术型最终用户产生了有着不可抗拒的魅力。
互联网的大规模市场推广,既增加了潜在开发者的数量,又降低了分布式开发的处理代价成本,这些影响可从XFree86之类的项目上看出。XFree86利用Internet为中心的模式建立了一个比官方X联盟更有效的开发组织。1992年诞生的第一版XFree86赋予了Linux和BSD一直缺乏的图形用户界面引擎。下个十年里,XFree86将领导X的开发,X联盟越来越多的X联盟行为都是把源自XFree86社区的创新汇聚回X联盟产业赞助者中。
  到1993年年末,Linux已经具备了Internet能力和X系统。整套GNU工具包从一开始就内置其中,以提供高质量的开发工具。除了GNU工具,Linux好像一个魅力聚宝盆,聚囊括了二十年来分散在十几种专有Unix平台上的开源软件之精华。尽管正式说来Linux内核还是测试版(0.99的水平),但稳定性已经让人刮目相看。Linux上软件之多、质量之高,已经达到一个产品级操作系统的水准。
  在旧学派的Unix开发者中,一部分脑筋活络的人开始注意到,做了多年的平价Unix之梦从一个意想不到的方向悄然成真。它既不是来自AT&T,也不是来自Sun,或者任何一个传统厂商,也不是出于学术界有组织的工作成果。它就这样从Internet的石头缝中跳了出来,浑然天成,以令人惊奇的方式重新规划组合拼装了Unix的传统元素。

  另一方面,商业运作继续进行。1992年AT&T1992年抛出售了其手中在Sun公司的股份,然后在1993年把Unix系统实验室(Unix Systems Laboratories)卖给了Novell;Novell又于1994年将Unix商标转手给X/Open标准组(X/open standards group);同年AT&T和Novell加入了OSF(开放软件基金会),Unix之战尘埃落定。1995年,SCO从Novell手中买下了UnixWare(以及最初Unix源码的权利)。1996年,X/Open和OSF合并,创立了一个大型Unix标准组。
  但是,传统Unix厂商和他们战后的烂摊子看来确是越来越无关紧要了。Unix社区的动作和精力都在转向Linux、BSD及开源开发者。1998年,IBM、Intel和SCO宣布启动蒙特里项目(the Moterey project),最后一次努力试图将所有现存的专有Unix整合成一个大系统,开发者和业内媒体坐看笑话。原地兜了三年的圈之后,此项目在2001年嘎然而止。
  2000年SCO把UnixWare和原始原创的Unix源码包出售给了Caldera——一家Linux发布发行商,整个产业变迁终告结束。但1995年后,Unix的故事就成了开源运动的故事。故事还有一半没讲呢,要想知道这另一半,我们要回到1961年,从互联网黑客文化的起源开始讲起。
  2.2 黑客的起源和历史:1961-1995
  Unix的传统是一种隐性的文化,不只是一书袋的技术窍门。这种传统传达着一个有关美和优秀设计的价值体系;里面有它的江湖和侠客。与Unix传统的历史交织在一起的则是另一种隐性文化,一种很更难归别的文化。这另一种文化。它也有自己的价值体系、江湖和侠客,部分与Unix文化交迭,部分源于它处。更多人人们老是把这种文化称为“黑客文化”,从1998年起,这种文化已经很大程度上和计算机行业出版界所称的“开源运动”重合了。
  Unix传统、黑客文化以及开源运动间的关系微妙而复杂。三种隐性文化背后固然往往是同一群人,然而其间的关系并无法未因此而简化。但是,从1990年以来,Unix的故事很大程度上已经是成了开源世界的黑客们改变规则、从保守的专有Unix厂商手中夺过取主动权的故事。因此,今天Unix身后的另外一半历史,有一半就是黑客的历史。

  2.2.1 游戏在校园的林间:1961-1980
  黑客文化的根源可以追溯到1961年,这一年MIT购买了第一台PDP-1小型机。PDP-1是最早的一种交互式计算机,并且(与不象其它机器不同的是)在那时并非天价,所以没有对它的使用做太多限时规定。因此PDP-1吸引了一帮好奇的学生。他们来自技术模型铁路俱乐部(TMRC,Tech Model Railroad Club)的好奇的学生,他们,带着一种好玩的心态摆弄这台设备。《黑客:计算机革命中的英雄》(Hackers: Heroes of the Computer Revolution )[Levy]一书对这个俱乐部的早期情况作了有趣的描写。他们最著名的成就是“太空大战(SPACEWAR)”,——一款宇宙飞船决斗游戏,灵感大概来自Lensman的星际故事《E.E.‘Doc’Smith》。
  TMRC来实验的几个实验者人后来是成为了MIT人工智能实验室的核心成员,而这个实验室在1960和1970六七十年代成为前沿计算机科学的世界级中心之一。这些人也把TMRC的行话和内部笑话带了进来,包括一种精巧(但无害)的传统恶作剧“hacks”。人工智能实验室的程序员应该是第一群自称“hacker”的人。
  1969年后,MIT AI 实验室和斯坦福、Bolt Beranek & Newman公司(BBN)、卡内基-梅隆大学(CMU:Carnegie-Mellon University)以及其它顶级计算机科学研究实验室通过早期的ARPANET联上了网。研究人员和学生第一次尝到了快速的网络联接消除了地域限制的甜头,通过网络,远方的人通常比与身边少有来往的同事更容易打交道合作和建立友谊。
  实验性的ARPANET网上到处都是软件、点子、行话和大量幽默。一种类似共享文化的东西开始成形,其中最早、最持久的典型产物之一就是“术语文件(Jargon File)”,列举了1973年发源于斯坦福、1976年后在MIT经过多次修订的共享行内名词,并一路收集了CMU(卡内基-梅隆大学)、耶鲁和其它ARPANET站点的行话。
  从技术性而言,早期的黑客文化大都寄宿在基于PDP-10小型机上。这些下列已经成为历史的操作系统他们都用过:TOPS-10、TOPS-20、Multics、ITS和SAIL。他们利用汇编器和各种Lisp方言编程。PDP-10的黑客们后来接手运行ARPANET,因为没别人不愿意干这件事。后来,他们成为了互联网工程工作组(IETF,Internet Engineering Task Force)的创建骨干,并成作为始作俑者,开创了通过RFC(Requests For Comment)进行标准化这一的传统的始作俑者。
  从社会性而言,他们年轻,天资过人,几乎全是男性,献身编程达到痴迷的地步,决不墨守成规——后来被人们唤做“极客(geek)”。他们往往也是头发蓬松的嬉皮士和准嬉皮士。他们有远见,把计算机看作构建社区的工具。他们读Robert Heinlein和J.R.R. Tolkien的书,参加复古协会(Society for Creative Anachronism),双关语说起来没完。抛开这些怪癖(也许正是因为这一点由于这些原因),他们中的许多人都跻身世界上最聪明的程序员之列。
  他们并不是Unix程序员。早期的Unix社群成员大部分来自院校、政府和商业研究实验室的同一帮“极客”,但是两种文化有明显的分野。其中之一就是我们前面已经谈到的早期Unix羸弱孱弱的网络能力。直到1980年后,才真正出现了基于Unix的ARPANET网络连接,而当时之前一个人同时涉足两个阵营的情况并不多见。
  协作式开发和源码共享是Unix程序员的法宝贵策略。另一方面然而,对于早期的ARRPNET黑客,这还不仅仅只是一种策略:,这它更像一种公众信仰,部分起源于“要么发表要么烂掉”的学术本能规则,并且(更极端的地)几乎发展成为关于精神网络思想社区的夏尔丹式理想主义(Chardinist idealism)。这些黑客中最著名的Richard M. Stallman后来成了严守教义的苦行僧。
2.2.2 互联网大融合与自由软件运动:1981-1991
  1983年后,随着BSD植入了TCP/IP,Unix文化和ARPANET文化开始融合。既然两种文化都由同一类人(实际上,就有少数几位很有影响的人同属两种文化阵营)构成,一旦沟通环节到位,两种文化的融合就水到渠成。ARPANET黑客学到了C语言,用起了管道、过滤器和shell之类的行话。Unix程序员学到了TCP/IP,也开始互称“黑客”。1983年,木星(Jupiter)项目的取消虽然葬送了PDP-10的前途,却加速了两种文化融合的进程。到1987年,这两种文化已经完全融合在一起,绝大多数黑客都用C进行编程,自如地使用来源于25年前技术模型铁路俱乐部(TMRC)创造的行话。
  (在1979年,我和Unix文化、ARPANET文化都有密切联系,当时这种情况还很少见。到1985年,这就已经不稀奇了。1991年我将以前的ARPANET“术语文件”(Jargon File)扩展成“新黑客词典”(New Hacker’s Dictionary)[Raymond96],此时两种文化实际上已经融为一体。把生于ARPANET、长于Usenet的“术语文件”作为这种这次融合的标志真是再恰当不过了。)
  但是TCP/IP联网和行话并不是后1980黑客文化从其ARPANET根源继承的唯一全部东西。他们,还得到了有Richard M. StallMan和他的精神革命圣战。

  Richard M. Stallman(他的登陆名RMS更为人熟知的是他的登陆名RMS)早在1970年代晚期就已经证明他是当时最有能力的程序员之一。Emacs编辑器只是就是他众多发明中的之一项。对RMS来说,1983年木星(Jupiter)项目的取消仅仅只是宣告了麻省理工学院人工智能实验室(MIT AI Lab)文化的最终解体的终结,其实早在几年前随着实验室众多最优秀的成员纷纷离去,帮忙管理与之竞争的Lisp机器时,这种解体就已经开始了。RMS觉得自己被逐出了一个黑客的伊甸园,他把这一切都归咎于专有软件。
  1983年,Stallman创建了GNU项目,目标是致力于编一个完全自由的操作系统。尽管Stallman既不是、也从来没有成为一个Unix程序员,但在后1980的大环境下,实现一个类仿Unix操作系统成了他追求的一个明确战略目标。RMS项目早期的贡献捐助者大都是新踏入Unix土地的老牌ARPANET黑客,他们对代码共享的使命感甚至要比那些有更多Unix背景为主的人更强烈。
  1985年,RMS发表了GNU宣言(the GNU Manifesto)。在宣言中,他有意从1980年之前的ARPANET黑客文化价值中创造出一种意识形态——包括前所未见的政治伦理主张、自成体系而极具特色的论述以及激进的改革计划。RMS的目标是将后1980的松散黑客社群变成一台有序有组织的社会化机器以达到一个单纯的革命目标。也许他未意识到,他的言行动和文辞成了与当年卡尔·马克思动员号召产业底层无产阶级反对反抗工作异化的回应努力如出一辙。
  RMS宣言引发的争论至今仍存于黑客文化中。他的编排纲要远不止于维护一个代码库,已经暗含了废除软件知识产权主张的精髓。为了追求这个目标,RMS将“自由软件(free software)”这一术语大众化,这是将整个黑客文化的产品进行标识的首次尝试。他撰写了“通用公共许可证(General Public License , GPL)”,这后者成了一个既充满号召力又颇具争议的焦点,具体原因我们将在16章检视研讨。读者可以去GNU站点<http://www.gnu.org>了解RMS立场更多的RMS立场及自由软件基金会(Free Software Foundation)的更多情况:<http://www.gnu.org>。
  “自由软件(free software)”这个术语既是一种描述,也是为黑客进行文化标识的一个尝试。从某个层次上说,这还是相当成功的。在RMS之前,黑客文化中的人们彼此当作“同路人”,说着同样的行话,但没人费神去争辩 “黑客”是什么或者应该是什么。在他之后,黑客文化更加自醒有自我意识。价值冲突(即使反对RMS的人也经常以他的方式说话)成为辩论中的常见话题特点。RMS,这个魅力超凡又颇具争议的人物本身已经成为了一个文化英雄,因此到2000年时,人们已经很难将他本人和他的传奇区分开来。《自由中的自由Free as in Freedom》(Free as in Freedom )[Williams]对他的刻画非常精彩。
  RMS的论点甚至影响了那些对其理论持怀疑态度的黑客的行为。1987年,他说服了BSD Unix的看管方,让他们相信,将AT&T的专有代码清除出去、发布一个无限制的版本是个很好的主意。然而,尽管他花了不下十五年的不懈努力苦功夫,后1980黑客文化却从未统一在他的理想之下。
  其他黑客,更多出于实用角度而非思想观念的原因,重新认识到了不留私密的开放式协作开发的价值。在八十年代后期离Richard Stallman位于MIT九楼办公室不远的几座楼里,X开发组在1980年代后期搞得红红火火。这个项目由一些Unix厂商资助,这些厂商此前一直为X window系统的控制权和知识产权争论不休,结果发现还不如向所有人自由开放。1987至1988年间,X的开发预示了一个极为庞大的分布式社群,它后者将在五年后重新定义Unix的前沿方向。
  X是首批由服务于全球各地不同组织的许多个人以团队形式开发的大规模开源项目之一。电子邮件使创意得以在这个群体中快速传播,问题由此得以快速解决,而开发者可以人尽其才。软件更新可以在数小时之内发送到位,使得每个节点在整个开发过程中步调一致。网络拓展改变了软件的开发模式。
—Keith Packard
  X开发者们不替GNU总计划帮腔,但也不唱反调。1995年以前,GNU计划最强烈的反对者是BSD开发者。BSD开发者觉得自己编写自由发布和修改软件的年头比RMS宣言长得多,坚决抵制GNU自称的在历史性和思想性上的首创。他们尤其反对GPL的传染性或“病毒般”的特性,坚持BSD许可证比GPL“更自由”,因为BSD对代码重用的限制要比GPL少。
  尽管RMS的自由软件基金会已开发了整套软件工具包的绝大部分,但是未能开发出核心部件,因此形势对RMS仍然不利。GNU项目创立十年了,GNU内核仍付阙如是空中楼阁。尽管Emacs和GCC之类的单个工具被证明非常有用,但是没有内核的GNU既不能对专有Unix的霸权构成威胁,又不能有效抵抗日渐严重的微软垄断。
  1995年后,关于RMS思想体系的争论稍稍发生了变化。反对者的观点跟Linus Torvalds和本书作者越来越近。

  2.2.3 Linux 和实用主义者的应对:1991-1998
  即使在HURD(GNU内核)计划停转之时,新的希望还是出现了。1990年代早期,价廉性优的PC机加上方便快捷的互联网,对寻找机会挑战自我的新生代年轻程序员是一个极大的诱惑。自由软件基金会编写的用户软件工具包铺平了一条摆脱高成本专有软件开发工具的前进道路。上层思想跟随下层意识服从经济,不再占据首位而不是领导:一些新手加入了RMS的圣战革命运动,高举GPL大旗,另一些人则更认同整体意义上的Unix传统,加入了反对GPL的阵营,但大部分其他大部分人置身事外,一心编码。
  Linus Torvalds巧妙地跨越了GPL和反GPL的派别之争。他利用GNU工具包搭起了自创的Linux内核,用GPL的传染性质保护它,但拒绝认同RMS许可协议反映的思想体系计划。Torvalds明确表示,一般情况下,他认为自由软件通常更好,但他偶尔也用专有软件。即使在他自己的事业中,他也拒绝成为一个狂热分子,。这一点极大地吸引了大多数黑客,他们虽然早就反感RMS的言辞,但他们的怀疑论一直缺个有影响力或者令人信服的代言人。
  Torvalds令人愉快的实用主义及灵活而低调的行事风格,促成了使黑客文化在1993至1997年间取得了一连串令人惊奇的胜利,不仅仅在技术上的成功,还让围绕Linux操作系统周边的发行、服务和支持产业有了坚实的开端。结果,他的名望和影响也一飞冲天。Torvalds成为了互联网时代的英雄;到1995年为止,他只用了四年时间就在整个黑客文化界声名显赫,而RMS为此花了十五年,赢得了RMS花了十五年时间才取得的声名——而且他还远远超过了Stallman向外界贩卖“自由软件”的记录。与Torvalds相比,RMS的言辞渐渐显得既刺耳又无力。
  1991至1995年间,Linux从一个概念型的0.1版本的内核原型,试验品发展成为一个能够在性能和特性上均堪媲美专有Unix的操作系统,并且在连续正常工作时间等重要统计数据上打败了这些Unix中的绝大部分。1995年,Linux找到了自己的杀手级应用:开源的web服务器Apache,开源的webserver。就像Linux,Apache的出众地稳定和高效同样引人注目。很快,运行Apache的Linux机器成了全球ISP平台的首选;。约60%的网站选用Apache, 轻松击败了另另外两家个主要的专有型竞争对手。

  Torvalds唯一没有给出的是未作的一件事就是提供一个新的思想体系——一套关于黑客行为的新原理理论基础或繁衍神话,以及一套吸引黑客文化圈内圈外人士的正面论述,以消弭RMS对知识产权的不友善。1997年,当我试图探寻为什么Linux开发没有在几年前崩溃时,我偶然地填补了这个空白。我所发表论文[Raymond01]的技术结论归纳在本书第19章。对于这段历史梗概,只要看看第一条结论核心规则的影响冲击就够了:“如果有足够多眼睛的关注,所有的bug都无处藏身”。
  这段观察暗含了过去四分之一世纪来在黑客文化中从未有人敢相信的东西:用这种方法做出的软件,永远不仅比我们专有竞争者的东西更优雅、,而且更可靠、更好用。这个结果出乎意料地向“自由软件”的论述发起了直接挑战,而Torvalds本人从未有意于此。对于大多数黑客和几乎所有的非黑客而言,“用自由软件是因为它运行得更好”轻而易举地盖过了“用自由软件是因为所有软件都该是自由的”。
  在我的论文中关于“大教堂”(集权、封闭、受控、隐秘保密)和“集市”(下放分权、公开、精细的同僚复审)两种开发模式的对比成为了新思潮的核心隐喻中心思想。从某种重要意义上来说,这仅仅是对Unix在拆分前根源的回归——McIlroy在1991年阐述了同侪压力如何对1970年代早期Unix开的发展产生了积极影响、Dennis Rithchie在1979年对伙伴关系的反思了伙伴关系,这是此两者的延续,并受益于与早期ARPANET同侪评审这一的学术传统及其分布式精神社区的理想主义相得益彰精神。
  1998年初,这种新思潮促使网景公司(Netscape Communications)公布了其Mozilla浏览器的源码。媒体对此事件的关注促成了Linux在华尔街的上市,推动了1999-2001年间科技股的繁荣。事实证明,此事无论在对黑客文化的历史上还是在对Unix的历史上都是一个重要转折点。
2.3 开源运动:1998年及之后
  到1998年Mozilla源码公布的时候,黑客社区其实算是一个众多派系或部落的松散集合,包括了Richard Stallman的自由软件运动(Free Software Movement)、Linux社区、Perl社区、Apache社区、BSD社区、X开发者、互联网工程工作组(IETF),还有至少一打别的以上的其它组织。这些派系相互交叠,一个开发者很可能同时隶属两个或更多组织。
  一个部落的核心凝聚力可能是来自他们维护的代码库,或是一个或多个有着超凡影响力的领导者,或是一门语言、一个开发工具,或是一个特定的软件许可,或是一种技术标准,

  或是基础结构某个部分的管理组织。各派系既论资排辈,也追逐当前的市场份额及认知度。因此,资格最老的大概要算IETF,其历史可以连续追根溯源到1969年ARPANET的发源期。;BSD社区尽管市场安装数量要比Linux少得多,但是因为其传统可连续追溯到1970年代末,所以还是拥有相当高的声望。;可追溯到1980年代初的Stallman的自由软件运动,无论从历史贡献,还是从作为几个使用最频繁最常用的软件工具维护者的角度,都足以令其跻身高级部落行列。
  1995年后,Linux扮演了一个特殊的角色:既是社区内多数软件的统一平台,又是黑客中最被认可的品牌。Linux社区随之显现了兼并其它亚部落的倾向——甚至包括争取并吸纳一些专有Unix相关的黑客小派系。整个黑客文化开始凝聚在一个共同目标周围:尽力推动Linux和集市开发模式向前发展。
  因为后1980黑客文化已经深深植根于Unix,新目标成了Unix传统争取胜利这一的不成文纲要也就不言而喻地成为新的使命。。黑客社区的许多高级领导人,曾经也都是Unix的老前辈,仍然带着1980八十年代分拆后内战的伤痕犹在,他们将Linux作为实现Unix早期叛逆梦想的最后和最大的希望,而汇聚在Linux旗下。
  Mozilla源码的公布使各方意见更为集中。1998年3月,为了深入研究共同目标和策略,召开了一次空前的社团重要领导人峰会,与会者几乎代表了所有的主要部落。这次会议为所有派系的共同开发方式吸纳了一个新标记:开源。
  六个月之内,黑客社区中几乎所有部落都接受了用“开源”的新旗帜。IETF和BSD开发组这种老团体更是把他们从过去到现在一直以来的做法所作的东西都追加上了这一标记。实际上,到2000年,黑客文化不仅让“开源”这一个辞令不仅统一了黑客文化当前实践和未来计划,而且也让黑客文化对自己的历史重新有了鲜活的认识。
  Netscape开放源码的宣告和Linux的新近崛起产生的激励效应远远超越了Unix社区和黑客文化。从1995年开始,所有阻拦在微软视窗Windows滚滚巨轮前的各种平台(MacOS; Amiga; OS/2; DOS; CP/M;较弱小的专有Unix;各类大型机,小型机和过时的小型机微型机操作系统)的开发者团结到了Sun微系统公司的Java语言周围。许多不满微软的Windows开发者也加入了Java阵营,希望至少能够和微软保持名义上的独立。但是Sun公司运作Java在数的几个层面上对Java的都运作(我们将在第14章予以讨论)既拙劣又令人敬而远之排斥他人。许多Java开发者喜欢

  上了开源运动中的新生事物,于是就像此前跟随Netscape加入Java一样,又跟随它加入了Linux和开源运动。
  开源行动的积极分子热烈欢迎来自各地各个领域的移民潮。老一辈Unix人也开始认同新移民的梦想:不能只是被动忍受微软的垄断,而是要从微软手中夺回关键市场。开源社区成员们合力争取主流世界的认同,开始乐于同大公司结盟——这些公司,随着微软的锁定策略越来越大胆绳索勒得越来越紧,也越来越害怕对自己的业务失去控制。
  唯一的例外是Richard Stallman和自由软件运动。很明显,“开源”要用一个意识形态中立中性的公众标签来取代Stallman钟爱的“自由软件”,。新标签无论对于历史上一贯反对“自由软件”的BSD黑客之类的团体,还是对于不希望在赞成或反对愿在GPL是非之争中表态的人均能接受。Stallman尝试着接受这个术语,但随后又以其未能代表其思想的核心为由而排斥它。从此,自由软件运动坚持同“开源”划清界限,这也许成了2003年黑客文化中最重大的政治分歧。
  “开源”背后另一个(也是更重要的)意图是希望将黑客社区的方法以一种在更亲和`市场上更行得通、更少对抗性的方式介绍给外部世界(尤其是主流商用市场)。幸运的是,在这方面,它取得了绝对成功——这也重新激起了人们对其根源——Unix传统——的兴趣。
2.4 Unix的历史教训
  在Unix历史中,最大的规律就是:离开距开源越近就越繁荣。任何将Unix专有化的企图,只能导致陷入停滞和衰败。
  回顾过去,我们早该认识到这一点。1984年至今,我们浪费了十年时间才学到这个教训。如果我们日后忘记这个教训不思悔改,可能还得大吃苦头。
  虽然我们在软件设计这个重要但狭窄的领域比其他人聪明,但这不能使我们摆脱对技术与经济相互作用影响的茫然,而这些就发生在我们的眼皮底下。即使Unix社区中最具洞察力、最具远见卓识的思想家,他们的眼光终究有限最多也不过是只长了一只眼。对今后的教训就是:过度依赖任何一种技术或者商业模式都是错误的——相反,保持软件及其设计传统的的灵活性才是长存之道。

  另一个教训是:别和低价而灵活的方案较劲。或者,换句话说,低档的硬件只要数量足够,就能爬上性能曲线而最终获胜。经济学家Clayton Christensen称之为“破坏性技术”,他在《创新者窘境》(The Innovator's Dilemma)[Christensen]一书中以磁盘驱动器、蒸汽挖土机和摩托车为例阐明了这种现象的发生。当小型机取代大型机、工作站和服务器取代小型机以及民用日用Intel机器又取代工作站和服务器时,我们也看到了这种现象。开源运动获得成功正是由于软件的民用大众化。Unix要繁荣,就必须继续采用吸纳低价而灵活的方案的诀窍,而不是去反对它们。
  最后,旧学派的Unix社区因采用了常规传统的公司机构组织、财务和市场等指挥命令机制而最终未能实现“职业化”。只有痴迷的“极客”和具有创造力的怪人结成的反叛联盟才能把我们从愚蠢中拯救出来——他们会给接着教导我们展示,真正的专业和奉献精神,正是我们在屈服于世俗观念的“合理商业做法”之前的所行为作所为实际上就是真正的专业和奉献精神。
  如何在Unix之外的软件技术领域应用借鉴这些经验教训,这就作为一个简单的练习留给读者吧。

 
Copyright ©1998~2004 华储网. All rights reserved。
To comment on this site,E-mail :
webmaster@huachu.com.cn