當 DHH 在 Rails World 2026 登台 並公開談論對手寫程式碼「放下鉛筆」——以及他和 37signals 現在到底部署了多少 Rust——時,網路上可預期的一部分人把這當成了認輸致詞。
就連 Ruby on Rails 的創作者,也在同一句話裡打趣說讀 Rust 就像「把酸倒進我眼睛裡」,卻同時又盛讚在 AI 代理處理借用檢查器之後,速度能提升 30 倍到 100 倍、二進位檔極小、啟動時間低於毫秒。若 他 都開始擁抱 Rust,那這對 Ruby 和 Rails 代表什麼?
我認為,這種反應把整個故事完全看反了。
在過去一個月裡,我們在 Forem(支撐 DEV 的 Rails 單體應用)上,持續把數十個內部 Ruby 模組替換成 Rust。就像我在 Our Looping Factory Cut DEV Page Load Time by 75% and Counting 裡寫到的,我們持續執行於程式碼庫上的自主工作流程之一,是一個專門的 rust-loop,它透過 magnus 與 rb-sys,把 CPU 密集、配置大量記憶體的 Ruby 熱路徑轉換成進程內的 Rust 擴充套件(gems/forem_native)。
這件事不但沒有讓我質疑 Rails,反而讓我前所未有地欣賞 Rails。能夠這麼容易地把 Rust 放進 Rails 程式碼庫,這是優點,不是缺點。
動態網頁框架過去有一道不成文的斷崖:Ruby 讓你以無與倫比的開發者幸福感快速達到產品市場契合;接著,當你的字串解析、動態訊息排序或序列化路徑開始壓垮垃圾回收器時,就會有人提議拆出一個 Go 或 Rust 微服務。於是,原本一個連貫的應用程式,突然變成兩套部署、一個網路跳轉、重複的驗證假設,以及你從此必須永遠承擔的維運成本。
如今,這道斷崖大致上已經消失了——無論是使用體驗上,還是架構上。
在 Forem 內部,我們把 gems/forem_native 拆成一個純 Rust 的 forem_core crate(完全沒有 Ruby 相依性),以及一個每個函式大約 15 行的 magnus 包裝層,直接借用 Ruby 字串緩衝區,不做序列化,也不複製記憶體。我在 Ask More of Your UI 裡描述的控制面板中,與另外八個維護迴圈一起監控的 rust-loop,已經穩定地把高耗能的葉節點與管線模組遷移到 Rust:
pgvector SQL 表達式組裝(速度快約 20 倍,Ruby 物件配置減少 97%)。@username 提及解析、URL 正規化、Public Suffix 子網域路由、常數時間的 CSRF/JWT 驗證,以及代理轉錄內容上的 51 種模式秘密資訊遮罩。gemoji、emoji_regex、wcag_color_contrast)直接從我們的 Gemfile 中刪除。然而,任何複製 Forem 的人,都不需要安裝 cargo 就能執行 bin/dev。體積極小(約 300 KB)的預編譯平台二進位檔在 macOS 與 Linux 上都能在不到一毫秒內載入,我們的 Containerfile 會在多階段建置流程中編譯出一個剝除符號的共享函式庫,且正式環境映像檔裡完全不殘留 Rust 工具鏈;同時,每個已移植的函式都會透過 RSpec 差分規格測試,針對 1,000+ 個隨機輸入與舊版 Ruby 參考實作做比對,確保一致性。
在 Design for Churn 裡,我主張 AI 時代的程式碼庫,越來越不像靜態建築,而更像花園:當重寫實作程式碼變得便宜時,你真正的投資會轉向那些多年生花圃——也就是 schema、路由、邊界與契約;它們保持穩定,而裡面的年度植物則不斷更替。(這也是我們在 將 Jev 這類 System One 模型帶入 AI 技術棧 時採用的同樣原則:在 Ruby 中保持策略與領域結構清晰,然後在底層替換成專用引擎。)
Rails 就是 那片多年生花圃。正如 @techie_raj 在 Your Rails App Is Already AI-Ready. You Just Don't Know It. 裡說得很好,二十年累積的共同慣例——config/routes.rb、app/services/、宣告式 Active Record scope、可自我描述的背景工作——讓 Rails 擁有一種讓新進員工與程式碼代理都能輕鬆閱讀的可理解性。也如 @ttebify 在 Rust is amazing, as long as I’m not the one writing it 中指出的,嚴格的編譯器能為代理提供一個緊密而不寬容的回饋迴圈,特別適合低階運算。把 Rails 的高層一致性與 Rust 的裸機層能力結合起來,並不是拋棄 Rails——而是讓 Rails 做它一直最擅長的事:把整個系統清楚地編排起來,並在需要原生速度時退到一旁。
如果你想看一個具體例子,了解為什麼 Rails 會在長期發展中持續勝出,那就看看這個即將在 Rails 8.2 登場的精彩新增功能吧(也已透過 rails-query-command 回補到 Rails 7.2、8.0 與 8.1):
https://x.com/jchibbard/status/2120569126150127666
每個把 AI 程式代理真正投入實務的團隊,最後都會撞上同一面牆:代理把靜態原始碼檔案分開閱讀時,對生產環境瓶頸的猜測常常是錯的;而且你顯然也不可能把一個無限制的 rails console 或 rails runner 直接交給自治代理去操作正式資料。(我最近在 AI Engineering Has Entered Its Audit Era 裡寫過,如何界定代理權限與驗證輸出已經成為真正的工程工作;@oleksandr_sainchuk 也在寫入側的 How we keep AI agent actions under server side control in rails 探討了同樣主題。)
在 Forem,我們要把延遲從 70ms 降到 16ms,所需的關鍵之一,就是自己打造了一個專屬變通方案:一個唯讀的 Postgres 閘道(forem-db-query),再加上隱私防護層,讓我們的效能迴圈能在接觸程式碼之前,安全地檢視即時查詢計畫、順序掃描與資料列分佈。還有不少其他團隊也默默拼湊出了自己的唯讀包裝器、MCP 工具,或自訂 rake 任務,來解決同樣的問題。
即使我們和其他人早就已經有這類變通方案,Rails 的重點就在於:它會把那些直覺上必要的事,做成一等公民,而且這種做法長期來看會帶來回報。
當 bin/rails query 成為整個生態系統的標準動詞——契約上是唯讀的、輸出結構化 JSON,並內建 schema、models 與 explain——二十個量身打造的團隊腳本就會收斂成一套共享慣例。每位開發者、每份維運手冊、每個程式碼代理,都能立刻知道如何向 Rails 應用程式安全地詢問資料相關問題。
當框架把邊界當成純潔性測試時,它們就會衰退——堅持所有問題都必須用同一種語言解決,或忽視今日軟體實際上的建構方式。
Rails 能夠長期存在,而且持續領先,原因從來不只是 Ruby 語法。它的核心能力是品味與整合:看見開發者真正需要交付的那些混亂、務實的事物——從 migrations、背景工作、零停機的 Kamal 部署,到無痛的原生 Rust 擴充套件與對代理友善的資料庫內省——然後把它們整合成一些回頭看會覺得理所當然的預設值。
我們會持續在能讓 DEV 更快的地方,把高耗能運算迴圈替換成 Rust。而且我們也會繼續很愉快地在一個 Rails 單體應用中做這件事,讓它持續迎上時代。
Rails 萬歲,快樂寫程式 ❤️