程式碼不是文學作品

heloowird發表於2014-04-17

我在最近兩個工作過的公司—Etsy和Twitter—成立過程式碼閱讀小組,一些人向我徵詢關於閱讀程式碼以及運作程式碼閱讀小組的建議。想說的太多,一言以蔽之:不要成立程式碼閱讀小組。你應該去成立小組但不是我稍後提到的那樣,而在此之前,我要解釋一下我是如何得出目前觀點的。

作為一位曾讀英語專業的業餘作者,我以往總是被這樣的想法所吸引:程式碼就像文學作品,我們應該像通過閱讀優秀範文學寫英文那樣來學寫程式碼。當然,持這種觀點的不止我一個人。Donald Knuth(著名電腦科學家,譯者注),除了致力開發TeX軟體和編著《計算機程式設計藝術》,一直以來是被他稱作“文學程式設計”的提倡者,並已經把他的幾個大型程式出版成書。

另一方面,早在我加入Etsy併成立第一個程式碼閱讀小組之前,手頭上就已經有一些跡象本就表明:這是看待程式碼的一個錯誤方式。

首先,當我在編寫關於與程式設計師訪談的《程式設計人生》(書中記錄與15位世界級程式設計大師的對話,譯者注)一書時,我幾乎問了每個人關於閱讀程式碼的問題。大部分人說閱讀程式碼是重要的且程式設計師應該多讀,然而當我問到他們最近讀了哪些程式碼時,很少有人有好的答案。在他們還是年輕黑客時,其中有些人認真地讀過一些程式碼,然而幾乎沒人保有閱讀程式碼的習慣。Knuth作為偉大的電腦科學集大成者,閱讀了大量的程式碼;Brad Fitzpatrick談到出於惡作劇而閱讀過一些開原始碼片段。但他們倆是例外。

如果這還不夠,那麼在完成《程式設計人生》之後,我獲得一次採訪Hal Abelson的機會。Hal Abelson是麻省理工大學的著名教授,《計算機程式的構造和解釋》的合著者。當我首次跟他談論,問及之前那樣的閱讀程式碼問題時,他給出了普遍的答案:閱讀程式碼是重要的且程式設計師應該多讀。但他也沒有說出任何最近讀過的程式碼,除了不得不閱讀的程式碼之外,包括在谷歌休公假時審查同事的程式碼以及給麻省理工學生評分時的程式碼。後來我問他關於這種矛盾:

Seibel: 我對人們所說的和實際所做的之間的這種分裂很好奇。每個人說“程式設計師應該閱讀程式碼”,但似乎少數人真正去做了。我會感到驚訝:如果我採訪小說家們並問他們最近讀了哪本小說,他們回答說“哦,自從讀研究生後,我就沒真正地去讀一本小說了”。作家們實際上會讀其他作者的書,但程式設計師不會真正得去讀其他人的程式碼,儘管他們說應該去讀。

Abelson: 是的。你是對的。但記住,很多時候,你增刪查改一個程式最終使之能夠執行並完成你需要它做的所有事情,所以就有很多與核心思想無關緊要的東西。

Seibel: 所以基本上你最終是說,大多數程式碼不值得一讀?

Abelson: 或者說程式從一個初始計劃或某種虛擬碼構建起來。書中的許多程式碼,是一些淨化過的版本,不具備使程式執行起來的所有東西。

Seibel: 我想起了《計算機程式的構造和解釋》的前言,裡面寫道“程式應該是為了供人讀才寫的,然後順便讓機器執行了一下。”然而正好你所描述的事實在實際中卻是,大多數程式都是讓機器來執行才寫的,如果有的話,只順便供人閱讀。

Abelson: 嗯,我認為他們一開始是為了供人閱讀的,因為裡面包含著一些想法。你解釋的東西,僅有一小部分存在我們的書中。書中有一些相當重要的程式。而且部分原因是我們認為解釋它做什麼的最簡單方式就是表達在程式碼中。

然而即使明顯知道大部分真正的程式碼實際上不是採用人容易讀懂的方式去編寫的,但這不足以讓我在Etsy成立小組時放棄這種文學研討班模式。由於大多數Etsy開發者熟悉Javascript以及我知道Jeremy Ashkenas對可讀性程式碼的編寫有濃厚興趣,所以在第一次程式碼閱讀小組會時,我選取了Jeremy的backbone.js。我仍計劃了一些像文學研討會一樣的流程,但我發現許多人不會預習程式碼(嗯,這點跟文學研討班倒是一樣)。所以我決定在小組討論環節之前演示要討論的程式碼。

當準備我的演示文件時,我發現自己掉進了慣常模式:每當試圖真正理解或心領神會一段程式碼時,我不得不從根本上重寫它。為了更好理解,我將開始重新命名一些名稱,接著順著我組織程式碼思路去移動一些語句。很快,我就已經開始深入程式碼抽象化(或具體化),並開始對更大程度地重組程式碼結構。一旦完成程式碼重寫,我通常已很好地領悟了,甚至可以溯源並理解初始版本。我經常覺得這種閱讀程式碼的方式不好,但它是迄今為止我理解程式碼的唯一方式。

在程式碼閱讀小組演示時,我以初始的backbone.js作為開始,然後在自己想法的指引下,一步一步演變使之更易懂。當我問大家是否應該轉向小組討論環節時,但似乎沒有人很感興趣。好在看到我的重構讓組員對原始程式碼的底層結構有了與之前我通過重構獲得的相同見解。

