黑客與畫家 [好書推介]
本書適合所有程序員和互聯網創業者,也適合一切對計算機行業感興趣的讀者。
這是我第一本讀的IT書藉,亦是最好看的IT書藉。這本書寫得很有深度,是一本永不過時的IT人必看書藉。
我在這用了用一篇比較長的博文進行點評。
這樣一來,你就可以判斷——哪些書值得你看,哪些不值得你看。
這篇讀書筆記,首先是寫給自己看的,然後才是給讀者看的。
第一章 為什麽書呆子不受歡迎
他們的心思在別的地方。
我後來認識很多人,讀書的時候都被稱為書呆子。從他們身上我發現,“書呆子”與“高智商”有強烈的正相關關系。而這些人在中學裏都是不受歡迎的學生,你越喜歡讀書,就越不受別人的歡迎,因此“書呆子”和“受歡迎”之間,有一種更強烈的負相關關系。這樣看來,“髙智商”似乎導致了你不受歡迎。
為什麼會這樣?要是你眼下還在讀中學,你一定會覺得這個問題很蠢。無可爭議的事實就是,除了這樣以外,似乎很難想象還能有什麼別的結果。但是,的確會出現別樣的情況。比如,在小學裏,聰明的學生就沒有受到排擠。再比如,畢業後踏上社會,聰明也不是一件壞事。而且,據我所知,在大多數國家,事情也沒有如此嚴重。
為什麽聰明的小孩沒有讓自己變得受歡迎?如果他們真的很聰明,為什麽找不到受歡迎的訣竅呢?他們在標準化測試中表現得這麽好,為什麽就不能在這方面也大獲成功呢?
有一種觀點認為,其他小孩妒忌聰明學生,所以聰明的學生不可能受到歡迎。我倒希望這種解釋是對的。回想起來,要是初中裏真的有人妒忌我,那麽他們一定費了很大力氣才把這種妒忌隱藏得無法發現。而且,在任何情況下,如果聰明真的令他人妒忌,這反而會招來女生。因為女生喜歡被其他男生妒忌的男生。
在我就讀過的學校,聰明根本就是無足輕重的一樣東西。同學們既不看重它,也不唾棄它。如果別的事情都相同,那麽大家還是願意自己變得聰明一點,因為這總比做個笨人好。但是總的來說,智力在大家心裏的分量遠遠不如相貌、魅力和運動能力的分量重。
所以,如果智力本身與“受歡迎”無關,為什麽聰明的小孩一直不受同齡人的歡迎呢?我認為,答案就是他們真的不想讓自己受歡迎。
如果當時有人告訴我這個答案,我一定會嘲笑他。在學校裏不受歡迎,你的日子就很難過,有人甚至因此自殺。所以,要是你跟我說,是我本人不想受歡迎,那就好比你在說,我在沙漠裏快渴死了,卻又不想喝水。別搞錯了,讓自己更受歡迎,這才是我要的。
但是事實上,我並不是那麽強烈地渴望這個。我更想追求的是另一件事情——聰明。這不僅僅意味著在學校得到好成績(雖然某種程度上這也挺重要)。我真正想要的是,能夠設計奇妙的火箭、寫出漂亮的文章、理解編程原理。一句話,我想要做偉大的事情。
那時,我從沒試過將夢想分門別類、一一排序。要是我真做了,就會一眼看出聰明是排在最前面的。如果有人許諾,使我一舉成為全校最受矚目的學生,代價是從此智力平庸(請允許我在這裏自命不凡),我是絕不會答應的。
雖然“書呆子”飽嘗不受歡迎之苦,但是為了解除痛苦而讓他們放棄“聰明”,我想大多數人是不會願意的。對他們來說,平庸的智力是不可忍受的。不過,要是換了別的孩子,情況就不一樣了,大多數人會接受這筆交易。對於很多人來說,這反而是更上一層樓的機會。即使是那些智力排名在前20%的學生(我在這裏假設智力可以測量,那時的人們似乎都相信這一點),誰不願意用30分的成績換來別人的友愛和欽佩?
我認為,這就是問題的根源。“書呆子”的目標具有兩重性。他們毫無疑問想讓自己受歡迎,但是他們更願意讓自己聰明。“受歡迎”並不是你在課後時間隨便做一做就能實現的,尤其是在美國的中學中,在這裏,所有人為了個人魅力都會進行激烈競爭。
文藝復興時期的代表人物阿爾伯蒂有一句名言:“任何一種藝術,不管是否重要,如果你想要在該領域出類拔萃,就必須全身心投入。”
青少年往往很關註服飾。他們這樣做並不是有意讓自己贏得大眾,他們的目的只是要穿得好看。但是穿給誰看呢?無非就是其他小孩。同伴的意見成為他們判別事物的表示標準,這不僅體現在衣著上,還體現在他們做的幾乎每一件事情上,就連走路的姿勢也不例外。所以,他們為了把所有事情“做對”,所付出的任何努力,不管是有意還是無意,實際上都等同於努力在使自己變得更受歡迎。
書呆子沒有認識到這一點。他們沒有認識到“受歡迎”需要付出如此之多的努力。一般來說,對於那些高度困難的領域,只有身處其中的人,才能意識到成功需要不間斷(雖然未必是自覺的)付出。舉例來說,大多數人似乎認為,繪畫能力與生俱來,畫家就像髙個子一樣,是天生的。事實上,大多數“會畫”的人,本身就很喜歡畫畫,將許許多多時間投入其中,這就是為什麽他們擅長畫畫的原因。同樣的,受歡迎也不是天生的,而是要你自己做出來的。
書呆子不受歡迎的真正原因,是他們腦子裏想著別的事情。他們的註意力都放在讀書或者觀察世界上面,而不是放在穿衣打扮、開晚會上面。他們就像頭頂一杯水來踢足球,一邊踢球,一邊拼命保持不讓水灑出來。其他人都在一門心思玩足球,遇到這樣的對手,自然能夠毫不費力地擊敗,並且心裏還奇怪,對方怎麽如此無能。
就算書呆子心裏想著變得與其他小孩一樣受歡迎,做起來卻是難上加難。因為那些受歡迎的小孩從小就在琢磨如何受歡迎,打心底裏追求這個。但是,書呆子從小琢磨的卻是如何更聰明,心底裏也是這樣追求的。這都是受父母的影響,書呆子被教導追求正確答案,而受歡迎的小孩被教導討人喜歡。
孩子們欺負書呆子的另一個原因是為了讓自己感到好受一些。當你踩水的時候,你把水踩下去,你的身體就會被托起來。同樣,在任何社會等級制度中,那些對自己沒自信的人就會通過虐待他們眼中的下等人來突顯自己的身份。
哪怕你什麽也改變不了,但是僅僅是理解自己的處境,也能使得痛苦減輕一些。書呆子並不是失敗者。他們只是在玩一個不同的遊戲,一個更接近於真實世界狀況的遊戲。成年人明白這一點。成功的成年人,幾乎都聲稱自己在高中屬於書呆子。
對於書呆子來說,意識到學校並非全部的人生,也是很重要的事情。學校是一個很奇怪的、人為設計出來的體系,一半像是無菌室,一半像是野蠻洪荒之地。它就像人生一樣,裏面無所不包,但又不是事物的真實樣子。它只是一個暫時的過程,只要你向前看,你就能超越它,哪怕現在你還是身處其中。
如果你覺得人生糟透了,那不是因為體內激素分泌失調(你父母相信這種說法),也不是因為人生真的糟透了(你本人相信這種說法)。那是因為你對成年人不再具有經濟價值(與工業社會以前的時期相比),所以他們把你扔在學校裏,一關就是好幾年,根本沒有真正的事情可做。任何這種類型的組織都是可怕的生存環境。你根本不需要尋找其他的原因就能解釋為什麽青少年是不快樂的。
第二章 黑客與畫家
黑客也是創造者,與畫家、建築師、作家一樣。
人們無法考核你的工作,甚至誤解你的工作,都不是最糟的事。更大的危險是你自己也會誤解自己的工作。因為你總是從相關領域尋找新思想,如果你發現自己讀的是計算機科學系,很自然地,你就會以為“計算機科學”與其他“理論科學”並無不同,你的工作屬於“理論計算機科學”所涉及的那種理論的應用研究。讀研究生期間,我潛意識裏一直有一種很不舒服的感覺,覺得自己應該多學一點理論,不應該期末考試結束還不到三個星期,就把所有東西忘得一幹二凈,那樣真是不可饒恕。現在,我意識到自己錯了。黑客搞懂“計算理論”(theory of computation)的必要性,與畫家搞懂顏料化學成分的必要性差不多大。一般來說,在理論上,你需要知道如何計算“時間覆雜度”和“空間覆雜度”(time and space complexity);如果你要寫一個解析器,可能還需要知道狀態機(state machine)的概念;除此以外,並不需要知道特別多的理論。這些可比畫家必須記住的顏料成分少很多。
我在大學受到的教育是,在上機編程之前,應該先在紙上把程序搞清楚。可我自己一直不是這樣編程的,我喜歡直接坐在計算機前編程,而不是在紙上編程。更糟的是,我不是耐心地一步步寫出整個程序,確保大體上是正確的,而是一股腦不管對錯,先把代碼堆上去,再慢慢修改。書上說,調試(debugging)是最後的步驟,用來糾正打字的錯誤和疏忽。可是我的工作方法看上去卻像編程就是在調試。
很長一段時間內我都為此事沮喪,就像小學裏老師教我怎麽拿鉛筆,我卻總是學不會的那種感覺。如果我那時看到其他創作領域,比如繪畫或者建築,我就會想到,自己的方法其實有一個正式的名稱:打草稿。我現在認為,大學裏教給我的編程方法都是錯的。你把整個程序想清楚的時間點,應該是在編寫代碼的同時,而不是在編寫代碼之前,這與作家、畫家和建築師的做法完全一樣。
優秀的軟件也要求對美的狂熱追求。如果你查看優秀軟件的內部,就會發現那些預料中沒有人會看見的部分也是優美的。我對待代碼的認真程度遠遠超過我對待其他事情,如果我以這種態度對待日常生活的每件事,那麽我就夠資格找心理醫生開處方藥了。看到代碼前面的縮進亂七八糟,或者看到醜陋的變量名,都會把我逼瘋的。
如果黑客只是一個負責實現領導意志的技術工人,職責就是根據規格說明書寫出代碼,那麽他其實與一個挖水溝的工人是一樣的,從這頭挖到那頭,僅此而已。但是,如果黑客是一個創作者,他從事的就不是機械性的工作,他必須具備靈感。
黑客就像畫家,工作起來是有心理周期的。有時候,你有了一個令人興奮的新項目,你會願意為它一天工作16個小時。等過了這一陣,你又會覺得百無聊賴,對所有事情都提不起興趣。
很小的時候,我就被不斷告知,要設身處地為他人著想。現實中,這必然意味著你要做其他人需要的事情,而不是你自己想做的事情。這樣看上去好像對我很不利,所以我暗下決心不讓自己變成這樣的人。
但是,我完全錯了。事實表明,從他人的角度思考問題正是成功的奧秘所在。“換位思考”並不就意味著你要做自我犧牲。實際上,這是完全不同的兩回事。了解別人對於事情的看法,並不代表你為他的利益服務。某些情況下,比如打仗的時候,了解對手正是為了打擊對手。
第三章 不能說的話
如果你的想法是社會無法容忍的,你怎麽辦?
翻開老照片,看到以前的樣子,你會不會感到難為情?我當時真的是穿成這樣嗎?是的,你沒看錯,你就是穿成這樣。我們穿衣服的時候,根本不知道自己看上去有多傻,還以為很時尚。所謂“時尚”,本質上就是自己看不見自己的樣子。好比我們在地球上,卻感覺不到地球在動。
但真正令人驚恐的是,流行一時的不僅有衣服,還有道德觀念。明明是專橫武斷、毫無依據的錯誤觀點,但是大多數人卻深信不疑,受到影響而不自知。這是非常危險的。流行的衣服,其實是很難看的衣服;流行的道德觀念,其實不是善而是惡。但是,如果別人都穿流行的衣服,而你不穿,你就會遭到嘲諷;如果別人都遵守流行的道德觀念,而你不遵守,結果則要嚴重得多,你會被解雇、流放、監禁,甚至被殺。
不管哪一個年代,有一件事都是不會改變的,那就是“禍從口出”。你一定要小心自己說的話。自以為無害的言論會給你惹來大麻煩。今天,說地球圍繞太陽運轉真是再平常不過了,如果換在17世紀的歐洲,這麽說就大難臨頭了。伽利略說了這樣的話,結果遭到了宗教法庭的審判。
你是一個隨大流的人嗎
讓我先問你一個問題:大庭廣眾之下,你有沒有什麽觀點不願說出口?如果回答是沒有,那麽你也許應該停下來想一想了。你的每一個觀點都能毫不猶豫地說出口,你自己深深讚同這些觀點,並且你也確信肯定會獲得別人的讚同,這是否太過於巧合了?一種可能是,也許事情並沒有這麽巧合,你的觀點就是從別人那裏聽來的,別人告訴你什麽,你就相信了什麽,你把別人灌輸的觀點當作了自己的觀點。
另一種可能是,你的思想觀點確實是獨立思考得到的,碰巧與社會主流的思想觀點一模一樣。這種情況的可能性似乎不大,因為這意味著,如果別人犯錯了,你也必須碰巧犯一個同樣的錯誤。為了防止他人覆制,古代制作地圖的工匠會故意在地圖上畫錯一個小地方。如果你的地圖與他的地圖一樣,就說明不太可能是你自己獨立制作的。
與歷史上別的年代一樣,我們的思想幾乎肯定也是一張有錯誤的地圖。如果你也犯下與別人一樣的錯誤,那麽這個錯誤不太可能完全來自於你自己。這就像1972年喇叭褲剛剛開始流行,某人聲稱他覺得喇叭褲很時尚,你覺得這是他完全自發產生的觀點嗎?
如果別人告訴你應該相信什麽,你就真的相信了,那麽你就會和別人一樣犯下同樣的錯誤。如果你是南北戰爭前的南方莊園主,你會與北方開戰;如果你是20世紀30年代的德國人,你會相信希特勒。
有時候,別人會對你說:“要根據社會需要,改造自己的思想(well-adjusted)。”這種說法隱含的意思似乎是,如果你不認同社會,那麽肯定是你自己的問題。你同意這種說法嗎?事實上,它不僅不對,而且會讓歷史倒退。如果你真的相信了它,凡是不認同社會之處,你連想都不敢想,馬上就放棄自己的觀點,那才會真正出問題。
道貌岸然
孩子的大腦就是我們所有“不能說的話”的一面反射鏡。我們似乎認定,孩子的思想應當是光明純潔的。為了保證孩子不受外界“不良”思想的影響,我們對那些思想迸行消毒和屏蔽,把世界描述成光明的樣子,向孩子們灌輸,將他們的心靈塑造成我們想象中的樣子。
小孩子說臟話就是一個很好的切入點,你可以從這個小小的側面來思考這個問題。我的許多朋友現在都開始為人父母了。他們一個個都變得非常小心,不在孩子面前使用“fuck”、“shit”這樣的臟話,以免孩子學會這些詞。但是,這些詞是日常語言的一部分,成年人一天到晚都在用。所以,孩子從家長那裏得到一個錯誤的印象,以為它們是沒人用的。為什麽家長要這樣偽裝呢?因為他們覺得孩子不應該知道成年人語言的所有內容,只需知道一部分適合兒童的詞就行了。我們喜歡孩子們看上去天真無邪。^
^「很快,孩子就會從朋友那裏知道這些詞。但是他們明白,不能在大人面前使用。所以,沒過多久,一切就變得有點像諷刺劇了。家長在外使用這些詞,回家後就不用。孩子在外也使用這些詞,回家後也不用。雙方見面,就像演戲一樣。」
就是因為這個原因,大多數成年人故意讓孩子對世界有一個錯誤的認識。最鮮明的例子之一就是聖誕老人。我們覺得,小孩子相信聖誕老人,真是太可愛了。我本人其實也是這樣想。但是,捫心自問,我們向孩子灌輸聖誕老人的神話,到底是為了孩子,還是為了我們自己?
我在這裏不討論這樣做是否正確。家長想要塑造孩子的心靈,把他們裝扮成可愛的小寶寶,這可能是無法避免的。我也可能這樣做。但是,就本文而言,這樣做會產生一個重要結果,那就是孩子“被迫”在一個精心設計的環境中長大。他的頭腦或多或少是純潔無暇的,一點也不知道那些“不能說的話”,從來沒有被真實的社會生活“汙染”過。孩子眼裏的世界是不真實的,是一個被灌輸進他們頭腦的假想世界。將來當孩子長大以後接觸社會,就會發現小時候以為真實的事情,在現實世界中是荒唐可笑的。
那些“不能說的話”就是這樣被阻止進入我們頭腦的。你可以想象一下,假定有一個康拉德式的當代人物,他在非洲當雇傭兵,然後去了尼泊爾當醫生,後來又到邁阿密經營夜總會。具體幹什麽並不重要,反正他就是一個見多識廣的人。現在,我們把這個人的頭腦,與一個在美國郊區長大的、乖巧守規矩的16歲女生的頭腦,做一個比較。前者的所思所想會不會令後者驚駭不已?他知道真實世界是什麽樣,而她知道的,或者至少體現在她言行上的,不過是父母精心灌輸的一個假想世界。兩者減一下,我們就可以知道不能說的到底是哪些話了。
為什麽這樣做
做一個異端是有回報的,不僅是在科學領域,在任何有競爭的地方,只要你能看到別人看不到或不敢看的東西,你就有很大的優勢。
假設未來的某一天,世界上爆發了一場運動,黃顏色被禁止了。任何東西都不得塗成黃色,違者就是“黃色分子”(yellowist),以破壞社會穩定罪論處。橙色可以容忍,但也很可疑。有一天,你終於覺醒了,意識到錯的不是黃顏色,而是這個社會。如果公開這樣說,就會被打成“黃色分子”,無數正義人士義憤填膺,對你口誅筆伐。如果你以此作為人生目的,一定要為黃顏色平反昭雪,現在的局面可能正中你下懷。但是,如果你的興趣主要是別的事情,變成他人眼裏的“黃色分子”對你是極大的幹擾。與笨蛋辯論,你也會變成笨蛋。
這時你要明白,自由思考比暢所欲言更重要。如果你感到一定要跟那些人辯個明自,絕不咽下這口氣,一定要把話說清楚,結果很可能是從此你再也無法自由理性地思考了。我認為這樣傲不可取,更好的方法是在思想和言論之間劃一條明確的界線。在心裏無所不想,但是不一定要說出來。我就鼓勵自己在心裏默默思考那些最無法無天的想法。你的思想是一個地下組織,絕不要把那裏發生的事情一股腦說給外人聽。“格鬥俱樂部”的第一條規則,就是不要提到格鬥俱樂部。
1638年,英國詩人彌爾頓(John Milton)準備第一次訪問意大利。曾經擔任英國駐威尼斯大使的沃頓爵士(Hemy Wootton)告訴彌爾頓要記住一句座右銘“i pensieri stretti & il viso sciolto”。字面意思是“守口如瓶,笑臉相迎”,也就是說,你要對每一個人微笑,但是不要說出自己的真實想法。這是很明智的建議。因為彌爾頓是一個喜歡爭論、好打嘴仗的人,而當時羅馬教廷的宗教裁判所非常強勢,所以沃頓爵士才會這樣建議他。需要記住的是,彌爾頓的時代與我們的時代並沒有本質不同。每個時代都有自己的忌諱,如果你觸犯它們,就算沒有坐牢,至少也會為自己惹來麻煩,幹擾了正常生活。
我承認,“守口如瓶”看上去是一種怯儒的行為。可是問題在於,“不能說的話”太多了,如果口無遮欄,你就沒時間做正事了。為了與他人論戰,你不得不變成一個語言學家。
永遠質疑
如果你想要清晰地思考,就必須遠離人群。但是走得越遠,你的處境就會越困難,受到的阻力也會越大,因為你沒有迎合社會習俗,而是一步步地與它背道而馳。小時候,每個人都會鼓勵你不斷成長,變成一個心智成熟、不再耍小孩子脾氣的人。但是,很少有人鼓勵你繼續成長,變成一個懷疑和抵制社會錯誤潮流的人。
如果自己就是潮水的一部分,怎麽能看見潮流的方向呢?你只能永遠保持質疑。問自己,什麽話是我不能說的?為什麽?
第四章 良好的壞習慣
與其他美國人一樣,黑客的成功秘訣就是打破常規。
在大眾眼裏,“黑客”(hacker)就是入侵計算機的人。可是,在程序員眼裏,“黑客”指的是優秀程序員。這兩個含義其實是相關的。對於程序員來說,“黑客”這個詞的字面意思主要就是“精通”,也就是他可以隨心所欲地支配計算機。
更麻煩的是,“黑”(hack)這個詞也有兩個意思,既可以用作讚美,也可以用作羞辱。如果你解決問題的方式非常醜陋笨拙,這叫做你很“黑”。如果你解決問題的方式非常聰明高超,將整個系統操縱在股掌之間,這也叫做你很“黑”。日常生活中,前一種意思更多見,可能因為醜陋的做法總是多於聰明的做法。
總體來看,黑客是不服從管教的,這往往會激怒管理當局。但是,不服從管教,其實是黑客之所以成為優秀程序員的原因之一。當公司的CEO裝模作樣發表演說時,他們可能會嘲笑他;當某人聲稱某個問題無解時,他們可能也會嘲笑他。如果硬要他們服從管教,他們也就無法成為優秀程序員了。
不過,有些人的這種態度不是真的,而是裝出來的。某些年輕程序員註意到了知名黑客的怪癬,就會模仿,好使自己顯得更聰明。這種裝出來的不服從再加上故作姿態挑毛病的態度,不僅僅令人惱火,而且實際上會延緩創新的進程。
但是,即使考慮到黑客令人惱火的種種怪癖,他們不服從管教的性格依然是利大於弊。我希望人們能理解,能更多地看到這種性格的長處。舉例來說,好萊塢的電影人一直大惑不解,為什麽黑客不喜歡版權法。在黑客網站Slashdot上面,版權是永恒的討論熱點。為什麽程序員那麽關心版權,而不是其他事情?
部分原因是,有些公司為了防盜版而使用了禁止覆制的技術。這等於交給黑客一把鎖,他的第一反應肯定是如何才能打開它。但是,這裏面還有更深層次的原因,對於版權和專利這樣的制度,黑客深感擔憂。他們感到,保護“知識產權”的力度不斷增大,已經威脅到了他們完成工作所必需的“思想自由”。在這一點上面,他們的看法是正確的。
只有深入了解當前的技術,黑客才能構想下一代技術。知識產權的擁有者也許會說,不,謝謝,我們不需要你的幫助,我們自己就能開發下一代技術。他們錯了,在計算機工業的歷史上,新技術往往是由外部人員開發的,而且所占的比例可能要高於內部人員。1977年,IBM公司內部肯定有一些部門正在開發下一代電腦。他們沒有料到的是,真正的下一代電腦不是誕生於IBM實驗室,而是由兩個與他們完全不相幹的長頭發年輕人在舊金山的一間車庫裏開發出來的。這兩個年輕人,一個是史蒂夫·喬布斯,另一個是史蒂夫·沃茲尼亞克。差不多同一時間,計算機工業的幾大巨頭聚在一起,合作研發官方版的下一代操作系統Multics。但是,另外兩個年輕人——26歲的肯·湯普森和28歲的丹尼斯·裏奇——覺得Multics過分覆雜,就另起爐竈,寫出了一個自己的操作系統。他們參照Multics,為它取了一個搞笑式的名字Unix。
對於適當的不服從管教,保持寬容不會有太大的壞處,反而很有利於美國的國家優勢,它使得美國不僅能吸引聰明人,還能吸引那些很自負的人。黑客永遠是自負的。如果黑客有自己的節日,那就是4月1日愚人節,你可以放心地作弄其他人。黑客的這種自行其是的特點,很大程度上說明了,為什麽不管是出色的工作還是糟透了的工作,黑客都用同一個詞形容^。如果他們做出了一個東西,他們自己總是無法百分百確定那到底是什麽東西。有可能完全沒用,但是只要那些出錯的地方還算正常,那麽就是一個信號,表明這個東西還有希望。在人們心目中,編程是非常精確、有條不紊的,這真是非常奇怪的想法。計算機確實是非常精確、有條不紊的,但是黑客的所作所為完全出於興趣,想到哪裏就做到哪裏,沒有明確的計劃,只求開心。
那些占據高位、本能地想要約束黑客、強迫黑客服從的人們,請小心你們的要求,因為你們真有可能成為千古罪人。
第五章 另一條路
互聯網軟件是微機誕生後的最大機會。
軟件bug
解決新代碼的bug要比解決歷史遺留代碼的bug容易。在自己剛剛寫好的代碼中,找出bug往往會比較快。有時,你只要看到出錯提示,就知道問題出在哪裏,甚至都不用看源碼,因為潛意識中你已經在擔心那個地方可能會出錯。如果你要解決的bug出自於6個月前寫好的代碼(假定你一年發布一個新版本,那麽6個月就是發現bug的平均時間),那麽就麻煩了,就要大費周章了。那時,你對代碼也已經不熟悉了,就更可能采用危險的方式解決問題,甚至引入更多的bug。
早一點發現bug就不容易形成覆合式bug,也就是互相影響的兩個bug。舉例來說,一個bug是樓梯很滑,另一個bug是扶手松了,那麽只有當這兩個bug互相作用時,才會導致你從樓梯上摔下來。在軟件中,覆合式bug是最難發現的bug,往往也會導致最大的損失^。傳統的方法是:“把軟件徹底拆開,將所有bug統統清理幹凈。”這樣做難免產生一大堆的覆合式bug。如果軟件是經常性發布,每次只有小幅度的變化,那麽就不容易產生覆合式bug。這就好比做掃除:你一直在打掃大廳,掉落在地板上的東西會被立刻清理,省得它們時間一長與其他東西粘在一起。
覆合式bug有一個子類型:兩個bug是互相彌補的,好比“負負得正”,軟件反而能正常運行。這種bug可能才是最難發現的bug。當你修正了其中的一個bug,另一個bug才會暴露出來。這時對你來說,你會覺得剛才修正錯了,因為那是你最後修改的地方,你就懷疑自己在那裏做錯了,但是你其實是對的。
有一種編程方法叫做“函數式編程”(functional programming),它對你會有幫助,可以避免一些副作用。函數式編程在學術文獻中研究得比較多,在商業軟件中用得比較少。但是,對於互聯網軟件,它卻很有用。很難用純粹的“函數式編程”完成整個程序,但是它可以用來編寫一些重要的部分,使得這些部分易於調試,因為它們不包含“狀態”(state),非常便於不斷進行小幅的修改和測試。
客戶支持
大公司的做法不是立刻實現新功能,而是先對新功能做一個計劃。我們就是因為這個原因而遇到了麻煩。投資者和分析家會問,你們對未來有何計劃。真實的回答是,我們沒有任何計劃。我們有改進的想法,但是如果我們想到應該怎麽改進,就已經把它實現了。接下來六個月我們要做什麽?所有能想到的最佳改進。我不知道自己是否有膽量公開這麽說,但這是實話。計劃這個詞,只是將構思束之高閣的另一種表達方式。只要想到好的構思,我們就立刻著手實現。
逆向的人月神話
開發軟件需要的程序員人數減少,不僅意味著省下更多的錢。正如《人月神話》一書中所指出的,向一個項目增加人手,往往會拖慢項目進程。隨著參與人數的增加,人與人之間需要的溝通呈現指數式增長。人數越來越多,開會討論各個部分如何協同工作所需的時間越來越長,無法預見的互相影響越多越大,產生的bug也越多越多。幸運的是,這個過程的逆向也成立:人數越來越少,軟件開發的效率將指數式增長。我不記得我們開過討論如何編程的會議。步行去吃午飯的路上,我們就能把該說的話說完,從來沒有例外。
創業公司
創業公司的壓力很大,不幸的是,這一點在互聯網軟件業也發揮到了極致。許多軟件公司的開發者都有一段睡在桌子底下(或者類似經歷)的日子,尤其是在初創期。令人驚恐的是,對於互聯網軟件來說,這樣的日子沒有盡頭,什麽都不足以阻止這種事情成為常態。對於桌面軟件來說,睡桌子底下的經歷經常可以告一段落,等到軟件發布了,我們就都回家睡上一個星期。互聯網軟件永遠沒有收工的那一天,如果你願意,可以一直幹下去,每天忙上16個小時。而且,你能夠做到這一點,意味著競爭者也能做到這一點,所以長時間工作變成了一種必需,不得不如此。因為你能做到,所以你必須做到。
除了長期加班,更可怕的事情是沈重的壓力。傳統上,程序員和系統管理員有不同的工作職責。程序員關註bug,系統管理員關註系統的基礎設施。程序員可能一整天都在伏案編寫代碼,然後到了某個時間,就下班回家,不再去想代碼了。系統管理員則是永遠都無法把工作拋到腦後,可能淩晨4點就會被叫到機房,不過好在大多數時候他們的工作都不是很覆雜。互聯網軟件的出現使得這兩種工作結合在一起,因此把它們各自不同的工作壓力也合在一起。程序員變成了系統管理員,但是工作職責的範圍卻沒有明確界定,使得工作壓力陡然增加。
為什麽不嘗試一下?
不要被微軟嚇到。你能做到它做不到的事情,正如它能做到你做不到的事情一樣。開發互聯網軟件不需要得到任何人的許可,沒有人能夠阻止你。你不需要去申請許可證,不需要在零售店的貨架上謀得一席之地,也不需要卑躬屈膝地求人家,將你的軟件與操作系統捆綁在一起。你能夠通過瀏覽器發布軟件,沒有人能在你和瀏覽網站的用戶之間插上一腳。
你也許不會相信,但是我向你保證,微軟公司害怕你。它的那些目中無人的中層管理人員也許不是這樣想的,但是比爾·蓋茨肯定是,因為1975年,上一次發布軟件的新方式出現時,他也曾經跟你一樣白手起家。
第六章 如何創造財富
致富的最好方法就是為社會創造財富。創造財富的最好方法就是創業。
如果你想致富,應該怎麽做?我認為最好的辦法就是自己創業,或者加入創業公司。幾百年來,這一直是致富的可靠途徑。“創業公司”(startup)這個詞誕生於20世紀60年代,但是它與中世紀集資進行的航海冒險活動其實也相差無幾。
創業公司往往與技術有關,所以“高技術創業公司”這個短語幾乎就是同義重覆。創業公司其實就是解決了某個技術難題的小公司。
許多人對此一無所知,但也發了財。這就好像你不用學習物理學也能成為一個出色的棒球投球手。但是,我認為理解這些原理,有助於你取得成功。為什麽創業公司必須是小公司?當創業公司不斷變大時,它是否不可避免地失去創新能力?為什麽創業公司往往選擇在新技術領域創業?為什麽如此之多的創業公司在開發新藥或計算機軟件,而不是在賣玉米油或者洗衣粉?
一個命題
從經濟學觀點看,你可以把創業想象成一個壓縮過程,你的所有工作年份被壓縮成了短短幾年。你不再是低強度地工作四十年,而是以極限強度工作四年。在高技術領域,這種壓縮的回報尤其豐厚,工作效率越高,額外報酬就越高。
下面舉一個簡單的例子說明這個經濟學命題。如果你是一個20多歲的優秀黑客,每年的薪水大約是8萬美元。這意味著,平均來看,你必須每年至少為公司帶來8萬美元利潤,這樣才能保證公司沒有虧錢。但是,你的真正工作時間其實可以是公司上班時間的2倍,如果你全神貫註,每小時的產出可以提高3倍。
「往往只有在創業公司裏,你才能得到一種寶貴的工作環境,就叫做“不受幹擾”。不同的工作對“不受幹擾”有不同的要求。文稿校對人員每15分鐘被打斷一次,工作效率也不會有太大損失。但是,黑客要求的“不受幹擾”的時間是非常長的,有時你要用1個小時才剛剛把一個問題理清。所以,人事部突然打電話要你去填一張表格,會造成巨大的成本損失。
如果再把大公司裏令人討厭的中間管理層除去(他們經常以主管的身份妨礙你的工作),你的效率可以再提高2倍。還有一個可以提高效率的地方:你不用再完成強行指派給你的工作,盡可以根據自己的願望,做出最能發揮你聰明才智的成果。假定這會把工作效率再增加三倍。將這些因子放在一起做乘法,你的工作效率將是在公司時的36倍。如果一個優秀黑客在大公司裏的身價是每年8萬美元,那麽一個勤奮工作、擺脫雜事幹擾的聰明黑客,他的工作相當於每年新創造300萬美元的價值。
「那些大公司的執行官看到創業公司員工的生產率是本公司員工的20或30倍時,自然很想知道怎樣才能讓自己的手下也這樣拼命工作。答案很簡單,付錢就行了。
這就是為什麽當你打擾黑客讓他們從屏幕前扭過頭回答問題時,他們會惡狠狠地盯著你的原因。他們大腦內部精心構建的精巧建築,瞬間就崩潰了。
僅僅因為工作經常受到幹擾,黑客就會無法應對高難度的項目。這就是為什麽黑客往往在深夜工作的原因,也是黑客無法在小隔間裏寫出優秀軟件的原因(除非在半夜)。創業公司的一個巨大優勢就是不會有任何人來打擾你。沒有人事部,也沒有表格,自然也就不會有人打電話要求你填表格。」
許多大公司的內部,平均主義泛濫。如果采用自由市場制度那樣的機制,你的公司就可以變成一個很有效率的地方。
這裏的假設是,如果每個員工按照他創造的財富獲得報酬,那麽整個公司的利潤將將最大化。」
這個計算是很粗糙的,有很大的誤差。我不會爭論這些數字是否準確,但是計算的根據是靠得住的。我沒有說放大因子不多不少正好是36,但肯定是大於10的,在個別情況下甚至高達100。
如果你覺得一個程序員一年做出300萬美元的利潤不太可能,那麽不要忘記,我們談的是他在極限情況下可以創造多少利潤。這時,他的休閑時間為0,工作強度之大足以危害到健康。
創業公司不是變魔術。它們無法改變創造財富的法則,它們只是代表了財富創造曲線遠端上的一點。這裏有一個守恒定律:如果你想賺100萬美元,就不得不忍受相當於100萬美元的痛苦。比如,你終生為郵政局工作,省下每一分工資,那也是賺到100萬美元的一種方法。可是,不難想象為郵政局工作50年是何等漫長的壓力。創業公司將你所有的壓力壓縮到三四年。承受較大的壓力通常會為你帶來額外的報酬,但是你還是無法逃避基本的守恒定律。如果創業那麽輕松,那麽所有人就都去創業了。
運氣的成分
任何公司的成功歷程中,運氣都是一個很大的隨機因素。那些你在報紙上讀到的成功人士固然很聰明,很努力,但是他們的運氣也不壞。
金錢不等於財富
創造有價值的東西就是創造財富。你最好先搞清楚什麽是財富。財富與金錢並不是同義詞^。財富存在的時間與人類歷史一樣長久,甚至更長久,事實上螞蟻也擁有財富。金錢是一種歷史相對較短的發明。
大餅謬論
許多人從小就認定世界上的財富總額是固定不變的,這樣想的人數量多得驚人。任何一個正常的家庭,在某個時刻所擁有的財富總是一個固定的值。但是,家庭的財富總額與世界的財富總額不是一回事。
這裏令人混淆的地方就是金錢有其抽象含義的一面。金錢不是財富,而只是我們用來轉移財富所有權的東西。所以,雖然在某些特定的情況下(比如某個家庭當月的收入),你能用來與他人交換的金錢數量是固定不變的,但是大多數情況下,世界上可供交換的財富不是一個恒定不變的量。人類歷史上的財富一直在不停地增長和毀滅(總體上看是凈增長)。假設你擁有一輛老爺車,你可以不去管它,在家中悠閑度日,也可以自己動手把它修葺一新。這樣做的話,你就創造了財富。世界上因為多了一輛修葺一新的車,財富就變得更多了一點,對你尤其是如此。這可不是隱喻的用法,如果你把車賣了,你得到的賣車款就比以前更多。
手工藝人
程序員坐在電腦前就能創造財富。優秀軟件本身就是一件有價值的東西。這裏不存在大規模的流水線制造業,所以不用擔心問題被混淆。你輸入的文字符號就是一件完整的制成品。如果某人坐在電腦前,寫出了一個不那麽糟糕的瀏覽器(順便說一句,這是一件很值得做的事),世界就會變得富有得多。
公司就是許多人聚在一起創造財富的地方,能夠制造更多人們需要的東西。當然,有些雇員(比如收發室和人事部的員工)並不直接參與制造過程,但是程序員不然。他們真正地面對產品,一行行地寫代碼把產品做出來。所以,在程序員看來,事情再明顯不過,財富就是被做出來的,而不是某個想象出來的神秘人物分發的大餅。
另一件程序員看來顯而易見的事情就是創造財富的速率存在巨大的差異。Viaweb的一個程序員有著驚人的生產力,我記得看著他工作了整整一天,拿出來的產品估計使得公司的市場價值增加了幾十萬美元。一個優秀程序員連續工作幾個星期可能可以創造價值100萬美元的財富。同樣的時間內,一個平庸的程序員不僅無法創造財富,甚至還可能減少財富(比如引入了bug)。
這就是為什麽如此之多的最優秀程序員都是自由主義者的原因。我們這個世界,你向下沈淪或者向上奮進都取決於你自己,不能把原因推給外界。許許多多不創造任何財富的人——比如本科生、記者和政客——一聽到最富有的5%人口占有全社會一半以上的財富,往往會認定這是不公平的。一個有經驗的程序員很可能也認為這是不公平的。因為最頂尖的5%的程序員寫出了全世界99%的優秀軟件。
創造出來的財富不一定非要通過出售實現價值。至少直到最近,科學家一直在把他們創造的財富真正地捐獻給社會。青黴素的發現使得我們所有人都變得更富有,因為從此我們死於細菌感染的可能性變小了。人們需要的東西就是財富,治愈疾病肯定就是人們需要的東西。黑客經常開發開源軟件讓所有人免費使用,以此把自己的工作捐獻給社會。FreeBSD操作系統使我變得更富有。我自己的電腦就在使用FreeBSD,雅虎公司所有的服務器都是如此。
高科技=可放大性
創業公司為每個人提供了一條途徑,同時獲得可測量性和可放大性。因為創業公司是小團隊,所以具備可測量性。因為創業公司通過發明新技術盈利,所以具備可放大性。
什麽是技術?技術就是某種手段,就是我們做事的方式。如果你發現了一種做事的新方式,它的經濟價值就取決於有多少人使用這種新方式。技術就是釣魚的魚竿,而不是那條魚。這就是創業公司與餐館或理發店的區別。餐館煎雞蛋,理發店剪頭發,每次只能為一個顧客提供服務,但是如果你解決了一個熱門的技術難題,別人都會使用你的解決方案。這就是可放大性。
俗話說得好,最好的防禦就是進攻。如果你開發出來的技術是競爭對手難於覆制的,那就夠了,你不需要依靠其他防禦手段了。一開始就選擇較難的問題,此後的各種決策都選擇較難的那個選項。
如果創業就是比別人工作得更勤奮、賺到更多的錢,那麽很顯然人人都想去創業。而且一定程度上,創業也比較有趣。
但創業是有一些潛規則的,其中一條就是很多事情由不得你。比如,你無法決定到底付出多少。你只想更勤奮工作2到3倍,從而得到相應的回報。但是,真正創業以後,你的競爭對手決定了你到底要有多辛苦,而他們做出的決定都是一樣的:你能吃多少苦,我們就能吃多少苦。
俗話說得好,最好的防禦就是進攻。如果你開發出來的技術是競爭對手難於覆制的,那就夠了,你不需要依靠其他防禦手段了。一開始就選擇較難的問題,此後的各種決策都選擇較難的那個選項^。
^「總的來說,這也是很好的處事原則。如果你有兩個選擇,就選較難的那個。如果你要選擇是坐在家裏看電視,還是外出跑步,那就出去跑步吧。這個方法有效的原因可能是遇到兩個一難一易的選擇時,往往出於懶惰的緣故,你會選擇較易的那個選項。在意識深處,你其實知道不懶惰的做法會帶來更好的結果,這個方法只是迫使你接受這一點。」
潛規則
如果創業就是比別人工作得更勤奮、賺到更多的錢,那麽很顯然人人都想去創業。而且一定程度上,創業也比較有趣。我覺得許多人都不喜歡大公司處事按部就班、會議沒完沒了、人際關系冰冷、管理層瞎指揮……
但創業是有一些潛規則的,其中一條就是很多事情由不得你。比如,你無法決定到底付出多少。你只想更勤奮工作2到3倍,從而得到相應的回報。但是,真正創業以後,你的競爭對手決定了你到底要有多辛苦,而他們做出的決定都是一樣的:你能吃多少苦,我們就能吃多少苦。
另一條潛規則是,創業的付出與回報雖然總體上是成比例的,但是在個體上是不成比例的。我在前面說過,對於個人來說,付出與回報之間存在一個很隨機的放大因子。你努力30倍,最後得到的回報在現實中並不是30倍,而是0到1000倍之間的一個隨機數。假定所有創業者都努力30倍,最後他們得到的總體平均回報是30倍,伹中位數卻是0^。大多數創業公司都以失敗告終,其中並不都是很爛的項目(互聯網泡沫時期曾經出現過專門介紹狗糧的門戶網站)。一種很普遍的情況是,某個創業公司確實在開發一個很好的產品,但是開發時間太長了一點,結果資金都用完了,只好關門散夥。
^「平均數(mean)是算數平均值,會受到個別極端值的影響,中位數(median)是最中間的那個值,不受個別極端值的影響。所以,這句話的意思就是,由於存在個別極其成功的創業者,所以回報的平均值被拉到了30倍,但是大多數創業者其實都以失敗告終,所以中位數是0。」
創業公司不像能經受打擊的黑熊,也不像有盔甲保護的螃蟹,而是像蚊子一樣,不帶有任何防禦,就是為了達到一個目的而活著。蚊子唯一的防禦就是,作為一個物種,它們的數量極多,但是作為個體,卻極難生存。
創業公司如同蚊子,往往只有兩種結局,要麽贏得一切,要麽徹底消失。你通常不知道自己會是哪一個結局,只有等到最後一刻才會明了。有好幾次公司都接近失敗了,我們的發展軌跡就像正弦函數的波形。幸運的是,我們在波形的最高點被收購了,但是真是差一點就倒閉了。在我們去加州拜訪雅虎總部討論公司出售事宜的同時,我們還不得不借了一間會議室專門安慰一位投資人,防止他撤出新一輪融資,因為沒那筆錢我們就完蛋了。
創業公司這種大起大落的特點不是我們想要的。我公司的黑客都是極度厭惡風險的人。如果有別的方式可以讓努力與回報成正比,又不存在風險的因素,我們將很樂於嘗試。我們寧願以百分之百的把握去賺100萬美元,也不願以20%的把握去賺1000萬美元,盡管後者理論上的期望值比前者高出一倍。很不幸的是,如今的商界不存在百分之百把握賺到100萬美元的可能。
保險的做法就是在早期賣掉自己的創業公司,放棄未來發展壯大(但風險也隨之增大)的機會,只求數量較少但是更有把握的回報。我們曾經遇到過一個這樣的機會,但是自以為是地將它放過了,事後才覺得自己很愚蠢。此後,我們就急不可耐地盼著把公司賣掉。在第二年裏,只要有任何人對公司流露出稍微一點點的興趣,我們就試著努力把公司賣給他。但是,始終沒有買家,所以我們不得不繼續把公司開下去。
早期收購公司是一樁很合算的交易,但是收購方對便宜貨沒有興趣。一家大到有能力收購其他公司的公司必然也是一家大到變得很保守的公司,而這些公司內部負責收購的人又比其他人更保守,因為他們多半是從商學院畢業的,沒有經歷過公司的創業期。他們寧願花大錢做更安全的選擇,所以向他們出售一家已經成功的創業公司要比出售還處在早期階段的創業公司更容易,即使會讓他們付出多得多的價碼。
用戶數量
那麽,怎樣才能把公司賣掉呢?基本上,不管是否想出售公司,你要做的事情都是一樣的(比如多賺錢)。但是,被收購本身就是一門學問。
潛在的買家會盡可能地拖延收購。收購這件事最難的地方就是讓買方真正拿出錢。大多數時候,促成買方掏錢的最好辦法不是讓買家看到有獲利的可能,而是讓他們感到失去機會的恐懼。對於買家來說,最強的收購動機就是看到競爭對手可能收購你。我們發現這會使得CEO們連夜行動。次強的動機則是讓他們擔心如果現在不買你,你的高速成長將使得未來的收購耗資巨大,甚至你本身可能變成一個他們的競爭對手。
在這兩種收購動機中,歸根結底的因素都是用戶數量。你以為買家在收購前會做很多研究,搞清楚你的公司到底值多少錢,其實根本不是這麽回事。他們真正在意的只是你擁有的用戶數量。
事實上,買家假定用戶知道誰有最好的技術。雖然這聽上去很蠢,但是用戶是你證明自己創造了財富的唯一證據。財富就是人們需要的東西,如果沒人使用你的軟件,可能不是因為你的推廣活動很失敗,而是因為你沒有做出人們需要的東西。
財富和權力
創造財富不是致富的唯一方法。在人類的歷史長河中,它甚至不是最常見的方法。就在幾個世紀前,財富的主要來源還是礦石、奴隸、農奴、土地、牲畜,而快速獲得財富的方法只有繼承、婚姻、征服、沒收。所以,很自然地,財富的名聲不好。
一旦自己的財產有了保證,那些想致富的人就會願意去創造財富,而不是去偷竊。由此導致的新技術不僅被轉化成財富,還被轉化成軍事力量。隱形飛機的理論是由前蘇聯數學家提出的,但是因為前蘇聯沒有計算機工業,它就只能是一個理論,無法變成產品。前蘇聯沒有足夠快的硬件來完成設計飛機所需要的大量計算。
冷戰、第二次世界大戰、近代的大多數戰爭都說明了這個道理。要鼓勵大家去創業。只要懂得藏富於民,國家就會變得強大。讓書呆子保住他們的血汗錢,你就會無敵於天下。
第七章 關註貧富分化
“收入分配不平等”的危害,會不會沒有我們想的那樣嚴重?
當人們非常想把某件事做好的時候,有些人會做得比其他人好得多。達·芬奇的作品就比博格寧等同時代二流畫家的作品優秀很多。同樣的差距也存在於偵探小說家身上,雷蒙德·錢德勒的作品就比普通作家的作品好得多。頂級的國際象棋大師與普通的象棋俱樂部成員下一萬盤棋,一盤都不會輸。
與下棋、畫畫、寫小說一樣,賺錢也是一種專門的技能。但是,出於某種原因,我們以完全不同的態度對待這種技能。如果某些人善於下棋或寫小說,沒有人會有意見;伹是,如果某些人善與賺錢,報紙上就會有社論出來說這是不對的。
為什麽?賺錢看上去與其他技能沒有本質不同,為什麽人們的反應如此強烈?
我認為有三個原因使得我們對賺錢另眼相看。第一,我們從小被誤導的對財富的看法;第二,歷史上積累財富的方式大多名聲不好;第三,擔心收入差距拉大將對社會產生不利影響。就我所知,第一點是錯的,第二點已經過時了,第三點通不過現實的檢驗。有沒有可能,在現代社會中,收入差距拉大實際上是一種健康的信號?
財富的老爹模式
五歲時,我不知道電力是電廠生產的,以為插座就是發電的地方。同樣,很多孩子以為財富是直接從父母口袋裏流出來的,不知道財富是創造出來的。
由於孩子們接觸到錢的方式就是這樣的,他們往往會誤解財富,把財富與錢混為一談。他們認為財富的總量是不變的,某個權威負責分配財富(所以理應平均分配),沒有意識到財富是創造出來(而且創造得不太均等)。
事實上,財富與金錢是兩個概念。金錢只是用來交易財富的一種手段,財富才是有價值的東西,我們購買的商品和服務都屬於財富。你到海外旅行時,不用看當地人的銀行賬戶就會知道你來到的是富國還是窮國。你只要看看他們的財富就行了:建築、街道、服裝、健康狀況等。
財富從何而來?人類創造出來的。回到農業時代,這個概念就更容易理解。那時大多數人都務農,許多東西都需要自己生產出來。房屋、牲畜、谷倉等都是每個家庭自己生產出來的。這就很明顯地說明,財富總量不是固定不變的,不像大餅那樣會被分光。如果你想要更多的財富,自己生產就可以了。
這在今天的社會也成立,雖然已經很少有人直接創造財富供自己使用了(少量的家務活除外)。我們大多數人都在為其他人創造財富,然後用創造出來的財富交換金錢,再用金錢交換我們需要的另一種財富^。
^「為什麽財富的分配問題引起這麽多爭論?部分原因是反對聲最大的人當中,很多人都少有創造財富的經驗:大學生、繼承人、教授、政客、新聞記者。(如果你在酒吧裏聽過大家議論體育賽事,你一定很熟悉這種現象。)
大學生往往依靠父母的資助,還沒有想過父母的錢是從哪裏來的;繼承人靠著他人遺產過活;教授與政客距離創造財富最遠,不管是否努力工作,得到的報酬都差不多,新聞記者部分由於他們的專業守則,必須與本行業產生收入的那部分——廣告銷售部——保持隔離。所有這些人中,有許多人從來沒有直面過這個事實,那就是他們拿到手的金錢,都來自別人先前創造出來的財富(新聞記者除外,他們的工作是創造財富的,但是不直接用財富交換金錢)。在這些人的世界中,收入是由某個外部權威根據某種看似公平的抽象原則(對於繼承人來說則是隨機原則)進行分配,不是來自與他人交換別人需要的東西。所以,在這些人看來,真實世界的其他部分不采用同樣的分配方式就是不公平的事情。
(某些教授確實為社會創造了大量財富,但是他們拿到的工資卻不是對此的回報,更像是對他們的投資。)」
孩子沒有能力創造財富,他們享有的一切都來自別人無償的給予。既然得到財富不要求對應的付出,那麽它當然應該平均分配。大多數家庭都是這樣,如果兄弟姐姝中有人多得到了一份,其他孩子就會喊:“不公平!”
進入社會以後,你不能總是靠父母養活。如果你需要什麽東西,要麽你自己做出來,要麽做其他東西與需要的人交換金錢,再用金錢去買你想要的東西。在真實世界中,財富是你必須自己創造出來的東西(小偷和投機者除外),而不是等著老爹買給你。由於每個人創造財富的能力和欲望強烈程度都不一樣,所以每個人創造財富的數量很不平等。
你做別人需要的東西或事情,然後得到報酬。有些人報酬較高,原因很簡單,因為他們做得更好。大明星要比普通演員多賺許多錢,普通演員可能也有大明星的實力,但是人們在電影院選擇看什麽電影時總是被大明星吸引過去。
當然,做出人們需要的東西並不是賺錢的唯一方法。搶銀行、索賄、壟斷市場也能搞到錢,並且是某些富豪最大的財富來源,但是這些手段不能代表財富的全部,更不是貧富分化的主要原因。每個人的技能不同,導致收入不同,這才是貧富分化的主要原因,正如邏輯學的“奧卡姆剃刀”原則所說,簡單的解釋就是最好的解釋。
一些大型上市公司的CEO的收入大概是普通人的100倍。職業棒球選手的年收入是普通人的72倍,職業籃球選手的年收入則是普通人的128倍。報紙的社論用恐怖的語調引用這樣的統計數據。但是我覺得,想象一個人的產出是另一個人的100倍是一件毫無困難的事情。在古羅馬時代,根據奴隸的技能不同,他們的價格會相差50倍^^。上述收入差距還沒有考慮激勵因素或者現代科技帶給你的生產力放大效應。
^^「在古羅馬帝國的早期,一個普通成年男性奴隸的價格大約是2000賽斯特斯銀幣(參見Horace,S.7.43),一個女仆的價格是600銀幣(參見Martial vi.66),而一個熟練園丁的價格是8000銀幣(參見Columella iii.3.8〉。一位醫生(P.Decimus Eros Merula)為了換取他的自由,付出了5萬銀幣(參見Dessau,Inscriptiones 7812)。一位詩人(Calvisius Sabinus)出了10萬銀幣購買懂得希臘文學的奴隸(參見Seneca,Evii.7)。普林尼報告,在他的時代,奴隸的最高價格是70萬銀幣,這位奴隸是語言學家(可能也是教師)Daphnis(參見Pliny,Hist.Ni.39),但是這個價格後來被贖買自由的演員奴隸超越了。古希臘也出現了類似的價格分化。一個普通勞工的價格大約是125到150德拉克馬銀幣,但是價格波動範圍從50到6000銀幣(能夠管理銀礦的勞工)不等(參見Xeaophon M.5)。更多關於古代奴隸制的經濟學研究參見Jones A.H.M.所著的“Slavery in the Ancient World”一文,發表於1956年的雜志的第185~199頁。」
一個人的工作具有多少價值不是由政府決定的,而是由市場決定的。
“他一個人的價值真的等於我們100個人的價值嗎?”社論作者這樣問道。回答取決於你怎麽定義“價值”。如果你同意“價值”可以定義為實現自身技能而得到的報酬,那麽回答顯然就是“對的”。
確實有一些CEO的收入太高,不合理,但是有沒有CEO的收入不足以體現他所創造的財富的呢?喬布斯就是這樣的例子。他拯救了瀕臨崩潰的蘋果公司,扭轉了危機,削減了成本,成功決策了下一代產品,很少有人能做到這些事情。他的收入就低於他的工作所創造的價值。如果我們不考慮CEO的例子,只說職業籃球運動員的收入,那麽應該不會有太大爭論,大家都會同意,籃球運動員的身價反映了市場供需狀況,並沒有不合理的地方。
第一眼看上去,你可能會覺得難以接受,人與人之間創造財富能力的差別真的會這麽巨大嗎?理解這一點的關鍵就在於重新思考我們上面提過的那個問題,他一個人的價值真的等於我們100個人的價值嗎?你想一想,一個籃球隊會同意用一個運動員交換100個普通人嗎?如果蘋果公司不是由喬布斯掌管,而是由一個100人組成的委員會掌管,那麽這家公司的下一代產品會是什麽樣?人與人之間的差別並不是那麽穩定的線性關系。也許CEO和運動員的技能和決心只比普通人高出10倍(倍數不重要),但是人與人之間就是存在著重大差別。
當我們說一些工作報酬過高,另一些工作報酬過低,我們的真實想法到底是什麽?在自由競爭的市場經濟中,價格由買家的需求決定。如果人們喜歡棒球甚於喜歡詩歌,那麽棒球運動員的收入就是要比詩人的收入高。如果說某種工作的報酬過低,那就相當於說人們的需求不正確。當然,人們確實會需求不正確的東西。這有什麽好奇怪的呢?你不覺得聲稱某種工作報酬過低的說法更奇怪嗎?如果你覺得由於人們的需求不正確,導致某些工作的報酬過低而且不公平,那麽這個世界一定會讓你感到非常遺憾,人們就是喜歡看電視真人秀,而不是莎士比亞作品,人們就是喜歡吃玉米熱狗,而不是水煮蔬菜,這是不是很不公平呀?要是你覺得不公平的話,那你就同把藍顏色說成最漂亮的顏色、把方的說成圓的那樣蠻不講理。
當我們討論“收入分配不公平”時,我們還要問問收入從何而來,收入背後的財富到底是誰生產出來的。如果收入完全根據個人創造的財富數量而分配,那麽結果可能是不平均的,但是很難說是不公平的。
偷竊
很多人對貧富分化不滿意的第二個原因就是,在大部分的人類歷史中,積累財富最常見的方法其實是偷竊。遊牧社會是偷別人的牲口,農業社會是征稅(和平時期)和直接掠奪(戰爭時期)。
在戰爭中,勝利的一方將失敗的一方的財產全部占為己有。1060年,征服者威廉占領英格蘭,將當地貴族的財產全部分給他的隨從,這是戰爭導致財富分配變化的一個例子。1530年,亨利八世將修道院的財產分給大臣^,這是政治鬥爭導致財富分配變化的一個例子。不管是戰爭還是政治鬥爭,本質上都屬於偷竊。
在控制程度更高的社會,統治者和官僚階層用稅收代替直接充公。但是,根本的一點並沒有變,那就是致富的方法不是創造財富,而是以統治者的強權進行搜刮掠奪。
技術的杠桿效應
技術的發展是否加劇了貧富分化?首先,技術肯定加劇了有技術者與無技術者之間的生產效率差異,畢竟這就是技術進步的目的。一個勤勞的農民使用拖拉機比使用馬可以多耕六倍的田。但是,前提條件是他必須掌握如何使用新技術。
我自己就親眼目睹過技術的這種杠桿效應不斷擴大。高中時,我通過割草和在冰激淋店當服務員賺錢,它們是我能找到的僅有的工作。現在的高中生可以通過開發軟件或制作網站賺錢。不過,只有少數高中生具備這種能力,其余的人還是只能去冰激淋店當服務員。
我清楚地記得,技術的進步使得我在1985年終於可以擁有一台自己的電腦了。只過了幾個月,我就開始接一些編程的零活賺錢了。1985年之前我就做不到這一點,那時也沒有自由程序員這種工作。但是,蘋果公司推出了強大而且便宜的個人電腦,使得一切成為可能,這本身就是在創造財富。程序員馬上接了上去,使用蘋果公司的產品,再去創造更多的財富。
技術應該會引起收入差距的擴大,但是似乎能縮小其他差距。一百年前,富人過著與普通人截然不同的生活。他們住在大房子裏,有許多仆人服侍,穿著華麗但是不舒適的服裝,乘著馬車旅行(因此還有馬廄和馬夫)。現在,由於技術的發展,富人的生活與普通人的差距縮小了。
技術無法使其變得更便宜的唯一東西,就是品牌。這正是為什麽我們現在越來越多地聽到品牌的原因。富人與窮人之間生活差異的鴻溝正在縮小,品牌是這種差距的遺留物。但是,品牌只是商品的標簽,即使買不起名牌,至少你還可以買普通牌子,這總比根本無法消費這一種商品要好得多。1900年,只要你有一輛馬車,你就是富人,根本沒人問你馬車的牌子。沒有馬車的人就是窮人,只能擠公共交通或者步行。今天,即使最窮的美國人也有自己的汽車,那麽廠商只好通過廣告訓練我們識別品牌,以便我們能夠識別哪些汽車特別昂貴。
一旦產品能夠流水線生產,即使質量沒有改進,至少也會更便於使用。富人最喜歡的就是那些方便易用的產品。我認識的富人朋友,與其他朋友相比,開著同樣的車,穿著同樣的衣服,使用同樣的家具,吃著同樣的食品。雖然他們的房子是在不一樣的地方,或者即使與普通人在同一個社區,面積也要大得多,但是他們的生活確實與普通人是一樣的。房子的建造方法也是一樣,屋裏的東西也基本接近。擁有定制的昂貴商品反而不方便。
富人日常做的事情也和普通人差不多。無所事事的閑適生活早就成為罕見情況了。如今,確實有很多人非常有錢,完全不必再去工作,他們之所以還在工作,不是因為感到社會壓力,而是因為無所事事使人感到孤獨和消沈。
今天的社會身份(social distinction)差異也要比100年前來得小。
那時的小說和講解禮儀的手冊在今天讀起來好像是在說陌生的部落社會。Beeton夫人出版於1880年的《家務手冊》(Book of Household Management)這樣寫道:“至於說到朋友之間的友誼……在某些情況下,為了承擔家庭生活的責任,女主人可能必須放棄一些她早年認識的朋友。”一個女人嫁給了有錢人,就被認為應該放棄那些沒錢的朋友。要是你今天這樣做的話,別人會覺得你的行為很野蠻,而且你也會讓自己過上一種乏味無趣的生活。今天的人們多多少少還是有一些互相隔離的趨勢,但主要是因為教育層次的差別,而不是財富的差別^。
^「有人會說,教育程度的差別與財富的差別是一回事,因為富人得到高等教育的機會更大。這個論點是成立的、某種程度上可以做到用錢把孩子送進頂尖的大學。你只要把孩子送進昂貴的私立學校,就等於敲開了大學的門。
無論在物質上,還是在社會地位上,技術好像都縮小了富人與窮人之間的差距,而不是讓這種差距擴大了。如果參觀雅虎、英特爾、思科的辦公室,會看到每個人都穿著差不多的衣服,有著同樣的辦公室(或者小隔間)、同樣的家具,彼此直呼對方的名字,不加任何頭銜或敬語。表面看大家沒什麽差距,但如果看到每個人銀行戶頭上的余額差別如此之大,一定會感到震驚不已。
技術的發展加大了貧富差距,這是不是一個社會問題?好像沒有那麽嚴重。技術在加大收入差距的同時,縮小了大部分的其他差距。
公理的不同意見
你經常可以聽到有人批評某種政策會加劇貧富分化。隱藏的意思就是,貧富分化的加劇一定是壞事,這好像已經成了公理。收入差距的擴大可能確實不好,可是我不覺得這可以被看成公理。
實際情況是,在工業化的民主國家,這種觀點更可能是錯誤的。在農奴和貴族組成的社會,收入差距的加大肯定是社會問題加劇的信號,收入更多地從農奴流向了貴族。但是,搶奪他人的財富已經不再是收入的唯一來源了。波音747飛機駕駛員的收入大概是商場收銀員的40倍,但是前者不是貴族,後者也不是奴隸,這種收入差距只是因為前者的技能比後者的要值錢得多。
我想提出一種相反的觀點:現代社會的收入差距擴大是一種健康的信號。技術使得生產率的差異加速擴大,如果這種擴大沒有反映在收入上面,只有三種可能的解釋:(a)技術革新停頓了;(b)那些創造大部分財富的人停止工作了;(c)創造財富的人沒有獲得報酬。
我覺得可以很有把握地說,(a)和(b)都不是好事。如果你有不同意見,那不妨試試去過公元九世紀法蘭克王國的貴族生活,一年後再來告訴我們你的感受。(我很仁慈地沒有建議你去過石器時代的那種生活。)
如果你想讓社會保持繁榮,同時收入差距不擴大,那麽就只剩下(c)這一種可能了,即創造大量財富的人不獲取報酬。舉例來說,蘋果公司的兩位創始人將歡欣鼓舞地每天工作20個小時,為社會提供蘋果電腦,然後只領取一份相當於大公司裏朝九晚五的上班族領取的稅後工資。
如果得不到報酬,人們是否願意創造財富?唯一的可能就是,工作必須能提供樂趣。會有人願意免費寫一個操作系統,但是他們不願意免費為你安裝、提供電話支持、進行客戶培訓等。即使是最先進的高科技公司,也有至少90%的工作沒有樂趣、令人生厭。
一個社會需要有富人,這主要不是因為你需要富人的支出創造就業機會,而是因為他們在致富過程做出的事情。我在這裏談的不是財富從富人流向窮人的那種擴散效應(trickle-down effect),也不是說如果你讓亨利·福特致富,他就會在下一場宴會雇用你當服務員,而是說如果你讓他致富,他就會造出一台拖拉機,使你不再需要使用馬匹耕田了。
第八章 防止垃圾郵件的一種方法
不久前,許多專家還認為無法有效地過濾垃圾郵件。本文改變了他們的想法。
發送垃圾郵件的人形形色色。有的是公司,經營著一個所謂的郵件列表,表面上說你可以選擇訂閱,但是實際上根本無法退訂,他們肆無忌憚地向你發送廣告,有的是個人,專門劫持郵件服務器,推廣色情網站。如果我們的過濾器迫使他們只能把垃圾郵件寫成上面那樣,應該會使得垃圾郵件業中合法經營的那部分人退出這個行業。因為他們很樂於遵守各州的法律規定,在郵件中附上正式聲明,解釋為什麽自己不是垃圾郵件以及如何才能取消訂閱。這一類文字反而使得識別他們變得更容易了。
(我以前曾經認為,那些相信更嚴格的法律會遏制垃圾郵件的人真是太天真了。我現在認為,更嚴格的法律或許無法減少我們收到的垃圾郵件的數量,但是肯定有助於減少逃過過濾器攔截的垃圾郵件的數量。)
在垃圾郵件業中,如果發送銷售類垃圾郵件受到限制,那麽整個行業將不可避免地受到重創。“行業”這個詞是很準確的,發送垃圾郵件的人其實都是商人,他們這麽做只是因為這招很有效。雖然垃圾郵件的回應率低到不能再低了(不超過百萬分之15,相比之下,傳統的郵寄商品目錄的回應率是百萬分之3000),但是發送垃圾郵件的成本實際上為零,所以它還是有效的。但是對於收到垃圾郵件的人來說,成本卻很高昂,假定有100萬人分別收到一封垃圾郵件,每人花一秒鐘刪除,累計起來就相當於一個人5個星期的工作量,而發送人連一分錢也不用付出。
另一方面,垃圾郵件使用了那麽多推銷語言就是為了增加回應率。如果有一天推銷語言突然不能用了,對他們就是重大打擊。為了說明這一點,讓我們把自己想象成一個回應垃圾郵件的人,看看這些人到底是怎麽想的(這要比把自己想象成垃圾郵件發送者更讓人難受)。回應垃圾郵件的人要麽是驚人地輕信,要麽是表面上完全否認、但是私底下卻有著對性的強烈興趣。不管哪一種情況,也不管垃圾郵件在正常人看來是多麽令人反感或愚蠢萬分,總是可以讓這些人興奮不已,因為郵件內容寫得實在太誘人了,畢竟如果不是這樣,商家也就不發送垃圾郵件了。要是郵件內容改成“請點擊下面的鏈接”,對於收信人來說就沒有太大的吸引力了,根本比不上現在的效果。結果就是,如果垃圾郵件不能使用誘人的推銷語言,它作為推銷工具的價值就會大大降低,使用它的商家數量也會減少。
最終,我們將取得全勝。我開始寫垃圾郵件過濾器只是因為不想再讓這些東西煩我了。但是,如果我們把過濾器做得足夠好,那麽垃圾郵件將不再有效,商家最後將不再發送它。
在所有對抗垃圾郵件的方法之中(從軟件方法到法律方法),我認為單獨來看,“貝葉斯過濾”是最有效的工具。但是,我也認為,我們使用的不同方法越多,綜合效果就越好,因為任何對發送人構成限制的方法往往都會使得過濾器工作起來更順利。即使同樣是基於內容的過濾器,我也認為,如果有多種不同的軟件可以同時使用會比較好。過濾器的差異越大,垃圾郵件想要逃過攔截就越不可能。
第九章 設計者的品味
如何做出優秀的東西?
哥白尼不認同托勒密的體系,一個極其重要的原因是,他覺得托勒密提出的偏心等距點(equant)毫無美感……
——托馬斯·庫恩,《哥白尼革命》
美感是第一道關卡,醜陋的數學在世界上無法生存。
——GH.哈代,《一個數學家的道歉》
最近,我與一個在MIT教書的朋友交談。他的研究領域很熱門,每年申請他的研究生的人多得讓他應付不過來。“很多人看上去很聰明,”他說,“但是我不知道他們的品味如何。”
品味。如今很少聽到這個詞了,人們往往使用別的叫法,伹它卻的的確確是我們離不開的基本槪念。我的朋友的意思是,他想要的學生不僅應該技術過硬,還應當能夠使用技術做出優美的產品。
數學家會把出色的工作稱讚為“優美的”。無論古今,科學家、工程師、音樂家、建築師、設計師、作家、畫家都是這樣做的,他們都使用同一個詞。這僅僅是巧合嗎,還是他們之間有共識?如果真的有共識,那麽我們能不能將某一個領域發現的“美”的規律運用於另一個領域呢?
對於我們設計師來說,美就不僅僅是一個理論問題了。如果世界上真有“美”存在,我們需要能夠認出它。設計產品時,我們需要良好的品味。與其把“美”說成一個虛無縹緲的抽象概念,還不如讓我們考慮一個實際的問題(這樣就能避免喋喋不休的空談):如何才能做出優美的產品?
如果你在當今社會提到“品味”,很多人會對你說“品味是主觀的”。他們真的就是這麽認為的。喜歡一件東西,卻不知道為什麽自己喜歡它,原因可能是這件東西是美的,但也可能因為他們的母親也擁有同樣的東西,或者雜志上某個明星使用它,或者僅僅因為它的價格很昂貴。人類的思想就是沒有經過整理的無數雜念的混合。
我們大多數人從孩提時代起就被鼓勵不要去分析清楚自己的頭腦。如果你的小弟弟畫圖時把人都塗成綠色,你想取笑他,你媽媽很可能會對你說:“你有你喜歡的方式,他有他喜歡的方式。”
你媽媽這時不是教給你什麽是美學,而只是想阻止你們兩個爭吵。就像大人哄小孩的其他話一樣,這句話也是模棱兩可的,與其他話會發生沖突。大人教導你說品味只是每個人的偏好而已。但是來到博物館,他們卻對你說,仔細觀賞達·芬奇的作品,因為他是偉大的藝術家,品味超凡。
小孩子受到這樣的教導會怎麽想?他會怎麽理解“偉大的藝術家”?這麽多年來,別人無數遍地告訴他,品味就是一種偏好,是每個人自己的事情,所以他不可能直接就明白,所謂“偉大的藝術家”就是這個人的作品要比其他人的傑出。他更可能覺得,所謂“偉大的藝術家”只是針對我個人世界而言的,就是很符合我自己口味的藝術家,好比某本書上說食用西蘭花對我的健康有利,所以我就應該喜歡吃西蘭花一樣。
把品味說成個人的偏好可以有效地杜絕爭論,防止人們爭執哪一種品味更好。但是問題是,這種說法是不正確的。只要你自己開始動手設計東西,就能明白這一點。
不管每個人的工作是什麽,他們內心裏都有一種願望——把自己的工作做好。足球運動員想羸得比賽,CEO想增加利潤。做好自己的工作會真正令人感到自豪和偷快。但是,如果你是一個設計師,並且你不承認有一種人們共同認可的東西叫做“美”,那麽你就沒有辦法做好工作。如果品味只是一種個人偏好,那麽每個人都是完美無缺的:你喜歡自己看上的東西,那就足夠了。
就像別的工作一樣,只要你不斷地從事設計工作,你就會做得越來越好。你的品味會出現變化,你會像別人一樣有所提高。如果這樣的話,那麽你以前的品味就不只是與現在不同,而是不如現在的好。因此,所謂的“品味沒有好壞之分”的公理也就頓時見鬼去了。
現在流行“相對主義”,即認為真理是相對的。即使你已經從小孩變成了成年人,這種觀點依然可能妨礙你思考“品味”。但是,只要你走出狹隘的自我,至少在心裏對自己說,確實存在比其他設計更好的傑出設計,那麽你就能開始仔細研究了。你的品味是如何變化的?什麽原因使你做出不好的設計?其他人對設計是什麽觀點?
只要你開始思考這些問題,你就會發現,眾多不同學科對“美”的認識有著驚人的相似度。優秀設計的原則是許多學科的共同原則,一再反覆地出現。
好設計是簡單的設計
從數學領域到繪畫領域,你都可以聽到這種說法。在數學中,它表示簡短的證明往往是更好的證明。特別是對於數學公理來說,少即是多。在編程中,這種說法也基本適用。對於建築師和設計者,它意味著美依賴於一些精心選擇的結構性元素,而不依賴於表面裝飾品的堆砌。(裝飾品本身並不是壞事,只有當它被用來掩蓋結構的蒼白時,才變成了一件壞事。)繪畫也是類似的,認真觀察的、非常有代表性的靜物作品往往要比表面極盡華美、但是實質上只是無意義重覆的“巨作”(比如再現非常覆雜的花邊的繪畫作品)更有價值。在寫作上,這種說法意味著只說必須要說的話,並且說得簡短。
這樣強調簡單似乎有點奇怪。有人會說,簡單就是事物本來的樣子,裝飾反而意味著更多的工作。但是,當人們自己從事創造性工作的時候,好像就會忘了保持簡單這個原則。剛開始寫作的人喜歡用浮誇的語調,根本不像他們平時說話的樣子。設計師喜歡用波浪式卷曲表現他們的藝術感。畫家發現自己都是表現主義者(expressionist)。這些裝飾都是花架子,在作家的長句、畫家“表現主義”的畫筆之下,根本就是空洞無物,表面的裝飾掩蓋了內部的空虛,太可怕了。
當你被迫把東西做得很簡單時,你就被迫直接面對真正的問題。當你不能用表面的裝飾交差時,你就不得不做好真正的本質部分。
好設計是永不過時的設計
只要沒有錯誤,每一個數學證明都是永不過時的。所以,數學家哈代才會說:“醜陋的數學在世界上無法生存。”他的意思與飛機設計師凱利·約翰遜的觀點是一樣的:如果解決方法是醜陋的,那就肯定還有更好的解決方法,只是還沒有發現而已。
以永不過時作為目標是一種幫助自己找到最佳答案的方法:如果你不願別人的答案取代你的答案,你就只好自己做出最佳答案。某些大師的作品太過傑出,永不過時,使得後人幾乎難以在該領域立足。
以永不過時作為目標也是一種避開時代風潮的影響的方法。“風潮”這個詞,從字面上就可以看出,它就是一陣風似的,隨著時間經常改變。如果一件東西長盛不衰,那麽它的吸引力一定來自本身的魅力,而不是來自風潮的影響。
好設計是解決主要問題的設計
許多壞設計做得很辛苦,但是從一開始方向就錯了。20世紀中期,有一股使用無襯線(sans-serif)字體的潮流。這一類字體接近於純手寫的樣式,但是它無助於解決最主要的問題。印刷出來的文字首先應該是易於辨認的,所以能夠清晰地分辨字母就是最主要的問題——傳統的新羅馬(Times Roman)字體是一種有襯線的字體,雖然看上去古老得就像維多利亞女王時代的風格,但是它的小寫g就是可以很輕易地與小寫y區分。
答案可以不斷改進,同樣,問題本身也可以不斷改進。軟件的難題通常可以被改成等價的較易解決的形式。歷史上,物理學的主要難題曾經一度是如何詮釋經典著作,後來遂漸變成對可觀測到的行為進行預測,這種轉變使得物理學的發展速度大大加快。
好設計是啟發性的設計
英國女作家簡·奧斯汀的作品幾乎不帶有任何描述。她不告訴讀者每件東西看上去是什麽樣子,只是把故事講得非常生動,讓讀者自己把一切都想象出來。同樣,繪畫作品也分為描述性繪畫和啟發性繪畫,後者往往比前者更引人入勝。每個人看到《蒙娜麗莎》都有自己的理解。
在建築學和設計學中,這條原則意味著,一幢建築或一個物品應該允許你按照自己的願望來使用。舉例來說,一幢好的建築物應該可以充當平台,讓你想怎麽布置就可以怎麽布置,過上自己想過的家庭生活,而不是使得你像執行程序一樣只能過上建築師為你安排的生活。
在軟件業中,這條原則意味著,你應該為用戶提供一些基本模塊,使得他們可以隨心所欲自由組合,就像玩樂高積木那樣。在數學中,這條原則意味著,一個可以成為許多新工作基礎的證明要優於一個難度很高、但無助於未來學科發展的證明。在科學領域中,總體上可以把引用次數看作對他人啟發性大小的粗略指標。
好設計通常是有點趣味性的設計
這條原則可能不是所有情況下都成立。
我想,這是因為幽默一定程度上反映了力量。幽默感是強壯的一種表現,始終擁有幽默感就代表你對厄運一笑了之,而喪失幽默感則表示你被厄運深深傷到。所以,強壯的標志(或者至少是特點)就是輕松面對自己的人生。充滿自信的人常常像燕子一樣,以一種居高臨下的姿態輕盈地看待周圍的一切。
好的設計並非一定要有趣,但是很難想象完全無趣的設計會是好的設計。
好設計是艱苦的設計
如果觀察那些做出偉大作品的人,你會發現他們的共同點就是工作得非常艱苦。如果你工作得不艱苦,你可能正在浪費時間。
困難的問題需要艱巨的付出才能解決,高難度的數學證明需要結構非常精細的解決方法(它們往往做起來很有趣),工程學也是如此。
並非所有的痛苦都是有益的。世界上有有益的痛苦,也有無益的痛苦。你需要的是咬牙向前沖刺的痛苦,而不是腳被釘子紮破的痛苦。解決難題的痛苦對設計師有好處,但是對付挑剔的客戶的痛苦或者對付質量低劣的建材的痛苦就是另外一回事了。
在繪畫上,肖像畫通常占據最高地位。這不是偶然的,原因不僅是面部肖像比其他題材更能打動人,還因為我們太擅長觀察臉,所以肖像畫家不得不加倍努力才能達到我們的要求。如果畫的是樹,樹枝畫偏了五度也不會有人發現。但是,如果你把別人的眼睛畫偏了五度,人們一眼就能看出來。
好設計是看似容易的設計
優秀運動員比賽時,讓人覺得他輕輕松松就獲勝了,優秀設計師也是如此,他們的工作看上去很容易。大多數時候,這是一種錯覺。作家的文章讀起來流暢自如,但是背後其實經過了反覆修改。
科學和工程學的一些最重大的發現在形式上往往很簡單,會使得你覺得自己也想到過。可是,如果它真的那麽簡單,為什麽發現人不是你呢?
達·芬奇的有些肖像畫只是幾根線條。看著它們,你會想只要把這十根八根線條放對位置,你也能畫出如此優美的肖像畫。說的沒錯,可是難就難在找出正確的位置。只要位置偏移一點點,整幅作品就會一潰千裏。
在大多數領域,看上去容易的事情,背後都需要大量的練習。練習的作用也許是訓練你把刻意為之的事情變成一種自覺的行為。有時,我們的訓練只是為了讓身體養成下意識的反應。優秀鋼琴家彈奏名曲可以不經過大腦直接完成,藝術家也是這樣,熟練以後,腦海中的藝術形象會自動從手上流淌出來,仿佛有人在一旁為他打節奏一樣。
人們有時會說自己有了“狀態”,我的理解是,他們這時可以控制自己的脊髓。脊髓是更本能的反應,面對難題時,它能釋放你的直覺。
好設計是對稱的設計
對稱也許只是簡潔性的一種表現,但是它十分重要,值得單獨列為一點。自然界的對稱大量存在,這就說明了對稱的重要性。
對稱有兩種:重覆性對稱和遞歸性對稱。遞歸性對稱就是指子元素的重覆,比如樹葉上葉脈的紋路。
歷史上,對稱曾經泛濫一時,導致現在它在某些領域已經不流行了。從維多利亞女王時代開始,建築師就有意多建造不對稱的建築。20世紀20年代,不對稱成了現代主義建築的一個明確的前提條件。但是即使如此,這些建築物往往也只是在主軸上不對稱,細節部分依然大量使用對稱。
在寫作中,你會發現對稱無處不在,短語、句子、小說的情節都是如此。音樂和美術也大量使用對稱。拼接式的美術作品(還有塞尚的一部分作品)有非常強烈的視覺感染力,原因就是整幅作品由相同的作圖元素構成,這也屬於對稱。對稱性構圖產生了一些最讓人難忘的繪畫作品,尤其是那些兩個半邊互相呼應的作品,比如米開朗基羅的壁畫《創世紀》和格蘭特·伍德的油畫《美國式哥特》。
在數學和工程學中,遞歸尤其有用。歸納式證明方法既簡潔又美妙。在軟件中,能用遞歸解決的問題通常代表已經找到了最佳解法。
巴黎的埃菲爾鐵塔如此引人註目,部分原因就是它的外形是遞歸的,大塔上面還有小塔。
對稱的危險在於它可以用來取代思考,在大量使用重覆的時候這種危險性更大。
好設計是模仿大自然的設計
我不是說模仿大自然這種行為本身有多麽好,而是說大自然在長期的演化中已經解決了很多設計問題。所以,如果你的設計與大自然很接近,那麽它基本上不會很差。
模仿與剽竊並不相同。如果一部小說寫得好像真實生活的再現,沒人會提出異議。雖然寫實的價值常常被誤解,但它也是繪畫的一個重要工具。寫實的目的不是為了給生活留下一模一樣的記錄,而是為你的思想提供一個咀嚼點:你的眼睛看著某樣東西,你的手就代表你的思想, 畫出一些比較有意思的內容。
模仿大自然也是工程學的有效方法。長久以來,船只就像動物一樣有龍骨和肋骨。不過,前提條件是技術水平要達到,只有這樣才有可能模仿大自然。早期的飛機設計師按照鳥的形狀設計飛機,這樣做其實是錯的,因為那時還沒有足以模擬鳥類行為的輕型材料和能源,也做不出高度覆雜的控制系統,所以飛機還不可能像鳥類那樣飛。但是,我能想象五十年後,小型的無人偵察飛機可以做得完全像鳥一樣。
現在的計算機已經很強大了,不僅能模擬出大自然的環境,還能模擬大自然發展演變的結果。遺傳算法可能會創造出正常條件下難以設計的覆雜事物。
好設計是一種再設計
很少有人一次就把事情做對。專家的做法是先完成一個早期原型,然後提出修改計劃,最後把早期原型扔掉。
扔掉早期原型是需要信心的,你必須有本事看出什麽地方還可以改進。舉例來說,剛剛開始學畫的人往往不願意重畫畫錯的地方。他們覺得能畫成現在這樣已經很不錯了,如果重畫某些部分,結果可能還不如現在。所以,他們就說服自己,我的畫已經過得去了,沒準別人也會這麽看。
這想法很危險。你應該培養對自己的不滿。達·芬奇為了把一根線畫對,經常要畫五六次。
犯錯誤是很正常的事情。你不要把犯錯看成災難,要勇於承認、勇於改正。達·芬奇實際上重新發明了素描這種藝術形式,把它當作一種探索更多可能的方式。開源軟件因為公開承認自己會有bug,反而使得代碼的bug比較少。
好設計是能夠覆制的設計
我們對待覆制的態度經常是一個否定之否定的過程。剛入門的新手不知不覺地模仿他人,遂漸熟練之後才開始創作原創性作品。最後他會意識到,把事情做對比原創更重要。
不知不覺的模仿幾乎必然將導致壞設計。如果你不知道自己的想法從何而來,那麽你可能就是在模仿另一個模仿者。
等到你逐漸對一件事產生熱情的時候,就不會滿足於模仿了。你的品味就進入了第二階段,開始自覺地進行原創。
我想,最偉大的大師最終會達到一種超脫自我的境界。他們一心想找到正確答案,如果別人已經回答出了一部分,那就沒理由不拿來用。他們足夠自信地使用他人的成果,完全不擔心因此喪失個人的特點。
好設計常常是奇特的設計
我不太確定原因,可能是因為我不夠聰明,才會覺得它們看上去很奇特。一條狗看到開罐器也會認為那是一個奇跡。如果我是天才的話,可能會覺得eiπ = -1是再平常不過的事情,它又沒有說錯,有什麽好奇怪的。
我在前文提到的好設計的大多數特點都是可以培育出來的,但是我覺得“奇特”這個特點是無法培育的。你最多就是在它開始顯現時不要把它扼殺掉。愛因斯坦並不想讓相對論變得很奇特,他只想找出真理,是真理本身顯得很奇特。
你最後發展出來的風格是自然而然形成的。“奇特”這個特點尤其如此,沒有其他路可走。唯一達到“奇特”的方法,就是追求做出好作品,完成之後再回過頭看。
好設計是成批出現的
推動人才成批湧現的最大因素就是,讓有天賦的人聚在一起,共同解決某個難題。互相激勵比天賦更重要,達·芬奇之所以成為達·芬奇,主要原因不僅僅是他的天賦,更重要的是他生活在當時的佛羅倫薩,而不是米蘭。今天,人類生活的流動性高得多,但是偉大的項目依然不成比例地集中在少數幾個熱點上:德國包豪斯建築學院、曼哈頓計劃、《紐約人》雜志、洛克希德公司的臭鼬工作室、施樂公司的帕洛阿爾托研究中心。
在歷史的任何時刻都有一些熱點項目,一些團體在這些項目上做出偉大的成績。如果你遠離這些中心,幾乎不可能單靠自己就取得偉大成果。某種程度上,你個人最多可以對趨勢產生一定的影響,但是你不可能決定趨勢,實際上是趨勢決定了你。(或許有人辦得到,但是米蘭的達·芬奇顯然沒有辦到。)
好設計常常是大膽的設計
在任何一段歷史中,人們都會把某些荒謬的東西當作正確的,並且深信不疑,以至於一旦你出言質疑,就有被排擠或者被暴力傷害的危險。
我們自己的這個時代要是不同以往,當然令人歡欣鼓舞。伹是就我所知,它並沒有任何不同。
這個問題不僅存在於每個年代,還或多或少存在於每個領域。許多文藝覆興時期的藝術作品在當時都被認為極其大逆不道。根據意大利畫家瓦薩裏的記載,波提切利因此向教會懺悔並且放棄繪畫,巴爾托洛梅奧和洛倫索迪克雷迪則是把自己的作品燒掉。愛因斯坦的相對論觸犯了許多同時代的物理學家,許多年後還沒有被完全接受,法國物理學家直到20世紀50年代才接受相對論。
今天的實驗性錯誤就是明天的新理論。如果你想做出偉大的新成果,那就不能對常識與真理不相吻合之處視而不見,反而應該特別註意才對。實際上,我覺得發現醜陋的東西要比你想象出一個優美的東西更容易。大多數做出優美成果的人好像只是為了修正他們眼中醜陋的東西。偉大成果的出現常常來源於某人看到一樣東西後,心想我能做得比這更好。拜占庭帝國的《聖母像》最早是根據某個公認的模板畫的,非常機械呆板。幾百年後的14世紀,意大利畫家喬托看到以後,深感不滿,決定動手改進,他因此成為文藝覆興的先行者。哥白尼對地心說無法解釋的事情深感困擾,他的同時代人都覺得這可以忍受,他卻認為一定能找到一種更好的解釋。
單單是無法容忍醜陋的東西還不夠,只有對這個領域非常熟悉,你才可能發現哪些地方可以動手改進。你必須鍛煉自己。只有在成為某個領域的專家之後,你才會聽到心裏有一個細微的聲音說:“這樣解決太糟糕了!一定有更好的選擇。”不要忽視這種聲音,要培育它們。優秀作品的秘塊就是:非常嚴格的品味,再加上實現這種品味的能力。
第十章 編程語言解析
Vines: 這篇對IT人非常重要,我幾乎把整篇搬過來了。
什麽是編程語言?為什麽它們現在很熱門?
所有機器都有一張操作命令清單,讓你可以控制它。有時這個清單非常簡短。電水壺就只允許兩種操作:打開和關閉。CD播放器稍微覆雜點,除了打開和關閉以外,還能調節音量、播放、暫停、快進、快退、隨機播放等。
計算機和其他機器一樣,也有一張操作命令清單。比如,可以命令計算機把兩個數相加。這種操作命令的總和就是計算機的機器語言(machine language)。
機器語言 (Machine Language)
計算機剛發明的時候,所有程序就是一條條機器語言的命令。沒過多久,程序就改成使用匯編語言了,它要比機器語言寫起來稍微方便一點。命令清單還是一樣的,就是每個命令換了一個更人性化的名字。機器語言的加法命令是11001101,這可能就是計算機內部的加法表達方式,但是在匯編語言中,這條命令就改成了add。
機器語言和匯編語言的共同問題就是,只能讓大多數計算機做一些很簡單的事情。
編程語言的一個重要特點:一個操作所需的代碼越多,就越難避免bug,也越難發現它們。
高級語言 (High Level Language)
現在假設你不得不用匯編語言開發程序,但是你有了一個助手,他可以幫你承擔那些麻煩的臟活。你的助手會用匯編語言來實現這條命令(假定他不會產生bug)。
事實上大多數程序員就是這樣工作的,不同之處就是,程序員的助手不是一個人,而是編譯器(Compiler)。所謂“編譯器”,本身就是一個程序,作用是將簡便方式書寫的程序(就像上面這一行命令)轉變為硬件可以理解的語言。
這種簡便方式書寫的程序所使用的語言就叫做高級語言。它讓你能夠使用更強大的命令開發程序,比如現在你就有了“重覆n次操作”的命令,不再僅限於只能做簡單的“兩個數相加”。
寫程序時有了方便的命令,就可以把程序寫得更簡短。在上面假想的例子中,高級語言寫出來的程序的長度只有機器語言的五分之一。所以,要是你犯錯了,現在也更容易發現。
高級語言還有一個優點,它使得程序更具有可移植性。不同計算機的機器語言都不是完全相同的。所以,你無法將為某一種機型寫的機器語言程序放到另一種機型上運行,只有徹底重寫才能實現。但是,如果你的程序是用高級語言寫的,你只需要重寫編譯器就可以了。
編譯器不是高級語言唯一的實現方法,另一種方法是使用解釋器,它的作用是實時地將代碼解釋為相應的機器語言,然後一行行運行。相比之下,編譯器則是先將整個程序全部翻譯成機器語言,然後再運行。
開放源碼 (Open Source)
編譯器處理的高級語言代碼又叫做源碼(Source Code)。它經過翻譯以後產生的機器碼就叫做目標碼。顧客購買市場上的商業軟件時得到的往往只是目標碼。(目標碼很難讀懂,所以相當於被加密了,可以保護公司的商業秘密。)但是,後來出現另一種潮流:開放源碼的軟件。你可以得到源碼,並且可以不受限制地修改它。
這兩種方式的真正區別在於,開放源碼使你對軟件有更大的控制權,如果你想理解開源軟件如何運行,只要閱讀源碼就行了。如果願意,你甚至可以修改軟件、重新編譯。
你之所以需要這樣做,一個原因可能是為了修正bug。比如,你自己不可能修正Windows的bug,因為你沒有源碼。(理論上你也許可以破解目標碼,但是實際上這是非常難的。另一方面,軟件的授權協議一般也不允許你這樣做。)這會導致很大的問題。一旦Windows出現新的安全漏洞,只能等待微軟公司發布解決方法,這還算是快的。如果bug的危害性不嚴重,只是偶爾會讓你的機器死機,那麽可能不得不等到下一次全面升級後問題才會得到解決。
開放源碼的優勢還不僅局限於可以自己動手解決bug。這裏的關鍵是所有人都可以參與。所以,開源軟件就像一篇經受同行評議的論文。許許多多的聰明人仔細閱讀了Linux和FreeBSD這樣的開源操作系統的源碼,發現並且解決了大量的bug。相比之下,Windows的可靠性只能依賴於大公司自己的質量保證部門了。
開放源碼的擁護者常常被看作反對知識產權的怪人。其中有些人確實如此,但是我本人肯定不反對知識產權。只是如果你要我安裝沒有源碼的軟件,我會非常猶豫。普通的消費者也許不需要看到他們使用的文字處理器的源碼,但是在非常強調軟件可靠的情況下,出於強烈的工程需求的考慮,會要求開放源碼。
語言的戰爭
絕大多數程序員在絕大多數時候都使用高級語言編程。現在很少有人使用匯編語言。程序員的時間要比計算機的時間昂貴得多,後者已經變得很便宜了,所以幾乎不值得非常麻煩地用匯編語言開發軟件。只有少數最關鍵的部分可能還會用到匯編語言,比如開發某個計算機遊戲時,你需要在微觀水平控制硬件,使得遊戲速度得到最大限度的終極提高。Fortran、Lisp、Cobol、Basic、C、Pascal、Smalltalk、C++、Java、Perl和Python,全都是高級語言。它們只是比較出名的幾種而已。現在的高級語言大概有幾百種之多。不同機器語言的指令集基本相同,但是高級語言就不一樣,它們開發程序的模式差別相當大。
那麽,應該使用哪一種語言?嗯,關於這個問題,現在有很多爭論。部分原因是,如果你長期使用某種語言,你就會慢慢按照這種語言的思維模式進行思考。所以,後來當你遇到其他任何一種有重大差異的語言,即使那種語言本身並沒有任何不對的地方,你也會覺得它極其難用。缺乏經驗的程序員對於各種語言優缺點的判斷經常被這種心態誤導。
可能因為想炫耀自己見多識廣,某些黑客會告訴你所有高級語言基本相似。“所有編程語言我都用過。”某個看上去飽經風霜又酷的黑客往酒吧裏一坐,“你用什麽語言並不重要,重要的是你對問題是否有正確的理解。代碼以外的東西才是關鍵。”
這當然是一派胡言。各種語言簡直是天差地別,比如Fortran I和最新版的Perl就是兩種完全不同的語言,而早期版的Perl和最新版的Perl之間的差別也大得驚人。但是,那個誇誇其談的黑客可能真的相信自己的這番話,的確有可能使用所有不同的語言寫出了與用原始的Pascal語言寫的差不多的程序。If you only ever eat at McDonald’s, it will seem that food is much the same in every country.
一些黑客只喜歡自己用的語言,反感其他所有的語言。另一些黑客則說所有的語言都一樣。事實介於這兩個極端之間。語言之間確實有差別,但是很難確定地說明哪—種語言是最好的。這個領域依然還在快速發展。
抽象性
高級語言比匯編語言更接近人類語言,而某些高級語言又比其他語言更進一步。舉例來說,C語言是一種低層次語言,很接近硬件,幾乎堪稱可移植的匯編語言,而Lisp語言的層次則是相當高。
如果高層級語言比匯編語言更有利於編程,你也許會認為語言的層次越高越好。一般情況下確實如此,但不是絕對的。編程語言可以變得很抽象,完全脫離硬件,但也有可能走錯了方向。比如,我覺得Prolog語言就有這個問題。它的抽象能力強得不可思議,但是只能用來解決2%的問題,其余時間你苦思冥想、運用這些抽象能力寫出來的程序實際上就是Pascal語言的程序。
另一個你會用到低層次語言的原因就是效率問題。如果你非常關註運行速度,那麽最好使用接近機器的語言。大多數操作系統都是用C語言寫的,這並非偶然。不過,硬件的運行速度越來越快了,所以使用C這樣的低層次語言開發應用程序的必要性正在不斷減少,但是大家似乎還是要求操作系統越快越好。(另一種可能是,人們還是希望“緩存區溢出攻擊”繼續存在下去,以便讓大家時時保持警惕)^。
^「最常見的幾種入侵計算機的手法都是利用了C語言的某些特點。當你在C語言中為輸入的內容分配出一片內存(也叫“緩存”)時,它會被分配在當前運行代碼的返回地址旁邊。所謂“返回地址”指的是一塊特定內存,當前代碼運行完畢以後,就要運行這塊內存中包含的代碼。也就是說,它實標上是計算機下一步要做的事情。
假定有人打算入侵你的計算機,他們猜出你會為某種輸入分配256字節的緩存,於是他們就提交多於256字節的內容,目的是覆蓋旁邊的“返回地址”。那麽,當前代碼運行完畢之後,程序的控制權就交給了他們指定的內存地址。這個地處通常是緩存的首地址,緩存中是入侵者事前編好的機器碼。於是,入侵者的程序就運行在你的計算機上了。
如果使用更抽象的高級語言,上面的事情是不可能發生的。伹是,在C語言中,一旦接受用戶輸入的時候你沒有檢奔輸入長度,就創造出了一個安全漏洞。利用這種漏洞的攻擊行為就被稱為“緩沖區溢出攻擊”。在這種攻擊中,還有其他方法可以控制計算機,但是覆蓋返回地址是最經典的一種。
有意思的是,劫持飛機與“緩沖區溢出攻擊”有類似之處。在一般飛機上,乘客區與駕駛艙是相通的,就好像C語言中數據區與代碼區是相鄰的一樣。劫機者一且進入駕駛艙,實際上就相當於把自己從數據提升為代碼。」
安全帶還是手銬?
語言設計者之間的最大分歧也許就在於,有些人認為編程語言應該防止程序員幹蠢事,另一些人則認為程序員應該可以用編程語言幹一切他們想幹的事。Java語言是前一個陣營的代表,perl語言則是後一個陣營的代表。(美國國防部很看中Java也就不足為奇了。)
自由語言派的信徒嘲笑另一方是“B&D”(奴役和戒律,Bondage and Discipline)語言,很無禮地暗示用那些語言編程的人是下等人。我不知道對方如何反擊這些喜歡Perl的自由派,也許他們不喜歡給別人起綽號,因此我就無從知道。
由於防止程序員做蠢事有好幾種方法,所以上面的爭論逐漸分化成幾個較小的議題。目前最活躍的議題之一就是靜態類型語言與動態類型語言之爭。在靜態類型語言中,寫代碼時必須知道每個變量的類型。而在動態類型語言中,隨便什麽時候,你都可以把變量設為任意類型的值。
靜態類型語言的擁護者認為這樣可以防止bug,並且幫助編譯器生成更快的代碼(這兩點理由都成立)。動態類型語言的擁護者認為靜態類型對程序構成了限制(這點理由也成立)。我本人更喜歡動態類型,痛恨那些限制我的自由的語言。但是,確實有一些很聰明的人看來喜歡用靜態類型語言。所以,這個問題依然值得討論,並沒有固定答案。
面向對象編程 (OOP)
眼下另一個爭論的熱點則是面向對象編程。它是一種不同的組織程序的方法。假定你要寫一個程序,計算二維圖形的面積。首先,你必須知道到底是圓形還是正方形。一種解決方法是用一整塊的代碼判斷遇到的是什麽圖形,然後再用相應的公式計算面積。面向對象編程不是這樣,它的方法是寫出兩個類,一個是圓形類,另一個是正方形類,然後每個類裏面用一小塊代碼(叫做方法)計算該類圖形的面積。求面積的時候,你就問要用哪一個類,然後再使用相應的方法得出最後答案。
這兩種不同的計算方法可能聽上去很相似,事實上,運行代碼後,實際計算面積的運算過程也很相似。(這不奇怪,因為你本來就在解決同一個問題。)但是,代碼的形式卻是大相徑庭。在面向對象編程的方式中,計算圓面積和正方形面積的代碼可能分散在不同的文件中。與圓形有關的代碼都放在一個文件中,與正方形有關的代碼則放在另一個文件中。
面向對象編程的優點在於,如果你需要修改程序,計算另一種圖形的面積,比如三角形,你只需要再另外增加一塊相應的代碼就可以了,甚至可以不修改程序的其他部分。但是,批評者會反駁說,這種方法的缺點是,由於增加代碼不用考慮其他部分,結果往往導致寫出性能不佳甚至有副作用的代碼,就好比造房子不考慮已經完成的部分一樣。
關於面向對象編程優劣的爭論並不像靜態類型與動態類型之爭那樣壁壘分明,因為編程的時候你只能在靜態類型和動態類型之中選一種。但是,面向對象編程只是程度不同的問題。事實上有兩種程度的面向對象編程:某些語言允許你以這種風格編程,另一些語言則強迫你一定要這樣編程。
我覺得後一類語言不可取。允許你做某事的語言肯定不差於強迫你做某事的語言。所以,至少在這方面我們可以得到明確的結論:你應該使用允許你面向對象編程的語言。至於你最後到底用不用則是另外一個問題了。
文藝覆興
有一件事,我想所有軟件業的人都會同意,那就是最近出現了很多新的編程語言。直到20世紀80年代,只有大機構才買得起開發編程語言所需的硬件,所以大多數編程語言都是大公司的教授或者研究員開發的。而現在,一個高中生就能搞到所有必需的硬件。
Perl語言的設計者拉裏·瓦爾^的例子啟發了很多黑客:為什麽不動手設計一種自己的語言呢?只要你懂得駕馭開源軟件社區,就會有很多人在短期內為你提供大量的代碼。
^「Larry Wall(1954-)在大學裏主修語言學。1987年為了使管理機房的工作變得方便,他在業余時間創造了Perl語言。——譯者註」
結果就是產生了一些也許可以稱為“頭重腳輕”的語言:它們的內核設計得並非很好,但是卻有著無數強大的函數庫,可以用來解決特定的問題。(你可以想象一輛本身性能很差的小汽車,車頂卻綁著一個飛機發動機。)有一些很瑣碎、很普遍的問題,程序員本來要花大量時間來解決,但是有了這些函數庫以後,解決起來就變得很容易,所以這些庫本身可能比核心的語言還要重要。所以,這些奇特組合的語言還是蠻有用的,一時間變得相當流行。車頂上綁著飛機發動機的小車也許真能開,只要你不嘗試拐彎,可能就不會出問題^。
^「提醒各位親愛的黑客,我只是打一個比方,請不要嘗試在車頂綁上飛機發動機。另外,可以認為這類“頭重腳輕”的語言存在已久,Fortran語言的流行主要就是因為它的函數庫。」
另一個結果就是語言的多樣化。編程語言之間總是存在很大區別。Fortran、Lisp、APL都是1970年以前開發出來的,它們之間的區別大得就像海星、熊、蜻蜓之間的區別。新興的開源編程語言肯定將繼承這種傳統。
現在好像每隔一段日子就能聽到一種新出現的語言。喬納森·埃裏克森把這種現象稱為“編程語言的文藝覆興”。人們有時還會用另一個說法,即“編程語言的戰爭”。這並不矛盾,文藝覆興時期就是存在很多戰爭的。
實際上,很多歷史學家相信戰爭是文藝覆興的一個副產品^。當時,歐洲活力旺盛可能就是因為它分成許多互相競爭的小國。它們互相毗鄰,所以新思想能夠從一個國家傳播到另一個國家,但是它們又互相獨立,使得單個的統治者無法遏制創新的發展。相比之下,中國古代的封建皇朝禁止民間建造大型的遠洋船只,阻止了經濟的正常發展。
^「參見Carlo Cipolla所著的《槍,帆船,帝國:技術革新在1400~1700年歐洲擴張早期階段的作用》(Guns,Sails,and Empires: Technological Innovation and the Early Phases of European Expansion 1400-1700),Pantheon,1965年出版。」
所以,程序員活在這個文藝覆興時代可能是一件好事。如果我們所有人都使用同一種編程語言,反而有可能是壞事。
第十一章 一百年後的編程語言
一百年後,人類怎樣編程?為什麽不從現在開始就這樣編程呢?
很難預測一百年後的人類生活,只有少數幾件事是可以確定的。那時,汽車將具備低空飛行能力,城市規劃的法規將放寬,大樓可以造到幾百層,大街上一天到晚看不見太陽,女性個個都學過防身術。本文只想討論其中的一個細節:一百年後,人們使用什麽語言開發軟件?
為什麽這個問題值得思考?原因不是我們最終會用上這些語言,而是幸運的話,我們從現在開始就能用上這些語言。
編程語言就像生物物種一樣,存在一個進化的脈絡,許許多多分支最終都會成為進化的死胡同。這種現象已經發生了。Cobol語言曾經流行一時,但是現在看來沒有任何後續語言繼承它的思想。它就像尼安德特人^一樣,進化之路已經走到了盡頭。
^「尼安德特人(Neanderthal),一種生活在歐洲的古人類,三萬多年前已經全部滅絕。——譯者註」
我預言Java也會如此。有人寫信說:“你怎麽能說Java不會成功呢?它已經成功了。”我覺得這要看你的成功標準是什麽。如果標準是相關書籍的出版量,或者是相信學會Java就能找到工作的大學生數量,那麽Java確實已經成功了。當我說Java不會成功時,我的意思是它和Cobol—樣,進化之路已經走到了盡頭。
這只是我的猜測,未必正確。這裏的重點不是看衰Java,而是提出編程語言存在一個進化的脈絡,從而引導讀者思考,在整個進化過程中,某一種語言的位置到底在哪裏?之所以要問這個問題,不是為了一百年後讓後人感嘆我們曾經如此英明,而是為了找到進化的主幹。它會啟發我們去選擇那些靠近主幹的語言,這樣對當前的編程最有利。
無論何時,選擇進化的主幹可能都是最佳方案。要是你不幸選錯了,變成了一個尼安德特人,那就太糟了。你的對手克魯馬努人時不時就會來攻打你,把你的食物全部偷走。
這就是我想找出一百年後的編程語言的原因。我不願意押錯賭註。
當然,猜測一百年後人們使用什麽編程語言,這本身就是一個很大的假設。也許一百年後人類已經不編程了,或者直接告訴計算機想做什麽,計算機就會自動完成。
不過,到目前為止,計算機智能並沒有取得太大進展。我猜測一百年後,人們還是使用與現在差不多的程序指揮計算機。可能有一些我們今天需要編程解決的問題,那時已經不需要編程了,但是我想,那時還會存在大量與今天一樣的編程任務。
你可能認為只有那些自以為是的人才會去預言一百年後的技術。但是,請不要忘記,軟件發展的歷史已經走過了50年。在這50年中,編程語言的進化其實是非常緩慢的,因此展望一百年後的語言並不是虛無縹緲的想法。
編程語言進化緩慢的原因在於它們並不是真正的技術。語言只是一種書寫法,而程序則是一種嚴格符合規則的描述,以書面形式記錄計算機應該如何解決你的問題。所以,編程語言的進化速度更像數學符號的進化速度,而不像真正的技術(比如交通或通信技術)的進化速度。數學符號的進化是緩慢的漸變式變化,而不是真正技術的那種跳躍式發展。
無論一百年後的計算機是什麽樣子,我們基本上可以斷定它們的運行速度一定會快得多。如果摩爾定律依然成立,一百年後計算機的運行速度將是現在的74乘以10的18次方倍(準確地說是73 786 976 294 838 206 464倍)。真是讓人難以想象。不過實際上更現實的預測並不是速度會提高這麽多,而是摩爾定律最終將不成立。不管是什麽東西,如果每18個月就增長一倍,那麽最後很可能會達到極限。但那時的計算機比現在快得多大概是毫無疑問的。即使最後只是略微快了100萬倍,也將實質性地改變編程的基本規則。如果其他條件不變,現在被認為運行速度慢的語言(即運行的效率不高)將來會有更大的發展空間。
那時,依然會有對運行速度要求很高的應用程序。我們希望計算機解決的有些問題其實是計算機本身引起的。比如,計算機處理視頻的速度取決於生成這些視頻的另一台計算機。此外,還有一些問題本身就要求無限快的處理能力,比如圖像渲染、加密/解密、模擬運算等。
既然在現實中一些應用程序本身的效率較低,而另一些應用程序會耗盡硬件提供的所有運算能力,那麽有了更快速的計算機就意味著編程語言不得不應付更多的極端情況,涵蓋更大範圍的效率要求。我們已經看到這種情況發生了。要是以幾十年前的標準衡量,有一些使用新語言開發的熱門應用程序對硬件資源的浪費非常驚人。
不僅編程語言有這種現象,這實際上是一種普遍的歷史趨勢。隨著技術的發展,每一代人都在做上一代人覺得很浪費的事情。30年前的人要是看到我們今天如此隨意地使用長途電話,一定會感到震驚。100年前的人要是看到一個普通的包裹竟然也能享受一天內從波士頓發件、途經孟菲斯、抵達紐約的待遇,恐怕就要更震驚了。
我已經預測了,一旦未來硬件的性能大幅提高將會發生什麽事。新增加的運算能力都會被糟蹋掉。
在我學習編程的年代,計算機還是稀罕玩意。我記得當時使用的微機型號是TRS-80,它的內存只有4K,為了把BASIC程序裝入內存,我不得不把源碼中的空格全部刪除。我一想到那些極其低效率的軟件,不斷重覆某些愚蠢的運算,把硬件的計算能力全部占用,就感到無法忍受。但是,我的這種反應是錯的,我就像某個出身貧寒的窮孩子,一聽到要花錢就舍不得,即使把錢用在重要場合(比如去醫院看病)都覺得很難接受。
某些浪費確實令人厭惡。比如有人就很討厭SUV(運動型多用途車),即使它采用可再生的清潔能源也改變不了看法,因為SUV來自一個令人厭惡的想法(如何使得小貨車看上去更有男子漢氣概)。但是,並非所有的浪費都是壞的。既然如今的電信基礎設施已經如此發達,再掐著時間打長途電話就有點錙銖必較了。如果有足夠的資源,你可以將長途電話和本地電話視為同一件事,一切會變得更輕松。
浪費可以分成好的浪費和壞的浪費。我感興趣的是好的浪費,即用更多的錢得到更簡單的設計。所以,問題就變成了如何才能充分利用新硬件更強大的性能最有利地“浪費”它們?
對速度的追求是人類內心深處根深蒂固的欲望。當你看著計算機這個小玩意,就會不由自主地希望程序運行得越快越好,真的要下一番功夫才能把這種欲望克制住。設計編程語言的時候,我們應該有意識地問自己,什麽時候可以放棄一些性能,換來一點點便利性的提高。
很多數據結構存在的原因都與計算機的速度有關。比如,今天的許多語言都同時有字符串和列表。從語義上看,字符串或多或少可以理解成列表的一個子集,其中的每一個元素都是字符。那麽,為什麽還需要把字符串單列為一種數據類型呢?完全可以不這麽做。只是為了提高效率,所以字符串才會存在。伹是,這種以加快運行速度為目的、卻使得編程語言的語義大大覆雜的行為,很不可取。編程語言設置字符串似乎就是一個過早優化的例子。
對於大多數程序,速度不是最關鍵的因素,所以你通常不需要費心考慮這種硬件層面上的微觀管理。隨著計算機速度越來越快,這一點已經越發明顯了。
語言設計時,對實現方式少作限制還會使得程序具備更大的靈活性。語言的規格發生變化不僅是無法避免的,也是合理的。通過編譯器的處理,按照以前規格開發的軟件就會照常運行,這就提供了靈活性。
essay(論文)這個詞來自法語的動詞essayer,意思是“試試看”。從這個原始意義來說,論文就是你寫一篇文章,試著搞清楚某件事。軟件也是如此。我覺得一些最好的軟件就像論文一樣,也就是說,當作者真正開始動手寫這些軟件的時候,他們其實不知道最後會寫出什麽結果。Lisp語言的黑客早就明白數據結構靈活性的價值。我們寫程序的第一版時,往往會把所有事情都用列表的形式處理。所以,這些最初版本可能效率低下得驚人,你必須努力克制自己才能忍住不動手優化它們,這就好像吃牛排的時候必須努力克制自己才能不去想牛排是從哪裏來的一樣,至少對我來說是這樣的。
一百年後的程序員最需要的編程語言就是可以讓你毫不費力地寫出程序第一版的編程語言,哪怕它的效率低下得驚人(至少按我們今天的眼光來看是如此)。他們會說,他們想要的就是很容易上手的編程語言。效率低下的軟件並不等於很爛的軟件。一種讓程序員做無用功的語言才真正稱得上很爛。浪費程序員的時間而不是浪費機器的時間才是真正的無效率。隨著計算機速度越來越快,這會變得越來越明顯。
即使是應用程序,使用多層形式開發也是一種很強大的技巧。自下而上的編程方法意味著要把軟件分成好幾層,每一層都可以充當它上面那一層的開發語言。這種方法往往會產生更小、更靈活的程序。它也是通往軟件聖杯——可重用性(reusability)——的最佳路線。從定義上看,語言就是可以重用的。在編程語言的幫助下,你的應用程序越是采用這種多層形式開發,它的可重用性就越好。
可重用性這個概念多多少少與20世紀80年代興起的面向對象編程有些關聯。不管怎樣尋找證據,也不可能把這兩件事完全分開。某些使用面向對象編程開發出來的軟件確實具有可重用性,但是這不是因為它使用了面向對象編程,而是因為它的開發方法是自下而上的。以函數庫為例,它們具有可重用性,是因為它們屬於語言的一部分,而不是因為它們采用面向對象或者其他編程方法。
順便說一句,我不認為面向對象編程將來會消亡。我覺得,除了某些特定的領域,這種編程方法其實沒有為優秀程序員帶來很多好處,但是它對大公司有不可抗拒的吸引力。面向對象編程使得你有辦法對面條式代碼進行可持續性開發。通過不斷地打補丁,它讓你將軟件一步步做大。大公司總是傾向於采用這樣的方式開發軟件。我預計一百年後也是如此。
既然是談論未來,最好談談並行計算(parallel computation),因為看上去並行計算好像就是為未來而存在的。無論怎麽想,並行計算似乎都是未來生活的一部分。
它會在未來實現嗎?過去二十年,人們都在說並行計算馬上就會來臨。但是,到目前為止,它對編程實踐並沒有太大影響。這是真的嗎?芯片設計師已經不得不把它考慮在內,為多CPU計算機開發系統軟件的程序員也是如此。
但是,真正的問題在於,並行計算到底能達到哪個抽象層次?一百年後它就會影響到開發應用軟件的程序員嗎?或者,它還只是編譯器作者需要考慮的事情,在應用軟件的代碼中根本就無處尋覓?
一種可能是,大多數可以用到並行計算的場合,人們都會放棄使用並行計算。雖然我總的預測是未來的軟件會揮霍掉大部分新增的硬件性能,但是並行計算是一個特例。我估計隨著硬件性能得到驚人的提升,如果你明確地說想要並行計算,那麽肯定可以得到它,但是通常情況下你不會用到它。這意味著,除了一些特殊的應用程序,一百年後的並行計算不會是那種大規模的並行計算(massive parallelism)。我預料,對於普通程序員來說,一切更像對進程進行分叉,然後讓多個進程在後台並行運行。
這是編程進行到很後期才要做的事情,屬於對程序的優化,類似於你想開發一種特定的數據結構來取代現有的數據結構。程序的第一個版本通常會忽略並行計算提供的各種好處,就好像編程開始時會忽略某種特定的數據結構給你帶來的好處一樣。
除了某些特定的應用軟件,一百年後,並行計算不會很流行。如果應用軟件真的大量使用並行計算,這就屬於過早優化了。
一百年後會有多少種編程語言?從最近來看,出現了大量的新語言。硬件性能提高是一個原因,這就允許程序員根據使用目的在運行速度和編程便利性之間做出不同的取舍。如果這就是未來的趨勢,那麽一百年後強大的硬件只會使得語言數目變得更多。
伹是,另一方面,一百年後的常用語言可能只有很少幾種。部分原因是基於我的樂觀主義,我相信在未來,如果你的作品確實很出色,你可能選擇的是一種開發起來很方便的語言。使用這種語言寫出來的軟件第一版的運行速度很慢,只有對編譯器進行優化設置後運行速度才會提升。既然我抱有這種樂觀主義,那麽我還要做一個預言。有些語言可以達到機器的最高效率,另一些語言的效率則慢到剛剛可以運行而已,兩者之間存在巨大的差距。我預言一百年後,這段差距之間的各個點上都會有對應的編程語言存在。
因為這段差距正在變得越來越大,所以性能分析器(profiler)將變得越來越重要。目前,性能分析並沒有受到重視。許多人好像仍然相信,程序運行速度提升的關鍵在於開發出能夠生成更快速代碼的編譯器。代碼效率與機器性能的差距正在不斷加大,我們將會越來越清楚地看到,應用軟件運行速度提升的關鍵在於有一個好的性能分析器幫助指導程序開發。
我說將來可能只有很少幾種常用語言,但沒有把用於特定領域的“小眾語言”(little language)算進去。我覺得,這些嵌入式語言的想法很不錯,一定會蓬勃發展。但是我判斷這些“小眾語言”會被設計成相當薄的一層,使得用戶可以一眼看出在底下作為基礎的通用型語言,這樣就減少了學習時間,降低了使用成本。
誰來設計這些未來的語言?過去10年最激動人心的趨勢之一就是開源語言的崛起,比如Perl、Python和Ruby。語言設計已經被黑客接管。到目前為止這樣到底是好是壞還看不清楚,但是發展勢頭令人鼓舞。比如,Perl就有一些絕妙的創新。不過,它也包含了一些很糟糕的想法。對於一種充滿進取心、大膽探索的語言來說,這也是很正常的事。以它現在這種變化的速率,大概只有上帝才知道一百年後Perl會變成什麽樣。有一句俗話說,如果你自己做不到,那就去當老師。這在語言設計領域不成立,我認識的一些最出色的黑客就在當教授。但是,當老師的人確實有很多事情不能做。研究性職位給黑客帶來了一些限制。在任何學術領域,都有一些題目是可以做的,另一些題目是不可以做的。不幸的是,這兩類題目的區別通常取決於它們寫成論文後看上去是不是很高深,而不是取決於它們對軟件業的發展是否重要。最極端的例子可能就是文學,文學研究者的任何成果幾乎對文學創作者都毫無影響。
雖然科學領域的狀況要稍好一點,但是研究者可以做的題目與能夠對設計優秀語言有所幫助的題目之間的交集小得令人沮喪。(奧林·希弗斯曾經對這一點表達不滿,而且說得頭頭是道。)比如,研究變量類型的論文好像多得無窮無盡,盡管事實上靜態類型語言看來無法真正支持宏(在我看來,一種語言不支持宏,那就不值得使用了)。
新語言更多地以開源項目的形式出現,而不是以研究性項目的形式出現。這是語言的一種發展趨勢。另一種發展趨勢是,新語言的設計者更多的是本身就需要使用它們的應用軟件作者,而不是編譯器作者。這似乎是好的趨勢,我期待它繼續保持下去。
設計新語言的方法之一就是直接寫下你想寫的程序,不管編譯器是否存在,也不管有沒有支持它的硬件。這就是假設存在無限的資源供你支配。不管是今天還是一百年後,這樣的假設好像都是有道理的。
你應該寫什麽程序?隨便什麽,只要能讓你最省力地寫出來就行。但是要註意,這必須是在你的思維沒有被當前使用的編程語言影響的情況下。這種影響無處不在,必須很努力才能克服。你也許覺得,對於人類這樣懶惰的生物,喜歡用最省力的方式寫程序是再自然不過的事情。但是事實上,我們的思想可能往往會受限於某種現存的語言,只采用在這種語言看來更簡單的形式,它對我們思想的束縛作用會大得令人震驚。新語言必須靠你自己去發現,不能依靠那些讓你自然而然就沈下去的思維定勢。
采用程序的長度作為它耗費工作量的近似指標是個很有用的技巧。這裏的程序長度當然不是指字符的數量,而是指各種句法元素的總長度,基本上就是整個解析樹的大小。也許不能說最短的程序就是寫起來最省力的程序,但是當你一心想把程序寫得簡潔而不是松松垮垮時,你就更接近省力這個目標,你的日子也會變得好過得多。所以,設計語言的正確做法就變成了,看著一段程序,然後問自己是不是能把它寫得更短一點?
另一個極端是,我覺得今天你就能設計出一百年後的語言內核。事實上,在有些人看來,大部分語言內核在1958年就已經設計出來了^。
^「Lisp語言的第一版規格說明書是1958年發布的。——譯者註」
如果今天就能使用一百年後的編程語言,我們會用它編程嗎?觀古而知今。如果1960年就能使用今天的編程語言,那時的人們會用它們嗎?
在某些方面,回答是否定的。今天的編程語言依賴的硬件在1960年並不存在。比如,Python這樣的語言,正確的縮進(indentation)在編寫時很重要,但是1960年的計算機沒有顯示器,只有打印機終端,所以編寫起來就不會很順利。但是,如果把這些因素排除在外(你可以假設,我們只在紙上編程),20世紀60年代的程序員會喜歡用現在的語言編程嗎?
我想他們會的。某些缺乏想象力、深受早期編程語言思想影響的人可能會覺得不可能。(沒有指針運算,如何覆制數據?沒有goto語句,如何實現流程圖?)但是我想,那時最聰明的程序員一定能輕松地使用今天的大多數語言,假定他們能得到的話。
如果我們現在就能擁有一百年後的編程語言,那就至少能用來寫出優秀的偽碼^。我們會用它開發軟件嗎?因為一百年後的編程語言需要為某些應用程序生成快速代碼,所以很可能它生成的代碼能夠在我們的硬件上運行,速度也還可以接受。相比一百年後的用戶,我們也許不得不對這種語言做更多的優化,但是總的來看,它應該仍然會為我們帶來凈收益。
^「偽碼又稱虛擬代碼,用來抽象地描述算法,而不是現實存在的編程代碼。——譯者註」
現在,我們的兩個觀點就是:(1)一百年後的編程語言在理論上今天就能設計出來;(2)如果今天真能設計出這樣一種語言,很可能現在就適合編程,並且能夠產生更好的結果。如果我們把這兩個觀點聯系起來,那就得出了一些有趣的可能性。為什麽不現在就動手嘗試寫出一百年後的編程語言呢?
當你設計語言的時候,心裏牢牢記住這個目標是有好處的。學習開車的時候,一個需要記住的原則就是要把車開直,不是通過將車身對齊畫在地上的分隔線,而是通過瞄準遠處的某個點。即使你的目標只在幾米開外,這樣做也是正確的。我認為,設計編程語言時,我們也應該這樣做。
第十二章 拒絕平庸
別忘了你的對手與你一樣,能用任何想用的語言編寫互聯網軟件。
秘密武器
埃裏克·雷蒙德寫過一篇文章《如何成為一個黑客》(How to Become aHacker)。文中有一部分專門談到,在他看來,如果你想當一個黑客,應該學習哪些語言。他建議從Python和Java入手,因為它們比較容易學。想當高級一點的黑客,還應該學習C和Perl。前者用來對付Unix系統,後者用來系統管理和開發CGI腳本。最後,真正非常嚴肅地把黑客作為人生目標的人,應該考慮學習Lisp:
Lisp很值得學習。你掌握它以後,會感到它給你帶來的極大啟發。這會大大提高你的編程水平,使你成為一個更好的程序員。盡管在實際工作中極少會用到Lisp。
在討論學習拉丁語有何價值時,你往往也會聽到這一類的話。拉丁語無助於你找工作(也許古典文學教授的工作除外),但是它可以訓練你的思維,幫助你更好地運用母語(比如英語)進行寫作。
但是且慢,拉丁語的比喻並不完全適合Lisp語言。拉丁語無助於你找工作的原因是因為沒有人說拉丁語。如果你用它寫作,沒有人能看懂。但是,Lisp是一種計算機語言,無論我們程序員使用哪一種語言與計算機交談,它都能聽懂。
如果埃裏克·雷蒙德沒有說錯,Lisp語言確實可以使你成為更好的程序員,那麽為什麽你不使用它編程呢?如果畫家有一支讓他畫得更好的畫筆,我覺得他應該會用這支筆完成所有的畫作,對不對?我在這裏不是想證明埃裏克·雷蒙德錯了。他的觀點整體上非常正確,他對Lisp語言的看法確實是大多數人的看法,但是這裏面就是有一個矛盾:Lisp語言能讓你成為更好的程序員,但你卻不用它,這難道不奇怪嗎?
為什麽不用呢?編程語言畢竟是一種工具。如果Lisp語言真的能開發出更好的程序,你就應該用它。如果它無助於編程,那麽就不會有人需要它。
這不僅僅是一個理論問題。軟件業是競爭非常激烈的行業,而且容易出現壟斷。在不考慮其他情況的條件下,某家公司的軟件更快更好用,就會把競爭者趕出這個市場。一旦你開始創業,你就會更深切地感受到這一點。一般情況是,創業公司要麽贏得一切,要麽徹底失敗。你要麽成為富翁,要麽一無所獲。創業的時候,如果你選擇了錯誤的技術,競爭對手就會一舉打敗你。
我很了解Lisp語言,我相信自己的直覺,找不出任何不使用它的理由。我們知道其他人都用C++或Perl開發軟件, 但是我們不覺得這說明了什麽問題。如果別人用什麽技術,你也用什麽技術,那麽你大概只能使用Windows了。選擇使用哪一種技術的時候,你不能考慮別人的做法,只能考慮什麽樣的技術能最好地完成工作。
創業公司尤其如此。大公司可以互相模仿,但是創業公司就不行。我覺得很多人沒有意識到這一點,尤其是一些創業者。
大公司每年平均成長大約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黑客的公司,就會真的感到如臨大敵。
第十三章 書呆子的復仇
在高科技行業,只有失敗者采用“業界最佳實踐”。
軟件業有一場永不停息的戰鬥,書生氣的開發者與官僚主義的經理之間總是發生沖突。
那些經理奇跡般地同時具備了兩種很常見但很難結合在一起的特點:(a)對技術一無所知;(b)對技術有強烈的個人觀點。
舉例來說,假設你需要寫一個軟件。你的經理根本不懂這個軟件的運作機制,也不知道各種編程語言有什麽區別。但是,他竟然明確要求你一定要使用某一種語言進行開發。沒錯,他就是要求你一定要用Java語言。
為什麽他會提出這種要求?讓我們看看他腦袋裏是怎麽想的。他的想法無非就是,Java是業界的標準。我知道肯定如此,因為媒體對此有鋪天蓋地的報道。既然它是標準,那麽使用它就不會錯。另外,這也意味著人才市場上肯定有無數Java程序員,即使現在為我打工的這批人都辭職了(真奇怪,這種事情總是不斷發生),我也能夠輕易地找到替代者。
嗯,這聽起來也不無道理。但是,它的前提是一個沒有說出口的假設,而這個假設實際上是錯的。你的經理相信所有編程語言的功能都差不多,可以互相替代。如果這種想法是對的,那麽他要求你用Java編程就很合理了。反正編程語言之間沒有區別,那麽就用大家都在用的那種語言吧。
但是,編程語言是不一樣的。就算不探討各種語言之間的具體區別,我也能向你證明這一點。回到1992年,如果你問經理使用什麽語言開發軟件。他會像今天一樣毫不遲疑地回答說C++。如果所有編程語言都一樣,為什麽答案變了?進一步說,為什麽Java語言的設計者要如此麻煩地去創造一種新語言呢?
一般來說,如果你動手創造一種新語言,那是因為你覺得它在某些方面會優於現有的語言。Java語言之父詹姆斯·戈斯林在第一份《Java白皮書》中說得很清楚,之所以要設計Java,就是想解決C++的一些弱點。所以結論就是,各種編程語言的編程能力是不相同的。
當你按照Java、Perl,Python,Ruby這樣的順序觀察這些語言,你會發現一個有趣的結果。至少,如果你是一個Lisp黑客,你就看得出來,排在越後面的語言越像Lisp。Python語言模仿Lisp,甚至把許多Lisp黑客認為屬於設計錯誤的功能也一起模仿了。至於Ruby語言,如果回到1975年,你聲稱它是一種有著自己句法的Lisp方言,沒有人會提出反對意見。編程語言現在的發展不過剛剛趕上1958年Lisp語言的水平。
語言優勢真正體現的地方
許多項目是無所謂選擇哪一種編程語言,反正不同的語言都能完成工作。一般來說,條件越苛刻的項目,強大的編程語言就越能發揮作用。但是,無數的項目根本沒有苛刻條件的限制。大多數的編程任務可能只要寫一些很小“膠水程序”,然後再把這些小程序連起來就行了。你可以用自己熟悉的編程語言或者用對於特定項目來說有著最強大函數庫的語言來寫這些“膠水程序”。
向心力
我承認,使用一種不常用的技術也有代價。你的經理擔心這一點並不是完全沒有道理的。但是,因為他不懂風險出在什麽地方,所以往往把風險誇大了。
使用一種不常見的語言會出現的問題我想到了三個:你的程序可能無法很好地與使用其他語言寫的程序協同工作;你可能找不到很多函數庫;你可能不容易雇到程序員。
它們有多嚴重?第一個問題取決於你是否控制整個系統。如果你的軟件運行在客戶的機器上,而客戶又使用一個到處都是bug的專有操作系統(我可沒提操作系統的名字),那麽使用那個操作系統的開發語言可能會給你帶來優勢。但是,如果你控制整個系統,並且還有各個組成部分的源碼(正如我推測ITA就是這種情況),那麽你就能使用任何你想用的語言。如果出現不兼容的情況,你自己就能動手解決。
把軟件運行在服務器端就可以沒有顧忌地使用最先進的技術。喬納森·埃裏克森說現在是“編程語言的文藝覆興時期”,我想最大的原因就是有了服務器端軟件。這也能解釋為什麽像Perl和Python這樣的新語言會流行起來,它們之所以流行不是因為人們使用它們開發Windows應用程序,而是因為人們在服務器上使用它們。隨著軟件從桌面端向服務器端轉移(連微軟公司都看出這是未來的趨勢),逼迫你使用某一種語言的限制將越來越少。
至於第二個問題,函數庫的重要性也取決於你的應用程序。對於那些條件不苛刻的應用,有沒有一個好的函數庫比語言本身的能力更重要。那麽到底應該怎麽選擇語言?是根據函數庫,還是根據語言本身的能力?很難確切地找出一條清楚的規則,但是無論哪種情況,你都必須考慮到你開發的應用程序的特點。如果你是一家軟件公司,你開發的程序打算拿到市場上銷售,那麽這個程序可能會耗費好幾個優秀程序員至少6個月的時間。為一個這樣規模的項目選擇編程語言,語言本身要有強大的編程能力可能就是最重要的考慮因素,比是否有方便的函數庫更重要。第三個問題是你的經理擔憂雇不到程序員,我認為這根本就是混淆視聽。說實話,你究竟想雇用多少個黑客?到目前為止,大家公認少於10個人的團隊最適合開發軟件。雇用這樣規模的開發團隊,只要使用的不是無人知道的語言,應該都不會遇到很大麻煩。如果你無法找到10個Lisp黑客,那麽你可能選錯了創立軟件公司的城市。
事實上,選擇更強大的編程語言會減少所需要的開發人員數量。因為:(a)如果你使用的語言很強大,可能會減少一些編程的工作量,也就不需要那麽多黑客了;(b)使用更高級語言的黑客可能比別的程序員更聰明。
我不是說外界因素對你沒有影響,肯定還是會有很大壓力,逼迫你使用公認的“標準”技術。Viaweb創業期間,很多風險投資商和潛在的並購方看到我們使用Lisp語言都感到很吃驚和不以為然。但是,我們讓他們吃驚的還不止這一個地方,我們使用普通的兼容機充當服務器,而不是“企業級”的Sun服務器;我們使用那時還默默無聞的開源Unix系統FreeBSD,而不是流行的商業操作系統Windows NT,我們也沒有采用SET(Secure Electronic Transaction,安全電子交易),它被認為將成為電子商務標準,而實際上現在沒人記得它。諸如此類的事情還有很多。你不能讓那些衣冠楚楚、西裝革履的家夥替你做技術決策。潛在的並購方有沒有對我們使用Lisp語言感到很難接受?稍微有一點吧,但是如果我們不使用Lisp,我們就根本寫不出現在的軟件,也就不會有人想收購我們。他們眼中不正常的事情恰恰就是使得這一切發生的原因所在。如果你創業的話,千萬不要為了取悅風險投資商或潛在並購方而設計你的產品。讓用戶感到滿意才是你的設計方向。只要贏得用戶,其他事情就會接踵而來。如果沒有用戶,誰會關心你選擇的“正統”技術是多麽令人放心。
隨大流的代價
使用一種不強大的語言,你的損失有多大?實際上有一些現成的數據可以說明這個問題。
衡量語言的編程能力的最簡單方法可能就是看代碼數量。所謂高級語言,就是能夠提供更強大抽象能力的語言,從某種意義上,就像能夠提供更大的磚頭,所以砌墻的時候用到的磚頭數量就變少了。因此,語言的編程能力越強大,寫出來的程序就越短(當然不是指字符數量,而是指獨立的語法單位)。
強大的編程語言如何讓你寫出更短的程序?一個技巧就是(在語言允許的前提下)使用“自下而上”(bottom-up)的編程方法。你不是用基礎語言(base language)開發應用程序,而是在基礎語言之上先構建一種你自己的語言,然後再用後者開發應用程序。這樣寫出來的代碼會比直接用基礎語言開發出來的短得多。實際上,大多數壓縮算法也是這樣運作的。“自下而上”的編程往往也便於修改,因為許多時候你自己添加的中間層根本不需要變化,你只需要修改前端邏輯就可以了。
代碼的數量很重要,因為開發一個程序所耗費的時間主要取決於程序的長度。對於同一個軟件,如果用一種語言寫出來的代碼比用另一種語言長三倍,這意味著你開發它耗費的時間也會多三倍。而且即使多雇人手,也無助於縮短開發時間,因為當團隊規模超過某個門檻時,再增加人手只會帶來凈損失。Fred Brooks在他的名著《人月神話》中描述了這種現象,我的所見所聞印證了他的說法。
如果使用Lisp語言,程序能變得多短?以Lisp和C的比較為例,我聽到的大多數說法是C代碼的長度是Lisp的7倍到10倍。但是最近,New Architect雜志上有一篇介紹ITA軟件公司的文章,裏面說“1行Lisp代碼相當於20行C代碼”,因為此文都是引用ITA總裁的話,所以我想這個數字來自ITA的編程實踐。如果真是這樣,那麽我們可以相信這句話。ITA的軟件不僅使用Lisp語言,還同時大量使用C和C++,所以這是他們的經驗之談。
我認為,這種比例肯定不會是一個常數。如果你遇到更困難的問題,或者你雇到了更聰明的程序員,這個比例就會增大。一種出色的工具到了真正優秀的黑客手裏,可以發揮出更大的威力。
總之,根據上面的這個數字,如果你與ITA競爭,而且你使用C語言開發軟件,那麽ITA的開發速度將比你快20倍。如果你需要一年時間實現某個功能,它只需要不到三星期。反過來說,如果ITA開發某個新功能用了三個月,那麽你需要五年才能做出來。
你知道嗎?上面的對比還只是考慮到最好的情況。當我們只比較代碼數量的時候,言下之意就是假設使用功能較弱的語言也能開發出同樣的軟件。但是事實上,程序員使用某種語言能做到的事情是有極限的。如果你想用一種低層次的語言解決一個很難的問題,那麽你將會面臨各種情況極其覆雜乃至想不清楚的窘境。
所以,當我說假定你與ITA競爭,你用五年時間做出的東西,ITA在Lisp語言的幫助下只用三個月就完成了,我指的五年還是一切順利、沒有犯錯誤、也沒有遇到太大麻煩的五年。事實上,按照大多數公司的實際情況,計劃中五年完成的項目很可能永遠都不會完成。
我承認,上面的例子太極端。ITA似乎有一批非常聰明的黑客,而C語言又是一種很低層次的語言。但是,在一個高度競爭的市場中,即使開發速度只相差兩三倍,也足以使得你永遠處在落後的位置。
一個訣竅
由於選擇了不當的編程語言而導致項目失敗的可能性,是你的經理不願意考慮的問題。事實上大部分的經理都這樣。因為你知道,總的來說,你的經理其實不關心公司是否真的能獲得成功,他真正關心的是不承擔決策失敗的責任。所以對他個人來說,最安全的做法就是跟隨大多數人的選擇。
在大型組織內部,有一個專門的術語描述這種跟隨大多數人的選擇的做法,叫做“業界最佳實踐”。這個詞出現的原因其實就是為了讓你的經理可以推卸責任。既然我選擇的是“業界最佳實踐”,如果不成功,項目失敗了,那麽你也無法指責我,因為做出選擇的人不是我,而是整個“業界”。
我認為這個詞原來是指某種會計方法,大致意思就是不要采用很奇怪的處理方法。在會計方法中,這可能是一個很好的主意。“尖端”和“核算”這兩個詞聽上去就不適合放在一起。但是如果你把這個標準引入技術決策,你就開始要出錯了。
技術本來就應該是尖端的。正如伊拉恩·加內特所說,編程語言的所謂“業界最佳實踐”,實際上不會讓你變成最佳,只會讓你變得很平常。如果你選擇的編程語言使得你開發軟件的速度只有(選擇更激進技術的)對手的幾分之一,那麽“最佳實踐”真的起錯了名字。
所以,我們就有了兩點結論,我認為它們非常有價值。事實上,這是我用自己的經歷換來的。第一,不同語言的編程能力不一樣。第二,大多數經理故意忽視第一點。你把這兩點事實結合起來,其實就得到了賺錢的訣竅。ITA軟件公司是運用這個訣竅的典型例子。如果你想在軟件業獲得成功,就使用你知道的最強大的語言,用它解決你知道的最難的問題,並且等待競爭對手的經理做出自甘平庸的選擇。
第十四章 夢寐以求的編程語言
一種好的編程語言,是讓黑客可以隨心所欲使用的語言。
我的朋友曾對一位著名的操作系統專家說他想要設計一種真正優秀的編程語言。那位專家回答,這是浪費時間,優秀的語言不一定會被市場接受,很可能無人使用,因為語言的流行不取決於它本身。至少,那位專家設計的語言就遭遇到了這種情況。
那麽,語言的流行到底取決於什麽因素呢?流行的語言是否真的值得流行呢?還有必要嘗試設計一種更好的語言嗎?如果有必要的話,怎樣才能做到這一點呢?
為了找到這些問題的答案,我想我們可以觀察黑客,了解他們使用什麽語言。編程語言本來就是為了滿足黑客的需要而產生的,當且僅當黑客喜歡一種語言時,這種語言才能成為合格的編程語言,而不是被當作“指稱語義”(denotational semantics)或者編譯器設計。
流行的秘訣
沒錯,大多數人選擇某一種編程語言,不是因為這種語言有什麽獨特的特點,而是因為聽說其他人使用這種語言。但是我認為,外界因素對於編程語言的流行其實沒有想象中那麽大的影響力。我倒是覺得,問題出在對於什麽是優秀編程語言,黑客的看法與大多數的語言設計者不一樣。
黑客的看法其實比語言設計者的更重要。編程語言不是數學定理,而是一種工具,為了便於使用,它們才被設計出來。所以,設計編程語言的時候必須考慮到人類的長處和短處,就像設計鞋子的時候必須符合人類的腳型。如果鞋子穿上去不舒服,無論它的外形多麽優美,多麽像一件藝術品,你也只能把它當作一雙壞鞋。
大多數程序員也許無法分辨語言的好壞。但是,這不代表優秀的編程語言會被埋沒,專家級黑客一眼就能認出它們,並且會拿來使用。雖然他們人數很少,但就是這樣一小群人寫出了人類所有優秀軟件。他們有著巨大的影響力,他們使用什麽語言,其他程序員往往就會跟著使用。老實說,很多時候這種影響力更像是一種命令,對於其他程序員來說,專家級黑客就像自己的老板或導師,他們說哪種語言好用,自己就會乖乖地跟進。
專家級黑客的看法不是決定一種語言流行程度的唯一因素,某些古老的軟件(Fortran和Cobol的情況)和鋪天蓋地的廣告宣傳(Ada和Java的情況)也會起到作用。但是,我認為從長期來看,專家級黑客的看法是最重要的因素。只要有了達到“臨界數量”(critical mass)的最初用戶和足夠長的時間,一種語言可能就會達到應有的流行程度。而流行本身又會使得這種優秀的語言更加優秀,進一步拉大它與平庸語言之間的好壞差異,因為使用者的反饋總是會導致語言的改進。你可以想一下,所有流行的編程語言從誕生至今的變化有多大。Perl和Fortran是極端的例子,除它們兩個之外,甚至就連Lisp都發生了很大的變化。
所以,即使不考慮語言本身的優秀是否能帶動流行,我想單單流行本身就肯定會使得這種語言變得更好,只有流行才會讓它保持優秀。編程語言的最高境界一直在發展之中。雖然語言的核心功能就像大海的深處,很少有變化,但是函數庫和開發環境之類的東西就像大海的表面,一直在洶湧澎湃。
當然,黑客必須先知道這種語言,才可能去用它。他們怎麽才能知道呢?就是從其他黑客那裏。所以不管怎樣,一開始必須有一群黑客使用這種語言,然後其他人才會知道它。我不知道“一群”的最小數量是多少,多少個黑客才算達到“臨界數量”呢?如果讓我猜,我會說20人。如果一種語言有20個獨立用戶,就意味這20個人是自主決定使用這種語言的,我覺得這就說明這種語言真的有優點。
達到這一步並非易事。如果說用戶數從0到20比從20到1000更困難,我也不會感到驚訝。發展最早的20個用戶的最好方法可能就是使用特洛伊木馬:你讓人們使用一種他們需要的應用程序,這個程序偏巧就是用某種新語言開發的。
外部因素
我們得先承認,確實有一個外部因素會影響到語言的流行。一種語言必須是某一個流行的計算機系統的腳本語言(scripting language),才會變得流行。Fortran和Cobol是早期IBM大型機的腳本語言。C是Unix的腳本語言,後來的Perl和Python也是如此。Tel是Tk的腳本語言,Visual Basic是Windows的腳本語言,(某種形式的)Lisp是Emacs的腳本語言,PHP是網絡服務器的腳本語言,Java和JavaScript是瀏覽器的腳本語言。
編程語言不是存在於真空之中。“編程”其實是及物動詞,黑客一般都是為某個系統編程,在現實中,編程語言總是與它們依附的系統聯系在一起的。所以,如果你想設計一種流行的編程語言,就不能只是單純地設計語言本身,還必須為它找到一個依附的系統,而這個系統也必須流行。除非你只想用自己設計的語言取代那個系統現有的腳本語言。
這種情況導致的一個結果就是,無法以一種語言本身的優缺點評判這種語言。另一個結果則是,只有當一種語言是某個系統的腳本語言時,它才能真正成為編程語言。如果你對此很吃驚,覺得不公平,那麽我會跟你說不必大驚小怪。這就好比大家都認為,如果一種編程語言只有語法規則,沒有一個好的實現(implementation),那麽它就不能算完整的編程語言。這些都是很正常很合理的事情,編程語言本來就該如此。
當然,編程語言本來就需要一個好的實現,而且這個實現必須是免費的。商業公司願意出錢購買軟件,但是黑客作為個人不會願意這樣做,而你想讓一種語言成功,恰恰就是需要吸引黑客。
編程語言還需要有一本介紹它的書。這本書應該不厚,文筆流暢,而且包含大量優秀的範例。布賴恩·柯尼漢和丹尼斯·裏奇合寫的《C程序設計語言》(C Programming Language)就是這方面的典範。眼下,我大槪還能再加一句,這一類書籍之中必須有一本由O’Reilly公司出版發行。這正在變成是否能吸引黑客的前提條件了。
編程語言還應該有在線文檔。事實上,在線文檔可以當作一本書來寫,但是目前它還無法取代實體書。實體書並沒有過時,它們讀起來很方便,而且出版社對書籍內容的審核是一種很有用的質量保證機制(雖然做得很不完美)。書店則是程序員發現和學習新語言的最重要的場所之一。
簡潔
假定你的語言已經能夠滿足上面三項條件——一種免費的實現,一本相關書籍,以及語言所依附的計算機系統——那麽還需要做什麽才能使得黑客喜歡上你的語言?
黑客欣賞的一個特點就是簡潔。黑客都是懶人,他們同數學家和現代主義建築師一樣,痛恨任何冗余的東西或事情。有一個笑話說,黑客動手寫程序之前,至少會在心裏盤算一下哪種語言的打字工作量最小,然後就選擇使用該語言。這個笑話其實與真實情況相差無幾。就算這真的是個笑話,語言的設計者也必須把它當真,按照它的要求設計語言。
簡潔性最重要的方面就是要使得語言更抽象。為了達到這一點,首先你設計的必須是高級語言,然後把它設計得越抽象越好。語言設計者應該總是看著代碼,問自己能不能使用更少的語法單位把它表達出來。如果你有辦法讓許多不同的程序都能更簡短地表達出來,那麽這很可能意味著你發現了一種很有用的新抽象方法。
簡潔性是靜態類型語言的力所不及之處。不考慮其他因素時,沒人願意在程序的頭部寫上一大堆的聲明語句。只要計算機可以自己推斷出來的事情,都應該讓計算機自己去推斷。舉例來說,hello-world本應該是一個很簡單的程序,但是在Java語言中卻要寫上一大堆東西,這本身就差不多可以說明Java語言設計得有問題了。
1 | public class Hello { |
如果你從來沒有接觸過編程,看到上面的代碼可能會很奇怪,讓計算機顯示一句話為什麽要鎬得這麽覆雜?有意思的是,資深程序員的反應與你一樣。」
單個的語法單位也應該很簡短。Perl和Common Lisp在這方面是兩個不同的極端。Perl的語法單位很短,導致它的代碼可以擁擠得讓人無法理解,而Common Lisp內置運算符的名稱則長得可笑。Common Lisp的設計者們可能覺得文本編輯器會幫助用戶自動填寫運算符的長名稱。但是這樣做的代價不僅是增加了打字的工作量,還包括提高了閱讀代碼的難度,以及占用了更多的顯示器空間。
可編程性(Hackability)
對黑客來說,選擇編程語言的時候,還有一個因素比簡潔更重要,那就是這種語言必須能夠幫助自己做到想做的事。在編程語言的歷史上,防止程序員做出“錯誤”舉動的措施多得驚人。這是語言設計者很自以為是的危險舉動,他們怎麽知道程序員該做什麽不該做什麽?我認為,語言設計者應該假定他們的目標用戶是一個天才,會做出各種他們無法預知的舉動,而不是假定目標用戶是一個笨手笨腳的傻瓜,需要別人的保護才不會傷到自己。如果用戶真的是傻瓜,不管你怎麽保護他,他還是會搬起石頭砸自己的腳。你也許能夠阻止他引用另一個模塊中的變量,但是你沒法防止他日日夜夜不知疲倦地寫出結構混亂的程序去解決完全錯誤的問題。
優秀程序員經常想做一些既危險又令人惱火的事情。所謂“令人惱火”,我指的是他們會突破設計者提供給用戶的外部語義層,試著控制某些高級抽象的語言內部接口。比如,黑客喜歡破解,而破解就意味著深入內部,揣測原始設計者的意圖。
你應該敞開胸懷,歡迎這種揣測,對於制造工具的人來說,總是會有用戶以違背你本意的方式使用你的工具。如果你制造的是編程語言這樣高度組合的系統,那就更是如此了。許多黑客會用你做夢也想不到的方式改動你的語法模型。我的建議就是,讓他們這樣幹吧,而且應該為他們創造便利,盡可能多地把語言的內部暴露在他們面前。
其實,黑客並不會徹底顛覆你的工具,在一個大型程序中,他可能只是對語言改造一兩個地方。但是,改動多少地方並不重要,重要的是他能夠對語言進行改動。這可能不僅有助於解決一些特殊的問題,還會讓黑客覺得很好玩。黑客改造語言的樂趣就好比外科醫生擺弄病人內臟的樂趣,或者青少年喜歡用手擠破青春痘的那種感覺。至少對男生來說,某些類型的破壞非常刺激。針對青年男性讀者的Maxim雜志每年出版一本特輯,裏面一半是美女照片,另一半是各種嚴重事故的現場照片。這本雜志非常清楚它的讀者想看什麽。
戈雷和我要了一個大比薩,找了一張空桌子坐下。他點起一根香煙,說:“那些內科醫生真是令人討厭,總是喜歡談論一輩子只能遇到一次的病例。這就是他們的問題,他們只喜歡古怪的東西,討厭普通的常見病例。這就是我們和他們的區別。你看,我們喜歡腰椎間盤突出,覺得像比薩一樣又大又好吃,但是他們看到高血壓就憎恨不已……”
很難把腰椎間盤突出與又大又好吃聯系在一起,徂是,我想我知道他們指的是什麽。我經常覺得某個bug非常誘人,一定要追蹤下去。不是程序員的人很難想象bug有什麽好玩的。一切正常當然很好,但是不可否認,能夠抓到某些bug會讓人興奮到極點。」
一種真正優秀的編程語言應該既整潔又混亂。“整潔”的意思是設計得很清楚,內核由數量不多的運算符構成,這些運算符易於理解,每一個都有很完整的獨立用途。“混亂”的意思是它允許黑客以自己的方式使用。C語言就是這樣的例子,早期的Lisp語言也是如此。真正的黑客語言總是稍微帶一點放縱不羈、不服管敎的個性。
優秀的編程語言所具備的功能,應該會使得言必稱“軟件工程”的人感到非常不滿、頻頻搖頭。與黑客語言形成鮮明對照的就是像Pascal那樣的語言,它是井然有序的模範,非常適合教學,但是除此之外就沒有很大用處了。
一次性程序
為了吸引黑客,一種編程語言必須善於完成黑客想要完成的各種任務。這意味著它必須很適合開發一次性程序。這一點可能出乎很多人的意料。
所謂一次性程序,就是指為了完成某些很簡單的臨時性任務而在很短時間內寫出來的程序。比如,自動完成某些系統管理任務的程序,或者(為了某項模擬任務)自動生成測試數據的程序,以及在不同格式之間轉化數據的程序等。令人吃驚的是,一次性程序往往不是真的只用一次,就像二戰期間很多美國大學造的一大批臨時建築後來都成了永久建築。許多一次性程序後來也都變成了正式的程序,具備了正式的功能和外部用戶。
我有一種預感,最優秀的那些大型程序就是這樣發展起來的,而不是像胡佛水壩那樣從一開始就作為大型工裎來設計。一下子從無到有做出一個大項目是很恐怖的一件事。當人們接手一個巨型項目時,很容易被它搞得一蹶不振。最後,要麽是項目陷入僵局,要麽是做出來一個規模小、性能差的東西。你想造一片鬧市,卻只做出一家商場;你想建一個羅馬,卻只造出一個巴西利亞;你想發明C語言,卻只開發出Ada。
開發大型程序的另一個方法就是從一次性程序開始,然後不斷地改進。這種方法比較不會讓人望而生畏,程序在不斷的開發之中逐漸進步。一般來說,使用這種方法開發程序,一開始用什麽編程語言,就會一直用到最後,因為除非有外部政治因素的幹預,程序員很少會中途更換編程語言。所以,我們就有了一個看似矛盾的結論:如果你想設計一種適合開發大型項目的編程語言,就必須使得這種語言也適合開發一次性程序,因為大型項目就是從一次性程序演變而來的。
Perl就是一個鮮明的例子。它不僅僅設計成適合開發一次性程序,而且它本身就很像一次性程序。最初的Perl只是好幾個生成表格的工具收集在一起而已。後來程序員用它寫一次性程序,當那些程序逐漸發展壯大後,Perl才隨之發展成了一種正式的編程語言。到了Perl 5,這種語言才適合開發重要的程序,但是在此之前它已經廣為流行了。
什麽樣的語言適合寫一次性程序?首先,它必須很容易裝備。一次性程序是你只想在一小時內寫出來的程序,所以它不應該耗費很多時間安裝和配置,最好已經安裝在你的電腦上了。它必須是想用就用的。C語言可以想用就用,因為它是操作系統的一部分;Perl可以想用就用,因為它本來就是一種系統管理工具,操作系統已經默認安裝它了。
很容易裝備不僅僅指很容易安裝或者已經安裝,還指很容易與使用者互動。一種有命令行界面、可以實時反饋的語言就具有互動性,那些必須先編譯後使用的語言就不具備互動性。受歡迎的編程語言應該是前者,具有良好的互動性,可以快速得到運行結果。
一次性程序的另一個特點就是簡潔。對黑客來說,這一點永遠有吸引力。如果考慮到你最多只打算在這個程序上耗費一個小時,這一點就更重要了。
函數庫
簡潔性的最高形式當然是有人已經幫你把程序寫好,你只要運行就可以了。函數庫就是別人幫你寫好的程序,所以它是編程語言的另一個重要特點,並且我認為正在變得越來越重要。Perl就贏在它具有操作字符串的巨大函數庫。這類函數庫對一次性程序特別重要,因為開發一次性程序的原始目的往往就是轉化或提取字符串。許多Perl程序的原型可能就是把幾個函數庫調用放在一起。
我認為,未來50年中,編程語言的進步很大一部分與函數庫有關。未來的函數庫將像語言內核一樣精心設計。優秀函數庫的重要性將超過語言本身。某種語言到底是靜態類型還是動態類型、是面向對象還是函數式編程,這些都不如函數庫重要。那些習慣用變量類型考慮問題的語言設計者可能會對這種趨勢感到不寒而栗。這不等於把語言設計降到開發應用程序的層次嗎?哦,真是太糟了。但是別忘了,編程語言是供程序員使用的,而函數庫就是程序員需要的東西。
設計優秀的函數庫是很難的,並不只是寫一大堆代碼而已。一且函數庫數量變得太多,找到一個你需要的函數有時候還不如自己動手寫來得快。函數庫的設計基礎與語言內核一樣,都是一個小規模的正交運算符集合。函數庫的使用應該符合程序員的直覺,讓他可以猜得出哪個函數能滿足自己的需要。
效率
眾所周知,好的編程語言生成的代碼有較快的運行速度。但是實際上,我覺得代碼的運行速度不是編程語言的設計者能夠控制的。高德納很久以前就指出,運行速度只取決於一些關鍵的瓶頸。而在編程實踐中,許多程序員都已經註意到自己很容易搞錯瓶頸到底在哪裏。
所以,編程時提高代碼運行速度的關鍵是使用好的性能分析器(profiler),而不是使用其他方法,比如精心選擇一種靜態類型的編程語言。為了提高運行速度,並沒有必要每個函數的每個參數類型都聲明清楚,你只需要在瓶頸處聲明清楚參數類型就可以了。所以,更重要的是你需要能夠找出瓶頸到底在什麽地方。
人們在使用非常高級的語言(比如Lisp)時,經常抱怨很難知道哪個部分對性能的影響比較大。可能確實如此,如果你使用一種非常抽象的語言,這也許是無法避免的。不管怎樣,我認為一個好的性能分析器會解決這個問題,雖然這方面還有很長的路要走,但是未來你可以快速知道程序每個部分的時間開銷。
這個問題一部分源於溝通不暢。語言設計者喜歡提高編譯器的速度,認為這是對自己技術水平的考驗,而最多只把性能分析器當作一個附送給使用者的贈品。但是在現實中,一個好的性能分析器對程序的幫助可能大於編譯器的作用。這裏又一次反映出語言設計者與用戶之間發生了脫節,前者竭盡全力想要解決的問題其實方向不甚正確。
讓性能分析器自動運行可能是一個好主意。它自動告訴程序員每個部分的性能,而不是非要等到程序員手動運行後才能知道。比如,當程序員編輯源碼的時候,代碼編輯器能夠實時用紅色顯示瓶頸的部分。另一個方法應該是設法顯示正在運行的程序的情況,這對互聯網軟件尤其重要,因為服務器上有很多程序同時運行,它們都需要你密切關註。自動運行的性能分析器用圖形實時顯示程序運行時的內存狀況,甚至可以發出聲音,表示出現了問題。
出現問題時,聲音是很好的提示。我們在Viaweb搞了一塊很大的面板,上面有各種各樣的儀表盤,用來顯示服務器的狀況。儀表盤的指針由微型馬達驅動,每當馬達旋轉的時候,就會發出一陣輕微的噪音。在我的工位沒法看到儀表盤,但是只要我聽到聲音,就能立刻知道服務器出現了問題。
性能分析器甚至有可能自動找出不合理的算法。如果將來有人發現某種形式的內存訪問是不合理算法的信號,我不會感到很驚訝。如果有一個小人兒可以鉆進計算機看看我們的程序是怎麽運行的,他可能會變成一個忙碌又悲慘的可憐蟲,就像那些為政府跑腿的小人物。我總覺得自己用處理器做了很多無用功,伹是一直沒有找到能夠看出程序是怎樣浪費運算能力的好辦法。
現在有一些語言先編譯成字節碼(byte code),然後再由解釋器執行。這樣做主要是為了讓代碼容易移植到不同的操作系統,伹是這也可以變成一項很有用的功能。讓字節碼成為語言的正式組成部分,允許程序員在瓶頸處內嵌字節碼,這可能是一個不錯的主意。然後,針對這部分字節碼的優化也就變得可以移植了。
正如許多最終用戶已經意識到的,運行速度的概念正在發生變化。隨著互聯網軟件的興起,越來越多的程序主要不是受限於計算機的運算速度,而是受限於I/O的速度。加快I/O速度將是很值得做的一件事。在這方面,編程語言也能起到作用,有些措施是顯而易見的,比如采用簡潔、快速、格式化輸出的函數,還有些措施則需要深層次的結構變化,比如采用緩存和持久化對象(persistent object)。
用戶關心的是反應時間(response time),但是軟件的另一種效率正在變得越來越重要,那就是每個處理器能夠同時支持的用戶數量。未來許多有趣的應用程序都將是運行在服務器端的互聯網軟件,所以每台服務器能夠支持的用戶數量就成了軟件業者的關鍵問題。互聯網軟件的資本支出就取決於這個指標。
許多年以來,大多數面向最終用戶的程序都不太關心效率。軟件開發者總是假設用戶桌面電腦的運算能力會不斷增長,所以不用刻意提高軟件的效率。帕金森定律^被證明與摩爾定律一樣顛撲不破。軟件不斷膨脹,消耗光所有可以得到的資源。這一切將隨著互聯網軟件的出現發生改變,因為硬件和軟件現在捆綁在一起供應。對於那些提供互聯網軟件的公司來說,每台服務器支持的用戶數量最大化會對降低成本產生巨大影響。
^「帕金森定律(Parkinson’s Law)的一種原始表達形式是“工作總是到最後一刻才會完成”,後來引申到計算機領域就變成了“數據總是會填滿所有空間”,更一般性的總結則是“對一種資源的需求總是會消耗光這種資源的所有供應”。——譯者註」
在一些應用程序中,處理器的運算能力是瓶頸,那麽最重要的優化對象就是軟件的運行速度。但是,一般情況下內存才是瓶頸,你能夠同時支持的用戶數量取決於用戶數據所消耗的內存。編程語言在這方面也能發揮作用,對線程的良好支持將使得所有用戶共享同一個內存堆(heap)。持久化對象和語言內核級別的延遲加載(lazy loading)支持也有助於減少內存需求。
時間
一種編程語言要想變得流行,最後一關就是要經受住時間的考驗。沒人想用一種會被淘汰的語言編程,這方面已經有很多前車之鑒了。所以,大多數黑客往往會等上幾年,看看某一種新語言的勢頭,然後才真正考慮使用它。
新事物的發明者通常對這個發現很震驚,他們沒想到人們居然這樣對待發明創造。但是,讓別人相信一種新事物是需要時間的。我有一個朋友,他的客戶第一次提出某種需求時,他很少理會。因為他知道人們有時候會想要自己並不真正需要的東西。為了避免浪費時間,只有當客戶第三次或第四次提出同樣的需求時,他才認真對待。這個時候客戶可能已經很不高興了,但是這至少保證他們提出的需求應該就是他們真正需要的東西。
大多數人接觸新事物時都學會了使用類似的過濾機制。甚至有時要聽到別人提起十遍以上他們才會留意。這樣做完全是合理的,因為大多數的熱門新商品事後被證明都是浪費時間的噱頭,沒多久就消失得無影無蹤。虛擬現實建模語言VRML剛誕生時曾經轟動一時,但是我決定等到一兩年後再去學習它,結果一兩年後已經沒有學習的必要了,因為市場已經把它遺忘了。
所以,發明新事物的人必須有耐心,要常年累月不斷地做市場推廣,直到人們開始接受這種發明。我們就耗費了好幾年才使得客戶明白ViaWeb不需要下載安裝就能使用。不過,好消息是,簡單重覆同一個信息就能解決這個問題。你只需要不停地重覆同一句話,最終人們將會開始傾聽。人們真正註意到你的時候,不是第一眼看到你站在那裏,而是發現過了這麽久你居然還在那裏。
新事物的發展改進一般也需要很長時間。大多數技術在誕生後都逐漸發生了巨大的變化,編程語言更是如此。誕生頭幾年,一小批早期使用者比其他因素更能促進技術發展。早期使用者都是行家,要求也很高,能夠很快找出你的技術中存在的缺點。而且,如果你的用戶只有很少幾個人,你就能夠與他們所有人保持密切接觸。只要不斷改進你的系統,即使給用戶造成了損失,早期使用者也會對你寬容大度的。
新技術被市場接納的方式有兩種,一種是自然成長式,另一種是大爆炸式。自然成長式的一個例子就是在車庫裏白手起家、自力更生的創業者。幾個好朋友埋頭工作,在外界毫不知曉的情況下開發出某種新技術。他們把它推向市場,沒有任何宣傳,最初的用戶寥寥無幾(但是熱心程度無與倫比)。創業者持續改進新技術,與此同時,通過口碑效應,用戶數量不斷增長。在創業者不經意間,他們已經壯大起來了。
大爆炸式的例子是有風險資本支持、在市場上大張旗鼓宣傳的創業公司。他們急急忙忙地開發一個產品,推向市場的時候大肆曝光,立刻就獲得了一大批使用者(至少他們希望如此)。
一般來說,車庫裏的創業者會妒忌大爆炸式的創業公司。後者的主導人物個個光彩照人、自信非凡,深受風險資本商的追捧。他們什麽都買得起,在公關公司配合產品推出的宣傳活動中,他們自己也附帶成為了明星人物。自然成長式的創業者坐在自家車庫裏,覺得自己又窮又可憐。伹是我想他們不必難過。最終來看,自然成長式會比大爆炸式產生更好的技術,能為創始人帶來更多的財富。如果你研究一下目前的主流技術,就會發現大部分都是源於自然成長式。
這種模式不僅存在於商業公司,還存在於科研活動中。Multics操作系統和Ada語言是大爆炸式項目,現在都已經銷聲匿跡了,而它們的繼承者Unix和C語言則是自然成長式項目。
再設計
著名散文家E.B.懷特說過,“最好的文字來自不停的修改”。所有優秀作家都知道這一點,它對軟件開發也適用。設計一樣東西,最重要的一點就是要經常“再設計”,編程尤其如此,再多的修改都不過分。為了寫出優秀軟件,你必須同時具備兩種互相沖突的信念。一方面,你要像初生牛犢一樣,對自己的能力信心萬丈;另一方面,你又要像歷經滄桑的老人一樣,對自己的能力抱著懷疑態度。在你的大腦中,有一個聲音說“千難萬險只等閑”,還有一個聲音卻說“早歲哪知世事艱”。
這裏的難點在於你要意識到,實際上這兩種信念並不矛盾。你的樂觀主義和懷疑傾向分別針對兩個不同的對象。你必須對解決難題的可能性保持樂觀,同時對當前解法的合理性保持懷疑。
做出優秀成果的人,在做的過程中常常覺得自己做得不夠好。其他人看到他們的成果覺得棒極了,而創造者本人看到的都是自己作品的缺陷。這種視角的差異並非偶然,因為只有對現狀不滿,才會造就傑出的成果。
如果你能平衡好希望和擔憂,它們就會推動項目前進,就像自行車在保持平衡中前進一樣。在創新活動的第一階段,你不知疲倦地猛攻某個難題,自信一定能夠解決它。到了第二階段,你在清晨的寒風中看到自己已經完成的部分,清楚地意識到存在各種各樣的缺陷。此時,只要你對自己的懷疑沒有超過你對自己的信心,就能夠坦然接受這個半成品,心想不管多難我還是可以把剩下的部分做完。
讓這兩股相反的力量保持平衡是很難的。初出茅廬的年輕黑客都很樂觀,自以為做出了偉大的產品,從不反思和改進。上了年紀的黑客又太不自信,甚至故意回避一些挑戰性很強的項目。
任何措施,只要能讓“再設計”周而覆始地進行下去,就都是可取的。文章可以修改到你滿意為止,但是軟件的修改通常來說可以無休止地進行下去。文章的讀者不可能抱怨修改後新增加的內容讓他們前後的思想產生了不協調,但是軟件的使用者就會抱怨修改後的版本有不兼容問題。
用戶是一把雙刃劍。他們推動語言的發展,但也使得你不敢對語言進行大規模改造。所以,一開始的時候要精心選擇用戶,避免使用者過快增長。發展用戶就像一種優化過程,明智的做法就是放慢速度。一般情況下,用戶比較少意味著你任何時候都可以加大修改的力度。這時,對語言規格做出改變就像撕繃帶,當你感到痛苦的一瞬間,痛苦就已經成為了回憶。如果用戶數量龐大,修改語言帶來的痛苦就將持續很長時間。
大家都知道,讓一個委員會負責設計語言是非常糟糕的主意。委員會只會做出惡劣的設計。但是我覺得,委員會最大的問題在於他們妨礙了“再設計”。在委員會的主持下,修改一種語言是非常麻煩的事,沒有人願意自討苦吃。而且,即使大多數成員不喜歡某種做法,委員會最後的決定往往還是維持現狀。
就算委員會只有兩個人,還是會妨礙“再設計”,典型例子就是軟件內部的各個接口由不同的人負責。這時除非兩個人都同意改變接口,否則接口就無法改變。因此現實中,盡管軟件功能越來越強大,內部接口卻往往一成不變,成為整個系統中拖後腿的部分。
一種可能的解決方法是,將軟件內部的接口設計成垂直接口而不是水平接口。這意味著軟件內部的模塊是一個個垂直堆積起來的抽象層,層與層之間的接口完全由其中的一層控制。如果較高的一層使用了較低的一層定義的語言,那麽接口就由較低的一層控制;如果較低的一層從屬於較高的一層,那麽接口就由較高的一層控制。
夢寐以求的編程語言
讓我們試著描述黑客心目中夢寐以求的語言來為以上內容做個小結。這種語言幹凈簡練,具有最高層次的抽象和互動性,而且很容易裝備,可以只用很少的代碼就解決常見的問題。不管是什麽程序,你真正要寫的代碼幾乎都與你自己的特定設置有關,其他具有普遍性的問題都有現成的函數庫可以調用。
這種語言的句法短到令人生疑。你輸入的命令中,沒有任何一個字母是多余的,甚至用到Shift鍵的杌會也很少。
這種語言的抽象程度很高,使得你可以快速寫出一個程序的原型。然後,等到你開始優化的時候,它還提供一個真正出色的性能分析器,告訴你應該重點關註什麽地方。你能讓多重循環快得難以置信,並且在需要的地方還能直接嵌入字節碼。
這種語言有大量優秀的範例可供學習,而且非常符合直覺,你只需花幾分鐘閱讀範例就能領會應該如何使用此種語言。你偶爾才需要查閱操作手冊,它本身很薄,裏面關於限定條件和例外情況的警告寥寥無幾。這種語言的內核很小,但很強大。各個函數庫高度獨立,而且和內核一樣經過精心設計,它們都能很好地協同工作。語言的每個部分就像精密照相機的各種零件一樣完美契合,不需要為了兼容性問題放棄或者保留某些功能。所有函數庫的源碼都很容易得到。這種語言能夠很輕松地與操作系統和用其他語言開發的應用裎序對話。
這種語言以層的方式構建。較高的抽象層透明地構建在較低的抽象層之上。如果需要的話,你可以直接使用較低的抽象層。
除了一些絕對必要隱藏的東西,這種語言的所有細節對使用者都是透明的。它提供的抽象能力只是為了方便你的開發,而不是為了強迫你按照它的方式行事。事實上,它鼓勵你參與它的設計,給你提供與語言創造者平等的權力。你能夠對它的任何部分加以改變,甚至包括它的語法。它盡可能讓你自己定義的部分與它本身定義的部分處於同等地位。這種夢幻般的編程語言不僅開放源碼,更開放自身的設計。
第十五章 設計與研究
研究必須是“新”的,而設計必須是“好”的。
如果把創造一種編程語言看成是設計問題,而不是科研方向,那麽有何不同?
最大的不同在於你會更多地考慮用戶。設計的時候,一開始總是問:我為誰設計?他們需要什麽?比如,優秀的建築師不會先設計,然後強迫用戶接受,而是先研究最終用戶的需求,然後做出用戶需要的設計。
註意,我說的是“用戶需要的設計”,而不是“用戶要求的設計”。我不想讓讀者產生一種印象,認為設計師就像廚師一樣,顧客點什麽菜就一模一樣做出來。藝術的各個領域有著巨大的差別,但是我覺得任何一個領域的最佳作品都不可能由對用戶言聽計從的人做出來。
有一句話說“顧客永遠是對的”,這是指評價優秀設計的標準是看它能夠多大程度上滿足用戶的需求。如果你的小說沒人愛看,或者你做的椅子極不舒服,那麽就說明你的作品失敗了,被一票否決了。就算你的小說(或者椅子)有著最先進的理論指導也無濟於事。
可是,讓用戶滿意並不等於迎合用戶的一切要求。用戶不了解所有可能的選擇,也經常弄錯自己真正想要的東西。做一個好的設計師就像做一個好醫生一樣。你不能頭痛醫頭,腳痛醫腳。病人告訴你癥狀,你必須找出他生病的真正原因,然後針對病因進行治療。
大多數優秀設計都是這樣產生的,它們關註用戶,並且以用戶為中心。
我說設計必須考慮用戶的需求,這裏的“用戶”並不是指所有普羅大眾。事實上,你可以選擇任何想要的目標用戶。比如,假定你正在設計一種工具,你可以把目標用戶定為初學者,也可以定為專家級用戶。一種人眼裏的優秀設計可能在另一種人眼裏卻是糟糕無比。這裏的重點是你必須選出某些人作為你的目標用戶。我覺得,除非設定目標用戶,否則一種設計的好壞根本無從談起。
如果目標用戶群體涵蓋了設計師本人,那麽最有可能誕生優秀設計。如果目標用戶與你本人差別很大,你往往會假定目標用戶的需求比你本人的需求更簡單,而不是更覆雜。低估用戶(即使出於善意)一般來說總是會讓設計師出錯。我懷疑那些設計“公共住宅項目”(housing project)^的建築師根本沒想過自己住在裏面會是什麽感覺。編程語言也有這種現象。C、Lisp和Smalltalk都是設計者為了自己使用而設計的,而Cobol、Ada和Java則是為了給別人使用而設計的。
^「“公共住宅”指的是由政府出資建造的房產,用來出租給低收入家庭居住,類似於廉租房。——譯者註」
如果你覺得自己在為傻瓜設計產品,那麽很可能不僅無法設計出優秀產品,而且就連傻瓜也不喜歡你的設計。
不過,就算你的設計針對的是最高端的用戶,你也一樣是設計給人類使用。研究就不一樣了。做數學研究時,你不會只為了方便讀者理解而故意選擇一種更麻煩的證明方式,你只會選擇最直接、最簡潔的證明。我想,一般來說科學研究都是這樣。科學觀點不需要服從人類工程學(ergonomic)。
到了藝術領域,情況就完全變了。設計必須以人為本。設計椅子的時候,你不能只考慮椅子,還必須考慮人體各種千奇百怪的特點,不可能回避掉這一點。所有的藝術都必須迎合人類的興趣和極限。舉例來說,不考慮其他因素時,肖像畫就是比風景畫更能引發觀眾的興趣。文藝覆興時期的經典繪畫作品都是畫人的,這並非巧合。如果繪畫藝術不能用來表現人類本身,那麽繪畫也不會成為今天這樣受推崇的藝術形式了。
不管你喜不喜歡,編程語言也是以人為本的。我懷疑人類的大腦與軀幹一樣,都有著許多令人琢磨不透的特點。否則為什麽有些事情人類特別擅長,而另一些事情人類幹起來特別困難。比如,人類似乎不善於處理精細的工作,所以最好還是交給計算機處理。另一方面,如果人類真的擅長和細節打交道,那麽我們應該都用機器語言編程才對。
另外,還要記住一點。怎麽理解編程語言?你不要把它看成那些已完成的程序的表達方式,而應該把它理解成促進程序從無到有的一種媒介。這裏的意思是說,成品的材料和開發時用的材料其實是不一樣的。搞藝術的人都知道,這兩個階段往往需要不同的媒介。比如,大理石是一種非常良好、耐用的材料,很適合用於最後的成品,但是它極其缺乏彈性和靈活性,所以不適合在構思階段用來做模型。
最後寫出來的程序就像已經完成的數學證明一樣,是一棵經過精心修剪的樹木,上面雜亂滋生的樹杈都已經被剪去了。所以,評價一種語言的優劣不能簡單地看最後的程序是否表達得很漂亮,而要看程序從無到有的那條完成路徑是否很漂亮。某種設計使得最後的程序非常漂亮,伹是不一定同時具備漂亮的編程過程。比如,我寫過一些宏,它們的作用是自動生成另一些宏,它們看上去非常精美優雅,就像一粒粒精細的寶石。但是,開發過程非常醜陋,我就是連續好幾個小時不停地試錯,而且老實說,至今仍然無法完全確定它們是否百分之百正確。
我們常常采用錯誤的方法評價編程語言,只看一眼最後完成的程序就做出判斷。同一個軟件有兩種不同語言開發的版本,你發現其中一個版本比另一個版本短得多,於是非常自信地認定前者的編程語言比後者的更好。但是,如果你從藝術創作的角度思考這個問題,就不太可能這樣評價編程語言。因為你不想最後只剩下一種像大理石那樣漂亮、又像大理石那樣難用的編程語言。
為了做出優秀的設計,你必須貼近用戶,始終寸步不離,永遠站在用戶的角度調整自己的構想。19世紀英國作家簡·奧斯汀的小說為何如此出色?一個原因就是她把自己的作品大聲讀給家人聽,所以她就不會陷入孤芳自賞難以自拔的境地,不會長篇累牘地讚嘆自然風光,也不會滔滔不絕地宣揚自己的人生哲學。(事實上,簡·奧斯汀還是在小說裏宣揚了自己的人生哲學,不過她把它編進故事之中,而不是直接像貼標簽那樣講出來。)你可以隨便找一本平庸的“文學”讀物,想象一下把它當作自己的作品讀給朋友們聽,這樣會讓你真切地感受到那些“文學”讀物高高在上的視角,讀者必須承受所有沈重的負擔才能閱讀這些作品。
在軟件領域,貼近用戶的設計思想被歸納為“弱即是強”(Worse is Better)模式^。這個模式實際上包含了好幾種不同的思想,所以至今人們還在爭論它是否真的成立。但是,其中有一點是正確的,那就是如果你正在設計某種新東西,就應該盡快拿出原型,聽取用戶的意見。
^「“弱即是強"指的是一種軟件傳播的模式,由Common Lisp專家理査德·加布裏埃爾(Richard P. Gabriel)於1991年在Lisp: Good News, Bad News, How to Win Big(m/WIB.html)一文中首先提出。它的含義非常廣泛,涉及軟件設計思想的各個方面,其中的一個重要結論就是軟件功能的增加並不必然帶來質量的提高。有時候,更少的功能(“弱”)反而是更好的選擇(“強”),因為這會使得軟件的可用性提高。相比那些體積龐大、功能全面、較難上手的軟件,一種功能有限但易於使用的軟件可能對用戶有更大的吸引力。加布裏埃爾本人經常舉Unix和C語言的例子,Unix和C在設計上考慮了實際環境,放棄了一些功能,但是保證了簡單性,這使得它們最終在競爭中勝出,成為主流操作系統和編程語言。——譯者註」
與之對照,還有另一種軟件設計思想,也許可以被稱為“萬福瑪麗亞”模式。它不要求盡快拿出原型,然後再逐步優化,它的觀點是你應該等到完整的成品出來以後再一下子隆重地推向市場,就像聖母瑪麗亞降臨一樣,哪怕整個過程漫長得像橄攬球運動員長途奔襲、達陣得分也沒有關系。在互聯網泡沫時期,無數創業公司因為相信了這種模式而自毀前程。我還沒聽說過有人采用這種模式而獲得成功。
軟件領域以外的人可能沒聽過“弱即是強”,所以意識不到這種模式在藝術領域普遍存在。以繪畫為例,文藝覆興時期就有人發現了這一點。如今,幾乎所有的美術老師都會告訴你準確畫出一個事物的方法,不是沿著輪廓慢慢一個部分、一個部分地把它畫出來,因為這樣的話各個部分的錯誤會累積起來,最終導致整幅畫失真。你真正應該采用的方法是快速地用幾根線畫出一個大致準確的輪廓,然後再逐步地加工草稿。
在大多數藝術領域,原型使用的材料與成品的材料一般來說是不一樣的。印刷活字先畫在紙上,然後才做成鉛字。雕塑先用石蠟創作,然後才用青銅澆鑄。地毯圖案先用墨水畫出紙型,然後才織成地毯。建築物先做出木模型,然後才做成石頭建築。
為什麽15世紀油畫首次亮相會引起轟動並很快流行起來?原因就是油彩使得畫家可以在原型上直接畫出最後的樣子。你可以按照自己的想法畫出初稿,但是它並不對你構成限制。接下來你可以逐步加上細節,甚至對初稿做出重大修改,直到最後完成。
軟件開發也可以這樣做。原型(prototype)並不只是模型(model),不等於將來一定要另起爐竈,你完全能夠在原型的基礎上直接做出最後的成品。我認為,只要有可能,你就應該這樣做。這樣的方式使得你可以利用在開發過程中一路產生的新想法。不過更重要的是,這樣做有助於鼓舞士氣。
士氣是設計的關鍵因素。令我吃驚的是,大家很少提到這一點。我的一位美術啟蒙老師告訴我:如果你覺得畫某樣東西很乏味,那麽你畫出來的東西就會真的很乏味。比如,假設你必須畫一幢建築物,你決定從每一塊磚頭開始畫起。你覺得自己可以堅持下去,但是畫到一半的時候突然感到很厭倦,於是你就不再認真觀察每塊磚頭並畫出它們各自不同的特點,而是以一種機械重覆的方式草草地把磚頭畫完了事。這樣一來,你的作品效果就很差,甚至還不如一開始就不采用寫實手法,只是若隱若現地暗示磚頭的存在。
先做出原型,再逐步加工做出成品,這種方式有利於鼓舞士氣,因為它使得你隨時都可以看到工作的成效。開發軟件的時候,我有一條規則:任何時候,代碼都必須能夠運行。如果你正在寫的代碼一個小時之後就可以看到運行結果,這好比讓你看到不遠處就是唾手可得的獎勵,你因此會受到激勵和鼓舞。其他藝術領域也是如此,尤其是油畫。大多數畫家都是先畫一個草圖,然後再逐步加工。如果你采用這種方式,那麽從理論上說,你每天收工的時候都可以看到整體的效果,不會對最後的成品一點感覺都沒有。跟你說實話吧,畫家之間甚至流傳著一句諺語:“畫作永遠沒有完工的一天,你只是不再畫下去而已。”這種情況對於第一線的程序員真是再熟悉不過了。
士氣也可以解釋為什麽很難為低端用戶設計出優秀產品。因為優秀設計的前提是你自己必須喜歡這種產品,否則你不可能對設計有興趣,更不要說士氣高昂了。為了把產品設計好,你必須對自己說:“哇,這個產品太棒了,我一定要設計好!”而不是心想:“這種垃圾玩意,只有傻瓜才會喜歡,隨便設計一下就行了。”
設計意味著做出符合人類特點和需要的產品。但是,“人類”不僅包括用戶,還包括設計師,所以設計工作本身也必須符合設計師的特點和需要。