JavaScript權威Douglas Crockford:程式碼閱讀和每個人都該學的程式設計

盼盼姐發表於2013-04-25

JavaScript權威Douglas Crockford:程式碼閱讀和每個人都該學的程式設計 受訪者:Douglas Crockford

Douglas Crockford現在供職於Paypal。曾是Yahoo!的資深JavaScript架構師,他在上世紀70年代初求學期間就開始從事程式開發工作了,那時的他主修電視廣播專業,但苦於無法進入演播室工作,轉而學習了學校開設的Fortran課程。在其職業生涯中,Crockford曾先後供職於Atari、Lucasfilm和Electric Communities,以各種方式聯姻計算機與傳播媒介。深感於XML的複雜性,他發明了JSON這一廣泛用於Ajax應用的資料交換格式。Crockford曾談到如果能避免使用某些特性的話,JavaScript實際上是一門相當優雅的語言。他強調了以子集方式來管理複雜度的重要性,同時介紹了他所使用的一種程式碼閱讀方法:從清理程式碼開始。

作者:Peter Seibel

關於JavaScript

Seibel:在程式學習之路上有哪些令你後悔的事情?

Crockford:我瞭解一些語言,但卻一直沒有機會使用。我花了不少時間學習APL並瞭解到其衰敗的原因,但這門語言真的非常優雅,可我卻沒有花時間使用它,這太遺憾了。除此以外,我還了解其他一些語言,知道能用它們做什麼,但實際上卻並沒有機會用這些語言思考。

Seibel:我聽說你喜歡ES3版本JavaScript的簡潔性。

Crockford:嗯,最終無論怎麼對語言進行修訂,其要義都是希望促進語言的不斷成功。語言越成功,修改的代價就越大。隨著你的不斷成熟,再教育的成本就會變得更大,同時還有潛在的破壞代價,而這些成本和代價也會變得難以接受。如果你確實非常成功,那就更要小心提防所做的任何變化了。反之,如果你尚未成功,那麼就有更大的自由空間來改變了。

JavaScript成為世界上最流行的程式語言純粹是偶然。目前世界上JavaScript處理器的數量要高於任何其他語言。得益於其安全模型帶來的種種問題,JavaScript是唯一一門可在任何機器上編寫並執行的語言。 這些還嫌不夠的話,再看看那麼多嵌入了JavaScript的應用吧。Adobe的大多數應用都嵌入了JavaScript,這樣就可以在本地編寫指令碼控制這些應用了。還有其他很多應用,不勝列舉。這麼一看,JavaScript已經變得非常流行了。

JavaScript這門語言的問題在於推向市場以及標準化的過程都過於匆忙了。其大多數缺陷都沒有出現在目前的實現當中——只存在於規範中。標準說照錯的做,這聽起來太嚇人了,但這就是JavaScript的狀態。它於1999年凍結了,接下來本應走向滅亡。但Ajax的橫空出世改變了這一切,JavaScript變成了世界上最重要的程式語言。

於是,我們現在認為應該修復它。但這事應該是在2000年就開始做的,而那時並沒有這麼做,因為根本沒人關注JavaScript。現在它已經長大了。

Web環境下的JavaScript還有一點非常怪異:如果編寫伺服器端應用、桌面應用或是嵌入式應用,你不僅需要選擇語言,還要選擇特定的編譯器以及特定的執行時。但對JavaScript而言你別無選擇,你必須在所有的環境下執行。

由於要在所有環境下執行,bug就沒法修復了。如果某個瀏覽器廠商搞出個bug,他們會說“天啊,搞砸了”,下個月就會發布另一個版本,但我們卻不能指望著所有使用者都會升級。大多數人一旦在機器裡裝上IE就再也不會升級了,那些bug就會常年駐留在瀏覽器上。

Seibel:你希望JavaScript有哪些變化呢?

Crockford:我認為改進JavaScript最好的辦法就是瘦身。如果我們能夠取其精華,棄其糟粕,那JavaScript會變得更棒。我認為這個辦法也適合於HTML、HTTP和CSS。我們應該仔細思考所用的各種標準,搞清楚需要哪些特性,遺漏了哪些特性並重新審視它們,絕不應該盲目地增加新特性。

程式碼閱讀

Seibel:能否詳細談談如何進行程式碼閱讀呢?

Crockford:每次開會都讓一些人閱讀他們各自的程式碼,他們會引領我們檢視其編寫的所有內容,其他人則負責檢查。對於團隊的其他成員來說,這絕對是個學習的好機會,通過這個過程他們就可以知道自己的東西該如何與他人的相配合。

