Loading...

击败平均水平

Original

2001年4月,2003年4月修订

(本文改编自2001年Franz开发者研讨会上的演讲。)

1995年夏天,我的朋友罗伯特·莫里斯和我创办了一家名为Viaweb的创业公司。我们的计划是编写让最终用户建立在线商店的软件。当时,这款软件的新颖之处在于它运行在我们的服务器上,使用普通的网页作为界面。

当然,很多人可能同时都有这样的想法,但据我所知,Viaweb是第一个基于网络的应用程序。这个想法对我们来说如此新颖,以至于我们以此命名了公司:Viaweb,因为我们的软件通过网络工作,而不是运行在您的桌面计算机上。

这款软件的另一个不同寻常的地方是,它主要是用一种名为Lisp的编程语言编写的。它是第一个大型最终用户应用程序,采用了Lisp,而Lisp此前主要用于大学和研究实验室。[1]

秘密武器

埃里克·雷蒙德写过一篇名为"如何成为一名黑客"的文章,其中除了其他内容,他还告诉想成为黑客的人应该学习哪些语言。他建议从Python和Java开始,因为它们很容易学习。认真的黑客还需要学习C,以便黑Unix,以及Perl,用于系统管理和CGI脚本。最后,真正认真的黑客应该考虑学习Lisp:

学习Lisp是值得的,因为当你最终理解它时,你会有一种深刻的启迪体验;这种体验会让你在余生中成为一个更好的程序员,即使你实际上并不经常使用Lisp本身。

这与人们通常听到的学习拉丁语的论点是一样的。它不会让你找到工作,除非也许是作为一名古典学教授,但它会提高你的思维能力,让你在你真正想使用的语言(如英语)中成为一个更好的作家。

但等一下。这个比喻并不完全适用。拉丁语不会让你找到工作的原因是,没有人说它。如果你用拉丁语写作,没有人能理解你。但是Lisp是一种计算机语言,计算机会说你,作为程序员,告诉它们要说的语言。

那么,如果Lisp像他说的那样让你成为一个更好的程序员,为什么你不想使用它呢?如果一个画家被提供一支能让他成为更好的画家的画笔,似乎他会想在所有的画作中使用它,不是吗?我并不是想取笑埃里克·雷蒙德。总的来说,他的建议是很好的。他对Lisp的说法基本上就是普遍的观点。但是,普遍的观点中存在一个矛盾:Lisp会让你成为一个更好的程序员,但你不会使用它。

为什么不呢?毕竟,编程语言只是工具而已。如果Lisp确实产生更好的程序,你应该使用它。如果不是这样,那又有什么需要呢?

这不仅仅是一个理论问题。软件是一个非常有竞争性的行业,容易形成自然垄断。一家能更快更好地编写软件的公司,在其他条件相同的情况下,就能把竞争对手挤出市场。当你创办一家初创公司时,你会非常强烈地感受到这一点。初创公司往往是一个非黑即白的命题。你要么发财,要么一无所有。在一家初创公司,如果你选错了技术,你的竞争对手会把你碾压。

罗伯特和我都很擅长Lisp,我们看不出有任何理由不相信我们的直觉,选择使用Lisp。我们知道其他人都在用C++或Perl编写他们的软件。但我们也知道,这并不意味着什么。如果你是这样选择技术的,你就会在使用Windows。当你选择技术时,你必须忽略其他人在做什么,只考虑什么最有效。

这在初创公司尤其如此。在大公司里,你可以做其他大公司都在做的事情。但初创公司不能做其他初创公司都在做的事情。我觉得很多人,甚至在初创公司里,也没有意识到这一点。

大公司平均每年增长10%左右。所以如果你经营一家大公司,你做的每件事都和其他大公司一样,你可以期望做得和平均大公司一样好——也就是说,每年增长大约10%。

同样的道理也适用于初创公司。如果你做的每件事都和其他初创公司一样,你应该期望获得平均水平的业绩。问题在于,平均水平的业绩意味着你会倒闭。初创公司的存活率远低于50%。所以如果你经营一家初创公司,你最好做一些与众不同的事情。否则,你就有麻烦了。

