Jamie Zawinski#

Lisp hacker、早期 Netscape 開發者、夜店老闆,人稱 jwz,是少數以三個字母縮寫聞名於世的程式設計師之一。

Zawinski 十幾歲時就在 Carnegie Mellon 的 AI 實驗室工作,之後在 Lisp 和 AI 世界待了近十年。他曾在 UC Berkeley 為 Peter Norvig 工作,後來加入 Lucid 公司主導開發 Lucid Emacs(後來更名為 XEmacs),最終在 1994 年加入 Netscape,成為 Unix 版瀏覽器和郵件閱讀器的核心開發者。1998 年他與 Brendan Eich 一起推動了 mozilla.org 的成立,但一年後因進度不佳而離開,買下了舊金山的 DNA Lounge 夜店。


學習程式設計的歷程#

啟蒙階段#

  • 大約在八年級時,第一次真正接觸電腦,使用 TRS-80 玩 BASIC
  • 從雜誌上打字輸入程式,因為當時沒有儲存程式的方法
  • 閱讀了大量關於程式語言的書籍,包括 APL,儘管手邊沒有電腦可以執行
  • 高中時學了 Fortran

進入 Lisp 世界#

  • 因為閱讀科幻小說,對 AI(人工智慧) 產生興趣,認為電腦終將接管世界
  • 高中朋友 Dan Zigmond 去了 Carnegie Mellon 的 Apple Users Group 聚會
  • 一位大學生建議他們去找 Scott Fahlman 教授求職
  • Fahlman 雇用了這兩個高中生,在 AI 實驗室做基礎的 grunt work(例如重新編譯程式碼)
  • 大約在 1984-85 年開始,放學後每天去實驗室工作到晚上八、九點

被丟入深水區#

  • 在實驗室中使用 PERQ 工作站Spice Lisp(後來成為 CMU Common Lisp)
  • 參加每週會議,透過旁聽學習軟體開發的運作方式
  • 經理 Skef Wholey 會站在他身後看他打字,偶爾說一聲「Ptthh, wrong!」就走開
  • Zawinski 形容這像是「禪宗式的教學法——師父用棍子打你,然後你去冥想」

Fahlman 評價 Zawinski 才華洋溢、學習速度極快,但有些缺乏紀律。Zawinski 承認撰寫可讀性高的程式碼是最重要的教訓之一,但當時年僅 15 歲的他對這些並不十分在意。


職業生涯#

Expert Technologies (ETI)#

  • 高中畢業後,Fahlman 推薦他去 ETI 工作(一間做黃頁自動排版的專家系統公司)
  • 使用 LispTI Explorer Lisp machines
  • 短暫嘗試進入 CMU 就讀大學,但只待了六到九週就輟學
  • 對大學教育極度失望:「高中時大家說上大學就好了,結果到了大學又說念研究所就好了——根本一樣爛」
  • 在 ETI 工作了約四年,直到公司倒閉

UC Berkeley — 為 Peter Norvig 工作#

  • ETI 結束後,在新聞群組上發布求職訊息,Peter Norvig 看到後安排了面試
  • 工作內容是將研究生留下的自然語言理解程式碼整合成一個可運作的系統
  • 工作非常困難,因為缺乏相關背景知識,經常完全卡住
  • Norvig 非常友善且耐心,會說「我週二坐下來跟你解釋」
  • 六到八個月後覺得自己在浪費時間,離開轉往 Lucid

Lucid — Emacs 與 Lisp 開發#

  • Lucid 是當時僅存的兩家 Lisp 環境開發商之一
  • 最初的專案之一是在一台 16 處理器的平行電腦上工作,開發 Lucid Common Lisp 的平行化變體
  • 負責在新架構上啟動 Lisp——解讀二進位檔案格式、用 Emacs 逐 byte 檢查執行檔
  • 公司從 Lisp 轉向 C++ IDE(即 Energize 開發環境)
  • 重寫了 Emacs byte compiler——這是他與 Stallman 的第一次衝突
    • Stallman 最初回應「I see no need for this change」
    • 後來要求逐行解釋 diff
    • 兩年後因為大量使用者的壓力才被納入 GNU Emacs

