一個月前,DEV 上一般的網頁請求在 Rails 內大約要花 70 毫秒,而 P99 回應時間在很長一段時間裡經常超過 1 秒。到了今天,在 Better Stack 中每天大約抽樣 30 萬個請求來看,這個數字已降到 16 毫秒。

每個請求的資料庫時間從 39 毫秒降到 12 毫秒以下。畫面渲染從 12 毫秒降到 2.6 毫秒。Redis 時間則從 7 毫秒降到 1.3 毫秒。在過去 30 天裡,我們向 Forem 合併了 475 個 Pull Request。這類工作對擴充性與使用者體驗至關重要,但面對其他同樣需要推進的進度時,總是很難排進優先順序。

DEV performance data

這些改善對使用者體驗的提升非常巨大。不再有間歇性的變慢,也不再在流量高峰時難以應付。這解決了長達十年的痛點。

我們之所以能優先處理這些效能改善,是因為設計出了一個回饋迴路,並且在這個專案上退開日常執行層。

我們是透過建立一座軟體工廠,並退出迴路,才做到這件事。

在代理式開發的第一階段,幾乎每個人都會踩到一個陷阱。你不再親自敲語法,這感覺像是提升了效率,卻很快發現自己其實只是升級成了「人類中介層」。你變成儀表板和終端機之間的剪貼板:一下午都在微調提示詞、盯著 CI 不穩定問題、替 diff 蓋章。你不是在手寫程式,但你也沒有在做深度工程。你成了一個有脈搏的 API 端點。

要跳出那個陷阱,花了好幾週在 OpenHands 與 Agent Client Protocol(ACP)之上建立並重新配置自主迴路。目標不只是讓 DEV 變快,而是把系統性的維護工作,和那些值得由人類品味來決定的創意型、客製化專案分開。

照料多年生植物

在 Design for Churn 一文中,我主張程式碼庫開始看起來不再像建築物,而更像花園。當撰寫程式碼成本很高時,耐久性就是你獲得回報的方式;當重寫成本變低時,你的投資就會轉向那些不會頻繁更動的部分:土壤、花圃和灌溉。把強約束、schema 與測試放在邊界,內部的程式碼就能持續翻新,而不會動搖根基。

10 月初,我和代理以互動方式做了這件園藝工作,推出了 31 個 PR,把平均延遲從 70 毫秒降到 50 毫秒。成果確實存在,但每次查詢稽核我還是得先啟動 session、貼上上下文,然後一路把分支護送到完成。

10 月 19 日,我們架起了常駐的自架 OpenHands hub,並把這些習慣轉成閉環系統。從那時起,Forem 已經合併了 444 個 Pull Request:其中 351 個來自自主迴路(172 個效能 PR、93 個測試套件加速、32 個 Rust 原生重寫、29 個相依套件升級、20 個正式環境錯誤修正、以及 5 個 issue-to-PR),另外還有 93 個由我直接推進的客製化 PR。

我們一路上踩壞的每一種設定

你不可能只靠一個排程工作就打造出可運作的軟體工廠,然後它自己說「把 app 變快」。我們經歷了半打配置,每一次都是從觀察前一版失敗後所產生的。

從讀程式碼到即時遙測。 我們最早的 perf-loop 會讀 Ruby 檔並猜測瓶頸,只產生些幾乎不會改變圖表的微優化。當我們把 Better Stack 的 ClickHouse spans 和唯讀的 Postgres 閘道(forem-db-query)接到每次 pre-flight snapshot 裡,並包上隱私保護後,一切都變了。當代理在動手改檔前就能看到即時的 sequential scan、未使用的 index,以及各端點的運算成本時,每個 PR 都必須拿真實流量來證明自己的價值。

