Ken Thompson#

人物背景#

Ken Thompson 是原始的留鬍子 Unix 駭客。他的職業生涯就是做他覺得有趣的事情——包括類比計算、系統程式設計、正規表達式和電腦西洋棋。

  • 在 Bell Labs 被聘為研究員,參與 MULTICS 專案
  • Bell Labs 退出 MULTICS 後,與 Dennis Ritchie 一起發明了 Unix
  • 發明了 B 語言——Dennis Ritchie 的 C 語言的前身
  • 建造了 Belle——第一台專用西洋棋電腦,也是當時最強的電腦棋手
  • 擴展了西洋棋殘局資料庫(endgame tablebases),涵蓋所有四子和五子殘局
  • 在 Bell Lab 的 Plan 9 作業系統中,設計了現今無所不在的 UTF-8 Unicode 編碼
  • 1983 年與 Ritchie 共同獲得 Turing Award
  • 也獲得了 National Medal of Technology 和 IEEE Tsutomu Kanai Award
  • 受訪時在 Google 工作

程式啟蒙之路#

從邏輯和二進位開始#

  • 從小就對邏輯著迷,小學就在做二進位算術
  • 自己研究出不同進位的加法演算法——什麼是進位、每一欄的含義
  • 有一個小型十進位計算器(像算盤),把它改造成做二進位運算
  • 七年級就在做這些——後來在課堂上正式學到二進位時如魚得水

電子學與類比計算的熱情#

  • 高中時對電子學非常著迷——造收音機、放大器、振盪器、特雷門琴
  • 進入 UC Berkeley 的電機工程系(double E)
  • 大三時首次見到真正的數位電腦——一台類比電腦和一台 G15 鼓式電腦
  • 瘋狂使用類比電腦——幾乎獨占使用,因為沒人用
  • 為類比電腦寫了縮放程式——類比計算的核心就是縮放(時間縮放和振幅縮放)

通過閱讀程式碼學會程式設計#

  • G15 有一個叫 Intercom 501 的直譯器
  • 一個研究生在大型 IBM 機器上為 Intercom 寫了一個直譯器
  • Thompson 在聖誕假期拿到那份程式清單,花了一整週仔細解剖
  • 不知道那是用 NELIAC(Algol 58 的系統程式設計版本)寫的,但從那份程式碼中學會了程式設計
  • 「那是一個寫得極漂亮的程式。我從中學會了程式設計、NELIAC、Intercom,以及如何解讀直譯器——一切。」

Thompson 的學習方式非常獨特:他不是從教科書學的,而是通過閱讀一份寫得很好的程式碼,在一週內自學了程式設計。這預示了他後來對「閱讀程式碼」的重視。

在 Berkeley 的非正統學術生涯#

  • 邊工讀邊念書,做研究助理、助教、電腦中心程式設計師
  • 教授朋友們會為他發明課程讓他去教——他還是學生時就在教課
  • 一個教授替他申請了研究所——他自己甚至沒申請
  • 大四和碩一「極度快樂」——沒有任何必修課,只做想做的事
  • 教了五門課,有的教了兩次;覺得教第一次是辛苦,第二次是樂趣,第三次就無聊了

Unix 的誕生#

從 MULTICS 到 Unix#

  • Bell Labs 參與了 MULTICS 專案,Thompson 被聘來做這個
  • MULTICS 過度設計、過度建構——「接近不可用」,是經典的第二系統症候群
  • Bell Labs 退出後,留下了一些閒置的 MULTICS 專用機器
  • Thompson 在這些機器上開始嘗試做一個小型作業系統
  • 後來找到一些沒人用的 PDP 小型機,在上面建構了 Unix

Unix 的設計過程#

  • 一群人坐下來討論了檔案系統的設計——Rudd Canady 把黑板上的設計打電話錄給秘書服務,第二天變成紙本文件
  • Thompson 在 PDP-7 上獨自實作了這個檔案系統
  • 為了測試檔案系統,他開始寫 shell 來驅動它
  • 「做到一半我意識到這是一個真正的分時系統。我在寫 shell 來驅動檔案系統,然後寫了幾個其他程式來驅動它。就在那裡我說:『我只需要一個編輯器,我就有了一個作業系統。』」