每個人都圍坐在桌邊,手裡拿一疊紙,同時還把程式碼在螢幕上打出來,大家一起閱讀。我們會在編寫程式碼的過程中加上註釋。有人會說“我看不懂這個註釋”或是“這個註釋與程式碼風馬牛不相及”。大家的意見極具價值,因為作為開發者的你是不會閱讀自己編寫的註釋的,你也根本沒有意識到自己寫的註釋誤導了讀者。有這麼多人幫助你編寫整潔的程式碼是多麼幸福的一件事啊——你會找到自己根本無法找到的缺陷。

我認為一小時的程式碼閱讀抵得上兩週的QA。這種剔除錯誤的手段真是很高效。如果你讓能力很強的同事閱讀程式碼,那麼他們周圍的新手們就會學到很多東西,而這一切是無法通過其他手段獲得的;如果新手來閱讀程式碼,那麼他會得到很多極具價值的建議。

但這件事我們不能一直留到最後再做。回憶過去,我們會在專案完成之際安排程式碼閱讀,但這個時候已經太遲了,只好取消。現在我深信程式碼閱讀應該伴隨著整個專案的生命週期。我花了很長時間才意識到這一點,這麼做的好處不勝列舉。

首先,這麼做有助於把控專案,我們能夠真切地看到大家的進度,也能及早發現是不是有人已經偏離了軌道。

我曾經管理過一些專案,馬上就到最後期限了,有人說“耶,馬上就幹完了”,然後我拿到了程式碼,發現裡面什麼都沒有,有的也是一些垃圾,離完成還遠著呢。管理層最厭惡這種事情了,我覺得程式碼閱讀能夠有效避免這種窘境的發生。

Seibel:那你需要指導別人如何進行程式碼閱讀麼?可以想象,既不想讓程式碼編寫者感覺受到侵犯,又能給出頗具價值的意見是很難的。

Crockford:沒錯,這需要給予團隊成員充分的信任,要明確界定好邊界。如果團隊不和睦,那就別指望這麼做了,這會導致團隊分崩離析。如果還沒有意識到團隊的不和睦,那這麼做很快就能發現。這個過程會讓你學到很多,也會揭示出很多問題。起初會覺得不太自然,但一旦適應後就會覺得再自然不過了。 另外,我們要編寫可讀性好的程式碼。大家都知道,整潔很重要,而程式碼風格也同樣如此。所有這一切會提升程式碼的質量並增強程式設計社群的能力。

Seibel:如何編寫可讀性好的程式碼呢?

Crockford:可讀性有幾個等級。最簡單的一級是與表達保持一致,適當地保持縮排,在適當的地方使用空格。我有一個習慣來自於早年學習Fortran的時候,那就是,我往往會使用過多的單字母變數名,這個習慣可不好。我真的在很努力改掉這個壞習慣,但太難了——這麼多年來還在與之鬥爭。

Seibel:有什麼具體的舉措可以提升程式碼的可讀性呢?

Crockford:子集的想法非常重要,尤其對於JavaScript來說更是如此,因為這門語言包含了太多的糟粕,當然其他語言也一樣。當還是個菜鳥時,我會翻閱語言規範並弄明白每個特性。我知道該如何使用這些特性並一直在用。但事實證明很多特性並非是深思熟慮的結果。

我現在想到的是Fortran,但其實所有語言都難逃這個宿命。有時語言設計者本身就錯了。依我看來,C在設計上存在很多不妥之處。

Seibel:你如何閱讀別人編寫的程式碼呢?

Crockford:清理。我會把程式碼放到文字編輯器中並開始修復。首先,我會統一標點符號,適當縮排,等等這類的事情。我有些程式可以完成這些事情,但從長遠來看自己完成會更加高效,因為這有助於我加深對程式碼的理解。Morningstar曾教會我如何完成這些事情。他非常善於重構別人的程式碼,並且這也是他所使用的方法,很好。

Seibel:你是否遇到過這種情況:看到程式碼寫得一團糟,然後進行清理,但最後發現原來的程式碼其實寫得很不錯?

Crockford:還沒遇到過。我認為隨隨便便寫出來的程式碼肯定不好。好的程式碼意味著可讀性要好。在某種程度上,如果我搞不懂程式碼的意圖,那麼寫得再好也沒用,有可能程式碼在我不關心的方面表現得很好,比如很高效、很緊湊,等等。

程式碼的可讀性是我的第一要義。它比速度還重要,可以與正確性一爭高下,可讀性是正確性的重要前提。如果可讀性不好,那就不是好程式碼,程式碼的編寫者可能做出了錯誤的權衡。

Seibel:你偏愛K&R風格?