1995年的时候,我们知道一些我觉得我们的竞争对手并不理解,即使现在也很少有人理解:当你编写只需在自己的服务器上运行的软件时,你可以使用任何语言。当你编写桌面软件时,有一种强烈的偏好,即使用与操作系统相同的语言编写应用程序。十年前,编写应用程序意味着用C编写应用程序。但是对于基于网络的软件,特别是当你拥有语言和操作系统的源代码时,你可以使用任何你想要的语言。

这种新的自由是一把双刃剑,然而。现在你可以使用任何语言,你必须考虑使用哪一种。试图假装什么都没变的公司可能会发现,他们的竞争对手并非如此。

如果你可以使用任何语言,你会选择哪一种?我们选择了Lisp。首先,很明显,快速开发在这个市场上很重要。我们都是从头开始的,所以一家能比竞争对手更快完成新功能的公司将拥有很大优势。我们知道Lisp是一种非常适合快速编写软件的语言,而基于服务器的应用程序会放大快速开发的效果,因为你可以在软件完成的那一刻就发布它。

如果其他公司不想使用Lisp,那就更好了。 这可能会给我们带来技术优势,而我们需要尽可能多的帮助。 当我们开始创办Viaweb时,我们在商业方面没有任何经验。 我们不知道任何关于营销、招聘人员、筹集资金或获取客户的知识。 我们两个人甚至从未有过所谓的"真正的工作"。 我们唯一擅长的就是编写软件。 我们希望这能拯救我们。 我们能获得的任何软件方面的优势,我们都会去利用。

所以你可以说使用Lisp是一个实验。 我们的假设是,如果我们用Lisp编写软件,我们就能比竞争对手更快地完成功能,并且还能在软件中做一些他们做不到的事情。 而且因为Lisp的高级性,我们不需要一个大型的开发团队,所以成本会更低。 如果这是真的,我们就可以以更低的价格提供更好的产品,并且仍能获得利润。 我们最终会获得所有用户,而我们的竞争对手则一个也得不到,最终他们会倒闭。 这就是我们希望发生的事情。

这个实验的结果如何? 令人惊讶的是,它奏效了。 我们最终有很多竞争对手,大约20到30家,但他们的软件都无法与我们的相媲美。 我们有一个在服务器上运行,但又像桌面应用程序一样的所见即所得的在线商店构建器。 而我们的竞争对手只有CGI脚本。 我们在功能上一直领先于他们很多。 有时,竞争对手会绝望地尝试引入我们没有的功能。 但有了Lisp,我们的开发周期如此之快,以至于我们有时能在竞争对手发布新闻稿后的一两天内复制新功能。 当报道该新闻稿的记者来找我们时,我们已经有了那个新功能。

对我们的竞争对手来说,这一定看起来像是我们有某种秘密武器 - 就好像我们在解密他们的密码通讯一样。 事实上,我们确实有一个秘密武器,但比他们想象的要简单得多。 没有人向我们泄露他们的功能信息。 我们只是能够以比任何人都认为可能的更快的速度开发软件。

大约9岁的时候,我偶然得到了一本弗雷德里克·福赛斯的《杰克尔的日子》。 主角是一名被雇来暗杀法国总统的刺客。 刺客必须设法逃过警察,进入一处俯瞰总统路线的公寓。 他伪装成一个拄着拐杖的老人,从他们身边走过,他们从未怀疑过他。

我们的秘密武器类似。 我们用一种奇怪的人工智能语言编写软件,语法充满了括号。 多年来,我一直讨厌听到Lisp被这样描述。 但现在它为我们带来了优势。 在商业中,没有什么比竞争对手不理解的技术优势更有价值了。 在商业中,就像在战争中一样,惊喜价值与力量一样。

因此,我不得不说,在我们开发Viaweb的时候,我从未公开提过Lisp。 我们从未向媒体提及过它,如果你在我们的网站上搜索Lisp,你只能找到我个人简历中两本书的书名。 这并非偶然。 一家初创公司应该尽可能少地向竞争对手透露信息。 如果他们不知道我们的软件是用什么语言编写的,或者不在乎,我想保持这种状态。[2]