妻兒外出的一個月#

  • 妻子和孩子外出一個月,Thompson 全力投入
  • 他的自然作息是 27-28 小時循環,睡 6 小時——家人不在時就順其自然
  • 「你在被驅動的時候才做得到。我不認為我做也行。」
  • 興奮的程式設計從不產生壓力;只有外部截止日期才會

從 MULTICS 帶走的東西#

  • 階層式檔案系統shell 作為獨立的可替換行程——這兩個是他喜歡到實際採用的功能
  • 之前所有系統都有某種「executive」——內建的處理語言;Unix 的 shell 是獨立的行程
  • 每次你輸入東西到 shell,它建立一個新行程,執行你輸入的內容,結束後回來——這讓你與正在執行的東西保持距離

Thompson 認為 MIT 對 Unix 一直有自卑情結。MULTICS 是經典的第二系統症候群——而他認為建造 Lisp 機器也是「有點蠢」的事,因為 PDP-11 和 PDP-10 本身就是很好的 Lisp 機器。

軟體設計方法#

金字塔式由下而上#

Thompson 的設計方法是獨特的由下而上金字塔建構

  • 大部分時間,設計在腦中醞釀——什麼都不寫,持續一段時間
  • 專注在困難的部分——容易的部分會從指尖自然流出
  • 困難的部分讓它醞釀一段時間,也許一個月
  • 某個時刻,底部的零件開始掉出來,他能看到金字塔從底部建構起來
  • 當金字塔在腦中夠高時,就從底部開始寫程式碼

資料結構先行#

  • 寫程式碼前通常先寫下資料結構——小方框加箭頭
  • 不寫演算法、不畫流程圖
  • 「你幾乎每一行程式碼都需要參考的東西——就是資料結構。」

隨時願意重寫#

  • 如果發現更好的分區方式,會毫不猶豫地把程式碼拆掉重來
  • 「很多人寫了一行程式碼之後,它就是具體的了,永遠不會改。特別是如果他們在信封背面寫了一個 API——就永遠不變了,不管它有多糟。」
  • 「我從來不是現有程式碼的愛好者。程式碼本身幾乎會腐爛。即使什麼都沒變,不知為何它就是得重寫。」

Thompson 定義脆弱程式碼:想要加一個功能時,好的程式碼只需要改一個地方就能加上去;脆弱的程式碼要改十個地方。「有些人寫脆弱的程式碼,有些人寫結構堅固的程式碼,這是人的條件。」

現代程式設計讓他害怕#

  • 現代程式設計中層層疊疊的抽象讓他困惑
  • 「層又層又層,只做翻譯,什麼都不做。它說『做某事』,你去找『某事』,它說『做某事別的』……什麼都不會真正完成。我無法在腦中保持住它。」
  • 他喜歡從底部閱讀——看到底層構件,想像它們能建構成什麼
  • 偏好由下而上的文件,而非由上而下

除錯方法#

  • 主要除錯工具就是印出值
  • 開發程式時做大量的印出——到最後移除或註解掉時,印出的內容已經很穩固了
  • 不從頭寫程式——而是拿一個程式來修改,逐步建構
  • 「即使是大程式,我會說『main, left, right, print, hello』——好吧,『hello』不是我想要的,那第一個要做的是什麼?我就寫那部分並除錯。開發過程中每小時跑程式 20 次。」

對 assert 的態度#

  • 很少使用 assert
  • 「你印出一個值,就能真正看到它是什麼,而不只是看到它是否等於某個特定值。你印出一堆不是 invariant 的東西。」
  • 說服自己正確後就把印出註解掉或移除

最難追的 Bug#

  • 基本上都是記憶體被損壞的 bug——早期常常是硬體問題
  • 最難的一個:PDP-11 的乘法器外接裝置(I/O 周邊設備)設計給沒有記憶體管理的機器,在有虛擬記憶體的新版 PDP-11 上會在忙碌測試時把實體位址送到虛擬位址上,隨機損壞記憶體
  • 追蹤方法:寫了一個大量使用乘除法的 e 位數計算程式,把崩潰頻率從幾天一次提高到幾分鐘一次
  • 最後拿到電路圖,在電路圖中找到了 bug——打電話給 DEC 說:「把這條線和那條線接上。」

