← 所有文章

工程哲学:Linus Torvalds,消失的特殊情况

Linus Torvalds,Linux 与 git 的创造者

核心要点

  • 优秀的品味,就是让特殊情况消失。 重塑数据结构——用指向指针的指针替代普通指针——那个处理边界情况的 if 便再无容身之处。
  • “把代码拿给我看”是一种认识论,而非一句口号。 设计只是假设;唯有能运行的代码才能为争论画上句号。
  • git 让分布式成为其数据结构的必然结果。 内容寻址的对象意味着每个仓库地位平等,于是”唯一真本”这种需要捍卫的东西从一开始就不存在。
  • 规模化的信任必须有结构,而不能靠假定。 Torvalds 把这个问题解决了两次——用维护者树来界定该负责,用防篡改的历史来记录发生了什么

原则

“我希望你明白,有时候你可以换一个角度看待问题,把它重写一遍,让一个特殊情况消失、变成普通情况——这就是好代码。” —— Linus Torvalds,TED,20161

Torvalds 站在 TED 的舞台上,并排举着两个 C 函数。两者都是从单向链表中删除一个节点。第一个函数用一个 prev 指针遍历链表,检测要删除的节点是否为头节点,然后分支:头节点走特殊情况,其余一切走普通情况。十行代码,一个 if。第二个函数用一个指向指针的指针——**indirect——来遍历链表,这样头节点根本就不是一个特殊位置。它只不过是那个指向指针的指针恰好指到的第一个东西而已。四行代码,没有 if1

行数更少从来不是重点。第一个版本里的那个条件判断之所以存在,只是因为程序员把链表的头节点建模成了与链表其余部分不同的东西。换一个更好的数据结构——用指向指针的指针替代普通指针——这种差异便烟消云散。边界情况从来不是问题本身固有的;它只是问题被表示方式留下的产物。在 Torvalds 的意义上,品味恰恰就是这一步动作,也正是这种信念让品味成为一套技术系统,而非一种审美偏好:优雅的版本之所以胜出,不是因为它更好看,而是因为它更正确——可能出错的地方更少了。

那种本能——消除特殊情况,让边界情况无处藏身——贯穿了 Torvalds 所构建的一切。它也解释了为什么他另一句名言读起来不像宣言,反倒像一条指令:”空谈无用。把代码拿给我看。”2

Torvalds TED 演讲中链表删除的两个版本:"显而易见"的版本用一个 if 对头节点做特殊处理;"优秀品味"的版本用指向指针的指针,让特殊情况彻底消失

不妨在上方试一试:删除一个中间节点,然后在两种模式下分别删除头节点。在”显而易见的方式”里,头节点会触发 if (!prev) 分支;在”优秀品味”里,头节点只是另一个普通链接,同一行代码就能处理它。

背景

Linus Benedict Torvalds 于 1969 年出生在芬兰赫尔辛基的一个讲瑞典语的家庭。在赫尔辛基大学读计算机科学时,他运行的是 Minix——一个小巧的类 Unix 操作系统,由荷兰教授 Andrew Tanenbaum 作为教学工具编写。Minix 颇具启发性,却被刻意限制了功能——Tanenbaum 让它保持简单,好让学生能读完它的全部代码。而 Torvalds 想要的,比允许他拥有的更多。

1991 年 8 月 25 日,他在 comp.os.minix Usenet 新闻组发帖:”我正在做一个(免费的)操作系统(只是个业余爱好,不会像 gnu 那样庞大专业),面向 386(486) AT 兼容机。”3 括号里那句留有余地的话,是软件史上被引用最多的一次误判。

Torvalds 1991 年 8 月 25 日在 comp.os.minix 上宣布项目的原始帖子——"只是个业余爱好,不会像 gnu 那样庞大专业"

按任何部署指标衡量,这个业余爱好都成了地球上运行最广泛的内核——它驱动着大多数 Web 服务器、每一部 Android 手机,以及绝大部分云计算和超算基础设施。

它的架构从一开始就饱受争议。1992 年初,Tanenbaum 开了一个题为”LINUX is obsolete”(LINUX 已经过时)的讨论帖,主张单体内核是”向 1970 年代倒退的一大步”,而微内核——把操作系统拆解为彼此隔离、通过消息传递通信的服务——才是未来。4 Torvalds 承认,从”理论和美学”的角度看微内核确实更优,然后他继续构建那个单体内核,因为它能用、它快,而且它真的发布了。这场辩论被铭记为一种气质的奠基文献:理论败给了能跑起来的系统。