Crockford:是的,我認為他們是對的,其最初的風格沒錯,對於JavaScript更是如此。JavaScript會自動插入分號,這樣如果將花括號放在左邊而不是右邊,那麼程式的含義就會發生天大的變化,這種變化是很糟糕的。事實表明K&R風格不會遇到這個問題,但flush風格會。

對於JavaScript來說,花括號是有著正確的擺放位置的;而其他C風格的語言則不是這樣,哪種擺放位置都可以看作是正確的。有些人喜歡flush風格的花括號,我也看過有人就風格的正確與否爭論了半天,但這些解釋都毫無意義,因為他們真正爭論的是自己在學校裡用的是什麼、在第一份工作中又用了什麼風格,或者是影響過他的某人使用了哪種風格,那這種風格就是正確的,而其他則是錯誤的。

這就好比是關於應該靠左還是靠右行駛的爭論,結果當然是無疾而終。如果住在孤島上,靠哪邊行駛都無所謂,但如果大家能達成統一確定走同一邊,整個社群都會受益無窮。

Seibel:在閱讀程式碼時你會先排版,那你會對程式碼進行多大程度上的重構呢?

Crockford:我會重新編排程式碼以便所有東西都會在使用前宣告和建立。有些語言提供了很大的靈活性,讓你無需再這麼做了。但這種靈活性我不需要。

Seibel:你曾在之前的一次演講中引用了《出埃及記》第23章第10節和第11節的內容——六年你要耕種田地,收藏土產,只是第七年你要叫地歇息,不耕不種。並建議每次第7個sprint都應該用來清理程式碼。那什麼時候做比較好呢?

Crockford:每6個週期——不管週期間是什麼都該如此。如果你是每月交付,那麼我覺得每隔半年都應該跳過一個週期,專門用來清理程式碼。

每個人的必修課:程式設計

Seibel:程式設計是不是越來越容易了,門檻逐漸降低?

Crockford:我對程式設計的興趣在於幫助其他人程式設計、設計特定的語言或程式設計工具,這樣會有越來越多的人能夠從事程式設計工作——這也是Smalltalk的初衷。Smalltalk後來的發展方向出現了變化,但最初的方向確實吸引了我。我們如何設計一門面向兒童的語言,如何為那些並非程式設計師的人們設計一種語言?

Seibel:你是不是認為每個人都應該學習程式設計,至少了解一些?

Crockford:沒錯。當今世界快被計算機控制了,為了保護自己或是讓自己更加全面,你應該瞭解這些東西的工作方式。

Seibel:有些人認為通過程式設計可以學到一種重要的思考方式,比如閱讀和數學就是不同的思考方式,但都非常重要。

Crockford:我以前也這麼想。在開始程式設計時我就有過這種想法:一切都是那麼地井然有序,我看到了之前從未接觸過的結構等東西。我在想“喔,這太神奇了。每個人都應該學習學習”,因為我突然之間感覺自己變聰明瞭。但不久之後,在與其他程式設計師交流的過程中發現,他們並沒有開竅。程式設計師其實與常人也沒什麼區別,有時他們也會出現誤解。當認識到這一點後我覺得很難過。

Seibel:那程式設計只是年輕人的專利麼?

Crockford:過去我是這麼認為的。幾年前我患有睡眠呼吸暫停的症狀,但沒有意識到。我想可能是太累了,年紀也有些大了吧,結果發現自己的注意力很難集中,甚至都沒法程式設計了,因為我的大腦沒法承載太多的東西。很多時候程式設計都需要先在腦子裡想好,然後再寫出來,但我卻不行。

我喪失了這種能力,想當然地認為是年齡太大的緣故。幸好,病情得到了好轉,於是我又開始程式設計了。現在的我程式設計水平可能比以前還要好,因為我知道如何不過多地依賴於記憶。現在的我更喜歡將程式碼文件化,因為我不敢保證下一週還能記得寫這些程式碼的意圖。事實上,有時我會檢查自己的程式碼,但會驚訝於自己怎麼會這麼寫程式碼:我壓根就不記得自己曾經這麼寫過,這些程式碼有的非常醜陋,有的卻非常優雅。我實在不知道怎麼會這樣。

Seibel:你曾說過文學程式設計就像Donald Knuth所說的那樣,是個非常棒的想法,那你使用過文學工具麼?

Crockford:沒有。我一直在考慮這個問題,併為我所使用的一些語言設計過文學工具,但我現在並沒有從事文學程式設計工作。

Seibel:這僅僅是個工具鏈問題麼?如果有現成的工具,你還會編寫文學程式麼?

Crockford:當然會了。比如說,如果使用文學風格編寫JSLint的話,那維護工作就輕鬆多了。我所說的文學風格是指在設計程式時要特別考慮到閱讀問題,這麼做會給程式帶來巨大的價值。

