翻译自 The Rise of ‘Worse is Better’

我和几乎每一位 Common Lisp 和 CLOS 的设计师都对 MIT / Stanford 设计风格有极大的接触。这种风格的本质可以通过”正确的事 (the right thing)”这个词来体现。对于这样的设计师来说,重要的是要获得以下所有特性:

注:下面有时候提到”正确的事”指的就是这个风格

  • 简单性 - 设计必须简单,无论是在实施和交互。接口比实现更简单更重要
  • 正确性 - 在所有可观察的方面,设计必须是正确的。简单错误也是不允许的
  • 一致性 - 设计不能不一致。设计允许稍微减少一点简单性和完整性,以避免不一致。一致性与正确性一样重要。
  • 完整性 - 设计必须涵盖尽可能多的重要情况。必须涵盖所有合理预期的情况。不能因简单性减少完整性。

我相信大多数人会同意这些都是很好的特点。我将称此设计理念为”MIT approach”. Common Lisp (包括 CLOS) 和 Scheme 代表了 MIT approach 的设计和实现。

更坏就是更好的哲学只是略有不同:

  • 简单性 - 设计必须简单,无论是在实施和交互。实现简单比接口简单更重要。简单性是设计中最重要的考虑因素。
  • 正确性 - 在所有可观察的方面,设计必须是正确的。简单比正确略好一点
  • 一致性 - 设计不能过分不一致。在某些情况下,为了简化可能会牺牲一致性,但最好放弃那些处理不太常见情况的设计部分,而不是为实现引入一些复杂性或不一致性。
  • 完整性 - 设计必须涵盖尽可能多的重要情况。应涵盖所有合理预期的情况。完整性可以被牺牲以致于提升其他性质。事实上,只要实施简单性受到损害,完整性就必须牺牲。如果保持简单性,可以牺牲一致性来实现完整性;特别值得一提的是接口的一致性。

早期的 Unix 和 C 就是使用这个设计的例子,我会称这种使用了这种设计的策略为”New Jersey approach”。我故意讽刺”更坏就是更好”的哲学来说服你,这显然是一种不好的哲学,而 New Jersey approach 是一种糟糕的做法。

注:Unix 是贝尔实验室开发的,而贝尔实验室在 New Jersey(美国的一个州),后面有时候会翻译成新泽西

然而,我认为”更坏就是更好”,即使故意曲解它,都比”正确的事”有更好的生存特征,并且 New Jersey approach 在用于软件时比 MIT approach 更好。

注:原文中用的是 Strawman form,大概的意思可以参考 相关 wiki

让我首先复述一个故事,说明 MIT / New Jersey 的区别是有效的,每个哲学的支持者实际上相信他们的哲学更好。

两位知名人士,一位来自麻省理工 (MIT) 和另一位来自伯克利(现在在 Unix 工作),有次见面讨论操作系统问题。来自 MIT 的人对 ITS(MIT AI 实验室操作系统)非常了解,并且一直在阅读 Unix 源代码。他对 Unix 如何解决 PC loser-ing 感兴趣。 PC loser-ing 会出现在当用户程序调用 system routine 执行可能具有重要状态的冗长操作(例如 IO 缓冲区)时。如果在操作过程中发生中断,则必须保存用户程序的状态。因为 system routine 的调用通常是单个指令,所以用户程序的 PC 不能充分捕获进程的状态。 system routine 必须退出或前进。正确的事是退出并将用户程序 PC 恢复到调用 system routine 的指令,以便在中断后恢复用户程序,例如重新进入 system routine 。它被称为”PC loser-ing”,因为 PC 被强制进入”loser mode”,其中”loser”是麻省理工对于”user”更亲热的叫法。

注: PC loser-ing 问题可以参考 wiki

这个来自 MIT 的没看到过处理这个问题的代码,于是就问这个新泽西的这个问题是怎么被解决的。新泽西的人说,Unix 的人意识到这个问题,但解决方案是让 system routine 总是完成,有时会返回一个错误代码,表示 system routine 未能完成其操作。一个正确的用户之后应当检查错误代码,以确定是否只是简单地再次尝试 system routine。这个 MIT 的人不喜欢这个解决方案,因为这不是”正确的事”。