作品

Linux 内核(1991 年至今):一个实现了规模化的单体

Tux,Linux 内核的吉祥物,由 Larry Ewing 绘制

Linux 是一个单体内核:调度器、内存管理器、文件系统和设备驱动全都运行在同一个特权地址空间里。Tanenbaum 的批评在理论上并没有错——单体内核中一个驱动的故障可能拖垮整个系统,而微内核能把这种故障隔离开来。Torvalds 的回应是经验性的。单体内核更快、更易编写,而且能由数千名贡献者修改,无需每个人都先去学习一套消息传递协议。这个输掉了学术辩论的架构,赢下了部署之战,因为它降低了贡献的门槛。

如今的内核是有史以来最庞大的协作工程产物之一——数千万行代码,每个发布版本都有数千名贡献者。这种规模没有一丝是预先设计出来的。它是一个一个合入的补丁逐渐累积而成的,运行在一种 Torvalds 同样不得不发明出来的开发模式之下。

维护者模式:作为一棵树的信任

Torvalds 并不阅读进入 Linux 的大部分代码。他做不到——代码量远远超出任何一个人的极限。取而代之的是,内核由一套信任的层级结构来治理。子系统维护者拥有自己负责的领域。他们审查补丁,把补丁合入自己的代码树,再向上把拉取请求发给副手们,最终汇到 Torvalds 那里,由他合入他所信任的那些树。他是位于根部的仁慈独裁者,但他真正的工作是甄选他信任谁,而不是审查他们产出的每一行代码。

维护者树是一种社会架构,它直面着每一条现代软件供应链都要面对的同一个问题:你无法亲自核验一切,所以信任必须有结构,而不能靠假定。这正是为什么一个仓库不该为自己的可信度投票,也是为什么开源不是一道安全边界——只有当有人对”去看”这件事负责时,众目睽睽才真正有用。那个以直言不讳的审查闻名的邮件列表,正是让这棵信任树清晰可读的机制:决策及其理由都是公开的、归档的、可追溯到人的。

git(2005 年):作为数据结构的分布式信任

git log --graph 的输出,展示内容寻址的提交 DAG——分支、合并和简短的 SHA 哈希,没有任何享有特权的中央副本

多年来,内核的开发一直使用 BitKeeper——一个专有的分布式版本控制系统,其制造商授予了该项目免费使用权。2005 年,这一安排在一场授权纠纷中崩盘,Torvalds 突然失去了一个能驾驭内核工作流的工具。5 于是他自己写了一个。git 的第一次提交是在 2005 年 4 月 7 日;大约十天之内,它就实现了自托管,并开始管理内核本身。6

让 git 成为与链表那个例子相同原则之体现的,是它的核心数据结构。git 并不存储差异再重建状态。每一个文件的每一个版本、每一棵目录树、每一次提交,都以其自身内容的 SHA-1 哈希为名存储为一个对象——一个内容寻址的仓库。Torvalds 明确表示,哈希”从来不是为了安全。它是为了发现损坏。”6 身份即是内容:两个字节相同的文件会自动成为同一个对象,而单个翻转的比特会产生不同的名字,因而是可检测的。又因为”每个仓库都相同且平等”,所以不存在享有特权的中央服务器——“唯一真本”这个特殊情况消失了,正如”链表头节点”那个特殊情况消失的方式一样。6 分布式不是后来加装到 git 上的一项特性;它是选对了数据结构的必然结果。

最后那个属性——一条防篡改的、由内容寻址的提交构成的链条——正是提交图能够承载超越代码之意义的原因,也是我为何把会话视作提交信息:历史本身就是产物,而非它的副产品。

方法

Torvalds 的方法,是被证据所强制执行的实用主义。”空谈无用。把代码拿给我看”在内核邮件列表上,是对某人描述其补丁将会做什么的一句直白回复。2 设计是假设;补丁是实验。在代码存在并运行起来之前,争论尚无定论。

