### 12.拒絕平庸
1995年,羅伯特·莫里斯和我一起創辦了Viaweb。我們打算開發軟件,讓用戶可以自己搭建網上商店。當時,我們的創意是把軟件放在服務器端,使用普通的網頁作為用戶界面。
當然,那個時候許多人可能都想到過這個主意。但是,就我所知,Viaweb是第一個互聯網應用程序。在我們看來,這真的是很新穎的想法,所以我們就把公司命名為Viaweb,意即我們的軟件通過網絡使用,而不是運行在你的桌面電腦上^。
^「在英語中,via是一個介詞,意為“經過……”,所以Viaweb的意思就是經過網絡。——譯者注」
另一個特別之處是,這個軟件主要采用Lisp語言開發^。它是最早的用Lisp語言開發的大型應用程序,在此之前,Lisp語言主要用于大學和實驗室中。
^「一開始的時候,Viaweb有兩個部分——編輯器和訂單處理系統。前者用Common Lisp開發,主要供用戶搭建自己的網站。后者用C語言開發,主要用來處理訂單。在Viaweb的第一版中,Lisp是最主要的開發語言,因為訂單處理系統非常小,占用的代碼很少。2003年1月,Yahoo發布了Viaweb編輯器的新版本,采用C++和Perl開發。但是,為了把原始程序翻譯成C++,他們可能不得不專門寫一個Lisp解釋器,因為據我所知,Viaweb所有的頁面生成模板還沒變,都是使用Lisp代碼。(參見Greenspun寫的Tenth Rule一書第198頁。)」
### 秘密武器
埃里克·雷蒙德寫過一篇文章《如何成為一個黑客》(How to Become aHacker)。文中有一部分專門談到,在他看來,如果你想當一個黑客,應該學習哪些語言。他建議從Python和Java入手,因為它們比較容易學。想當高級一點的黑客,還應該學習C和Perl。前者用來對付Unix系統,后者用來系統管理和開發CGI腳本。最后,真正非常嚴肅地把黑客作為人生目標的人,應該考慮學習Lisp:
> Lisp很值得學習。你掌握它以后,會感到它給你帶來的極大啟發。這會大大提高你的編程水平,使你成為一個更好的程序員。盡管在實際工作中極少會用到Lisp。
在討論學習拉丁語有何價值時,你往往也會聽到這一類的話。拉丁語無助于你找工作(也許古典文學教授的工作除外),但是它可以訓練你的思維,幫助你更好地運用母語(比如英語)進行寫作。
但是且慢,拉丁語的比喻并不完全適合Lisp語言。拉丁語無助于你找工作的原因是因為沒有人說拉丁語。如果你用它寫作,沒有人能看懂。但是,Lisp是一種計算機語言,無論我們程序員使用哪一種語言與計算機交談,它都能聽懂。
如果埃里克·雷蒙德沒有說錯,Lisp語言確實可以使你成為更好的程序員,那么為什么你不使用它編程呢?如果畫家有一支讓他畫得更好的畫筆,我覺得他應該會用這支筆完成所有的畫作,對不對?我在這里不是想證明埃里克·雷蒙德錯了。他的觀點整體上非常正確,他對Lisp語言的看法確實是大多數人的看法,但是這里面就是有一個矛盾:Lisp語言能讓你成為更好的程序員,但你卻不用它,這難道不奇怪嗎?
為什么不用呢?編程語言畢竟是一種工具。如果Lisp語言真的能開發出更好的程序,你就應該用它。如果它無助于編程,那么就不會有人需要它。
這不僅僅是一個理論問題。軟件業是競爭非常激烈的行業,而且容易出現壟斷。在不考慮其他情況的條件下,某家公司的軟件更快更好用,就會把競爭者趕出這個市場。一旦你開始創業,你就會更深切地感受到這一點。一般情況是,創業公司要么贏得一切,要么徹底失敗。你要么成為富翁,要么一無所獲。創業的時候,如果你選擇了錯誤的技術,競爭對手就會一舉打敗你。
羅伯特·莫里斯和我都很了解Lisp語言,我們相信自己的直覺,找不出任何不使用它的理由。我們知道其他人都用C++或Perl開發軟件, 但是我們不覺得這說明了什么問題。如果別人用什么技術,你也用什么技術,那么你大概只能使用Windows了。選擇使用哪一種技術的時候,你不能考慮別人的做法,只能考慮什么樣的技術能最好地完成工作。