最了解我们技术的人是客户。 他们也不在乎Viaweb是用什么语言编写的,但他们注意到它运作得非常出色。 它让他们能够在几分钟内建立出色的在线商店。 因此,主要通过口碑,我们获得了越来越多的用户。 到1996年底,我们已经有大约70家商店在线。 到1997年底,我们有500家。 六个月后,当雅虎收购我们时,我们有1070名用户。 如今,作为雅虎商店,这款软件继续主导着它的市场。 它是雅虎最赚钱的部分之一,而用它建立的商店是雅虎购物的基础。 我在1999年离开雅虎,所以我不知道他们现在有多少用户,但我最后听说大约有2万家。

Blub悖论

Lisp有什么了不起的? 如果Lisp如此出色,为什么不是人人都在使用它? 这听起来像是修辞性的问题,但实际上它们有直接的答案。 Lisp如此出色,不是因为只有信徒才能看到的某种魔力,而是因为它简单地是最强大的语言。 而每个人都不使用它的原因是,编程语言不仅仅是技术,也是思维习惯,而没有什么比思维习惯更难改变了。 当然,这两个答案都需要解释。

我将以一个令人震惊的有争议性声明开始:编程语言各有不同的功能。

至少,没有人会争辩高级语言比机器语言更强大。 大多数程序员今天都会同意,通常情况下,你不应该用机器语言编程。 相反,你应该用高级语言编程,然后让编译器将其转换为机器语言。 这个想法现在甚至已经内置到硬件中了:自20世纪80年代以来,指令集就是为编译器而不是人类程序员设计的。

每个人都知道,完全用机器语言手写整个程序是一个错误。 但较少被理解的是,这里有一个更普遍的原则:如果你有几种语言可选,那么在其他条件相同的情况下,用最强大的那种语言编程是一个错误。[3]

这条规则有很多例外。如果你正在编写一个必须与某种语言编写的程序非常紧密合作的程序,那么用同一种语言编写新程序可能是个好主意。如果你正在编写一个只需要做一些非常简单的事情的程序,比如数字运算或位操作,那么使用一种更不抽象的语言可能更好,特别是因为它可能稍微快一些。如果你正在编写一个短暂的程序,你可能最好使用任何一种语言,只要它为这个任务提供最好的库函数。但总的来说,对于应用程序软件,你想使用尽可能强大(合理高效)的语言,使用任何其他语言都是一种错误,虽然可能程度较小,但与使用机器语言编程是同样的错误。

你可以看到,机器语言是非常底层的。但至少作为一种社会习惯,高级语言通常都被视为等同。它们并不等同。从技术上讲,术语"高级语言"没有很明确的定义。没有一个明确的界限,将机器语言放在一边,而所有的高级语言放在另一边。语言沿着一个连续体[4]从最强大一直延伸到机器语言,而机器语言本身也各不相同。

以Cobol为例。Cobol是一种高级语言,因为它被编译成机器语言。有人会认真地认为Cobol与Python等价吗?它可能更接近机器语言,而不是Python。

或者Perl 4呢?在Perl 4和Perl 5之间,词法闭包被添加到了这种语言中。大多数Perl黑客都会同意,Perl 5比Perl 4更强大。但一旦你承认了这一点,你就承认了一种高级语言可以比另一种更强大。从而不可避免地得出结论,除了特殊情况外,你应该使用尽可能强大的语言。

这个想法很少被推到最后。过了一定年龄,程序员很少主动切换语言。不管人们使用的是什么语言,他们都倾向于认为它足够好了。

程序员对自己最喜欢的语言非常依恋,我不想伤害任何人的感情,所以为了解释这一点,我将使用一种假设的语言,称之为Blub。Blub正好位于抽象性连续体的中间。它不是最强大的语言,但比Cobol或机器语言更强大。

事实上,我们假设的Blub程序员也不会使用它们。当然,他不会用机器语言编程。那是编译器的工作。至于Cobol,他不知道任何人怎么能用它完成任何事情。它甚至没有x(你选择的Blub特性)。

只要我们假设的Blub程序员向下看这个能力连续体,他就知道自己在向下看。比Blub更弱的语言显然更弱,因为它们缺少一些他习惯使用的特性。但当我们假设的Blub程序员向上看能力连续体时,他就不会意识到自己在向上看。他看到的只是一些奇怪的语言。他可能认为它们与Blub的能力差不多,只是多了一些其他复杂的东西。Blub对他来说足够好,因为他是用Blub思考的。