在这之下,是他关于工程判断力究竟扎根何处的最精准的论述:”糟糕的程序员操心代码。优秀的程序员操心数据结构及其相互关系。”7 链表那个例子,就是这句话的具体化身。如果数据结构对了,操作它的代码就会简短、分支寥寥,因为复杂度已经被结构吸收了。如果数据结构错了,你就得永远为它在特殊情况上付出代价——为那些仅仅为掩盖一个糟糕模型而存在的 if 语句付出代价。操心代码是在治标。操心数据结构才是治本。

治理方法与技术方法相互呼应。仁慈独裁者与副手们的模式之所以存在,与其说是为了集中自我,不如说是为了让合入决策对单一的品味负责,同时把审查的劳作分散到最贴近每个子系统的那些人身上。而他代码审查中的直言不讳——按他本人后来的承认,有时已越界为不必要的苛刻——源自同一个根:代码受评判的依据是它对不对,而不是谁写的、或它代表了多少工作量。即便表达方式并不客观,那把标准也是对事不对人的。

影响链

谁塑造了他

Andrew Tanenbaum 与 Minix。 Minix 是 Torvalds 借以入门的操作系统,也是他试图超越的对象。Tanenbaum 给了他一个可读的类 Unix 系统供他钻研,又通过”LINUX is obsolete”那场辩论,给了他一个足够锋利的陪衬,把 Torvalds 所看重的东西刻画得清清楚楚:一个能发布的系统,胜过一个令人满意的架构。(奠基性影响)4

Unix 与 GNU 工具链。 在设计血统上,Linux 是一脉 Unix——进程、文件、管道,以及”一切皆文件”的抽象。而它之所以有用,只是因为 GNU 项目的编译器、shell 和各种工具已经存在,可以运行在它之上;Torvalds 在内核还干不了多少事之前,就移植了 bash 和 gcc。3 他构建了那块唯一缺失的拼图——内核——然后让既有的拼图去完成其余的一切。需要什么就构建什么;什么管用就复用什么。(直接影响)

他塑造了谁

整个开源世界。 Linux 证明了一支全球分布、志愿者与企业混编的队伍,能在最大的规模上胜过专有团队的工程能力,而维护者模式也成了大型开源项目运作方式的范本。

它之后的每一个分布式版本控制系统。 git 不只是赢了——它成了底层基质。GitHub、GitLab,以及现代的拉取请求工作流,全都建立在 Torvalds 在那十天里选定的那个内容寻址、分布式的模型之上。这个数据结构的寿命,超越了催生它的那场危机。

贯穿始终的脉络

John Carmack 和 Torvalds 从两个相反的专长出发,却抵达了同一个地方。Carmack 把一个问题压榨到算法与硬件严丝合缝、毫无浪费;Torvalds 则把一个问题重塑到数据结构让特殊情况自行消失。两人都把性能与优雅当作同一种属性从不同侧面看到的样子,也都拒绝让理论凌驾于一件确凿能运行的东西之上。在这一系列文章里,优秀的品味从来不意味着装饰;它意味着你能感觉到的正确性。(系列之桥)

我从中获得的

链表这一课,是我最常拿来用的。当代码长出一个 if 来处理”第一个”或”空的情况”或”管理员用户”时,那个分支通常是一种供认:数据模型有点不对劲。修复之道很少是一个更好的 if。它是一种更好的表示方式,在那之后,这个分支不再被需要,因为它所防范的那种情况已不可能发生。那是代价最低的防御:一个不可能存在的边界情况,根本不需要任何代码去处理。

第二课是关于规模化的信任,而它正是在我如今所构建的世界里——智能体系统,你在其中编排自己并未逐行写下的工作——最为要紧的那一课。Torvalds 把同一个问题解决了两次:在社会层面,用一棵维护者树来构建该负责;在技术层面,用 git 内容寻址的历史让发生了什么变得防篡改。你无法读完一个智能体产出的一切,正如 Torvalds 无法读完每一个内核补丁。于是你照他所做的去做——让信任有结构,让历史可核验——这恰恰是为什么我把品味当作基础设施,把供应链当作攻击面。那把从业余爱好里造出一个内核的功夫,与那把让代码库加速而非腐化的功夫,是同一把功夫:把结构搞对,特殊情况就不再繁衍。

常见问题

Linus Torvalds 对代码中”优秀品味”的定义是什么?