程式語言觀點#

B 語言的故事#

  • B 語言起初打算做成 Fortran
  • 開始實作時拿到了 BCPL 的描述,喜歡它乾淨的語意
  • 放棄了 Fortran,轉向「基本上是 C 語法加 BCPL 語意」
  • B 是一個「試圖逃離 Fortran」的 Fortran 編譯器

對 C++ 的嚴厲批評#

Thompson 與 Bjarne Stroustrup 在 AT&T 共事過:

  • 試用過 C++ 的開發版本,發現它非常不穩定——寫的東西第二天就因為語言改了而無法運作
  • 某次受訪說他不用 C++ 只因為它連兩天都不穩定——Stroustrup 衝進他房間大吼
  • 從此以後他避免公開評論 C++

但他還是說了:

  • 「整體來看,我認為它是一個糟糕的語言。它做很多事情都做一半,它就是一堆互相矛盾的想法的垃圾堆。」
  • 每個人或公司都選擇一個子集使用——所以它不適合用來傳遞演算法
  • Stroustrup 為了讓語言被採用,花了多年推廣,主持標準委員會——對誰都不說「不」,把所有功能都加進去
  • C++ 在 Google 正在失去地位——不喜歡它的人比喜歡的多了

Thompson 對 C++ 的評價:「它不是被乾淨地設計的。它只是所有曾經存在的語言特性的聯集。我認為它因此深受其害。」

對垃圾回收的矛盾態度#

自稱在這個問題上「精神分裂」:

  • 寫作業系統或 C 編譯器時:垃圾回收是錯誤——它是在偷懶,讓你的使用者變慢
  • 寫一次性程式時:垃圾回收很美妙——免去一層你不想思考的東西,電腦夠快所以負擔得起
  • 問題是不同的 GC 演算法有極不同的特性——如果作業系統不能容忍即時暫停,而底下的 GC 是 mark-and-sweep,那就完蛋了
  • GC 和 cache coherency 的互動也是重大問題——應該把 GC 與機器綁定得更緊

喜愛的工具#

  • 愛用 yacc——「它完全做你想做的事」
  • 討厭 Lex——「可怕。它什麼你想做的事都做不了。」
  • 自己手寫 lexer,覺得容易得多
  • 在 Google 用 C 寫所有東西——雖然 Google 是 C++ 環境
  • 曾在 Google 但一直沒通過語言認證來 check in 程式碼——「我就是沒做。到目前為止沒發現需要。」

其他喜歡的語言#

  • 各種「好玩的語言」都會嘗試——Maple、Macsyma(解方程式用)、SNOBOL(字串處理用)
  • 玩過幾十種語言,只要它們做有趣的事情

測試與品質#

測試方法#

  • 如果程式是翻譯器(A 到 B),會做回歸測試——拿一堆 A 和對應的 B 來比較
  • 其他類型的程式不太喜歡做測試——覺得測試太難維護
  • 作業系統和裝置驅動最好的測試就是讓人實際使用
  • 「有什麼比讓人打擊作業系統更好的測試?」

優化哲學#

  • 第一次就盡可能簡單地寫,很多時候這就永遠夠用了
  • 「為永遠不會執行的東西寫複雜演算法是愚蠢的。那是時間的浪費。那是 bug 生成器。」
  • 99% 的時候簡單的東西加暴力法就夠了
  • 偏好簡單演算法和簡單程式碼,而非複雜演算法
  • 「如果有一個東西能描述我的程式碼特色,那就是:簡單、短小、精簡。不花俏。任何人都能讀。」

編譯器優化的看法#

  • 不值得花時間做到「非常好」的優化——從「好」到「非常好」的時間裡,Moore’s Law 已經讓電腦快了一倍
  • GCC 產生的程式碼很糟糕——「你看 GCC 出來的程式碼,天哪。它就是不好。而且慢。」
  • 但 GCC 看起來沒變慢是因為電腦變快了 1000 倍
  • 手寫組合語言除非能得到一個數量級的提升,否則不值得