但是,当我们转换到使用能力连续体上更高语言的程序员的观点时,我们会发现他反过来看不起Blub。你怎么能在Blub中完成任何事情?它甚至连y都没有。

归纳起来,只有那些理解最强大语言的程序员才能看到各种语言之间的能力差异。(这可能就是埃里克·雷蒙德所说的Lisp会让你成为一个更好的程序员的意思。)你不能相信其他人的意见,因为存在Blub悖论:他们满足于他们正在使用的任何语言,因为它决定了他们思考程序的方式。

我从自己的经验中知道这一点,当我还是一个高中生用Basic编写程序的时候。那种语言甚至不支持递归。很难想象不使用递归就能编写程序,但当时我并没有感到缺失。我是用Basic思考的。我在那方面很出色。掌握了所有我所掌握的。

埃里克·雷蒙德推荐给黑客的五种语言位于能力连续体的不同点上。它们相对于彼此的位置是一个敏感的话题。我要说的是,我认为Lisp位于顶端。为了支持这一说法,我将告诉你我在看其他四种语言时发现的一件事。我想,没有宏,你怎么能在它们中完成任何事情呢?[5]

许多语言都有一些叫做宏的东西。但Lisp宏是独一无二的。令人难以置信的是,它们的作用与括号有关。Lisp的设计者并不是为了与众不同而把所有这些括号放进这种语言。对于Blub程序员来说,Lisp代码看起来很奇怪。但这些括号是有原因的。它们是一个基本差异的外在证据,这个差异存在于Lisp和其他语言之间。

Lisp代码是由Lisp数据对象构成的。这不仅仅是源文件包含字符,而字符串是该语言支持的数据类型之一这么简单。Lisp代码,在被解析器读取之后,是由可以遍历的数据结构组成的。

如果你了解编译器的工作原理,真正发生的情况并不是Lisp有一种奇怪的语法,而是Lisp根本没有语法。你是在编写那些在其他语言被解析时在编译器内部生成的解析树。但这些解析树完全可以被你的程序访问。你可以编写程序来操作它们。在Lisp中,这些程序被称为宏。它们是编写程序的程序。

编写程序的程序?你什么时候会想要这样做?

如果你用COBOL思考,那就很少。如果你用Lisp思考,那就随时都会。如果我能在这里给出一个强大宏的例子,并说"看,就是这样!"那就太好了。但如果我这样做,对于不了解Lisp的人来说,那看起来就像是胡言乱语。在这里没有足够的空间来解释你需要知道的一切。在Ansi Common Lisp中,我尽可能快地推进,即使如此,我也直到第160页才讲到宏。

但我想我可以给出一种可能令人信服的论点。Viaweb编辑器的源代码大约有20-25%是宏。编写宏比编写普通的Lisp函数要困难,被认为是不好的风格,除非它们是必需的。所以这个程序中的每一个宏都是必需的。这意味着至少20-25%的代码在做其他语言很难做到的事情。无论Blub程序员对Lisp神奇力量的说法有多怀疑,这应该会引起他的好奇。我们编写这些代码并不是为了自己的娱乐。我们是一家小型创业公司,尽全力编程,以在我们和竞争对手之间设置技术障碍。

一个多疑的人可能开始怀疑这里是否存在某种相关性。我们代码的一大部分在做其他语言很难做到的事情。结果软件能做竞争对手的软件做不到的事情。也许这之间存在某种联系。我鼓励你追究这一线索。那个一瘸一拐走在拐杖上的老人可能有更多值得注意的地方。

创业公司的合气道

但我不指望说服任何人(25岁以上)去学习Lisp。这篇文章的目的不是改变任何人的想法,而是安慰那些已经对使用Lisp感兴趣的人--那些知道Lisp是一种强大语言,但担心它没有广泛使用的人。在竞争环境中,这是一种优势。Lisp的力量被放大了,因为你的竞争对手不理解它。

如果你考虑在创业公司使用Lisp,你不应该担心它不被广泛理解。你应该希望它保持这种状态。而且很可能会如此。编程语言的性质就是让大多数人满足于他们目前使用的任何东西。计算机硬件的变化速度远远快于个人习惯,以至于编程实践通常落后于处理器10到20年。在麻省理工学院等地方,他们在20世纪60年代初就在高级语言中编写程序,但许多公司一直到20世纪80年代才开始用机器语言编写代码。我敢说,直到处理器像急于打烊回家的酒保一样把他们踢出去,转而使用RISC指令集,很多人才停止用机器语言编写代码。