Zawinski 在 Lucid 的經歷讓他成為更好的程式設計師。他表示那裡是他遇過最聰明的人才聚集地:「當有人說『我們應該這樣做』,你可以直接相信他們知道自己在說什麼。」

Netscape — 瀏覽器與郵件閱讀器#

  • Lucid 倒閉後,寄信給認識的人說自己在找工作
  • Marc Andreessen 回信說:「你應該知道,我們剛剛上週成立了一間公司。」
  • 幾乎是立刻開始做 Unix 版瀏覽器的開發工作
  • 團隊非常小——整個客戶端團隊只有約六到七人
  • Netscape 的程式碼是全新撰寫的,沒有重用 NCSA/Mosaic 的程式碼

開發文化#

  • 極度專注於截止日期:「六個月內出貨,否則就等死」
  • 直接且不客氣的溝通方式:有人會走到你隔間說「你 check in 的東西是什麼垃圾」
  • 每個人最多負責兩個專案區域,不超過兩人同時工作在同一部分
  • 工作時數極長(每週 80+ 小時),但他承認「這絕對不健康」

最驕傲的成就#

  • 不是任何特定的程式碼,而是成功出貨這件事本身
  • 推出 0.96 beta 版的那個晚上,團隊在辦公室裡聽著下載的聲音觸發器
  • 一個月後有兩百萬人在使用他寫的軟體

Netscape Mail Reader#

  • 在 2.0 版時,Marc Andreessen 說「我們需要一個郵件閱讀器」
  • Terry Weissman 搭檔開發,默契極佳
  • 與瀏覽器團隊截然不同的工作氛圍——從不互相大吼,自然地分配工作
  • 以遠端方式合作:「我不進辦公室,你也不用進辦公室」

Netscape 的衰落#

  • Collabra 被收購後,管理層被替換,原本成功的團隊被邊緣化
  • 4.0 版使用了 C++ 重寫,引入了大量相容性問題和程式碼膨脹
  • Zawinski 認為 4.0 的重寫是「有史以來最大的軟體災難之一」,基本上摧毀了這間公司
  • 曾嘗試用 Java 重寫郵件閱讀器(代號 Grendel),效果很好但最終因為 HTML 顯示層未完成而被取消

Zawinski 對 second-system syndrome(第二系統症候群) 有深刻體會:Netscape 1.0 的成功團隊避免了這個陷阱,是因為極度專注於截止日期;但 4.0 的新團隊完全忽視了前人的經驗教訓,最終導致災難性的後果。


對程式語言的看法#

C 與 C++#

  • Lisp 之後認真使用的第一個語言是 C——「就像從 Apple II 組合語言倒退回去」
  • C++ 極度厭惡:「一切都是錯的,各方面都是」
    • C++ 程式一旦使用函式庫就會急劇膨脹
    • 編譯器之間不相容
    • 沒有人能同意哪百分之十的語言特性是安全的
  • 在 Netscape 盡可能使用 ANSI C 而非 C++

Java#

  • Java 讓他感覺像是「回到 Lisp 的一點味道」
  • 記憶體管理、函式的模組化程度、強制的結構化——這些概念讓他感到舒適
  • 在 Netscape 用 Java 重寫郵件閱讀器的經驗相當愉快

Perl#

  • 目前主要使用 Perl 寫小型伺服器腳本和工具
  • 認為 Perl 是「可鄙的語言」,但它無處不在,不需要說服別人安裝
  • 語法瘋狂,資料結構混亂,但至少比 C 更適合做文字處理

Objective-C#

  • 移植 XScreenSaver 到 OS X 時使用了 Objective-C
  • 評價相當正面:「感覺像 Java 的好處,但也像 C」
  • 可以直接與 C 程式碼連結,不需要彎腰遷就

關於「scripting」vs「programming」的區分#

  • Zawinski 認為這種區分是「胡說八道」
  • 如果工作是操作文字、啟動程式、做 pattern matching,Perl 比 Emacs Lisp 更適合