在他 2016 年的 TED 访谈中,Torvalds 用两种从链表中删除元素的实现来定义优秀品味。他称之为缺乏品味的那个版本,用一个 if 语句对删除链表头节点做特殊处理;他称之为好代码的那个版本,用一个指向指针的指针,让头节点根本不再是特殊情况。他的总结是:”有时候你可以换一个角度看待问题,把它重写一遍,让一个特殊情况消失、变成普通情况——这就是好代码。”1

Linus Torvalds 创造了什么?

Torvalds 创造了 Linux 内核——他于 1991 年 8 月 25 日在 comp.os.minix 新闻组首次宣布,如今它已是全世界部署最广泛的操作系统内核。2005 年,在 Linux 项目失去对专有工具 BitKeeper 的使用权之后,他还创造了分布式版本控制系统 git。他至今仍是 Linux 内核的首席维护者。35

Linus Torvalds 为什么要构建 git,又花了多长时间?

Linux 项目此前一直使用专有的分布式版本控制系统 BitKeeper,直到 2005 年的一场授权纠纷终结了项目的免费使用权。Torvalds 写出 git 作为替代品,第一次提交是在 2005 年 4 月 7 日,而这个工具在大约十天之内就开始管理内核——不过他指出,自己在此之前已经花了数月时间把设计想透。56

“空谈无用。把代码拿给我看。”是什么意思?

Torvalds 于 2000 年 8 月 25 日把这句话发到 Linux 内核邮件列表上,作为对某段关于”某些代码会做什么”的讨论的直接回复。2 它道出了他的实用主义:对一种做法的描述只是一个假设,而争论要等到存在能够运行和测试的可用代码时才算尘埃落定。(注:与之相关的”只要眼睛足够多,所有 bug 都无所遁形”是 Eric Raymond 所表述的Linus 定律,而非 Torvalds 本人的原话。8

来源


  1. Linus Torvalds, “The mind behind Linux,” TED interview with Chris Anderson, 2016 (good-taste / linked-list segment, approx. 14:10). Because the TED transcript renders client-side, the quote and the pointer-to-a-pointer technique are corroborated in full by the annotated source walkthrough at mkirchner/linked-list-good-taste, which reproduces the talk’s exact wording and timestamp. 

  2. Linus Torvalds, “Talk is cheap. Show me the code,” message to the Linux Kernel Mailing List, 25 August 2000. The line is catalogued with that exact date and source at Wikiquote: Linus Torvalds and archived in the LKML thread at lkml.org/lkml/2000/8/25/132

  3. Linus Torvalds, “What would you like to see most in minix?” comp.os.minix Usenet newsgroup, 25 August 1991. The “just a hobby, won’t be big and professional like gnu” announcement. Context: Tom’s Hardware, “Linux is 34 years old today.” 

  4. “Tanenbaum-Torvalds debate,” Wikipedia. The “LINUX is obsolete” thread, 1992; “giant step back into the 1970s”; microkernel vs. monolithic kernel; Torvalds’ “theoretical and aesthetical” concession. 

  5. “A Git Origin Story,” Linux Journal. The BitKeeper licensing collapse of 2005 and git’s creation; first commit 7 April 2005. 

  6. “Git turns 20: A Q&A with Linus Torvalds,” The GitHub Blog, 2025. “Every repository is the same and equal”; “SHA-1 hashes were never about the security. It was about finding corruption”; the ~10-day timeline. 

  7. Linus Torvalds, “Bad programmers worry about the code. Good programmers worry about data structures and their relationships,” Linux Kernel Mailing List, 27 June 2006. 

  8. Eric S. Raymond, “The Cathedral and the Bazaar,” 1997. Raymond coined and named “Linus’s Law” – “given enough eyeballs, all bugs are shallow” – as his own formulation, crediting Torvalds for the underlying development model rather than the wording. 

相关文章

工程哲学:Mark Shuttleworth

Mark Shuttleworth 把 Ubuntu 建立在一个理念之上——为普通人而生的 Linux,人人可用的自由软件——其根基是 ubuntu:待人以仁,并按时交付。

5 分钟阅读

工程哲学:Thompson 与 Ritchie,把一件事做好

Thompson 与 Ritchie 用通过单一通用接口——文本流与管道——组合而成的小巧锋利的工具,构建了 Unix 与 C。简洁胜于功能堆砌。

3 分钟阅读

The Shader Gallery That Lied: Debugging 216 WebGL Presets

A user said the shader playground looked broken. Pixel-readback testing found 30 dead presets, 11 that never compiled, a…

11 分钟阅读