通常,技术变化很快。但编程语言不同:编程语言不仅仅是技术,也是程序员的思维方式。它们既是技术,又是宗教。[6]因此,中位数语言,也就是中位数程序员使用的任何语言,移动速度如同冰山一般缓慢。Lisp在大约1960年引入的垃圾收集现在被广泛认为是一件好事。动态类型,同样,正在变得越来越流行。Lisp在20世纪70年代初引入的词法闭包,现在才刚刚进入人们的视野。Lisp在20世纪60年代中期引入的宏,仍然是一片未知领域。

很明显,中位数语言有着巨大的惯性。我不建议你可以抗衡这股强大的力量。我提出的恰恰相反:就像合气道的实践者一样,你可以利用它来对付你的对手。

如果你在一家大公司工作,这可能不太容易。你很难说服尖头老板让你用Lisp来构建东西,当他刚刚在报纸上读到另一种语言,就像20年前的Ada一样,即将统治世界。但如果你在一家还没有尖头老板的创业公司工作,你可以像我们一样,把Blub悖论变成你的优势:你可以使用你的竞争对手,牢牢粘在中位数语言上的技术永远无法匹敌的技术。

如果你真的在一家创业公司工作,这里有一个很方便的技巧来评估竞争对手。阅读他们的招聘信息。他们网站上的其他内容可能都是标准照片或等同的文字,但招聘信息必须具体说明他们想要什么,否则他们会招到错误的候选人。

在我们为Viaweb工作的那些年里,我读了很多工作描述。似乎每个月都会冒出一个新的竞争对手。我首先要做的就是检查他们是否有在线演示,然后看看他们的招聘信息。经过几年的这样做,我能够判断哪些公司值得担心,哪些不值得。工作描述越有IT味道,公司就越不危险。最安全的是那些想要Oracle经验的公司。你永远不必担心那些。如果他们说他们想要C++或Java开发人员,你也是安全的。如果他们想要Perl或Python程序员,那就有点让人担心--这听起来像是一家至少在技术方面由真正的黑客运营的公司。如果我曾经看到过一个招聘Lisp黑客的职位,我会非常担心。

注释

[1] Viaweb起初有两个部分:用Lisp编写的编辑器,人们用它来构建自己的网站,以及用C编写的订单系统,用于处理订单。第一个版本主要是Lisp,因为订单系统很小。后来我们又添加了两个模块,一个用C编写的图像生成器,一个主要用Perl编写的后台管理器。

2003年1月,雅虎发布了一个新版本的编辑器,用C++和Perl编写。不过很难说这个程序是否不再用Lisp编写,因为要把这个程序翻译成C++,他们实际上不得不编写一个Lisp解释器:据我所知,所有页面生成模板的源文件仍然是Lisp代码。(见Greenspun的第十条规则。)

[2] 罗伯特·莫里斯说,我不需要保密,因为即使我们的竞争对手知道我们在使用Lisp,他们也不会明白为什么:"如果他们那么聪明,他们早就在编程Lisp了。"

[3] 所有语言在图灵等价的意义上都是同等强大的,但这不是程序员关心的意义。(没有人想编程图灵机。)程序员关心的那种力量可能无法正式定义,但可以这样解释:它指的是在较弱的语言中只能通过编写解释器来获得的特性。如果语言A有一个去除字符串中空格的操作符,而语言B没有,这可能不会使A更强大,因为你可以在B中编写一个子程序来实现它。但如果A支持递归而B不支持,这可能不是通过编写库函数就能解决的问题。

[4] 注意,书呆子:或者可能是一个向顶部收敛的格子;重要的不是形状,而是存在至少一个偏序关系的想法。

[5] 将宏视为一个独立的特性是有点误导性的。在实践中,它们的有用性大大增强了,得益于其他Lisp特性,如词法闭包和剩余参数。

[6] 因此,编程语言的比较要么是宗教战争,要么是刻意保持中立的本科教科书,实际上是人类学作品。重视和平或想获得tenure的人会避开这个话题。但这个问题只有一半是宗教性的;如果你想设计新的语言,这里确实值得研究。