從單一模型到跨家族路由器。 一開始我們綁定 Claude Opus 5.5(claude-acp),並從 macOS Keychain 同步 OAuth token。當配額上限與 token 更新衝突出現後,我們建立了一個橫跨 Claude Opus 5.5、OpenAI 的 codex-acp(GPT-6.1 Sol),以及透過 Antigravity CLI(agy)連接的 Google Gemini 4 Argon 的三供應商路由器;最初是透過反向 WebSocket 隧道連回我的 Mac,之後則在 Linux 上以 Medium reasoning 原生安裝。每個迴路都會以輪詢方式輪替,並設有 8 小時冷卻上限;只要某個 PR 修復失敗,就切換到不同的模型家族。

從共用 checkout 到隔離 worktree。 在同一個容器裡同時跑八個迴路,會把 Git 和 Linux 的每個銳角都暴露出來。平行 fetch 會觸發 git gc 衝突,當機的啟動流程會留下殘存的 .gitconfig.lock,而殭屍程序也會越堆越多,直到我們把 tini 加為 PID 1。於是我們把每次執行都搬到一個 detached-HEAD 的 git worktree,搭配自我修復的鎖檔清理,並在每個 cron 前放上可重現的 Python gate,讓滿佇列能在兩秒內結束,完全不耗 token。

從單一迴路到專門花圃。 當容易處理的 SQL 優化被清掉後,我們把工作拆成彼此正交的迴路,採用白天 10 分鐘節奏(週一到週五 上午 7 點到晚上 7 點 ET,週末為四分之一頻率),並以 5/10/20/40 分鐘的指數退避方式進行 PR 回訪:

  • perf-loop:處理 ActiveRecord 查詢、Redis 快取與視圖 partial,並強制現有開啟 PR 之間的類別正交性。
  • rust-loop:透過 magnus 將熱門 Ruby 路徑移植到 gems/forem_native,限制同時只開一個 PR,以避免預編譯二進位檔衝突,並用 1,000 筆輸入的差分測試驗證。
  • test-loop:解析 30 個 Knapsack RSpec shard,以減少 FactoryBot 的反覆建立成本與緩慢的 system spec。
  • error-loop 與 deps-loop:採用嚴格過濾條件,跳過逾時、含糊的 bug 和雜訊式補丁。
  • github-pr-reviewer 與 pr-merge-loop:由不同模型家族上的第二道審核者檢查影響範圍,並在 CI 通過後自動合併低風險的效能與測試 PR。

系統性的土壤,客製化的果實

真正的回報不只是 475 個 PR 的數量,甚至也不只是 16 毫秒的回應時間;而是其他那 93 個 Pull Request 所帶來的改變。

因為我不再把早晨花在找 sequential scan、或在分頁之間搬運 stack trace,我就有了心力去做更深入的工作。當那些迴路在壓縮查詢與測試規格時,我則在互動式 session 裡重新設計我們首頁 feed 的演化方式(加入目標分群、年齡多樣性權重,以及黏著式重訪設定),分四個階段現代化 JavaScript 的傳遞流程,把 application.js 縮小 71%,把 base.js 縮小 55%,建立 L1 本地 Redis 快取,並打造觀測性擴充功能來監看整個系統的運作。

照料這套系統,並把心力放在高槓桿的邊際工作上,終於讓我感覺自己跨過了 AI 輔助軟體開發那種尷尬的中間地帶,不再像個肉身路由器。Brownfield 與 greenfield 專案之間恰當的互動方式,以及讓工作更高產、更有創造力的工具,現在都已經在這裡了。


原文出處:https://dev.to/dailycontext/our-looping-factory-cut-dev-page-load-time-by-75-and-counting-1hnf


精選技術文章翻譯,幫助開發者持續吸收新知。

共有 0 則留言


精選技術文章翻譯,幫助開發者持續吸收新知。
🏆 本月排行榜
🥇
boluoji
📝26   💬3   ❤️6
593
🥈
站長阿川
📝4   💬2   ❤️2
193
🥉
mike
1
評分標準:發文×10 + 留言×3 + 獲讚×5 + 點讚×1 + 瀏覽數÷10
本數據每小時更新一次
📢 贊助商廣告 · 我要刊登