Featured image of post 超越平庸

超越平庸

探讨了编程语言选择对创业公司的影响,特别是Lisp语言的优势,以及为什么选择正确的技术栈对创业公司至关重要。

📚 返回 Paul Graham 文章目录

超越平庸

想要创办一家创业公司?申请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语言,以便能够hack Unix系统,以及Perl用于系统管理和cgi脚本编写。最后,真正认真的黑客应该考虑学习Lisp:学习Lisp值得,因为当你最终理解它时,你会获得深刻的启发;这种经历会让你在余下的日子里成为一个更好的程序员,即使你实际上并不经常使用Lisp本身。这就像人们常说的学习拉丁语的理由一样。它不会给你找到工作,除非可能是作为古典文学教授,但它会提升你的思维,让你在使用你真正想用的语言(如英语)时成为更好的写作者。

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

所以如果Lisp能让你成为更好的程序员,就像他说的那样,为什么你不想使用它呢?如果一个画家得到一支能让他成为更好画家的画笔,在我看来他会想在所有画作中都使用它,不是吗?我并不是在取笑Eric Raymond。总的来说,他的建议是好的。他对Lisp的说法基本上就是传统的智慧。但在传统智慧中存在一个矛盾:Lisp会让你成为更好的程序员,但你却不会使用它。

为什么不呢?编程语言毕竟只是工具。如果Lisp真的能产生更好的程序,你就应该使用它。如果不能,那谁需要它呢?

这不仅仅是一个理论问题。软件是一个非常具有竞争性的行业,容易形成自然垄断。在其他条件相同的情况下,能够更快更好地编写软件的公司会让其竞争对手倒闭。当你创办一家创业公司时,你会非常强烈地感受到这一点。创业公司往往是非成即败的命题。你要么变得富有,要么一无所有。在创业公司中,如果你押错了技术,你的竞争对手会把你击垮。

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

这在创业公司中尤其如此。在大公司中,你可以做所有其他大公司都在做的事情。但创业公司不能做所有其他创业公司都在做的事情。我认为很多人没有意识到这一点,即使在创业公司中也是如此。

普通大公司每年增长约10%。所以如果你在经营一家大公司,并且用普通大公司的方式做所有事情,你可以期望做得和普通大公司一样好——也就是说,每年增长约10%。

如果你在经营一家创业公司,当然也会发生同样的事情。如果你用普通创业公司的方式做所有事情,你应该期望得到普通的业绩。这里的问题是,普通业绩意味着你会倒闭。创业公司的存活率远低于50%。所以如果你在经营一家创业公司,你最好做一些与众不同的事情。如果不是,你就有麻烦了。

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

然而,这种新的自由是一把双刃剑。既然你可以使用任何语言,你就必须考虑使用哪一种。那些试图假装什么都没有改变的公司可能会发现他们的竞争对手并不这样认为。

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

如果其他公司不想使用Lisp,那就更好了。这可能会给我们带来技术优势,而我们需要所有能得到的帮助。当我们创办Viaweb时,我们在商业方面没有任何经验。我们对营销、招聘、融资或获取客户一无所知。我们俩甚至都没有过你所说的真正的工作。我们唯一擅长的是编写软件。我们希望这能拯救我们。在软件部门,我们会抓住任何能得到的优势。

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

这个实验的结果如何?有点令人惊讶的是,它成功了。我们最终有了很多竞争对手,大约有二十到三十个,但他们的软件都无法与我们的竞争。我们有一个运行在服务器上但感觉像桌面应用的所见即所得在线商店构建器。我们的竞争对手只有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个。

人们有时会问我Yahoo Store是否还在使用Lisp。是的,所有的Lisp代码都还在那里。Yahoo有使用Eric Raymond推荐给黑客的所有五种语言编写的服务器端软件。

Blub悖论

Lisp有什么了不起的?如果Lisp这么好,为什么不是每个人都在使用它?这些听起来像是修辞问题,但实际上它们有直接的答案。Lisp之所以如此伟大,不是因为只有信徒才能看到的某种神奇品质,而是因为它就是最强大的编程语言。而每个人都不使用它的原因是,编程语言不仅仅是技术,也是思维习惯,而没有什么比思维习惯变化得更慢。当然,这两个答案都需要解释。

我先说一个令人震惊的有争议的声明:编程语言在能力上是有差异的。

