Douglas Crockford#
Yahoo! 資深 JavaScript 架構師、JSON 發明者、JSLint 作者。 Crockford 自 1970 年代初期開始程式設計,職業生涯橫跨 Atari、Lucasfilm、Electric Communities 和 Yahoo!,一直致力於將電腦與媒體結合。
Crockford 本質上是一位簡化者和整理者。他發明了 JSON(因為覺得 XML 太複雜),著有 JavaScript: The Good Parts,主張 JavaScript 只要避開某些特性,其實是一門很好的語言。他是 ECMAScript 4 (ES4) 提案的知名批評者,主張更溫和的 ES3.1 路線——最終 ES3.1 被重命名為 ES5,ES4 被正式放棄。
學習程式設計的歷程#
意外的開始#
- 進入 San Francisco State University 是為了學電視製作
- 第一年拿不到攝影棚的使用時間,隨機選了一門數學系的 Fortran 課
- 意外發現自己很擅長程式設計,於是繼續修了第二學期
- 那是 1971-72 年——用打孔卡片在圖書館地下室的電腦上工作
跨學科的環境#
- San Francisco State 沒有強大的工程系,電腦分散在各個學院
- 自然科學、商學院、教育學院、人文學院都有電腦實驗室
- 他先在科學實驗室工作,後來轉到人文學院實驗室
- 接觸到經濟學家、心理學家、地理學家——「他們是最有趣的人」
- 很早就培養出對一般使用者如何與電腦互動的敏感度
早期有趣的程式#
- 寫了一個程式來反組譯 Fortran 系統的 runtime
- 透過這樣做,學到了系統運作方式和許多通常不會被公開的程式設計知識
效率到表達力的轉變#
- 早期微處理器時代,效率至關重要——記憶體極小、CPU 極慢
- 需要寫組合語言來做遊戲和音樂等應用
- 隨著 Moore’s Law 生效,這種約束逐漸消失
- 如今在瀏覽器中用 JavaScript 寫大型應用——「一個相對低效的環境,但 Moore’s Law 讓一切都 OK 了」
職業生涯#
SRI → Basic Four → Atari#
- 完成廣播學位後,開始攻讀教育技術碩士,但覺得太浪費時間,一年後離開
- 在 SRI (Menlo Park) 擔任研究員
- 轉到 Basic Four 公司,開發小型商用電腦的文字處理系統
- 試圖推動公司進入 PC 領域,但無法改變公司文化
- 1981 年聖誕節買了 Atari 800,開始寫遊戲
- 賣了一款遊戲給 Atari,獲得在他們研究實驗室工作的機會
- 那是 Alan Kay 在 PARC 之後創立的研究實驗室——「去了那裡,很棒。看著公司融化倒閉。但做了一些有趣的工作,和一些很好的人共事。」
Lucasfilm(八年)#
- Atari 倒閉後轉到 Lucasfilm
- 見證了 Habitat 的誕生——由朋友 Chip Morningstar 發起的圖形化虛擬世界專案
- 運行在 Commodore 64 上,使用 x25 離峰網路
- 發明了 avatar(虛擬化身)的概念
- 設計上有驚人的遠見
Electric Communities#
- Morningstar 和 Randy Farmer 離開 Lucasfilm 創辦了 American Information Exchange(線上市場的先驅,如果晚幾年可能就是 eBay)
- 後來一起創辦 Electric Communities——打造一個完全分散式的社交平台
- 需要一個安全的程式語言,先嘗試了 Joule(actor 語言),後來開發了 E 語言(在 Java 之上重新實現 Joule 的 actor 概念)
- 在 Electric Communities 學會了 closures 的概念——後來將這個理解帶到 JavaScript
- 親歷了令人心碎的 second-system syndrome:團隊極其聰明,嘗試重建全球分散式的 Habitat,但一步到位太困難了
Crockford 從 Electric Communities 的失敗中學到:漸進式方法遠勝於一步到位的重寫。如果當時拆成兩個平行工作流——一個做安全分散式平台,一個用現代語言重建 Habitat——再逐步合併,結果可能完全不同。「程式設計師是樂觀主義者。如果我們不是樂觀主義者,就做不了這份工作。但這也是為什麼我們會掉進 second-system syndrome。」
JavaScript 與 Web 標準#
發現 JavaScript 的好#
- 在 Electric Communities 接觸 closures 後,開始做 web 開發
- 看到 JavaScript 中有「熟悉的東西」——JavaScript 的血統很大程度來自 Scheme
- 「文件裡沒有任何地方告訴你 JavaScript 有 closures。我是偶然發現的。」
- 從此推廣 JavaScript 可以做嚴肅的程式設計
JavaScript 的問題#
- 語言被過於倉促地推向市場並過快地標準化
- 大部分缺陷都在規格中——「規格不正確地描述了這些事情,令人震驚」
- 1999 年凍結後本應被忽視和淘汰,但 Ajax 的出現讓它突然成為世界上最重要的程式語言
- 最大的問題:依賴全域物件(global object),沒有 linker、沒有 compilation units、沒有資訊隱藏
- 所有 script 都共享相同的全域空間和 DOM 存取權限——這是 XSS 攻擊的根本原因
對 ES4 的批評#
- ES4 「在解決錯誤的問題——解決人們討厭 JavaScript 的問題,而不是修復 Web 的根本安全問題」
- 主張漸進式改進:先加入模組系統和安全選擇,就已經前進了很多
- ADsafe:他設計的 JavaScript 安全子集,禁止存取全域物件和危險功能,但保留了 lambda 的全部力量
讓 JavaScript 更好的方法#
- 「讓 JavaScript 變得更好的最佳方式是讓它更小」
- 去掉那些無價值的特性,語言本身就會更好
- 同樣的方法可以應用於 HTML、HTTP、CSS
- 認為 jQuery 的 CSS selector 方式是個好主意——隱藏了 DOM 的醜陋介面
JSON 的誕生#
- 發明 JSON 是因為覺得 XML 太複雜
- JSON 是 JavaScript object literal 語法的子集,用於資料交換
Crockford 對 JavaScript 的核心理念是 subsetting(子集化):不要使用語言的所有功能,只使用那些好的部分。這個理念不僅適用於 JavaScript,也適用於任何語言——「當我還是 journeyman 時,我會讀語言手冊,學會每個功能,然後全部使用。結果發現很多功能設計得不好。」
程式碼閱讀#
Code Reading 作為團隊活動#
- 這是 Crockford 在 Yahoo! 最積極推動的實踐
- 「我認為一小時的 code reading 相當於兩週的 QA」
如何進行 Code Reading#
- 每次會議由一位成員負責展示自己的程式碼
- 所有人拿到紙本列印,同時在螢幕上投影
- 作者逐行講解程式碼,其他人觀察和評論
- 評論範例:「我不理解這個註解」、「這個註解似乎和程式碼不符」
Code Reading 的好處#
- 及早發現弱點和混淆——你自己會停止閱讀自己的註解,不知道它們在誤導讀者
- 指導作用:強者可以教弱者,弱者也能給強者好建議
- 追蹤進度:比問「你完成了嗎?」更有效——直接看程式碼就知道真實狀況
- 避免「我快完成了」的謊言——管理上最痛苦的經驗
- 應該貫穿整個專案生命週期,而非只在最後才做
Code Reading 的前提#
- 需要團隊成員之間的信任
- 如果團隊功能失調,code reading 會暴露這一點——但這本身也是有價值的資訊
- 「最初感覺不自然,但一旦進入節奏,就會感覺非常自然」
程式碼可讀性與風格#
可讀性是第一優先#
- 「可讀性現在是我的第一優先。比快更重要,幾乎和正確一樣重要。」
- 「如果程式碼不可讀,我就無法判斷它是否正確——那麼它可能不是好程式碼」
- 不可讀的程式碼即使效率很高或很精巧,也不是好的程式碼
具體的可讀性建議#
- 一致的排版:正確的縮排、空白、標點——就像英文寫作中的語法
- 有意義的變數名稱:承認自己有 Fortran 時代留下的壞習慣(單字母變數名),正在努力改正
- 避免 ++(自增運算子):鼓勵把太多東西塞進一行,容易導致 buffer overrun 等安全問題
- 避免 continue:從未見過一段用了 continue 而無法透過重構移除的程式碼
- 避免 one-liners:停止寫一行搞定的程式碼後,程式品質立刻提升
- K&R brace style:在 JavaScript 中這不只是風格問題——由於 semicolon insertion,把花括號放在右邊可能導致語義完全改變
Subset 的概念#
- 語言中有好的部分和壞的部分——只使用好的部分
- 「C 語言中有一堆錯誤。switch statement 的 fall-through 是錯的。++ 有巨大的安全問題。」
- 即使在 JavaScript 中也不需要所有功能——禁止使用危險功能後,語言反而更好
閱讀他人程式碼的方法#
清理法#
- 先丟進文字編輯器,從整理格式開始
- 修正標點、縮排、空白——雖然有工具可以自動做,但手動做可以更快地熟悉程式碼
- 這個方法學自 Chip Morningstar——「他很擅長重構別人的程式碼,這是他的做法」
判斷程式碼品質#
- 「我從未見過格式混亂但本質是好程式碼的情況。好程式碼很難用混亂的方式寫出來。」
- 如果清理完格式後仍然無法理解,那程式碼本身可能有問題
程式碼組織偏好#
- 不想要 forward references(前向引用)——所有東西都應該在使用前宣告
- 喜歡 literate programming 的概念——程式碼應該為閱讀而設計
- 讀過 Knuth 的 TeX: The Program——「我像讀小說一樣閱讀它」
軟體設計方法#
設計哲學#
- 「不是寫一個程式然後就結束了——是讓程式能夠存活多次迭代」
- 軟體必須被改變,而改變往往會破壞東西
- 關鍵問題:如何不把自己逼入死角?如何保留足夠的彈性?
JavaScript 的重構優勢#
- JavaScript 中的重構非常容易——因為 soft objects(物件就是你說它是什麼)
- 不需要深層 class hierarchy,可以直接調整物件
- 相比之下,重構深層的 class hierarchy「非常痛苦」
Prototypal vs Classical#
- 在 prototypal(原型式)的世界中,分類錯誤較不嚴重——找到一個典型實例就行了
- 在 classical(類別式)的系統中,你必須從抽象回推到實例,建立層級結構,而且分類錯誤的代價很高
- JSLint 已經轉變了很多次——「如果我用 Java 寫 JSLint,這種靈活性是不可能的」
設計方式#
- 以前使用 design language 或 semi-English 的 meta-language
- 現在如果用 JavaScript,設計語言就是 JavaScript 本身
- 偏好同時思考所有部分——divide and conquer,但先在腦中掌握整體結構
- 「一旦你搞清楚結構是什麼,剩下的就自然落定了」
工具#
- 使用一個簡單的免費文字編輯器——不需要花俏的功能
- 瀏覽器本身就是編譯器和 runtime
- JSLint 是不可或缺的工具——「今天我不會在沒有 JSLint 的情況下做任何複雜的 JavaScript 專案」
- 除錯工具:Firefox 用 Firebug,IE 用 Visual Studio debugger
除錯方法#
除錯風格#
- 主要使用瀏覽器內建的 debugger
- 只在追蹤特定 bug 時才做 stepping——不用它來做一般性的程式碼檢查
- 不太使用 assertions——雖然喜歡 Eiffel 的 precondition/postcondition 概念
- 測試方面比較 ad hoc,承認這是他需要改進的地方
最困難的 Bug#
- 在 Basic Four 開發文字處理終端機時遇到的 real-time bug
- Z80 終端機,64K 記憶體,full-page 顯示,透過本地網路連接伺服器
- 螢幕偶爾會整個變空白——由DMA 處理器和程式同時存取記憶體的 race condition 造成
- 某天在家遠端工作時突然靈光一現,打電話告訴團隊如何修復
對 Threads 的看法#
- 「最糟的 bug 都是 real-time bug——必須處理多個 thread 的互動」
- 認為 threads 是「可怕的程式設計模型」——「偶爾必要的邪惡,但大多數情況下不需要」
- 很慶幸瀏覽器的 JavaScript 是單線程的
- 偏好事件驅動模型——Google Gears 的 worker process 模型是個好例子
對形式驗證的看法#
- 在 1970 年代密切關注過形式驗證,但看不到它能產出什麼成果
- 「軟體就是它自己的規格。任何比完整規格少的東西都無法真正告訴你軟體會如何運行。」
對測試的看法#
- 自認「比較 ad hoc」,正在考慮改變
- JavaScript 的 UI 測試特別困難——因為 UI 依賴於太多東西,拆成 unit 不太有效
- JavaScript 的函式不像 Java 的 class 那樣自然地分成可獨立測試的單元
- QA 和開發團隊之間不應該對立——最好的模式是 QA 幫助開發者改進程式,而不是「抓耙子」
- 最有效的測試方式:到客戶現場,幫他們安裝和使用系統——這給了他巨大的洞察力
對程式碼重寫的看法#
何時該重寫#
- 只有在程式碼已經 unworkable,且你能合理判斷重寫比修復更快時
- 必須極度自律:「不是 blank slate——是重新實作我們已經知道的東西」
Second-System Syndrome#
- 在 Electric Communities 親身經歷——最聰明的團隊、充足的資金、明確的方向,但結果太宏大而失敗
- 「程式設計困難的原因之一是我們大部分時間都在做以前沒做過的事。如果是做過的事,我們就會重用它。」
遺留知識的問題#
- Web 規格不完整且被廣泛誤解——很多「誤解」已經成為事實標準的一部分
- 這些系統中有大量未文件化的知識隱藏在程式碼中
- Microsoft 的作業系統也有同樣問題——必須保持向後相容性,讓下一個系統的設計受到嚴重限制
- 「跨瀏覽器的東西比它應該的難得多——因為 Web 的規格不夠好,而各家實作又千差萬別」
對教育與數學的看法#
是否每個人都應該學程式設計#
- 認為是的——「世界已經被電腦接管了,為了保護自己、成為一個完整的公民,你必須理解這些東西如何運作」
- 對讓程式設計更容易上手有興趣——Smalltalk 最初的方向(為兒童設計語言)很吸引他
數學的角色#
- 數學重要但不是唯一重要的東西
- 「如果你過度強調數學,你就會忽視其他可能更重要的東西——比如素養(literacy)」
- 更希望聘請英文主修而非數學主修的人——因為程式設計師花大量時間寫 email、文件、規格
- 引用 Dijkstra 的名言:「如果你不能用母語寫作,就放棄吧。」
自我定位#
- 「我認為自己是一個作家。有時候用英文寫,有時候用 JavaScript 寫。」
- 歸根結底都是溝通——人類語言和程式語言的運作方式不同,但好程式最終是要能被人類讀者理解的
Crockford 曾因為睡眠呼吸中止症而以為自己因年老而失去程式設計能力。治療後能力恢復,他也學到了不要過度依賴記憶——現在更注重文件化,對自己的程式碼更少自信(反而是好事)。「有時候我翻看自己的舊程式碼,不記得寫過它,結果它要麼非常糟糕要麼非常精彩。」
Literate Programming#
- 認為 Knuth 的 literate programming 是個極好的想法
- 核心概念:可以不按語言要求的順序,而是按展示順序來組織程式碼
- 允許把相關但分散在各處的程式碼收集在一起描述
- 解放了函式大小的限制——不必為了可讀性而把函式切得太碎
- 遺憾的是目前成功的 literate programming 範例不多——「也許這意味著 literate programming 失敗了」
- 希望看到從底層就設計為 literate 的新語言
推薦書籍#
- The Art of Computer Programming by Donald Knuth — 強烈推薦
- 除了最後一卷都讀了(從頭到尾,跳過太多星號的數學部分)
- 「在我看來,任何自稱專業程式設計師的人都應該讀過 Knuth 的書,或者至少擁有它們」
- 曾試圖把「讀過 Knuth」列為招聘標準,但找不到足夠多符合條件的人
- TeX: The Program — 像小說一樣閱讀
- 不是為了修改 TeX,而是為了看 Knuth 如何做事
- 「他寫得很好,偶爾還會在裡面藏小笑話」
- JavaScript: The Good Parts — 自己的著作,主張 subsetting 的理念
關於軟體工程的現況#
Web 的困境#
- 「Web 建立在一個又一個的錯誤之上。我們有這一大堆意外事故。」
- 瀏覽器的安全模型不支援互不信任的元件合作
- Mash-ups 雖然實現了二十年來軟體工程的理想(可組合元件),但安全模型完全跟不上
- 規格錯誤一旦進入標準就幾乎不可能移除
樂觀主義的代價#
- 程式設計師天生是樂觀主義者——這是優點也是缺點
- 正因為樂觀,才會掉入 second-system syndrome、無法準確估計時程
- 「如果我們不是樂觀主義者,我們根本做不了這份工作」
經典語錄#
“Readability of code is now my first priority. It’s more important than being fast, almost as important as being correct.”
“I think an hour of code reading is worth two weeks of QA.”
“The best way to make JavaScript better would be to make it smaller.”
“I think of myself as a writer. Sometimes I write in English and sometimes I write in JavaScript.”
“In my experience, the worst bugs are the real-time bugs, which have to do with interactions with multiple threads. My approach to those bugs is to avoid making them. I don’t like threads.”
“Programmers are optimistic. And we have to be because if we weren’t optimists we couldn’t do this work. Which is why we fall prey to things like second systems.”
“I would actually rather see people start as English majors than as math majors to get into programming.”