Erlang之父Joe Armstrong訪談:程序調(diào)試與啤酒
以啤酒收取程序調(diào)試報(bào)酬
Seibel:你是如何開始學(xué)習(xí)編程的?是從什么時(shí)候開始的?
Armstrong:是從中學(xué)時(shí)開始的。我出生于1950年,上中學(xué)那會(huì)兒還沒有幾臺(tái)計(jì)算機(jī)。到了中學(xué)最后一年,那年我應(yīng)該是17歲,我們當(dāng)?shù)氐淖h會(huì)得到一臺(tái)大型計(jì)算機(jī),好像是IBM的。我們可以在上面寫Fortran程序。通常,我們?cè)诰幋a紙上寫好程序,然后發(fā)出去。一個(gè)星期后,等編碼紙和穿孔卡拿回來的時(shí)候還必須確認(rèn)一下。但是制作穿孔卡的人總會(huì)出點(diǎn)錯(cuò),所以可能要反復(fù)1~2次才能弄好。最后這些穿孔卡就可以送到計(jì)算機(jī)中心了。
卡片進(jìn)入計(jì)算機(jī)中心后會(huì)再拿回來,因?yàn)镕ortran編譯器會(huì)在程序中出現(xiàn)第一個(gè)句法錯(cuò)誤的地方停下來,后面的程序就都不處理了。你的第一個(gè)程序似乎需要3個(gè)月才能跑通。我認(rèn)識(shí)到,不能每次只送一個(gè)程序,應(yīng)當(dāng)并行地開發(fā)多個(gè)單一子例程并且一次都送去。我記得寫過一個(gè)顯示國(guó)際象棋棋盤的小程序,用打印機(jī)繪制出來。但是因?yàn)橹虚g等待的時(shí)間太煩人了,我不得不把所有的子例程都當(dāng)做并行的任務(wù)一次寫完。
Seibel:你學(xué)的是物理學(xué),是從什么時(shí)候開始轉(zhuǎn)向編程的?
Armstrong:嗯,有一些本科生的課程需要編寫程序,而我又特別喜歡編程。我還非常善于調(diào)試程序。如果別人程序出了問題,我就會(huì)去調(diào)試別人的程序。標(biāo)準(zhǔn)調(diào)試的開價(jià)是一杯啤酒。也可能提價(jià),還有兩杯啤酒、三杯啤酒的問題。
Seibel:在給他們調(diào)試程序時(shí),是以他們必須給你買多少杯啤酒而論的,對(duì)嗎?
Armstrong:對(duì),等我修復(fù)了程序時(shí)他們要給我買啤酒。我在讀程序的時(shí)候總是在想:“他們?yōu)槭裁匆@樣寫程序呢,太復(fù)雜了。”我會(huì)重新編寫并簡(jiǎn)化程序。看到人們編寫復(fù)雜的代碼我感到很吃驚。有些問題用幾行代碼就能解決,但是他們要寫上幾十行。我有點(diǎn)好奇,他們?yōu)槭裁纯床坏胶?jiǎn)單的方法呢。而我就頗為擅長(zhǎng)采取簡(jiǎn)單的方法。
我真正開始編程是拿到第一個(gè)學(xué)位并打算讀博士學(xué)位的時(shí)候。我開始讀高能物理博士學(xué)位并加入了那里的氣泡室小組,他們有一臺(tái)計(jì)算機(jī)。那是一臺(tái)DDP-516,是Honeywell公司的。我可以獨(dú)自一人使用它。它是穿孔卡式的,但是可以在上面直接運(yùn)行程序,只要把穿孔卡放進(jìn)去,按一下按鈕,答案刷地一下就出來了。我特別喜歡那臺(tái)計(jì)算機(jī)。我在上面編寫了一個(gè)小象棋程序。
那時(shí)的實(shí)際磁心存儲(chǔ)器是由婦女編織而成的,能夠看到磁心和一塊塊的小磁鐵和穿進(jìn)穿出的線路。它的價(jià)格高得驚人,有一個(gè)大約10MB的磁盤驅(qū)動(dòng)器,上面有20個(gè)小底板,大約15公斤重。它還配了一個(gè)電傳文本的界面,可以在上面輸入程序。
后來又出現(xiàn)了“玻璃電傳打字終端”,那是最早的視頻顯示器設(shè)備,可以在上面輸入并編輯程序。我覺得這太神奇了,再也不需要穿孔卡了。我記得當(dāng)時(shí)和計(jì)算機(jī)管理員說:“要我說,將來有一天人人都會(huì)有這樣一套機(jī)器。”他說道:“我看你瘋了,Joe,你真是瘋了!”“為什么不可能呢?”“這些東西貴得離譜。”
正是從那時(shí)我真正開始學(xué)習(xí)編程了。當(dāng)時(shí)我的導(dǎo)師對(duì)我說:“你不應(yīng)該再讀物理學(xué)博士了,改行吧。你熱愛計(jì)算機(jī),應(yīng)當(dāng)搞計(jì)算機(jī)。”我說道:“不,不,不。我不能半途而廢。”但實(shí)際上他的話是對(duì)的。
不同尋常的工作經(jīng)歷
Seibel:那你拿到博士學(xué)位了嗎?
Armstrong:沒有。我沒錢了,所以沒有讀完。我后來去了愛丁堡大學(xué)。此前在讀物理的時(shí)候我們常常到物理系圖書館去學(xué)習(xí)。在圖書館的角落里有一些計(jì)算機(jī)科學(xué)書籍。有一些棕色封底的雜志叫做《機(jī)器智能》,一共有4期,是愛丁堡大學(xué)的機(jī)器智能系編輯出版的。我學(xué)的是物理學(xué),但我卻渴望閱讀這些雜志,并且在想:“真是太有趣了。”DonaldMichie那時(shí)擔(dān)任愛丁堡大學(xué)機(jī)器智能系的主任,我給他寫了封信,說我對(duì)這種東西非常感興趣,問他那里有沒有工作可做。他給我回了信,說目前還沒有,不過無論如何,他很想和我見一面,看看我是什么樣的人。
幾個(gè)月后我接到一個(gè)電話,也可能是一封信,是Michie的。他說:“我周二去倫敦,我們見一面如何?我要乘火車回愛丁堡,你能來車站嗎?”我去了車站,見到Michie,他說:“嗯,不能在這兒面試—我們?nèi)フ覀€(gè)酒吧。”于是我們到一家酒吧聊了聊。過了沒多久又收到他的一封信,說:“在愛丁堡大學(xué)有一份研究工作,你申請(qǐng)一下吧。”于是我成了DonaldMichie的研究助理并去了愛丁堡大學(xué)。我就這樣從物理學(xué)轉(zhuǎn)到了計(jì)算機(jī)。
Michie在二戰(zhàn)期間曾經(jīng)和圖靈在布萊切利公園(BletchleyPark)(編者注:二戰(zhàn)爆發(fā)前,英國(guó)在距離倫敦不遠(yuǎn)的布萊切利公園設(shè)置了國(guó)家密碼破譯機(jī)構(gòu),許多破譯員在那里工作,破解德國(guó)電報(bào)密碼)一起工作過,拿到了圖靈所有的論文。我在圖靈圖書館有一張書桌,周圍也全都是圖靈的論文。我在愛丁堡大學(xué)待了一年。此后由于數(shù)學(xué)家JamesLighthill的原因,愛丁堡大學(xué)都有點(diǎn)維持不下去了。Lighthill受雇于政府,前往愛丁堡大學(xué)調(diào)查人工智能。他回去后說道:“那個(gè)地方什么有商業(yè)價(jià)值的東西也弄不出來。”
說得就像一個(gè)巨大的兒童游戲區(qū)。我是英國(guó)機(jī)器人學(xué)會(huì)的創(chuàng)始成員,我們都認(rèn)為這個(gè)工作意義重大。但是撥款機(jī)構(gòu)卻說:“機(jī)器人!這是什么東西!我們不打算在這上面投入資金了。”我記得那是1972年前后,所有的資金來源都枯竭了,大家都說:“嗯,在這里度過的時(shí)光非常美好,但現(xiàn)在最好還是找點(diǎn)別的事情做吧。”
于是我又回去從事物理學(xué)工作了。我到了瑞典,在EISCAT科學(xué)協(xié)會(huì)得到一份物理學(xué)程序員的工作。我的上司來自IBM,年紀(jì)比我大,他想要上頭給出一份規(guī)格說明書,這樣他就可以拿去實(shí)行。我們?cè)?jīng)討論過這個(gè)問題。他說:“如果沒有任務(wù)說明,也沒有規(guī)格說明,這樣的工作太糟糕了。”我說:“嗯,如果沒有任務(wù)說明,那才是一個(gè)好任務(wù)。因?yàn)槟憧梢园凑兆约合矚g的方式來完成。”一年后我的上司離職了,我接替了他的工作,擔(dān)任首席設(shè)計(jì)師。
我為他們?cè)O(shè)計(jì)了一個(gè)系統(tǒng),可以稱為應(yīng)用操作系統(tǒng),那是一個(gè)在普通操作系統(tǒng)上運(yùn)行的系統(tǒng)。那個(gè)時(shí)候計(jì)算機(jī)的價(jià)格已經(jīng)比較合理了。我們有一些NORD-10計(jì)算機(jī),是挪威制造的—我覺得他們這種型號(hào)的計(jì)算機(jī)想要進(jìn)入PDP-11的市場(chǎng)。
我在那里工作了將近4年。接著在瑞典空間研究中心得到一份工作,構(gòu)建了另外一個(gè)應(yīng)用操作系統(tǒng),用于控制瑞典發(fā)射的名為“海盜”的第一顆衛(wèi)星。那是一個(gè)有趣的項(xiàng)目,不過我忘了那臺(tái)計(jì)算機(jī)的名字了,只記得它克隆的是Amdahl公司的計(jì)算機(jī)。那上面還只有行編輯器,沒有全屏幕編輯器。所有的程序都只能放到一個(gè)目錄下面。文件名是10個(gè)字母,擴(kuò)展名是3個(gè)字母。還有一個(gè)Fortran編譯器或匯編語(yǔ)言編譯器,全部東西就是這些了。
有趣的是,現(xiàn)在回頭想想,我不認(rèn)為當(dāng)今這些小玩意會(huì)讓你的生產(chǎn)率更高。比如說分層文件系統(tǒng),它怎么可能讓生產(chǎn)率更高呢?很多程序開發(fā)方式是在腦海中形成的。我認(rèn)為在那些簡(jiǎn)單的系統(tǒng)上工作可以強(qiáng)制你規(guī)范地進(jìn)行思考。如果沒有目錄系統(tǒng),就只能把所有的文件都放到一個(gè)目錄下面,你只能變得相當(dāng)規(guī)范。如果沒有修訂控制系統(tǒng),你也只能變得相當(dāng)規(guī)范。如果自己做的事情能夠規(guī)范起來,那我覺得分層文件系統(tǒng)和修訂控制系統(tǒng)也就沒什么可取之處了。它們解決的問題并不能從本質(zhì)上解決你的問題。如果多人一起工作,它們可能會(huì)讓事情容易一些。但對(duì)個(gè)人來說,我看不出來有什么差別。
另外,我覺得我們現(xiàn)在因?yàn)檫x擇過多而不堪重負(fù)。我的意思是,那時(shí)候我只能使用Fortran。甚至連Shell腳本也沒有。只有可以運(yùn)行程序的批處理文件,編譯器,還有就是Fortran。如果確實(shí)需要的話,還可能有匯編語(yǔ)言編譯器。不需要痛苦地做出選擇。今天年輕的程序員肯定會(huì)感到很不舒服,面對(duì)20種編程語(yǔ)言和幾十種框架,該如何選擇,真是無所適從。我們那時(shí)沒有這些難以選擇的地方。只要開始做就行了,因?yàn)槭褂檬裁凑Z(yǔ)言、什么工具都已經(jīng)是定下來的。不需要考慮該做些什么,只管做就行了。
打開黑盒的重要性
Seibel:另外一個(gè)差別是現(xiàn)在也無法徹底了解整個(gè)系統(tǒng)了。也就是說不僅僅是要做出很多選擇,而且在選擇要使用哪些黑盒的時(shí)候,還不一定完全理解黑盒的工作方式。
Armstrong:是啊,如果這些大黑盒不能正常工作,必須做出修改,我覺得自己把所有的內(nèi)容都從頭開始編寫一次會(huì)更容易些。做不到軟件復(fù)用,真是太糟糕了。
Seibel:但是如果把所有這些黑盒都打開,看看里面有什么,看看它們的工作方式,再確定如何對(duì)它們做一點(diǎn)改造來滿足自己的需要。你覺得這樣做確實(shí)是可行的嗎?
Armstrong:這些年我犯了一些人們常犯的錯(cuò)誤,那就是沒有打開黑盒。有時(shí)候想一想,覺得這個(gè)黑盒無法理解,難度太大,所以不想打開它。我曾經(jīng)打開過1~2個(gè)黑盒。有一次我需要做一個(gè)窗口系統(tǒng),為Erlang做一個(gè)圖形系統(tǒng),我在想:“嗯,就在XWindows上運(yùn)行吧。”XWindows是什么呢?它是一個(gè)套接字,上面跑著協(xié)議。只要打開套接字,往里面注入這些消息就可以了。為什么要用庫(kù)呢?Erlang是基于消息的。整體指導(dǎo)思想是向其他東西發(fā)出消息,讓它們執(zhí)行操作。嗯,XWindows中的指導(dǎo)思想則是,有一個(gè)窗口,向窗口發(fā)送消息,再由窗口執(zhí)行操作。如果在窗口中執(zhí)行操作,它會(huì)把消息回送給你。這非常像Erlang。但是XWindows的編程方式是運(yùn)用回調(diào)庫(kù)—如果出現(xiàn)了這個(gè)情況就調(diào)用這個(gè)函數(shù)。這不是Erlang的思考方式。Erlang的思考方式是,給某個(gè)東西發(fā)送消息,讓它做一些事情。所以,等一下,把其中的庫(kù)去掉吧,直接和套接字對(duì)話。
猜猜結(jié)果會(huì)怎么樣?非常簡(jiǎn)單。X協(xié)議收到了一些消息,我不知道具體是多少條,也許是100條、80條,大致就是這么多。但實(shí)際上只需要其中的20條就能完成有用的工作了。把這20條消息映射到Erlang術(shù)語(yǔ)上,變個(gè)小魔術(shù),然后可以向窗口直接發(fā)送消息,它們就開始執(zhí)行動(dòng)作了。這樣做的效率也很高。但界面不是很好,因?yàn)槲覜]有把太多的精力用到圖形和藝術(shù)標(biāo)準(zhǔn)上。如果為了讓界面再美觀一些,要做的工作還很多。但是不管怎么說,實(shí)際上并不難。
另外一個(gè)例子是我做的排版系統(tǒng),我打開的抽象邊界是PostScript。到了邊界的地方你會(huì)想:“我不想越過這個(gè)邊界。”因?yàn)槟銜?huì)認(rèn)為邊界里面的東西極其復(fù)雜。但是我再次發(fā)現(xiàn),它實(shí)際上是很簡(jiǎn)單的。那是一種編程語(yǔ)言,一種不錯(cuò)的編程語(yǔ)言。抽象邊界很容易穿越,而一旦穿越,會(huì)有很多收益。
在出版我那本Erlang編程書時(shí),出版社說:“我們有畫圖工具。”但是畫圖工具真的很難精確地對(duì)準(zhǔn)箭頭,所以我不喜歡那些工具。而且畫圖的時(shí)候手也很難受。我想:“編寫一個(gè)生成PostScript的程序,然后在‘這里畫個(gè)圓圈、那里畫個(gè)箭頭’,讓程序正常運(yùn)轉(zhuǎn)起來,這樣一比,編程花的時(shí)間并不長(zhǎng)。”編寫程序需要幾個(gè)小時(shí)。以所見即所得的方式畫圖也需要這么長(zhǎng)時(shí)間。只是自己編寫程序還有兩個(gè)好處。你的手不會(huì)難受,而且即使把圖形放大一萬(wàn)倍,看到的箭頭也是對(duì)得整整齊齊的。
我并不是說剛?cè)胄械某绦騿T應(yīng)當(dāng)把所有這些抽象的東西都打開。我的意思是,一定要考慮是否可以打開它們。不要完全放棄這個(gè)想法??纯粗苯拥竭_(dá)的途徑是不是比包裝后的途徑要快一些,這是值得一看的。一般來說,如果購(gòu)買軟件或是使用其他人的軟件,一定要充分考慮還需要花很長(zhǎng)時(shí)間來加工這套軟件,因?yàn)樗湍阆胍牟煌耆粯?。軟件的?zhí)行方式有微妙的差別,而這個(gè)差別可能需要很長(zhǎng)時(shí)間來解決。
編程這些年的變化
Seibel:同剛開始編程時(shí)相比,你在看待該如何編程的問題上最大的變化是什么?
Armstrong:我認(rèn)為編程方式中的最大變化與硬件無關(guān)。顯然,現(xiàn)在的計(jì)算機(jī)速度要快得多,功能要強(qiáng)大得多,但是人的大腦比最好的軟件工具還要強(qiáng)大一百萬(wàn)倍。我在編寫程序的時(shí)候,幾天之后會(huì)突然說:“程序中有一個(gè)錯(cuò)誤—如果這樣、那樣、那樣、這樣的話,程序就要崩潰了。”然后我去看了代碼,確實(shí)如此。此前一點(diǎn)征兆也沒有。你能告訴我哪一個(gè)開發(fā)系統(tǒng)能夠做到這一點(diǎn)嗎?作為一個(gè)程序員,我所發(fā)生的變化是內(nèi)心思想的變化。
我認(rèn)為在經(jīng)過多年的編程之后會(huì)有兩個(gè)變化。一個(gè)變化是,在年輕的時(shí)候,我會(huì)不停地寫程序,直到完成。當(dāng)程序完成后,我就不再管它了。程序?qū)懞昧?,完工了。然后我?huì)突然領(lǐng)悟:“啊!搞錯(cuò)了!真是笨蛋!”我會(huì)重新編寫程序,后來再次發(fā)現(xiàn):“噢,程序是錯(cuò)的。”于是又重新編寫。
我記得當(dāng)時(shí)有這樣一個(gè)想法:“先不要?jiǎng)邮謱懘a,把這些東西都想好,這樣做不是很好嗎?”如果我不寫代碼就能獲得那番領(lǐng)悟,不是很好嗎?我認(rèn)為現(xiàn)在可以做到這一點(diǎn)了。那20年可以算作是學(xué)習(xí)如何編程的時(shí)期。現(xiàn)在知道該如何編程了。我以前通過實(shí)驗(yàn)來學(xué)習(xí)編程。現(xiàn)在我知道該如何編程了,不需要再做實(shí)驗(yàn)了。
偶爾,我也得做一些很小的實(shí)驗(yàn),比如編寫一些非常小的程序來回答某個(gè)問題。我會(huì)把事情想清楚,等到開始編程的時(shí)候,這些程序就可以或多或少地像我預(yù)計(jì)的那樣運(yùn)行起來了,因?yàn)橹拔乙呀?jīng)想清楚了。這也意味著要花很長(zhǎng)時(shí)間。編寫程序、有所醒悟、重新編寫。這樣可能需要花上一年的時(shí)間來寫程序。所以我現(xiàn)在可能不這樣做,而是先思考上一年。我不會(huì)再做那種簡(jiǎn)單的輸入工作。
這是第一個(gè)變化。出現(xiàn)的第二個(gè)變化是直覺。在年輕的時(shí)候,我會(huì)通宵地寫程序,干到凌晨4點(diǎn)鐘,精疲力盡,那是男子漢氣概的編程,一個(gè)小時(shí)接著一個(gè)小時(shí),不停地編寫代碼。即使情況不好我也堅(jiān)持不懈,總要讓代碼能夠跑起來。即使沒有直覺,我也要繼續(xù)編程。
我得到的教訓(xùn)是,在疲憊的時(shí)候編寫的程序都是垃圾,第二天就要把它們都扔掉了。20年前,就算強(qiáng)烈地感到事情不對(duì)勁、代碼中有錯(cuò)誤時(shí),我也會(huì)繼續(xù)編程。這些年來我注意到,真正好的代碼是我完全進(jìn)入狀態(tài)的時(shí)候編寫的,時(shí)間不知不覺地過了,而我甚至沒有在考慮程序,只是很放松地坐在那里,輸入這些東西,看著自己輸入的東西出現(xiàn)在屏幕上。這樣的代碼會(huì)很不錯(cuò)。如果你不能集中注意力,弄出來的東西會(huì)說:“不行,不行,這兒錯(cuò)了,那兒也錯(cuò)了。”可我在多年前并沒有注意到這一點(diǎn)。寫出來的代碼都被扔掉了。現(xiàn)在,如果覺得不行,我就不再編程了。“不能再寫了。”這是我根據(jù)經(jīng)驗(yàn)得到的,停下來,不要再寫代碼了。不要再處理這個(gè)問題了。干點(diǎn)別的。
我在上學(xué)的時(shí)候很擅長(zhǎng)數(shù)學(xué)之類的課程,所以在想:“噢,我是一個(gè)按照邏輯思考的人。”但是我參加心理測(cè)試時(shí),在直覺上得了高分,而邏輯思考方面的分?jǐn)?shù)卻有點(diǎn)低。不是很低,我還是可以做數(shù)學(xué)這類的題目,我相當(dāng)擅長(zhǎng)。但正是因?yàn)槲疑瞄L(zhǎng)數(shù)學(xué),所以我過去認(rèn)為科學(xué)是關(guān)于邏輯和數(shù)學(xué)的。我現(xiàn)在就不會(huì)這樣說了。我要說科學(xué)也有很多直覺,根據(jù)直覺能夠知道什么是正確的。
Seibel:你現(xiàn)在在編碼之前會(huì)花更長(zhǎng)的時(shí)間思考,那么在思考階段會(huì)做些什么呢?
Armstrong:噢,我會(huì)記些筆記,我不僅僅是在思考。在紙上隨便寫點(diǎn)什么。我可能不會(huì)寫很多代碼。如果你密切注意我的活動(dòng),會(huì)發(fā)現(xiàn)我大部分時(shí)間都在思考,偶爾寫點(diǎn)什么。另外一件對(duì)解決問題非常重要的事情是問問我的同事:“你將如何解決這個(gè)問題?”你找到他們,說:“我不知道應(yīng)當(dāng)采取這種方式還是那種方式。必須在A和B之間做出選擇。”然后你向他們描述A和B,等講到一半的時(shí)候,你會(huì)說:“啊,是B。謝謝你們。非常感謝。”這樣的事情發(fā)生過很多次。
你需要這樣一塊智能白板,如果你只是獨(dú)自一人在一塊白板上寫寫畫畫,是得不到反饋的。但是如果面對(duì)的是人,你會(huì)在白板上向他們解釋替代方案,他們也會(huì)加入討論,提出一點(diǎn)建議。然后突然間你就知道答案是什么了。對(duì)我來說沒有涉及到代碼編寫。但是和處理同樣問題的同事進(jìn)行交談是非常有價(jià)值的。
原文鏈接:http://www.programmer.com.cn/4935/
【編輯推薦】