Lisp 的優勢:來自 Viaweb 早期的啟示

在 2001 年 4 月於 BBN Labs 的一次演講中,Paul Graham 詳細介紹了 Shopify 前身 Viaweb 的技術基礎。當時,業界由 C 和 C++ 主導,但 Graham 選擇了 Lisp。這個決定不僅僅是個人偏好;這是一個戰略性的技術選擇,讓一個小團隊能夠透過卓越的開發速度和架構靈活性,超越規模更大的競爭對手。

伺服器端的自由

使用 Lisp 的主要驅動力之一是從桌面端到網頁應用程式的轉向。在桌面時代,開發者很大程度上受限於作業系統的語言。然而,在伺服器端軟體中,開發者可以控制環境。

Graham 主張,這種自由是競爭的必要條件。在一個迭代速度至關重要的市場中,僅僅因為是業界標準而堅持使用標準(如 C++)可能是一種負擔。一個使用更具表達力、更強大語言的小型初創公司,可以透過更快地交付功能且錯誤更少,來「吃掉」大公司的午餐。

增量開發的力量

Lisp 實現了一種特定的軟體創建哲學:增量開發。Lisp 程式設計師通常不會花好幾週時間編寫一份詳盡的設計文件然後再進行實作,而是從一個幾乎不執行任何操作的程式開始,並在保持程式碼在每一步都可運行的同時,逐漸增加功能。

Graham 將 Viaweb 編輯器的成長描述為一個典型的例子:它從一個 120 行的範例程式成長為一個 25,000 行的系統,而沒有進行過一次完整的重寫。這種方法完美契合了網頁的「滾動發佈」特性,即軟體是持續更新的,而不是以盒裝產品的形式發佈。

快速除錯與互動式頂層環境

互動式頂層環境(REPL)在解決錯誤方面提供了巨大的優勢。因為使用者的數據存儲在公司的伺服器上,Graham 可以透過將程式碼載入解釋器並登入使用者的帳戶,來即時重現錯誤。

這帶來了極其快速的周轉時間:當使用者還在與客服人員通話時,錯誤可能就已經被修復並部署了。正如 Graham 所提到的,這通常帶有一點「狡黠」的魅力,客服人員只需告訴使用者刷新頁面,錯誤就會消失。

架構上的勝利:Macros 與 Rtml

Lisp 的宏系統(macro system)讓 Viaweb 能夠構建一個稱為 Rtml 的領域特定語言(DSL)。這種嵌入式語言服務了幾個關鍵目的:

  1. HTML 生成:由於 HTML 是遞迴的且使用前綴表示法,它能自然地映射到 Lisp macros,使得複雜的頁面生成變得易於管理。
  2. 「升級路徑」:Rtml 允許進階使用者撰寫自己的模板。雖然大多數使用者都使用預設值,但 Rtml 為進階使用者提供了「逃生閥」,並向開發者發出信號,告知哪些功能需要添加到標準模板中。
  3. 分層抽象:透過將頁面生成邏輯(Rtml)與底層系統程式碼分離,團隊可以對 UI 進行高層級的變更,而不會冒險於核心引擎的穩定性。

關鍵字參數的教訓

Graham 強調了一個節省了大量精力的技術細節:大量使用 keyword parameters。透過將 Rtml 運算符設計為接受關鍵字參數,他們可以在不破壞現有模板的情況下,為運算符增加新功能。這提供了一種在更僵化的語言中罕見的前向相容性。

使用閉包模擬狀態

早期網頁開發中最困難的問題之一是 HTTP 的無狀態性。Viaweb 解決了這個問題,透過使用詞法閉包(lexical closures)來模擬子程序般的行為。

軟體不再思考「我接下來該呼叫哪個 CGI script」,而是思考「我接下來該執行哪段程式碼」。透過將閉包存儲在一個全域雜湊表(global hash table)中,並將其與 URL 中的唯一 ID 關聯,系統可以跨請求維持上下文(context)。

這使得複雜的 UI 流程成為可能——例如一個顏色選擇器,它能將使用者「返回」到先前所在的物件編輯器狀態——這讓應用程式感覺比當時基於靜態表單的競爭對手先進得多。

現代視角

雖然原始演講的日期可以追溯到 2001 年,但 Lisp 驅動開發的原則仍然具有意義。現代開發者繼續在 Lisp 的互動性以及其創建強大 DSLs 的能力中發現價值。正如社群討論中所提到的,像 HTMX 和 Datastar 等工具現在正與 Lisp 契合得非常自然,證明了動態、互動式語言與靈活的前端結合,仍然可以產生極高效率的開發週期。

正如一位貢獻者所說,只要利用了像 Lisp 或 Scheme 等語言的架構力量,一小組程式設計師帶著正確的工具,通常可以勝過規模龐大的團隊,無論投入了多少資源。

Sources