Seibel:你覺得文學程式設計工具的主要特徵是什麼?

Crockford:Knuth的主要貢獻在於提出了以各種順序編寫程式碼的想法。這樣,如果我所關注的東西涉及很多地方的程式碼,那麼我會將這些程式碼整合起來並加以說明,然後工具會在適當的地方解決細節問題。 他還幫助你擺脫了函式大小的困擾。理想情況下,一個函式不應該超出螢幕的範圍,這樣就能一覽無餘了。如果達不到這個要求,那可以將一個函式拆分成多個函式,如果函式對程式結構起不到什麼作用,那麼它也沒有存在的價值。

Knuth建議抓住函式的各個方面,它們很可能是緊密相關的——具有一致性,但就是太大了;有時函式確實過於龐大——他建議使用具有描述性的標籤來表示每個函式,“這個函式是:”,然後列出這些標籤。你當然可以使用函式達成目的,但這兩者並不一樣,如果使用函式,你必須要處理函式之間的通訊,等等。這麼做會引入更多與問題不相關的結構。

最後,我非常希望看到新的文學程式語言的出現。Knuth非常擅於將這些想法應用到Pascal和C當中,但我打心底想看到有人能真的設計出一種新的使用這種風格的語言。

Seibel:你讀過Knuth的文學程式麼?

Crockford:當然讀過。

Seibel:如何讀的?像小說一樣?

Crockford:沒錯,就像小說一樣。我像在讀他的散文而非程式,喜歡他的展現方式,他寫得確實好,偶爾還會搞個笑話出來。我很享受這種閱讀體驗。

Seibel:Knuth的大部頭《計算機程式設計藝術》如何?你是從頭到尾讀過這本書呢,還是將其作為參考隨時翻閱,抑或是把它束之高閣碰也不碰呢?

Crockford:除了你說的最後一種情形之外。在上大學時,有那麼幾個月我連房租都沒交,就是為了買他的書。我讀過這些書,從中得到了不少樂趣,比如在第一卷的索引有個關於拖車的笑話就很好玩。我到現在為止還沒能把書上的內容全部搞懂。Knuth對某些地方的研究要比我深入得多,但我還是喜歡這些書並把它們當作參考資料。

Seibel:你是從頭到尾逐字閱讀,跳過那些不理解的數學部分?

Crockford:是的,我會很快略讀過星號太多的部分。我試圖將熟悉Knuth的書作為招聘標準,但結果卻大失所望,根本沒幾個人讀過他的書。依我看來,任何自稱為專業程式設計師的人都應該讀過Knuth的書,至少也應該買過他的書。

Seibel:也就是說Knuth講述的是如何實現最根本的東西,然後才有全景。即便清理了平臺,但使用理性的方式構建大型系統和設計也是非常困難的。請問你是如何設計程式碼的?

Crockford:編寫程式與對程式的生命週期進行迭代是不同的。通常,編寫軟體的原因在於我們知道將要修改它,而修改任何東西都不那麼容易,因為很多時候修改意味著打破舊有的東西。

你不能期望使用這種方式完成所有事情,但還是應該盡力保證足夠的靈活性,這樣不管做什麼都能適應。這就是我的觀點。如何避免誤入死衚衕?如何保證靈活性?

這就是我喜歡JavaScript的原因之一。我發現JavaScript可以輕鬆實現重構,而重構一個繼承層次很深的類實在太痛苦了。

Seibel:你覺得自己是個科學家、工程師、藝術家、工匠還是什麼?

Crockford:我覺得自己是個作家。有時我使用英語寫作,有時使用JavaScript。歸根結底,這完全取決於交流方式以及為了促進這種交流所採取的結構。人類語言與計算機語言在很多地方都是大相徑庭的,我們需要閱讀計算機語言,因此必須與之交流,我根據語言的這種交流能力判斷計算機程式的優劣。在這個層次上,人類語言與計算機語言的差別不大。

Seibel:你對自學的程式設計師有什麼建議呢?

Crockford:兩個字:多讀。現在有不少好書,去找些好書來看吧。如果從事Web開發工作,請找一些優秀的站點,看看他們的程式碼。話雖如此,其實我不太想這麼建議。大多數Web開發者都是從“檢視原始碼”開始走上Web開發之路的,但直到現在,大多數原始碼的質量都是非常低劣的。因此有一代程式設計師都被那些低劣的示例誤導了,他們寫的程式碼質量也不高。現在的情況已經有所改觀,但依然有很多低質量的程式碼遊離於你我之間,所以我是不太想給出這個建議的。

本文節選自《程式設計人生》

相關文章