击败平均水平
想开始创业吗? 获得Y Combinator的资助。
2001年4月,修订于2003年4月
(本文源自2001年Franz开发者研讨会上的演讲。)
1995年夏天,我的朋友 Robert Morris 和我创办了一家名为 Viaweb 的创业公司。我们的计划是编写软件,让最终用户能够构建在线商店。当时,这款软件的新颖之处在于它运行在我们的服务器上,使用普通的网页作为界面。
当然,很多人可能同时都有这个想法,但据我所知,Viaweb 是第一个基于 Web 的应用程序。这个想法对我们来说太新颖了,所以我们用它来命名公司:Viaweb,因为我们的软件通过 Web 工作,而不是在你的桌面电脑上运行。
这款软件的另一个不寻常之处在于,它主要使用一种名为 Lisp 的编程语言编写。它是最早用 Lisp 编写的大型最终用户应用程序之一,在此之前,Lisp 主要在大学和研究实验室中使用。[1]
秘密武器
Eric Raymond 写了一篇名为“如何成为黑客”的文章,在其中,他告诉有志成为黑客的人应该学习哪些语言。他建议从 Python 和 Java 开始,因为它们很容易学习。严肃的黑客还会想学习 C,以便破解 Unix,以及 Perl 用于系统管理和 cgi 脚本。最后,真正严肃的黑客应该考虑学习 Lisp:
学习 Lisp 值得,因为当你最终掌握它时,你会获得深刻的启发体验;这种体验会让你在余下的日子里成为一名更好的程序员,即使你实际上很少使用 Lisp 本身。
这和你经常听到的学习拉丁语的理由是一样的。它不会给你带来一份工作,除非是当古典文学教授,但它会提升你的思维,让你在你想要使用的语言(如英语)中成为一名更好的作家。
但是等等。这个比喻不能延伸那么远。拉丁语不能给你带来工作的原因是没有人说它。如果你用拉丁语写作,没有人能理解你。但是 Lisp 是一种计算机语言,计算机说的是你,程序员,告诉它们的任何语言。
所以如果 Lisp 让你成为一名更好的程序员,就像他说的那样,你为什么不想使用它呢?如果一位画家被提供一支能让他成为一名更好的画家的画笔,在我看来,他会想在所有的画作中使用它,不是吗?我不是想取笑 Eric Raymond。总的来说,他的建议是好的。他关于 Lisp 的说法在很大程度上是传统的智慧。但是传统的智慧中存在一个矛盾:Lisp 会让你成为一名更好的程序员,但你却不会使用它。
为什么不呢?毕竟,编程语言只是工具。如果 Lisp 真的能产生更好的程序,你应该使用它。如果它不能,那么谁需要它呢?
这不仅仅是一个理论问题。软件是一个竞争非常激烈的行业,容易出现自然垄断。一家能够更快更好地编写软件的公司,在所有其他条件相同的情况下,会让它的竞争对手倒闭。当你开始创业时,你会非常敏锐地感受到这一点。创业公司往往是一个要么全有要么全无的主张。你要么变得富有,要么一无所获。在一家创业公司中,如果你押注于错误的技术,你的竞争对手会击垮你。
Robert 和我都精通 Lisp,我们看不到任何理由不相信我们的直觉而选择 Lisp。我们知道其他所有人都在用 C++ 或 Perl 编写他们的软件。但我们也知道这并不意味着什么。如果你以这种方式选择技术,你就会运行 Windows。当你选择技术时,你必须忽略其他人在做什么,而只考虑什么才是最有效的。
在一家创业公司中,尤其如此。在一家大公司中,你可以做所有其他大公司都在做的事情。但是一家创业公司不能做所有其他创业公司都在做的事情。我不认为很多人意识到这一点,即使是在创业公司中。
普通的大公司每年增长约百分之十。所以如果你经营一家大公司,并且你所做的一切都像普通的大公司一样,你可以期望做得和普通的大公司一样好——也就是说,增长约百分之十。
当然,如果你经营一家创业公司,同样的事情也会发生。如果你所做的一切都像普通的创业公司一样,你应该期望获得平均水平的业绩。这里的问题是,平均水平的业绩意味着你将倒闭。创业公司的存活率远低于百分之五十。所以如果你经营一家创业公司,你最好做一些奇怪的事情。如果不是,你就有麻烦了。
早在 1995 年,我们就知道一些我不认为我们的竞争对手理解的事情,而且现在也很少有人理解:当你编写只需要在你自己的服务器上运行的软件时,你可以使用任何你想要的语言。当你编写桌面软件时,有一种强烈的偏见,倾向于用与操作系统相同的语言编写应用程序。十年前,编写应用程序意味着用 C 编写应用程序。但是对于基于 Web 的软件,特别是当你拥有语言和操作系统的源代码时,你可以使用任何你想要的语言。
然而,这种新的自由是一把双刃剑。现在你可以使用任何语言,你必须考虑使用哪一种。试图假装什么都没改变的公司可能会发现他们的竞争对手并没有这样做。
如果你可以使用任何语言,你使用哪一种?我们选择了 Lisp。首先,很明显,快速开发在这个市场上非常重要。我们都是从零开始,所以一家能够在竞争对手之前完成新功能的公司将拥有很大的优势。我们知道 Lisp 是一种非常好的快速编写软件的语言,而基于服务器的应用程序放大了快速开发的效果,因为你可以在软件完成的那一刻发布它。
如果其他公司不想使用 Lisp,那就更好了。它可能会给我们带来技术优势,我们需要所有我们能得到的帮助。当我们创办 Viaweb 时,我们没有任何商业经验。我们对营销、招聘人员、筹集资金或获得客户一无所知。我们俩甚至都没有你所说的真正的工作。我们唯一擅长的是编写软件。我们希望这能拯救我们。我们可以在软件部门获得的任何优势,我们都会抓住。
所以你可以说使用 Lisp 是一次实验。我们的假设是,如果我们在 Lisp 中编写我们的软件,我们将能够比我们的竞争对手更快地完成功能,并且还能够在我们的软件中做他们无法做到的事情。而且因为 Lisp 是如此高级,我们不需要一个庞大的开发团队,所以我们的成本会更低。如果是这样,我们可以以更少的钱提供更好的产品,并且仍然可以盈利。我们将最终获得所有的用户,而我们的竞争对手将一无所获,并最终倒闭。无论如何,这就是我们希望发生的事情。
这个实验的结果是什么?有点令人惊讶的是,它奏效了。我们最终有很多竞争对手,大约有二三十个,但他们没有一个软件能与我们的竞争。我们有一个 wysiwyg 在线商店构建器,它运行在服务器上,但感觉像一个桌面应用程序。我们的竞争对手有 cgi 脚本。而且我们在功能方面总是遥遥领先于他们。有时,在绝望中,竞争对手会试图推出我们没有的功能。但是有了 Lisp,我们的开发周期非常快,以至于我们有时可以在竞争对手在新闻稿中宣布新功能后的一两天内复制它。在报道新闻稿的记者打电话给我们时,我们也会有新功能。
我们的竞争对手一定觉得我们有什么秘密武器——我们正在破译他们的 Enigma 流量或其他什么。事实上,我们确实有秘密武器,但它比他们意识到的要简单。没有人向我们泄露他们的功能。我们只是能够以比任何人想象的更快的速度开发软件。
大约九岁的时候,我碰巧得到了一本 Frederick Forsyth 的《豺狼之日》。主角是一名被雇佣来刺杀法国总统的刺客。刺客必须通过警察才能到达可以俯瞰总统路线的公寓。他装扮成一个拄着拐杖的老人,直接从他们身边走过,他们从未怀疑他。
我们的秘密武器与之类似。我们用一种奇怪的 AI 语言编写我们的软件,这种语言有一种充满括号的怪异语法。多年来,听到 Lisp 以这种方式描述让我很恼火。但现在它对我们有利。在商业中,没有什么比竞争对手不理解的技术优势更有价值的了。在商业中,就像在战争中一样,出其不意与武力一样重要。
所以,我有点不好意思地说,在我们在 Viaweb 工作期间,我从未公开谈论过 Lisp。我们从未向媒体提及它,如果你在我们的网站上搜索 Lisp,你只会找到我的简历中的两本书的书名。这绝非偶然。一家创业公司应该给它的竞争对手尽可能少的信息。如果他们不知道我们的软件是用什么语言编写的,或者不在乎,我想保持这种状态。[2]
最了解我们技术的人是客户。他们也不在乎 Viaweb 是用什么语言编写的,但他们注意到它运行得非常好。它让他们可以在几分钟内构建出外观精美的在线商店。因此,主要通过口口相传,我们获得了越来越多的用户。到 1996 年底,我们有大约 70 家在线商店。到 1997 年底,我们有 500 家。六个月后,当 Yahoo 收购我们时,我们有 1070 个用户。今天,作为 Yahoo Store,这款软件继续主导着它的市场。它是 Yahoo 更有利可图的部分之一,用它构建的商店是 Yahoo Shopping 的基础。我于 1999 年离开了 Yahoo,所以我不知道他们现在有多少用户,但我最后一次听说大约有 20,000 个。
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。
通过归纳,唯一能够看到各种语言之间所有威力差异的程序员是那些理解最强大语言的程序员。(这可能就是 Eric Raymond 所说的 Lisp 让你成为一名更好的程序员的原因。)你不能相信其他人的意见,因为 Blub 悖论:他们对他们碰巧使用的任何语言都感到满意,因为它决定了他们思考程序的方式。
我从我自己的经验中知道这一点,当时我还是一个高中生,用 Basic 编写程序。这种语言甚至不支持递归。很难想象在不使用递归的情况下编写程序,但我当时并不怀念它。我用 Basic 思考。而且我在这方面是个天才。我所调查的一切的主人。
Eric Raymond 推荐给黑客的五种语言位于威力连续统一体中的不同位置。它们彼此之间的相对位置是一个敏感的话题。我要说的是,我认为 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 的威力因你的竞争对手不了解它而倍增。
如果你考虑在一家创业公司中使用 Lisp,你不应该担心它没有被广泛理解。你应该希望它保持这种状态。而且它很可能会这样。编程语言的本质是让大多数人对他们目前使用的任何语言感到满意。计算机硬件的变化速度比个人习惯快得多,因此编程实践通常比处理器落后十年到二十年。在 MIT 等地方,他们在 20 世纪 60 年代初用高级语言编写程序,但许多公司一直用机器语言编写代码,直到 20 世纪 80 年代。我敢打赌,很多人一直用机器语言编写代码,直到处理器,就像一个急于关门回家调酒师一样,最终通过切换到 risc 指令集将他们踢出去。
通常情况下,技术变化很快。但是编程语言是不同的:编程语言不仅仅是技术,而且是程序员思考的方式。它们一半是技术,一半是宗教。[6] 因此,中位数语言,意味着中位数程序员使用的任何语言,移动得像冰山一样缓慢。垃圾回收,由 Lisp 在大约 1960 年引入,现在被广泛认为是件好事。运行时类型,同上,越来越受欢迎。词法闭包,由 Lisp 在 20 世纪 70 年代初引入,现在,勉强出现在雷达屏幕上。宏,由 Lisp 在 20 世纪 60 年代中期引入,仍然是未知领域。
显然,中位数语言具有巨大的动力。我不是建议你可以对抗这种强大的力量。我建议的恰恰相反:就像合气道的练习者一样,你可以利用它来对付你的对手。
如果你为一家大公司工作,这可能不容易。你很难说服那些刚在报纸上读到某种语言(就像 20 年前的 Ada 一样)即将接管世界的尖头老板让你用 Lisp 构建东西。但是如果你为一家还没有尖头老板的创业公司工作,你可以像我们一样,将 Blub 悖论转化为你的优势:你可以使用你的竞争对手(牢牢地固定在中位数语言上)永远无法匹敌的技术。
如果你发现自己为一家创业公司工作,这里有一个评估竞争对手的便捷技巧。阅读他们的招聘信息。他们网站上的其他一切都可能是库存照片或散文等价物,但招聘信息必须具体说明他们想要什么,否则他们会得到错误的候选人。
在我们在 Viaweb 工作的几年里,我读了很多职位描述。似乎每个月左右都会出现一个新的竞争对手。在检查他们是否有在线演示之后,我做的第一件事就是查看他们的招聘信息。经过几年的这样做,我可以分辨出哪些公司需要担心,哪些公司不需要担心。招聘信息的信息技术味道越浓,公司就越不危险。最安全的是那些需要 Oracle 经验的公司。你永远不必担心那些。如果他们说他们想要 C++ 或 Java 开发人员,你也很安全。如果他们想要 Perl 或 Python 程序员,那会有点吓人——这听起来像是一家至少技术方面由真正的黑客运营的公司。如果我曾经看到过寻找 Lisp 黑客的招聘信息,我会非常担心。
注释
[1] Viaweb 最初有两个部分:编辑器,用 Lisp 编写,人们用它来构建他们的网站;以及订购系统,用 C 编写,处理订单。第一个版本主要是 Lisp,因为订购系统很小。后来我们又添加了两个模块,一个用 C 编写的图像生成器,以及一个主要用 Perl 编写的后台管理器。
2003 年 1 月,Yahoo 发布了一个用 C++ 和 Perl 编写的新版本的编辑器。很难说这个程序是否不再用 Lisp 编写,因为为了将这个程序翻译成 C++,他们实际上必须编写一个 Lisp 解释器:据我所知,所有页面生成模板的源文件仍然是 Lisp 代码。(参见格林斯潘第十定律。)
[2] Robert Morris 说我不需要保密,因为即使我们的竞争对手知道我们正在使用 Lisp,他们也不会理解为什么:“如果他们那么聪明,他们已经在用 Lisp 编程了。”
[3] 所有语言在图灵等价的意义上都同样强大,但这不是程序员关心的词义。(没有人想为图灵机编程。)程序员关心的那种威力可能无法正式定义,但解释它的一种方法是说它指的是你只能在威力较弱的语言中通过在其中编写更强大语言的解释器才能获得的功能。如果语言 A 有一个从字符串中删除空格的运算符,而语言 B 没有,这可能不会使 A 更强大,因为你可能可以在 B 中编写一个子程序来完成它。但是,如果 A 支持递归,而 B 不支持,那么这不太可能通过编写库函数来解决。
[4] 给书呆子的提示:或者可能是一个格子,向上变窄;重要的不是形状,而是至少存在一个偏序的想法。
[5] 将宏视为一个单独的功能有点误导。在实践中,它们的有用性通过其他 Lisp 功能(如词法闭包和 rest 参数)大大增强。
[6] 因此,编程语言的比较要么采取宗教战争的形式,要么采取本科教科书的形式,这些教科书坚定地保持中立,以至于它们实际上是人类学著作。珍视和平或想要终身教职的人会避免这个话题。但这个问题只有一半是宗教问题;那里有一些值得研究的东西,特别是如果你想设计新的语言。