Seibel:你是怎么開始編程的?
Bloch:我想這是受益于我的家庭影響。我父親是Brookhaven國(guó)家實(shí)驗(yàn)室的化學(xué)家。當(dāng)我上小學(xué)四年級(jí)的時(shí)候,他參加了一個(gè)程序設(shè)計(jì)培訓(xùn)班。當(dāng)然在那個(gè)時(shí)候,電腦都是放在玻璃窗背后的大型機(jī),你只能把寫好的程序卡片交給操作員。雖然沒法兒親自動(dòng)手,但我還是被電子計(jì)算機(jī)可以幫助你做事兒這一點(diǎn)震撼了。所以,我在父親上課的那段時(shí)間,跟他學(xué)了一點(diǎn)兒Fortran。
Seibel:那大概是哪一年?
Bloch:我想是1971年。直到很多年以后我才真的對(duì)程序產(chǎn)生了強(qiáng)烈的興趣。讓我產(chǎn)生興趣的當(dāng)然是分時(shí)系統(tǒng)。長(zhǎng)島有一臺(tái)DEC system-10電腦,供Suffolk縣內(nèi)所有的學(xué)校使用。Nassau縣也有一臺(tái)。很神奇的是,很多著名人物的事業(yè)都是從這兩臺(tái)DEC system-10電腦開始的。
你的程序一旦有交互,就會(huì)有Bug。大概是從1973~1976年,那時(shí)候我跟其他人一樣,在寫B(tài)ASIC程序。我就是從那時(shí)開始正式寫程序的。你知道嗎,我還保存著當(dāng)年寫的程序,是印在電信打印紙上的。如今回頭再看這些程序的時(shí)候我發(fā)現(xiàn),我代碼風(fēng)格中的某些部分從那個(gè)時(shí)候起就一直沒變過。
Seibel:你還記得你寫的第一個(gè)有趣的程序是什么嗎?
Bloch:噢,我記得那是1977年7月4日,我為經(jīng)典的二十問游戲?qū)懥艘粋(gè)程序,叫“猜動(dòng)物”。這個(gè)程序包含一個(gè)二叉樹,是非題位于它的內(nèi)部節(jié)點(diǎn),動(dòng)物位于它的葉節(jié)點(diǎn)上。如果用戶所提的動(dòng)物是葉節(jié)點(diǎn)上沒有的,它會(huì)向用戶提出是非題,通過區(qū)別新動(dòng)物和它猜出的錯(cuò)誤動(dòng)物之間的差異來(lái)了解新動(dòng)物。二叉樹保存在硬盤上,這樣程序可以越來(lái)越“聰明”。
我當(dāng)時(shí)想,“天啊,真酷,程序真的能學(xué)習(xí)。”這是我一生難忘的瞬間。我還記得另一件事。當(dāng)時(shí)我在高中,應(yīng)該是10年級(jí)吧。是關(guān)于DEC system-10的。當(dāng)時(shí)不允許我們編寫現(xiàn)在叫做即時(shí)消息軟件的東西,因?yàn)樗鼈儗?duì)系統(tǒng)資源的消耗實(shí)在太大了。
Seibel:如果時(shí)光能夠倒流,可以一切從頭來(lái)過,有什么東西是你真的希望改變的?Basic對(duì)你來(lái)說(shuō)太簡(jiǎn)單了?其他還有什么?
Bloch:我沒什么遺憾的,實(shí)際上Basic很有趣。我覺得Dijkstra對(duì)Basic的看法是完全錯(cuò)誤的。原諒我這么評(píng)價(jià)已故的人,愿他在天堂安息。我知道很多非常好的程序員,他們是從BASIC編程開始的,因?yàn)槟鞘撬麄兡苷业降奈ㄒ坏恼Z(yǔ)言。
然而我覺得使用多種語(yǔ)言是件好事。上大學(xué)的時(shí)候,我用很多語(yǔ)言編程。每門課都可以用一門語(yǔ)言。在數(shù)學(xué)課或者理工科課上,應(yīng)該用Fortran。那時(shí)候編程課學(xué)的都是Pascal、SAIL、Simula或者類似的東西。在人工智能課上,用LISP。
不過也許我應(yīng)該學(xué)更多的語(yǔ)言。有意思的是,一開始我對(duì)面向?qū)ο蟛⒉桓忻,直到那個(gè)二十問游戲開發(fā)快結(jié)束了,我才真正對(duì)面向?qū)ο笥辛烁杏X。嚴(yán)格來(lái)說(shuō),Java才是我真正使用的第一種面向?qū)ο笳Z(yǔ)言,某種程度上是因?yàn)槲也惶胗肅++。
Seibel:那是什么時(shí)候?
Bloch:那是我1996年加入Sun公司時(shí)。我覺得要是我能更早學(xué)習(xí)這些概念就好了。我不認(rèn)為這些概念都是好的。面向?qū)ο蠛苡幸馑,它有兩層含義。第一,它意味著模塊化。模塊化是非常好的。但是我不認(rèn)為這是創(chuàng)造面向?qū)ο蟮娜藗兊膶@。你可以去看以前的文獻(xiàn),例如,Parnas關(guān)于信息隱藏的論述,就會(huì)發(fā)現(xiàn)這種概念可以看作面向?qū)ο缶幊讨蓄惛拍畹囊环N抽象的原型。第二,它意味著繼承,我認(rèn)為繼承有利也有弊,這跟如今很多人的使用感受一致。
另外,我應(yīng)該進(jìn)入更多的領(lǐng)域,計(jì)算機(jī)科學(xué)領(lǐng)域內(nèi)外都應(yīng)涉獵。你學(xué)的東西越多,開始得越早,對(duì)你越好。我一直沒有真正做過的就是GUI編程,在某種程度上說(shuō)我應(yīng)該強(qiáng)迫自己做做看。但是由于種種原因,如這些年來(lái)開發(fā)庫(kù)代碼,構(gòu)建他人可以使用的代碼塊,這些事情已經(jīng)占據(jù)了我的大部分時(shí)間。這樣算來(lái),我做數(shù)據(jù)結(jié)構(gòu)和算法等方面的工作已經(jīng)有幾十年了。
Seibel:有什么書是所有程序員都應(yīng)該看看的?
Bloch:《設(shè)計(jì)模式》無(wú)疑是一本,雖然我對(duì)它的感情有點(diǎn)復(fù)雜,但是我還是認(rèn)為每個(gè)人都應(yīng)該讀一下。書中列出了通用的詞匯,也提出了很多好的創(chuàng)意。另一方面,這本書有點(diǎn)兒像方法和語(yǔ)言的大雜燴,內(nèi)容也有些過時(shí)了。但是我認(rèn)為它絕對(duì)值得一讀。
另外一本書是《Elements of Style》,它甚至不是一本編程書。為什么要看這本書呢?理由有兩條。首先,每個(gè)軟件工程師工作中很大一部分是寫文檔。如果你無(wú)法寫出精確、統(tǒng)一、易讀的說(shuō)明書,那么沒人會(huì)去用你的產(chǎn)品。所以說(shuō)可以改善你寫作風(fēng)格的東西都值得借鑒。其次,該書里面的大部分思想都適用于編程。
我的荒島列表有點(diǎn)古怪。例如,最重要的書是Herry Warren寫的《高效程序的奧秘》(Hacker’s Delight)。
Seibel:這是一本位操作(bit-twiddling)書?
B loch:是的。我愛位操作,這跟我的工作有關(guān)聯(lián)。如果你寫庫(kù)、編譯器、底層圖形代碼或者加密代碼,這本書是不可或缺的。Warren把曾經(jīng)口口相傳的東西放在一起,用嚴(yán)謹(jǐn)?shù)臄?shù)學(xué)去進(jìn)行驗(yàn)證。這本書出版的時(shí)候,我被震驚了。
當(dāng)然還有Knuth的《計(jì)算機(jī)程序設(shè)計(jì)藝術(shù)》。事實(shí)上,我從來(lái)沒有讀完這一套書,至少?zèng)]有從頭到尾看過。但當(dāng)我研究某個(gè)具體算法的時(shí)候,我就去看他會(huì)怎么說(shuō)。往往可以得到我想要的東西,這套書太全面了。
但是我沒有能力、也沒有時(shí)間去讀完整套書,所以如果我告訴你我讀完了,那么我就是在說(shuō)謊。我覺得還有一本非常好的老書,是Kernighan和Plauger寫的The Elements of Programming Style。書里面的例子都是用Fortran IV和PL/I寫的,所以有點(diǎn)過時(shí)。不過,雖然這本書這么老,但里面的思想?yún)s從未過時(shí)。
另外一本老書是Frederick Brooks的《人月神話》。這本書都出版40年了,里面的思想仍舊同出版時(shí)一樣有影響力。閱讀它是一種快樂,每個(gè)人都應(yīng)該讀一下。這本書的主要信息是“給一個(gè)延期的項(xiàng)目加人,會(huì)讓它延期得更加厲害”,今天這一點(diǎn)仍舊是正確的。里面還有其他很多重要的觀點(diǎn)。有些細(xì)節(jié)雖然過時(shí)了,但仍值得一讀。
現(xiàn)在每個(gè)人都必須要學(xué)習(xí)并發(fā)編程。所以應(yīng)該看看《Java并發(fā)編程實(shí)踐》這本書。雖然標(biāo)題中有Java,但是很多內(nèi)容并不限于任何具體的編程語(yǔ)言。
Seibel:這就是你和Brian Goetz合著的那本書?
Bloch:我的名字是印在封面上的,但是我提到它的原因恰恰是因?yàn)檫@不是我寫的書。第一作者是Brian,第二作者是Tim Peierls,制定Java并發(fā)標(biāo)準(zhǔn)JSR-166的每一個(gè)人也都是這本書的作者。把我的名字印在了封面上僅僅是出于禮貌,我貢獻(xiàn)了些材料,但是沒有正式參與編寫此書。
噢,還有一本:《韋氏學(xué)院詞典(第11版)》。我去哪里都帶著它。這倒不是你實(shí)際上要讀的東西,但是我說(shuō)過,寫程序的時(shí)候,必須能命名好變量。你的文筆必須好。沒有好的字典,我就會(huì)覺得少了點(diǎn)兒什么。
Seibel:除了命名好變量,盡量少的復(fù)制粘貼以外,你經(jīng)驗(yàn)豐富后,還有哪些寫程序的習(xí)慣改變了?
Bloch:隨著年齡的增長(zhǎng),我逐漸意識(shí)到編程不僅僅是讓程序運(yùn)行而已;編程是創(chuàng)造一個(gè)易于理解的、可以維護(hù)的、高效的作品。一般來(lái)說(shuō),我發(fā)現(xiàn),干凈整潔的代碼,往往運(yùn)行起來(lái)更快。這與流行觀點(diǎn)正好相反。而且即使它們不快,也可以很容易地讓它們變快。正如人們所說(shuō)的,優(yōu)化正確的代碼比改正優(yōu)化過的代碼容易多了。
我的一些改變是跟具體語(yǔ)言相關(guān)的。每種語(yǔ)言都提供了一個(gè)工具箱。你要使用正確的工具,在這種語(yǔ)言中正確的工具在另外一種語(yǔ)言中可能不是最好的。舉一個(gè)簡(jiǎn)單的例子:如果你用Java 5,使用枚舉來(lái)代替整數(shù)常量或者布爾常量可以大大簡(jiǎn)化程序,讓它更安全,更可靠。
Seibel:說(shuō)到這兒,你能否談?wù)勅绾文芸焖偈煜ひ环N新語(yǔ)言?
Bloch:這跟人類的語(yǔ)言很類似。一種方法是學(xué)會(huì)很多語(yǔ)言。如果你已經(jīng)熟悉意大利語(yǔ)和西班牙語(yǔ),那么學(xué)葡萄牙語(yǔ)就不需要花太多時(shí)間了。你知道的越多,你能吸收的就越多。
學(xué)習(xí)一種新語(yǔ)言的時(shí)候,要利用以前所學(xué)的語(yǔ)言的功底,但是也要保持開放的心態(tài)。有些人執(zhí)著于一種理念:“這就是寫所有程序必須遵循的方法!蔽也徽f(shuō)是哪種語(yǔ)言,但是某些語(yǔ)言,出于某種原因,令人執(zhí)著于這樣的理念。當(dāng)他們開始學(xué)習(xí)新的語(yǔ)言的時(shí)候,他們批評(píng)這種語(yǔ)言跟真正的神的語(yǔ)言的所有不同之處。當(dāng)他們使用新的語(yǔ)言時(shí),他們極力使用真正的神的語(yǔ)言的方法去寫。這樣,你就會(huì)錯(cuò)過這個(gè)新語(yǔ)言真正的獨(dú)特之處。
這就像你本來(lái)只有一個(gè)榔頭,有人給了你一個(gè)螺絲刀,你說(shuō):“唉,這不是一把好榔頭,但是我應(yīng)該可以倒著抓住螺絲刀,用螺絲刀把來(lái)砸東西。”你得到了一個(gè)很爛的榔頭,但事實(shí)上它是一把很不錯(cuò)的螺絲刀。所以你應(yīng)該對(duì)所有事物保持開放和積極的心態(tài)。當(dāng)然,最重要的是代碼!代碼!代碼!要多用語(yǔ)言,這樣才能學(xué)得更快。
Seibel:為什么人們對(duì)所選的計(jì)算機(jī)語(yǔ)言那么虔誠(chéng)?
Bloch:我不知道。但是選擇一種語(yǔ)言時(shí),所考慮的不僅僅是一系列技術(shù)上的權(quán)衡,而是在選擇一個(gè)社群。這就像選擇一個(gè)酒吧。沒錯(cuò),你希望去一個(gè)提供美酒的酒吧,但是美酒不是最重要的。主要是那個(gè)酒吧里都有什么樣的人,他們?cè)谡務(wù)撔┦裁础_x擇計(jì)算機(jī)語(yǔ)言也是這樣的。時(shí)間一長(zhǎng),就這門語(yǔ)言也形成了一個(gè)社群,社群里不僅僅有人群,還有他們的軟件成果,如工具、庫(kù)等。這就是有些理論上看起來(lái)更好的語(yǔ)言無(wú)法成功的原因,他們無(wú)法在周圍構(gòu)建成功的社群。
Seibel:要是這么理解的話,Java非常有趣,它有兩個(gè)社群。一個(gè)是實(shí)現(xiàn)者和系統(tǒng)開發(fā)者,也就是在Javasoft、Weblogic或者類似地方工作的人們。另一個(gè)是所有用Java、應(yīng)用服務(wù)器、構(gòu)建好的框架來(lái)構(gòu)建商業(yè)應(yīng)用的人們。這兩個(gè)酒吧差別非常大。
Bloch:與Java或者其他語(yǔ)言關(guān)聯(lián)的社群很多。如果語(yǔ)言周圍沒有形成社群,這通常表明,要么這個(gè)語(yǔ)言無(wú)人問津,要么就還很不成熟。語(yǔ)言繁榮發(fā)展,就會(huì)自然地表現(xiàn)為出現(xiàn)越來(lái)越多各式各樣的社群。同時(shí),如果對(duì)一門語(yǔ)言的投入總額增長(zhǎng)了,那么它的價(jià)值也會(huì)相應(yīng)地增長(zhǎng)。
這就像梅特卡夫定律(編者注:一種網(wǎng)絡(luò)技術(shù)發(fā)展規(guī)律,由3COM公司創(chuàng)始人、計(jì)算機(jī)網(wǎng)絡(luò)先驅(qū)羅伯特·梅特卡提出。):網(wǎng)絡(luò)的價(jià)值與用戶數(shù)量的平方成正比。這對(duì)于編程語(yǔ)言也適用。所有使用這種語(yǔ)言的用戶構(gòu)成社群,然后突然間出現(xiàn)了Eclipse,出現(xiàn)了FindBugs,出現(xiàn)了Guice。即使Java對(duì)你來(lái)說(shuō)不是最好的語(yǔ)言,但是使用它有這么多附加的好處,所以你還是會(huì)創(chuàng)建社群,解決如何在Java中進(jìn)行數(shù)學(xué)編程,或者你需要的其他類型的編程方法。
Seibel:你有沒有過這樣的感覺:你越來(lái)越清楚那程序就是搞不定,到處都是這樣那樣的問題,幾乎令人絕望?
Bloch:當(dāng)然有過。寫書也是這樣的。每次開始一件事情的時(shí)候,我總想逃避。開始是最艱難的,有時(shí)候我會(huì)鼓勵(lì)自己:“加油Josh!這行你都干了三十多年了,你知道怎么能做到跟別人一樣好,不必瞻前顧后,動(dòng)手吧!被蛘邔(duì)自己說(shuō):“你瞧,以前的一切你都做的挺好的,這次也錯(cuò)不了。”
Seibel:你剛才提到你的生活體驗(yàn)變寬廣了,這可能會(huì)影響編程,但是有沒有什么東西,是編程以外的體驗(yàn),但是幫助你成為了一個(gè)更好的程序員呢?
Bloch:當(dāng)然有。我認(rèn)為你能做好的每件事情都有這個(gè)作用。思想是沒有學(xué)科限制的。我想到了一個(gè)例子。我寫論文的時(shí)候,要對(duì)一種分布數(shù)據(jù)結(jié)構(gòu),RSM(Replicated Sparse Memory,復(fù)制型稀疏內(nèi)存)做一個(gè)分析。而做這個(gè)分析的基礎(chǔ)思想來(lái)自于我所上的化學(xué)課。那是一個(gè)動(dòng)態(tài)平衡公式:如果系統(tǒng)里有一個(gè)動(dòng)態(tài)的平衡關(guān)系,就可以寫出一個(gè)等式,“事物進(jìn)入一個(gè)特定狀態(tài)的速度,和他們離開這個(gè)狀態(tài)的速度相等!边@樣就得到了三個(gè)變量的三個(gè)等式,求解這三個(gè)等式,計(jì)算出來(lái)的結(jié)果和觀察到的這種復(fù)雜的分布數(shù)據(jù)結(jié)構(gòu)的行為恰好匹配。這就是我直接從化學(xué)里偷來(lái)用于計(jì)算機(jī)科學(xué)的思想。
你在生活中看到的很多東西,不管是架構(gòu)上的,即建筑物構(gòu)建的方法,還是在語(yǔ)言上的,即人們進(jìn)行溝通的方法,很多思想都是可以借用的。當(dāng)然包括數(shù)學(xué)。數(shù)學(xué)和編程相當(dāng)類似。所以要睜大雙眼,積極地吸收重組各種思想,這樣做絕對(duì)錯(cuò)不了。