Piotr Sarnacki 分析了 Ruby on Rails 創建者 DHH 使用 AI 代理將聊天應用程式 Campfire Once 從 Ruby on Rails 重寫為 Rust、Elixir 和 Go 的結果。由於 DHH 本人不願閱讀或撰寫 Rust 代碼,他讓 AI 代理執行重寫工作。Sarnacki 指出,這些重寫結果並不樂觀,顯示若期望停止閱讀代碼或停止思考,目前尚為時過早。文章強調,若提示詞不夠具體,許多設計決策(如向後兼容性、延遲與吞吐量優先級、記憶體限制、崩潰後通知丟失的可接受性)將由 LLM 隱式決定,導致不同語言版本在約束條件上存在差異。例如,Rust 版本為了簡化快取而移除了 CSRF token,並用進程內佇列取代 Redis;而 Elixir 版本則更接近原始 Rails 實現。這種語言無關的差異使得直接比較變得無意義。

在代碼質量方面,Sarnacki 指出 Elixir 版本存在單進程順序處理所有 SQL 查詢的問題,即使這些讀取操作本可並行執行。DHH 認為這並非 Elixir 的最佳形象,但 Sarnacki 反駁稱 Rust 版本也存在問題:部分數據庫操作未使用非同步(async)方式,這在 Rust 的協作式非同步調度模型下可能導致更嚴重的阻塞,因為任務若未主動讓出執行權,同一工作執行緒上的其他任務將無法運行。同樣,Rust 版本混用了非同步鎖與同步鎖,若長時間持有同步鎖,將導致該執行緒上的所有任務等待。

基準測試方面,原有的吞吐量測試被批評為「垃圾」(slop),因為它們忽略了系統的其他特性。Zach Daniels 的測試顯示,在高負載下,Rust 版本的新訊息通知送達率僅為 1%。然而,Sarnacki 指出這些測試多為閉環測試(closed-loop),即客戶端等待響應後才發送下一個請求,這與真實場景中大量用戶同時發送請求的恆定到達率(constant arrival rate)不同。當改用恆定到達率測試時,結果更為複雜:在 100 POSTs/s 的負載下,Rust 版本的客戶端僅收到約 14% 的事件,而 Elixir 版本約為 60%。但 Rust 版本沒有 HTTP 錯誤,而 Elixir 版本約 23% 的 HTTP POST 請求超時,且最差的事件送達延遲接近 180 秒。Sarnacki 認為,Rust 版本讓滯後的客戶端斷線並重新連接以獲取最新消息,可能比讓用戶等待 3 分鐘的更新具有更好的用戶體驗。

技術細節上,Rust 版本使用容量為 256 的 `tokio::sync::broadcast` 通道,當接收者處理速度不足時會產生 `RecvError::Lagged` 錯誤。將容量改為 16384 後,送達率提升至約 90%,但最差延遲從 11 秒升至超過 130 秒,這被認為比斷線重連更糟。相比之下,Elixir 使用無限制的 GenServer 信箱,雖然處理了背壓,但在 100 req/s 測試中記憶體使用量達到 1.8GB,面臨 OOM(記憶體溢出)風險。Sarnacki 總結道,沒有哪種語言能自動解決所有並發問題,開發者必須理解故障模式與權衡取捨,不能僅憑單一指標做出判斷。

事件背景

Campfire Once 是一款最初使用 Ruby on Rails 構建的群組聊天應用程式。Rails 的創建者 DHH 使用 AI 代理將其重寫為 Rust 和 Elixir,且未手動審查代碼。該分析比較了不同語言運行時在處理並發和背壓方面的差異:Rust 使用協作式非同步調度,任務需主動讓出執行權;Elixir 基於 BEAM 虛擬機,使用搶佔式 Actor 模型,擅長並發但缺乏底層控制且記憶體使用較高。

社群觀察

評論者 variety8675 指出,AI 生成的「工作垃圾」(workslop)難以反駁,因為產生它無需努力,但反駁它需要巨大努力。stephbook 質疑在多代碼庫移植後,新功能應在哪個代碼庫中實現,以及維護的負擔。as1mov 擔憂未來「你必須思考」會被視為爭議性觀點。discreteevent 指出,此案例是 LLM 的理想用例,因為 90% 的思考已由現有系統的開發者完成。Ozzie_osman 強調,開發者需足夠理解系統以做出明智決策,目前仍建議閱讀或瀏覽代碼,而非完全依賴 AI。