圖12-1 我和羅伯特·莫里斯在Viaweb,1996年年初
創業公司尤其如此。大公司可以互相模仿,但是創業公司就不行。我覺得很多人沒有意識到這一點,尤其是一些創業者。
大公司每年平均成長大約10%。所以,如果你掌管一家大公司,只要每件事都做到大公司的平均水準,你就能得到大公司的平均結果,也就是每年成長大約10%。
如果你掌管創業公司,當然也可以這樣。你把每件事都做到平均水準,就能得到平均結果。問題在于,小公司的平均結果就意味著關門倒閉。創業公司的生存率遠低于50%。所以,如果你掌管創業公司,最好做一些獨特的事情,否則就會有麻煩。
回到1995年,我們懂得一些競爭對手不懂的事情(至少在我們看來是如此),這些事情甚至直到今天都很少有人懂:如果開發只在自己服務器上運行的軟件,這意味著你想用什么語言就能用什么語言。如果開發桌面軟件,就完全不一樣了,大多數情況下你只能使用操作系統所用的開發語言。10年前,開發桌面軟件就意味著要使用C語言。但是,對于互聯網軟件,你能使用任何你想用的語言。如果你還同時擁有操作系統和語言的源碼,那么你的自由就更大了。
但是,這種新出現的自由是一把雙刃劍。既然你可以使用任何語言,你就不得不思考到底使用哪一種語言。如果你的公司對這種選擇的自由視而不見,而競爭對手看到了,那么你就有被擊敗的危險。
如果選擇哪種語言都行,你到底使用哪一種語言?我們選擇Lisp。首先,很明顯,對于這個市場來說,快速開發出產品是很重要的。我們所有人都是從零開始,所以能夠快速做出新功能的公司就會取得巨大的競爭優勢。我們知道Lisp語言真的非常合適快速開發軟件,而且我們的軟件運行在服務器端,你一寫完代碼就能發布出去,所以這又進一步放大了快速開發的效果。
如果其他公司不想使用Lisp語言,那就更好了。這會讓我們擁有技術優勢。我們不能放過任何有利的因素。創辦Viaweb的時候,我們對于如何經營一家公司毫無經驗,對市場推廣、雇用員工、融資、發展新客戶等都一無所知。在此之前,我和莫里斯甚至連一夭正式上班的經歷都沒有。我們唯一擅長的事情就是開發軟件。我們希望這一點可以彌補我們的劣勢。任何在軟件開發上面有助于我們獲得優勢的事情我們都不能放過。
可以這樣說,我們使用Lisp只是一個大膽的冒險。我們設想如果用Lisp語言開發自己的軟件,就能比競爭對手更快地寫出新功能,還能做到他們做不到的事情。同時,因為Lisp是一種抽象層次非常高的語言,所以就不需要非常龐大的開發團隊,這會降低成本。如果我們的設想是正確的,那么我們就能用更少的錢做出一個更好的產品,從而獲得利潤。最終,我們將獨占市場,競爭對手什么也得不到,到頭來只能退出這個行業。我們當時心里就是這么盤算的。
這次冒險的結果如何?多少有點出人意料,它竟然達到了我們的設想。我們前前后后遭遇到很多競爭對手,一共大概有二三十個,但是他們的軟件沒有一個能與我們競爭。我們的軟件運行在服務器端,用戶可以“所見即所得”地搭建網上商店,感覺就像在操作桌面軟件。我們的競爭對手使用CGI腳本。我們在功能上總是遙遙領先于他們。有時,他們出于絕望,試圖引入我們沒有的功能。但是,有了Lisp語言的幫助,我們的開發周期很短。有時候,競爭對手剛剛發布新聞稿宣布將引入新功能,我們就能在一兩天內做出自己的版本。當對手找來的記者抽出時間打電話過來想了解我們的反應,我們就會告訴他我們已經有了這個功能。
競爭對手一定覺得我們好像擁有了某種秘密武器,能夠破解他們內部的通信或者其他機密。事實上,我們的確擁有秘密武器,但是沒他們想的那么復雜。從來沒有人向我們泄露他們的內部機密,只是我們的開發速度比別人想象的更快而已。
9歲時,我碰巧讀過弗雷德里克·福賽思的小說《刺殺戴高樂》(The Day of the Jackal)。小說的主角是一個刺客,有人雇他暗殺法國總統。那個刺客必須通過警察的崗哨才能到達可以俯視總統行進路線的公寓。他扮成柱著拐杖的老頭從警察身邊經過,沒有引起任何人的懷疑。
我們的秘密武器很類似上面的情景。我們使用一種奇特的人工智能語言開發軟件,它的語法非常古怪,大量使用括號。多年來,要是聽到別人這樣描述Lisp語言,我會勃然大怒。但是現在,這卻成了我們的優勢。在競爭中,你的對手無法理解你的技術優勢,這可是再寶貴不過了。商場如戰場,對手摸不透你,你的勝算就增加了。
雖然有些令人難為情,但是我必須承認,就是因為這個原因,在Viaweb創業期間我從來沒有公開談論過Lisp語言。我們對新聞媒體閉口不談Lisp,如果你在我們的網站上捜索Lisp,只會發現我在個人介紹中提到過兩次,那是我寫的兩本關于Lisp的書。這是故意的,創業公司對競爭對手應該越保密越好。如果他們不知道(或者不關心)我們的軟件用什么語言開發,我就要把這個秘密保持下去^。
^「莫里斯覺得不用這么保密,因為即使競爭對手知道我們使用Lisp語言,對他們也不會有幫助:“如果他們真的聰明,早就已經在用Lisp編程了。”」
最了解我們技術的人就是客戶。他們不關心Viaweb用什么語言開發,但是發現它真的很好用。Viaweb可以讓用戶在幾分鐘內搭建起漂亮的網上商店。因此,主要通過口碑效應,我們得到了越來越多的新客戶。1996年年底,我們支持的網上商店大約是70家。1997年,變成了500家。6個月后,雅虎收購我們的時候,我們有1070個用戶。更名為Yahoo Store之后,這個軟件繼續主導市場,它是雅虎獲利最豐厚的業務之一,用它搭建的商店成為“雅虎購物”(Yahoo Shopping)的基礎。我在1999年離開了雅虎,所以不知道現在的準確用戶數量,但是我上一次聽到的數字是超過了2萬。
### Blub困境
Lisp語言到底好在什么地方?如果它真的這么好,為什么沒有得到廣泛使用呢?這種問題聽起來有點像繞口令,但是實際上回答起來很簡單。Lisp語言的好處不在于它有一些狂熱愛好者才明白的優點,而只在于它是目前最強大的編程語言。它沒有得到廣泛使用的原因就是因為編程語言不僅僅是技術,也是一種習慣性思維,非常難于改變。當然,上面兩句話都需要進一步解釋。
我先從一個爭議極大的命題開始講起:編程語言的編程能力有差異。至少不會有人反對高級語言比機器語言更強大這一觀點。今天的大多數程序員通常情況下都不會想用機器語言編程,而是使用一種高級語言,然后再讓編譯器幫你把它翻譯成機器語言。這種觀念甚至已經移植到了硬件,從20世紀80年代開始,硬件的指令集都是針對編譯器而不是針對程序員設計的。
大家都知道,徒手用機器語言寫出整個程序是一件很蠢的事。但是,把這個觀點推廣到一種更普遍的情況,知道的人就不多了。如果你有好幾種語言可以選擇,在不考慮其他因素的情況下,你不選擇最強大的那種語言就是一件很蠢的事^。
^「如果從圖靈等價(Turing-equivatent)的角度來看,所有語言都是一樣強大的,但是這對程序員沒有意義。(沒人想為圖靈機編程。)程序員關心的那種強大也許很難正式定義,但是有一個辦法可以解釋,那就是有一些功能在一種語言中是內置的,但是在另一種語言中需要修改解釋器才能做到,那么前者就比后者更強大。如果A語言有一個運算符,可以移除字符串中的空格,而B語言沒有這個運算符,這可能不足以稱A語言比B語言強大,因為你可以在B語言里寫一個函數實現這個功能。但是,如果A語言支持某種高級功能(假定是遞歸),而B語言不支持,你就不可能通過自己編寫函數庫解決了,所以這就代表A語言比B語言更強大。」
上面這個觀點有許多例外情況。如果在開發的程序必須與另一個程序緊密配合,那么可能最好還是使用后者的開發語言。如果你的程序只是要做一些很簡單的事(比如整數運算或者位操作),那就不妨使用一種比較靠近機器的低層次語言,主要原因是這樣運行起來會更快一些。如果你的程序很短,只是為了特定場合一次性使用,那么你最好根據自己要解決的問題選擇具有最強大函數庫的語言,不過,總的來看,對于應用程序來說,還是應該選擇總體最強大、效率也在可接受范圍內的編程語言,否則都是不正確的選擇,就好像你選擇機器語言編程一樣,只是程度上有差異而已。
大家都公認機器語言屬于非常低層次的語言。但是,至少在社會上很多人眼里,高級語言其實也差不多。但事實并非如此,高級語言與機器語言的差別很大。從技術上看,“高級語言”并不是一個定義很清晰的名詞。在高級語言與機器語言之間并不存在一條明確的分界線。語言的抽象性是一條連續曲線,從最強大的語言一直到最底層的機器語言,每一種語言的能力都有差異^。
^「語言之間的關系或許還可以比喻成柵格結構(lattice),從下往上朝著頂端慢慢收窄。具體的形狀在這里并不重要,重點是語言之間至少存在著一種偏序關系(partial order)。」
以Cobol語言為例,通過編譯器,它可以被編譯成機器語言。從這個角度來說它是一種高級語言。但是,有誰會真的把Cobol當成與其他高級語言(比如Python)—樣強大的語言?比起Python,它可能更接近機器語言。
Perl 4如何?與Perl 5相比,它不支持閉包。所以,大多數Perl的黑客都認為Perl 5比Perl 4更強大。如果你同意這一點,就意味著你也認可一種高級語言可以比另一種高級語言更強大。因此,必然能夠接著推導出,除了某些特殊情況,你就是應該使用目前最強大的語言。
不過在現實中這個結論很少能落實。到了一定年齡之后,程序員極少主動更換自己的編程語言。不管習慣使用的是哪一種語言,他們往往認為這種語言已經足夠好了。
程序員非常忠于他們心愛的語言,我不想傷害任何人的感情,所以為了解釋我的觀點,我假設有一種Blub語言。它的抽象程度正好落在編程能力曲線的中點。它不是最強大的語言,但是要比Cobol或機器語言更高級。
我們假設Blub程序員既不使用機器語言也不使用Cobol語言。他認為前者是編譯器的工作,后者他不知道有什么用(Cobol語言甚至連XX功能也沒有,Blub語言就具備這個功能)。
只要這位程序員向曲線下方望去,他就肯定知道自己正在看的是一些比較低層次的語言。因為那些語言明顯不如Blub語言強大,缺少他習慣使用的某些功能。但是,當他向曲線上方望去,他不會意識到自己正在看更高層次的語言,而是僅僅覺得自己正在看某些奇怪的語言。他可能認為那些語言也許與Blub一樣強大,但是加入了不少怪東西。他覺得Blub語言已經夠用了,不用再考慮那些語言了。這時,他的思維就是已經被Blub同化了。
但是,當我們轉換視角,把自己想象成使用曲線更上方某一種語言的程序員并往下看的時候,我們就會發現,自己也同樣輕視Blub語言。你怎么用Blub語言完成工作呢?它甚至連YY功能都沒有!
通過歸納法我們就會知道,唯一洞悉所有語言優劣的人必然是懂得最強大的那種語言的人。(這大概就是埃里克·雷蒙德所說的Lisp語言使你成為一個更好的程序員的意思。)由于Blub困境的存在,你無法信任其他人的意見:他們都滿足于自己碰巧用熟了的那種語言,他們的編程思想都被那種語言主宰了。
我自己的經歷也證實了這個看法。高中時我喜歡用Basic語言編程。這種語言功能很弱,甚至不支持遞歸,很難想象沒有遞歸還怎么編程。但是我那時根本沒覺得有損失,Basic語言控制了我的思維。當時我非常精通Basic語言,只要是學過的部分都能熟練地使用。
雷蒙德推薦的五種黑客應該學會的語言,其強大程度各有不同,分布在編程能力曲線五個不同的點上。它們的相對位置是一個敏感的話題。我只想說,我認為,Lisp語言在最上方。為了證明這個論斷,讓我告訴你,我發現Lisp有一個功能,其他四種語言都沒有。我覺得,沒有宏(macro)的話,那些語言怎么編程呢^?
^「把宏說成一種獨立的功能有誤導之嫌。在實際運用中,如果沒有其他Lisp功能(比如閉包和函數的rest參數)的配合,Lisp的宏也不會有太大作用。」
許多語言自稱也有宏,但是Lisp的宏是獨一無二的。信不信由你,Lisp宏的作用與括號有關。Lisp語言的設計者大量使用括號并不是為了標新立異。Blub語言的程序員會覺得Lisp代碼看上去很怪,有那么多括號,但這是有原因的。它們是Lisp與其他語言存在巨大差異的外在表現。
Lisp代碼由Lisp數據對象構成。其他語言的源代碼一般由字符組成,字符串是主要數據類型之一,但是Lisp語言不完全是這樣。經過解析器處理之后,Lisp代碼就變成了你可以遍歷的數據結構。
如果你理解編譯器的工作原理,那么事實是,與其說Lisp有一種很奇特的語法,還不如說它根本沒有語法。一般的源代碼程序經過編譯器解析會生成解析樹。Lisp的奇特之處就在于,你可以完全寫出程序,控制這種解析樹,進行任意的存取操作。Lisp的這種程序就叫做宏,它們可以用來生成其他程序。
生成其他程序的程序?什么時候需要用到它們?如果你用Cobol語言思考,會覺得很少需要用到它們。如果你用Lisp語言思考,會發現它們無所不在。我要是在這里舉一個Lisp宏功能強大的實例,可能更便于說明問題。你看這個例子!是不是很方便啊?但是如果這樣做,對于不懂Lisp語言的人來說,這篇文章就不知所云了。本文沒有辦法把所有事情都解釋清楚,無法幫助你徹底理解這門語言。我在Ansi Common Lisp一書中已經盡可能地簡化內容、快速講解,但是也要到全書篇幅將近一半的地方(第11章)才能講到宏。
但是我想可以給出事實證明我的這個觀點。Viaweb編輯器的源碼之中大約20%~25%是宏。它們比普通的Lisp函數難寫,而且如果用在不必要的地方,反而是一種很不良的編程習慣。所以,我們代碼中的每一個宏都有充分的使用理由。這意味著這個程序至少20%~25%代碼的功能無法輕易地用其他語言實現。我在前文一再聲稱Lisp語言無比強大,無論Blub語言的程序員對此多么懷疑,看到這個事實應該足以讓他感到很好奇,我們居然用到了這么多宏。我們這樣寫代碼并不是為了好玩。我們是一家小創業公司,拚盡全力寫代碼,只是為了給競爭對手布下重重障礙,不讓他們趕上來。
抱有懷疑態度的人可能會想上面的論斷是否成立,兩者之間是否存在相關關系。我們的一大塊代碼能夠做到其他語言很難做到的事。只憑這一點是否能得出結論:我們的軟件能夠做到競爭對手的軟件做不到的事?我必須說,這里面可能就是存在相關關系。我鼓勵你繼續深入思考這個問題。表面上,一個老年人拄著拐杖蹣跚而行,你不要只是看看而已,他背后可能有更多的故事值得了解,你應該想得更深一些。
### 創業公司的合氣道^
^「合氣道(Aikido)是一種日本的武術,主要特點是“以柔克剛”、“借勁使力”、“不主動攻擊”。——譯者注」
盡管Lisp語言非常強大,但是我并不期望有誰(超過25歲的人)讀完這篇文章就立刻開始學習它。我寫這篇文章的目的不是想改變任何人的觀點,而是想讓那些有興趣學習Lisp語言的人放心,他們知道Lisp是一種強大的語言,但是擔心使用者太少,學會了也沒什么用。我想讓他們明白,在商業競爭中使用Lisp語言就會帶來優勢。你的競爭對手不懂Lisp,這將使得它的強大更充分地表現出來。
如果你想在創業公司中使用Lisp語言,你不僅不應該擔心使用它的人太少,反而應該希望這種局面保持下去。事實上,現狀很可能真的會保持下去。因為編程語言的特點之一就是它會使得大多數使用它的人滿足于現狀,不想改用其他語言。人類天性變化的速度大大慢于計算機硬件變化的速度,所以編程語言的發展通常比CPU的發展落后一二十年。在麻省理工學院這樣的地方,20世紀60年代初就開始使用高級語言了。但是,許多公司直到80年代還在用機器語言編程。我敢打賭,很多人對機器語言戀戀不舍,直到CPU開始采用精簡指令集^了才不得不放棄使用機器語言。這就好比酒吧已經到了打烊時間,酒保開始整理桌子、收拾東西準備回家,客人才被迫離開。
^「精簡指令集計算機(Reduced Instruction Set Computer,簡稱RISC)是CPU的一種架構,對指令數目和尋址方式都做了精簡,使其實現更容易,執行速度更快,編譯器的效率更高。它在20世紀80年代開始得到大規模采用。——譯者注」
技術的變化速度通常是很快的。但是,編程語言不一樣,與其說它是技術,還不如說是程序員的思考模式。編程語言是技術和宗教的混合物^。所以,一種很普通的編程語言就是很普通的程序員使用的語言,它的變化就像冰山那樣緩慢。大概在1960年,Lisp語言引入了垃圾回收機制(Garbage Collection),今天已經被廣泛認為是非常好的做法。Lisp的動態類型特點也同樣受到越來越多人的認同。閉包是20世紀60年代Lisp語言引入的功能,現在的接受程度還很低。宏也是60年代中期Lisp語言引入的,現在還是一片處女地。
^「所以,如果你想對編程語言進行比較,那就做好準備打一場宗教戰爭,或者索性就寫一本絕對不帶個人色彩的大學教材,枯燥得像人類學研究一樣。那些喜歡平靜生活的人以及想要得到終身教職的人對這個話題唯恐避之不及。但是,必須承認的是,它只是一半與宗教有關,所以剩下的一半依然值得研究,尤其是當你要設計新語言的時候。」
很顯然,那些很普通的編程語言正在主導一切。我不建議你挑戰這種強大的習慣勢力,相反,我建議你向日本合氣道選手學習,利用這種勢力削弱你的競爭對手,讓他們自食其果。
如果你為大公司工作,想要改用Lisp語言可能不是一件容易的事。你很難說服自以為是的老板,讓他允許你用Lisp語言開發程序。老板受到報紙的影響,認為某些其他語言將主宰世界(就像20年前Ada語言受到的評價)。但是,如果你為創業公司工作,那里沒有這樣的老板,那么你就能和我們一樣,將他人的Blub困境轉變為你的優勢。你的競爭對手被牢牢粘在那些很普通的語言上面,永遠都追不上你使用的技術。
如果你為創業公司工作,那么這里有一個評估競爭對手的妙招——關注他們的招聘職位。他們網站上的其他內容無非是一些陳腐的照片和夸夸其談的文字,但是招聘職位卻不得不寫得很明確,反映出他們到底想干什么,否則就會引來一大批不合適的求職者。
在Viaweb創業期間,我讀過大量競爭對手的招聘職位。差不多每個月都有一個新的競爭對手浮出水面。我首先會看他們的產品有沒有一個試用版,然后就去找他們的招聘職位。這樣過了幾年,我就知道哪些公司值得關注,啷些公司不用在意。有些公司的職位描述使用了大量的IT詞匯,這樣的內容越多,這家公司就越不構成威脅。最不用擔心的競爭對手就是那些要求應聘者具有Oracle數據庫經驗的公司,你永遠不必擔心他們。如果是招聘C++或Java程序員的公司,對你也不會構成威脅。如果他們招聘Perl或Python程序員,就稍微有點威脅了。至少這聽起來像一家技術公司,并且由黑客控制。如果我有幸見到一家招聘Lisp黑客的公司,就會真的感到如臨大敵。