Etsy的第二次程式碼閱讀小組會由Avi Bryant主持,展示瞭如何利用SmallTalk的程式碼瀏覽功能來檢視一些程式碼。因為在Etsy少數工程師跟Smalltalk打過交道,所以我們對組員會預習程式碼這件事不抱任何希望。但這次演示,對組員來說是一次領略SmallTalk魅力的絕佳機會,也讓有我有機會發難Avi關於Smalltalk和Lisp的區別。

當我來到Twitter,文學研討會模式仍莫名其妙地盤旋在腦海中,儘管在Etsy的兩次看起來備受青睞的小組會幾乎沒有遵循這種模式。當我發郵件邀請twitter的工程師參加程式碼閱讀小組時,迴應相當熱情。再次,第一次小組會由Marius Eriksen演示了一段程式碼。在這個示例中,展示了Scala語言實現的Future包的內部構件。這個構件被用於Twitter的很多服務,其大部分由Eriksen本人編寫。

在演示了一段時間後,我終於明白一個淺顯的道理:程式碼不是文學作品。我們不去閱讀程式碼,而是解譯、審查它。一段程式碼不是文學片段,而是樣本。當我問Knuth關於他自己閱讀程式碼時,他回答的其實早就給我指明瞭這個方向:

Knuth: 但建立在大腦的東西是真正有價值的。那麼我怎麼利用它的呢?曾經有臺型號為Bunker Ramo 300的機器,有人告訴我這臺機器的Fortran編譯器真的是不可思議的快,但沒有人知道它是怎麼做到的。我得到了編譯器原始碼的副本。因為我沒有機器的說明書,所以甚至連機器語言是什麼都不知道。

但是我把它當成是一項有趣的挑戰。我能搞清楚BEGIN,然後我就開始解碼。這些指令碼對應著雙字指令助記符,所以我開始合計著“這個可能是裝載指令,而這個可能是分支”。接著我知道它是Fortran編譯器,所以到一定程度後,看著卡片的第七列就能分辨是不是註釋。

三個小時後,我已經弄懂機器的一小部分。接著我碰到了重大問題 — 跳轉表。因此這是一個難題,之後我堅持畫了些圖表,就像我在某安全域性試圖解譯一個密碼一樣。但我知道它是個執行很快的Fortran編譯器,在某種意義來說這不是加密而是有意地掩蓋;因為弄不到機器的說明書,所以答案就藏在程式碼中。

最終我弄明白了為什麼這個編譯器如此快。不幸的是,它並不是因為使用了卓越的演算法,僅僅是因為他們採用非結構化程式設計並且最大限度地優化了程式碼。

畫圖表、獲取更多一點資訊並作假設僅是你基本上解決某種難題的方法。通常,當我閱讀技術檔案時,是同樣的挑戰。我試圖理解作者的思想,嘗試搞懂這個概念是什麼。我認為,你試著去讀別人的東西越多,未來你更能創造屬於自己的東西。

他沒有在描述文學作品的閱讀,而在描述一個科學性調查。所以現在我對人們應該如何一起從程式碼中獲得深刻見解這個問題有了新答案,正如我向Twitter程式碼閱讀小組解釋的一樣:

在準備與一起程式設計的女兒們即將進行的對話時,我開始思考告訴她們一些關於程式碼閱讀以及應該讀什麼程式碼的事情。我再次突然想到了那些所有口惠而實不至的程式碼閱讀想法,絕大部分程式設計師不會真正地閱讀大量程式碼,至少不是純粹為了閱讀程式碼而讀。這有一個簡單檢驗方法:說出一段你讀過的程式碼並且肯定大部分優秀程式設計師會去讀或者至少聽說過。不多,對不對?可能一行都沒有。

但我想到程式碼不是文學作品,我們不是讀者。更確切地說,有趣的程式碼片段是樣本,我們是博物學家。所以我認為更好的方式是:我們其中的一位扮演著一個剛從異國回來的19世紀博物學家在國內科學界引發關於他們所發現的一隻新型昆蟲的議論:“看這怪物的觸鬚!這些觸鬚看起來非常笨拙,然而該物種的雄性可利用它們殺死小青蛙,然後雌性將卵產在其屍體中”,而不是像一群學比較文學的研究生那樣挑出一段程式碼並去閱讀、討論它。

這種演示的關鍵在於介紹者要選一段自己深刻理解的程式碼,並通過從進化碎屑層(亦為臨時補救方案–指快速有效但醜陋的方案,譯者注)中指出核心思想,有助於聽眾理解。一種合理的方式應該是展示真正的原始碼並剝離、重寫關鍵部分,就像一個生物學家去染色樣本,使不同特徵更容易辨別一樣。

典型的演示應面向所有程式設計師,或男或女,或聰明或一般,但必須對與程式碼出處有關的任何特定知識不作要求。為了讓組員理解程式碼,演示文件應該提供足夠的上下文,解釋對一般水平程式設計師而言比較晦澀的實現語言的任何細節。

由於我的頓悟,我們採用新模式,已成功舉行了幾次程式碼閱讀小組會議,現在被稱為Twitter的旨在提高編碼知識的英國皇家學會。我們仍在摸索講演程式碼的最佳方法,儘管目前方法感覺很不錯。另外,我不再覺得我這種解剖式閱讀程式碼的方式是糟糕的。

至今最大的教訓是,程式碼是非常稠密的。半小時的報告只夠用來呈現大約十二行耐人尋味的程式碼和一個主要思想。幾乎可以肯定的是:報告人必須真正深入某段程式碼,要比任何人有更深的理解。除此之外,一個優秀的演示至少可讓組員接觸到的核心思想,對於決定自己去閱讀程式碼的人們來說,可能是一個好的開端。

相關文章