新泽西的人说,Unix 解决方案是对的,因为 Unix 的设计理念很简单,”正确的事”太复杂了。此外,程序员可以轻松地插入这个额外的测试和循环。MIT 的人指出,实现很简单,但功能的接口很复杂。新泽西的人说,在 Unix 中选择了正确的权衡 - 即实现简单性比接口简单性更重要。

这个 MIT 的人喃喃道 sometimes it takes a tough man to make a tender chicken,但这个新泽西的人没懂。(我不确定我懂不懂)

注:原作者在括号里说 I’m not sure I do either

现在我想说的是”更坏就是更好”更好。C 是一种为编写 Unix 而设计的编程语言,它是使用 New Jersey approach 设计的。因此 C 是一种很容易写出像样的编译器的语言,它要求程序员编写易于编译器解释的文本。有些人称 C 为花哨的汇编语言。早期的 Unix 和 C 编译器都具有简单的结构,很容易移植,只需很少的机器资源就可以运行,并且可以从操作系统和编程语言所需的中提供大约 50%-80%。

任何情况下,存在一半的计算机比中位数更差(更小或更慢)。Unix 和 C 对它们工作正常。”更坏就是更好”的理念意味着简单实现具有最高的优先级,这意味着 Unix 和 C 很容易在这些机器上移植。因此,人们期望如果 Unix 和 C 支持的 50%功能令人满意,它们将开始出现在任何地方。这是必然的,不是吗?

Unix 和 C 是终极电脑病毒。

“更坏就是更好”的理念的另一个好处是程序员有条件牺牲一些安全,方便和麻烦来获得良好的性能和适度的资源使用。使用 New Jersey approach 编写的程序无论在小型机器还是大型机器上都能正常工作,并且代码将可移植,因为它是写在病毒顶部的。

记住最初的病毒基本上是好的,这很重要。如果是这样,只要它是便携式的,病毒传播就会得到保证。一旦病毒传播,将会有改善它的压力,可能通过将其功能增加到接近 90%,但用户相对于”正确的事”已经习惯于接受”更坏”。因此,”更坏就是更好”的软件首先会获得认可,其次会让用户期望更少,再其次会改善到接近”正确的事”。具体而言,尽管 1987 年的 Lisp 编译器与 C 编译器差不多,但相对于让 Lisp 编译器更好还有更多的编译器专家希望使 C 编译器更好。

好消息是,在 1995 年,我们将拥有一个好的操作系统和编程语言;坏消息是他们将是 Unix 和 C++。

“更坏就是更好”有一个最终的好处。由于新泽西语言和系统的功能不足以构建复杂的 monolithic 软件,因此必须设计大型系统以重用组件。因此,融合的传统涌现出来。

“正确的事”如何叠加?有两个基本的情景:”big complex system” 和 “diamond-like jewel”。

“big complex system” 的情景是这样的:

首先,需要满足”正确的事”的设计。那么它的实现需要被设计。最后它被执行。因为它是正确的,它具有接近 100%的所需功能,并且从不关心实现简单性,因此需要很长时间才能实现。它庞大而复杂。它需要复杂的工具才能正确使用。最后的 20%需要花费 80%的努力,所以正确的事情需要很长时间才能脱身,而且它只能在最复杂的硬件上满意地运行。

“diamond-like jewel” 情景如下:

永远需要满足”正确的事”的设计,但在整个过程中的每一点都很小。要快速实现它,要么是不可能的,要么超出了大多数实现者的能力。

这两种情况对应于 Common Lisp 和 Scheme。

第一种情况也是经典人工智能软件的场景。

“正确的事”往往是一个单一的软件,但除了一个单一设计的软件,没有任何理由用”正确的事”。也就是说,这是偶然的。

从中学到的教训是,首先去做”正确的事”往往是不可取的。最好能获得一半正确的东西,以便像病毒一样传播。一旦人们对此感兴趣,花点时间将其提高到正确的 90%。

一个错误的教训是从字面上理解比喻并得出结论:C 是 AI 软件的正确媒介。50%的解决方案基本上是正确的,在这种情况下不是。

但是,我们只能得出结论,Lisp 社区需要认真反思它在 Lisp 设计上的立场。我稍后会详细说明这一点。