對文件和註解的看法#

文件是一門藝術#

  • 文件和程式設計一樣是一門藝術——很少見到他喜歡的文件
  • 大部分文件太細、太多不相關的東西、有很多懸空引用和假設讀者已知的知識
  • 「要做好文件,你得把它解構、拼在一起、用好的方式重寫、發現錯了再重寫。人們不這麼做。」
  • 偏好由下而上的文件

對文學式程式設計的看法#

  • 很棒的想法,但實際上幾乎不可能做到
  • 「那是同一個程式的兩個表述,常常不同步且互相矛盾。沒辦法解決。」
  • 如果程式碼寫得好,它本身就是可讀的——註解只需要用在演算法或棘手的地方
  • 不是寫大量註解的人——「這是傳奇性的。」

對書的態度#

  • 不讀初學者程式設計書
  • 學新語言時偏好直接給語法和語意的密集書籍
  • 教課時會挑教科書,所以熟悉那些領域的基本文獻——但其他時候不太讀

在 Google 的工作#

基礎設施與可靠性#

  • 做基礎設施、作業系統相關的東西——各部分之間的膠合
  • 挑戰:讓一群不可靠的機器像一台可靠的多處理器機器一樣工作
  • 估計超過 50% 的程式碼都是「what-if」類型——「如果這個不行、那個不行怎麼辦」
  • 目標是把可靠性的負擔從個別程式設計師身上移走

對 Google 的看法#

  • 部分很喜歡,部分覺得沉重——「bug 裡面有錢,很多東西裡面有錢」
  • 規模不可想像——「某天你緩慢地推進,第二天你就有兩百萬使用者」
  • 不做產品、不做基礎研究——做那些會變成產品但做完就不管的專案
  • 工作描述:找到能讓事情更好的新東西,或是替換老東西讓它更好

識別人才的方法#

熱情計量器#

Thompson 的面試方法:

  • 問他們做過最有趣的程式是什麼
  • 讓他們描述演算法和細節
  • 如果他能攻擊他們的問題和解法,而他們無法防禦,那就不夠好
  • 同時感受他們的熱情程度——這不是直接問的,而是從對話中感受到的
  • 讓對方選題——「我是外行,他們是這個題目的專家。如果他們連一個外行問他們專業問題都受不了,那他們不屬於這裡。」
  • 據說被這樣面試的感受「是毀滅性的」

Thompson 識別人才的核心指標是熱情。「我從未遇到一個在某件事上真正投入心血的人不願意急切地描述他們做了什麼、怎麼做的、為什麼這麼做。」

自我定位#

  • 不喜歡用 scientist 這個詞——「那是菁英主義的。沒有哪張證書上面寫『科學家』。」
  • 有工程學位,所以可以用 engineer
  • 填表格時寫 engineer 或 programmer
  • 認為自己更像底層的工匠(craftsman),帶有一定的藝術性

工作與生活#

驅動力是內在興奮#

  • 寫 Unix 時被驅動著——覺得自己不可能不做
  • 妻兒外出時自然進入 27-28 小時循環,睡 6 小時
  • 「興奮的程式設計從來不會產生壓力。」
  • 外部截止日期才會產生壓力——那不好玩
  • 持續的截止日期壓力會導致倦怠

對脆弱程式碼的看法#

  • C 語言指標亂飛的問題?「你用語言的慣用法來避免。有些人寫脆弱的程式碼,有些人寫堅固的程式碼。」
  • 他承認每次寫 strcpy 這類非比較副程式呼叫時,都知道自己在寫 bug
  • 但語意上的問題(截斷字串導致其他地方出問題)不會因為安全語言就消失——bug 還在,只是沒有溢出緩衝區而已

Thompson 對程式設計的態度極為務實:不計畫、不做學問、做自己想做的事、下一步怎麼走就怎麼走。「基本上我什麼都不計畫,只是走下一步。如果要重來,我確定我也不會改變什麼——我就是沒辦法改。」