除錯方法與工具#

偏好的除錯方式#

  • 在 Lisp 時代:使用互動式檢查器(inspector),停下程式後瀏覽資料結構
  • 轉到 C 後:嘗試在 Emacs 中使用 GDB,但逐漸放棄,改用 print statements
  • 「隨著時間過去,我越來越少使用那些工具,就只是加 print statement 然後重複執行」

對 GDB 的不滿#

  • GDB 在 Lisp 系統上完全無法運作——不認識 Lisp 編譯器產生的除錯資訊
  • 在 C 語言中,GDB 中的陣列只是一堆數字,需要自己轉型才能看到實際內容
  • stack 資訊經常不可靠——「我永遠覺得不能真正信任除錯器告訴我的東西」

最困難的 Bug#

  • 在 Lucid 時期,嘗試在新架構上啟動 Lisp,執行 500 條指令後就當掉
  • 每次當掉的位置都不同,毫無規律
  • 最終發現是推測執行(speculative execution) 的早期機器——分支指令的兩側都會被執行
  • GDB 單步執行時總是走分支的同一側,造成誤導
  • 為了繞過這個問題,他修改了 GDB 的單步指令邏輯,在分支前設斷點
  • 花了大約一週時間才確認問題並解決

Zawinski 對除錯的基本哲學是:「越早意識到你的地圖是錯的,就越快能找出哪裡出了問題。」他強調不僅文件可能是錯的,連除錯工具本身也可能有 bug。

對 Assertions 的看法#

  • 在 Netscape 大量使用 assert statements——主要用於除錯和表達程式意圖
  • 但生產環境中 assertion 失敗時的處理方式是:回傳零值並繼續執行
  • 「讓瀏覽器掛掉比回到 idle loop 並洩漏一些記憶體更糟糕」

對測試的看法#

  • 在 Netscape 早期,開發者幾乎不寫 unit tests
  • 有一個獨立的 QA 團隊做正式測試
  • 郵件日期解析器是少數有大量測試案例的部分——收集了大量真實世界的奇怪日期格式
  • 認為在當時的高壓環境下,更多測試只會拖慢速度:「如果客戶不去 unit test,那就不是最關鍵的事」

程式設計方法與風格#

設計流程#

  • 偏好儘早讓東西跑起來——先在螢幕上看到東西,再決定下一步
  • 不做太多預先設計:「你永遠不知道設計是什麼,直到程式寫完」
  • 通常把第一版全部放在一個檔案裡,然後看到結構後再拆分

關於重寫 vs 修復#

  • 重寫別人的程式碼很有趣,但「重點不是寫漂亮的程式碼——你是來出貨的」
  • 有時候重寫是必要的:當理解別人的程式碼比自己重寫還花時間的時候
  • 框架的陷阱:「如果你花三年建完美框架,你的競爭對手六個月就出了 1.0,你就出局了」

Zawinski 最著名的觀點之一:「Ship the fucking thing!」——在一天結束時,出貨才是重點。重寫程式碼讓它更乾淨很棒,但如果這不能幫助你出貨,那就是在浪費時間。

程式碼可讀性#

  • 註解很重要——應該描述假設條件、資料結構佈局、函式用途
  • 討厭那種「函式叫 push_stack,註解寫『推到 stack 上,謝謝』」的無用註解
  • 偏好長變數名稱,使用實際英文單字描述(反對 Hungarian notation)
  • 在 C 語言中,為每個 .c 檔案維護一個 .h 檔案,未匯出的都宣告為 static

程式碼組織#

  • 通常將 leaf nodes(底層函式)放在檔案最上方,API 入口點放在最上面
  • 有時從頂層開始寫,有時從底層開始——兩種方式都用
  • 第二或第三次複製貼上同樣的程式碼時,就是該抽成函式的時候