至少很少有人会否认,高级语言比机器语言更强大。今天的大多数程序员都会同意,你通常不想用机器语言编程。相反,你应该用高级语言编程,然后让编译器把它翻译成机器语言。这个想法现在甚至已经内置到硬件中:自1980年代以来,指令集就是为编译器而不是人类程序员设计的。

每个人都知道完全用手写机器语言来编写整个程序是一个错误。但不太常被理解的是,这里有一个更普遍的原则:如果你有几种语言可以选择,在其他条件相同的情况下,使用任何不是最强大的语言都是一个错误。[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,你不应该担心它不被广泛理解。你应该希望它保持这种状态。而且它很可能会。这是编程语言的本性,让大多数人对他们当前使用的任何语言都感到满意。计算机硬件变化得比个人习惯快得多,以至于编程实践通常比处理器落后十到二十年。在像MIT这样的地方,他们在1960年代初就开始用高级语言编写程序,但许多公司直到1980年代还在用机器语言编写代码。我敢打赌,很多人继续用机器语言编程,直到处理器,就像一个急于关门回家的酒保,最终通过切换到RISC指令集把他们赶了出去。

通常技术变化很快。但编程语言是不同的:编程语言不仅仅是技术,而且是程序员的思维方式。它们一半是技术,一半是宗教。[6]因此,中位数语言,也就是中位数程序员使用的语言,移动得像冰山一样慢。垃圾回收,由Lisp在1960年左右引入,现在被广泛认为是一件好事。运行时类型,同样,正在变得越来越流行。词法闭包,由Lisp在1970年代初引入,现在才刚刚进入人们的视野。宏,由Lisp在1960年代中期引入,仍然是未知领域。

显然,中位数语言有巨大的惯性。我不是在提议你可以对抗这种强大的力量。我提议的恰恰相反:像合气道练习者一样,你可以用它来对付你的对手。

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

如果你发现自己为创业公司工作,这里有一个评估竞争对手的实用技巧。阅读他们的职位列表。他们网站上的其他内容可能是库存照片或类似的文字,但职位列表必须具体说明他们想要什么,否则他们会得到错误的候选人。

在我们为Viaweb工作的那些年里,我读了很多职位描述。似乎每个月左右就会有一个新的竞争对手从某个地方冒出来。在检查他们是否有在线演示后,我要做的第一件事就是看他们的职位列表。经过几年的观察,我可以分辨出哪些公司需要担心,哪些不需要。职位描述中的IT味道越浓,公司就越不危险。最安全的是那些想要Oracle经验的公司。你永远不需要担心这些。如果他们说要C++或Java开发者,你也是安全的。如果他们想要Perl或Python程序员,那会有点可怕——这开始听起来像是一家至少技术方面是由真正的黑客管理的公司。如果我曾经看到过寻找Lisp黑客的职位发布,我会真的很担心。

注释

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

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

[2] Robert Morris说我不需要保密,因为即使我们的竞争对手知道我们在使用Lisp,他们也不会理解为什么:“如果他们那么聪明,他们早就用Lisp编程了。”

[3] 所有语言在图灵等价的意义上都是同等强大的,但这不是程序员关心的那种意义。(没有人想编程图灵机。)程序员关心的那种力量可能无法正式定义,但解释它的一种方式是,它指的是在较弱语言中只能通过为较强语言编写解释器才能获得的功能。如果语言A有一个删除字符串中空格的运算符,而语言B没有,这可能不会使A更强大,因为你可能可以在B中写一个子程序来做这件事。但如果A支持,比如说,递归,而B不支持,这不太可能是你能通过写库函数来修复的东西。

[4] 给极客的注释:或者可能是一个向顶部收窄的格;这里重要的不是形状,而是至少存在部分序的想法。

[5] 把宏当作一个单独的特性有点误导。在实践中,它们的实用性大大增强了其他Lisp特性,如词法闭包和剩余参数。

[6] 因此,编程语言的比较要么采取宗教战争的形式,要么采取如此坚决中立的本科教科书形式,以至于它们实际上是人类学著作。重视和平或想要终身教职的人避免这个话题。但这个问题只有一半是宗教性的;这里有一些值得研究的东西,特别是如果你想设计新的语言。

英文版:paulgraham.com/avg.html|中文版:HiJiangChuan.com/paulgraham/006-beating-the-averages

📚 返回 Paul Graham 文章目录

更新记录: