关于UNIX哲学的误解 (2024)
摘要
对关于UNIX哲学的常见误解的分析,认为通常将小程序通过管道通信的解释是对原始设计原则的误解。
<p><a href="https://lobste.rs/s/dysrh2/misconceptions_about_unix_philosophy">评论</a></p>
查看缓存全文
缓存时间: 2026/05/18 20:34
# 关于 UNIX 哲学的误解
来源:https://posixcafe.org/blogs/2024/01/05/0/
最近我和一位朋友讨论了一些观点,这些观点来自 Jonathan Blow 在 Oxide 的《On The Metal》播客中接受的采访(https://oxide.computer/podcasts/on-the-metal/jonathan-blow),其中他谈到了“UNIX 哲学”。我将摘录一段提供的文字记录放在这里(稍微做了编辑,因为我听到 Jonathan 说的内容和记录有些出入)。
```
Jonathan
我要再扔一块石头,估计又得惹恼一些人。
但说到所有需要被消解的复杂性,
我认为每样东西都有自己的时代。问题是——
Bryan
天啊,接下来是什么?你还要往哪里去?
Jonathan
嗯,比如说 UNIX 哲学,它已经被 Windows 继承了一些,
尽管它们是不同的操作系统,对吧?
UNIX 哲学就是所有那些小程序,你用某种方式组合起来,
我认为这是错误的。在今天它是错误的,
而且它也被 Plan 9 采纳了,所以——
Bryan
微服务,微服务是 UNIX 哲学的一种体现。
所以 UNIX 哲学,我对 UNIX 哲学有种复杂的关系。Jess,
我想你也是。就像,我喜欢它,我喜欢管道,当我想要做一些
临时性的、不是为了永久存在而设计的事情时,它对我很有帮助——而且你
之前也谈到 Rust 在视频游戏中的问题,以及为什么它可能不适合快速原型开发,
UNIX 哲学非常适合临时原型开发。
```
有一种观点认为,UNIX 就意味着大量的小型程序通过管道相互通信,有些人甚至进一步暗示这种通信必须是纯文本的。这种分类是对 UNIX 所提出思想的深刻误解,然而我发现许多同龄人都持有这种立场。我看到的是,当在现代系统的背景下提到 UNIX 哲学时,人们会指向微服务并说:“看,微服务就是 UNIX,而微服务很糟糕!”
### 这是怎么发生的?
我觉得这是人们将实现与设计混淆的典型案例,只见树木不见森林。我相信这是因为人们在没有上下文的情况下引用并重复某些说法,把它们当作格言。我经常听到的一句是“编写做一件事并且做得好的程序”,这句话出自 Peter H. Salus 的《Unix 的四分之一世纪》。我也经常看到 Doug McIlroy 在《贝尔系统技术期刊》中写的一段引用,特别是 Doug 在标题为“风格”的部分中给出的一个列表:
```
在 UNIX 系统的构建者和用户中,流传着一些格言,用来解释和促进
其特有的风格:
(i) 让每个程序只做好一件事。要完成新任务,
应从头构建,而不是通过添加新功能来使旧程序复杂化。
(ii) 期待每个程序的输出成为另一个尚未可知的程序的输入。
不要用无关信息污染输出。避免严格的列式或二进制输入格式。
不要坚持交互式输入。
(iii) 设计和构建软件,甚至是操作系统时,要尽早尝试,理想情况下在几周内。
不要犹豫,扔掉笨拙的部分并重新构建。
(iv) 优先使用工具而非不熟练的帮手来减轻编程任务,即使你必须绕道
去构建这些工具,并预期在使用完其中一些后将它们扔掉。
```
前两段引用似乎非常重要,如果你去维基百科的“UNIX 哲学”页面,在“起源”部分给出的前两段引用就是这些。表面上看,这些说法并非完全错误,我并不是说两位作者错了,你可以观察到 UNIX 在*实现*上遵循了这些想法。错误在于,当人们将这些实现细节外推为哲学本身时,实际上这些只是将哲学应用于操作系统而产生的副产品。Doug 给出的前两条风格规则具体指的是*程序*,这是一种只有操作系统(其主要职责是管理它们)才会关心的组织单元。第三条规则开始变得稍微抽象一些,特别是因为它涉及的是软件而非程序,这也是我认为在操作系统之外一般也适用的好建议。继续看第四条规则,我们再次看到 Doug 提到了*工具*而非进程,因此这也是我认同的、普遍适用于大型软件的建议。
然而,为什么在讨论“UNIX 哲学”时,后两条风格规则没有被更多地重复?为什么人们似乎只停留在那些将哲学与操作系统概念紧密联系的东西上?认为微服务是 UNIX,因为它是一堆相互通信的小程序,这没有意义,因为微服务是*分布式系统*的架构,而小程序相互通信的概念是*操作系统*的规则。人们遇到的摩擦正是由于试图将方塞子塞进圆孔。
### 真正的 UNIX 哲学
让我们再深入挖掘一下,看看能否找到更抽象的东西。一个很好的起点是 Brian Kernighan 和 Rob Pike 的《UNIX 编程环境》一书的序言。以下是摘录:
```
尽管 UNIX 系统引入了一些创新的程序和技巧,
但并没有哪一个单独的程序或想法使其运行良好。
相反,使 UNIX 有效的是编程方法,是使用计算机的哲学。
虽然这种哲学无法用一句话写下来,但其核心思想是:
一个系统的力量更多来自于程序之间的关系,而非程序本身。
许多 UNIX 程序单独看只完成很琐碎的任务,但当与其他程序结合时,
就变成了通用而有用的工具。
我们这本书的目标是传达 UNIX 编程哲学。由于这种哲学
基于程序之间的关系,我们必须将大部分篇幅用于讨论
各个工具,但贯穿始终的主题是组合程序以及用程序构建程序。
要很好地使用 UNIX 系统及其组件,你不仅需要理解如何使用程序,
还需要理解它们如何融入环境。
```
那么,当我们抽象掉那些讨厌的操作系统特定术语(如“程序”和“进程”)时,我们发现 UNIX 哲学的核心是组合性。我认为程序的大小和用途并不比它与其他程序一起使用的能力更重要。使用像 UNIX 这样的操作系统时感觉很棒的一点是,你可以以非预期的方式组合代码,各个部分像乐高积木一样契合。
让我们重新审视微服务这个话题。我经常看到(并且也经历过)的问题是,微服务之间的信息流动方式很复杂。数据通过 UNIX 管道线性流动,从一个到下一个,整个链条都呈现在命令中;而在一个采用微服务设计的分布式系统中,数据流通常更像是一个复杂的图,节点之间有多条边。我们可以清楚地看到,根据 Rob 和 Brian 对 UNIX 设计的定义,微服务是失败的,因为它们的组合性很差。图中的每个新边都会带来复杂的依赖关系和开销。
组合性不一定只在程序之间。例如,如果你正在构建一个游戏或最终用户程序,组合性可能意味着整体程序的各个库或组件能够很好地配合。一个单一程序也可以是 UNIX 风格的,只要其内部各个部分能够很好地组合在一起。
### 结语
我想用 Ken Thompson 和 Dennis Ritchie 的论文《UNIX 分时系统》中的一段摘录来结束,特别是标题为“观点”的部分。
```
回顾过去,有三个考虑因素影响了 UNIX 的设计。
第一,由于我们是程序员,我们自然设计了这个系统,使其易于编写、测试和运行程序。
我们对编程便利的渴望的最重要表现是,系统被安排成交互式使用,
尽管最初的版本只支持一个用户。我们认为,一个设计得当的交互式系统
比“批处理”系统更具生产力和满足感。而且,这样的系统相当容易适应非交互式使用,
反之则不成立。
第二,系统和它的软件一直面临相当严格的尺寸限制。
考虑到对合理效率和表达能力的部分矛盾需求,
尺寸限制不仅鼓励了经济性,还鼓励了某种设计上的优雅。
这可能是“通过受苦获得救赎”哲学的变相版本,但对我们来说它行之有效。
第三,几乎从一开始,系统就能够自我维护,并且确实做到了。
这一点比看起来更重要。如果系统的设计者被迫使用该系统,
他们很快就会意识到其功能和表面上的缺陷,并受到强烈的激励
在来不及之前纠正它们。由于所有源程序始终可用并且可以轻松地在线修改,
我们愿意在新的想法被别人发明、发现或提出时,修订和重写系统及其软件。
```
相似文章
管道、Fork 和僵尸进程
本文来自哈佛大学的 CS 61 课程,涵盖了 Unix 中的管道、Fork 和僵尸进程概念,解释了在关闭时管道如何自动终止程序,以及如何使用管道实现对子进程的阻塞等待。
系统编程入门,第一部分:程序员编写程序(2025)
一篇系统编程入门文章,涵盖诸如位操作、解析、文件系统、系统调用和内存管理等基础知识,面向程序员。
TTY 解密 (2008)
详细解释Linux和UNIX中的TTY子系统,涵盖从电传打字机到现代模拟终端的历史,以及线路规程的作用。
赛博自由主义令人难以容忍的虚伪
本文批判赛博自由主义是一种虚伪的意识形态,认为约翰·佩里·巴洛等早期互联网先锋人物的基本信念存在缺陷且具有误导性。
七大编程原语言(2022)
一篇文章探讨了七种构成大多数现代编程语言基础的编程语言原型(原语言),认为学习植根于这些原型的基础知识比选择特定语言更重要。