閱讀程式碼的方法#

  • 直接跳進程式碼開始讀
  • 如果有文件,先找出自己感興趣的 API 部分
  • 有時從 build system 開始——瞭解程式碼如何組合在一起
  • 最好的方式是選一個任務然後嘗試完成它——透過實際動手來理解系統
  • 對於 Emacs 這類系統:拿一個現有模組,把內容剝除只留框架,然後開始放入自己的東西

對軟體工程的觀點#

團隊組織#

  • 理想的日常協作團隊不超過三到四人
  • 大專案可以切分為多個獨立模組,每個由一個小團隊負責
  • 模組間的介面必須「清晰且簡單——讓出錯的方式越少越好」
  • 同時支援個人程式碼所有權和集體所有權各有優缺點

識別人才#

  • 承認自己很難透過面試判斷一個人是否優秀
  • 能辯論自己觀點的能力很重要(至少在 Netscape 的團隊文化中是如此)
  • C++ templates 的愛好者可能是一個警訊(雖然承認這可能是偏見)

導師的角色#

  • 好的導師會在適當時機給予更有挑戰性的任務
  • 不怕承認自己的無知非常重要:「不知道某件事不代表你笨——只是你還不知道而已」
  • 閱讀大量程式碼和提出問題是學習的關鍵

對電腦科學教育的看法#

  • 自認不是科學家或工程師——「我不做很多數學、不畫藍圖、不做證明」
  • 將自己定位在工匠與藝術家之間
  • 程式設計的學習目標是讓機器做事,電腦科學是達成目標的手段
  • 在 Lucid 時期偶爾會覺得有知識黑洞——同事在討論的理論概念自己完全沒接觸過
  • 但也認為許多理論性的電腦科學家並不擅長實際寫程式

數學與程式設計#

  • 自認「不是數學人」——高中只學了代數和微積分,數學不是強項
  • 認為 pattern matching 和對數量級的直覺是重要的,但不需要正式的數學訓練
  • 程式設計更像寫散文而非數學——是向一個詞彙有限的笨對象表達概念

推薦書籍與學習資源#

  • Structure and Interpretation of Computer Programs (SICP) — 唯一推薦的書
    • 「用 Lisp 教程式設計但不教語言的好書」
    • 批評大多數入門課程只是在教語法(分號放哪裡),這會嚇跑人
  • Design Patterns — 持負面看法
    • 「那是程式設計的複製貼上——翻食譜找到差不多的就照抄,那不是程式設計,是著色本」
  • 沒有讀過 Knuth 的 The Art of Computer Programming,承認應該讀但自己不是數學人

對程式設計未來的看法#

  • 程式設計的門檻已經改變——以前需要學組合語言理解機器運作,現在可能不再必要
  • 新一代的程式設計師可能是從建網站或寫 Facebook 插件開始的
  • 現代裝置沒有「可拆解的零件」——手機、平板不像以前的收音機可以拆開看齒輪如何咬合
  • 曾經很重要的底層知識(如 XOR 指標技巧)已經不再重要
  • 理解他人程式碼的能力變得更加重要——因為現代軟體都依賴大量框架和函式庫
  • 好奇心是程式設計師最重要的特質:「想知道底層到底發生了什麼事——我認為這才是真正的基礎」

Zawinski 認為程式設計師最關鍵的技能是好奇心——想要拆解東西、理解底層運作。他說這是獲取知識的主要方式,沒有這個特質很難走得遠。


經典語錄#

“At the end of the day, ship the fucking thing! It’s great to rewrite your code and make it cleaner and by the third time it’ll actually be pretty. But that’s not the point – you’re not here to write code; you’re here to ship products.”

“The sooner you realize that your map is wrong, the sooner you’ll be able to figure out where it went wrong.”

“Not knowing something doesn’t mean you’re dumb – it just means you don’t know it yet.”

“Worse is better… if you spend the time to build the perfect framework, release 1.0 is going to take you three years and your competitor is going to ship their 1.0 in six months.”

“I’ve always seen much more in common with writing prose than math. It feels like you’re writing a story and you’re trying to express a concept to a very dumb person – the computer – who has a limited vocabulary.”