Uber 工程團隊發表部落格文章,介紹內部系統 AutoClean:它串接公司的功能開關管理平台,找出已經可以安全下線的開關,自動產生刪除程式碼的 diff,測試通過後交給工程師核准。過去幾年,這套系統清理了超過 1 萬 6000 個 feature flag、100 多萬行程式碼,目前仍在 Uber 多個 monorepo 中持續運作。
文章署名的是 Uber 資深軟體工程師 Daniel Ramos、Diego Marcilio,以及軟體工程師 Nikhil Parasaram。
刪程式碼為什麼這麼難
Uber 的新功能靠功能開關進行灰度上線,平台上同時掛著數千個開關。全量放行之後,判斷分支、輔助函式、呼叫點、設定檔與測試往往還留在原處。要刪掉一個開關,必須同時動到這幾個地方,還得確保線上行為完全不變。
部落格還提到一項新的成本:死碼不只是讓人讀起來吃力,AI 程式開發助手在解析程式碼庫時,也得為這些分支多花時間和 token。
三段式流水線
第一段,改寫。代理取得程式碼庫的存取權限,透過 MCP 呼叫 Uber 自行研發並開源的程式碼轉換引擎 PolyglotPiranha,由後者處理布林化簡與條件消除。作者的理由很直接:布林化簡一旦出錯,就會 "can silently change program behavior",也就是悄悄改掉程式行為,因此盡量交給具確定性的工具。
第二段,修復 CI。簡單的失敗交由確定性修復器處理,例如移除用不到的預設值、清掉 lint 錯誤;複雜的則交給代理,例如判斷某個測試該刪還是該改。每個修復器的權限都被嚴格限縮,測試修復器只能動測試檔案。這個循環會一直跑到 CI 通過,或嘗試次數用完為止。
第三段,驗證。CI 通過後先跑靜態檢查,再交給名為 CodeCourt 的驗證層,由多個專門的審查代理平行檢查。部落格列出的規則包括:
- 只刪不加,不引入新程式碼;
- 可觀察的行為保持不變;
- 只處理指定的開關,不順手刪掉相關的其他開關;
- 不留下代理推理過程的註解或痕跡。
任何一項沒通過,這份 diff 就直接作廢,不會送到人的手上。作者表示,幾個各司其職的子代理,效果比讓單一代理從頭到尾審完整份 diff 來得好。
從 Piranha 到智慧代理
AutoClean 的底子是 Uber 幾年前開源的 Piranha。那個工具當初就是為了刪除過期開關而寫的,靠規則比對進行靜態改寫。後來的 PolyglotPiranha 把規則引擎擴充到多種程式語言。這次的變化在外圍:規則引擎仍然負責最容易出錯的布林邏輯,代理則接手規則寫不全的部分,例如修測試、補呼叫點,再由另一批代理互相把關。
部落格也坦承了幾種失敗模式:代理會為了讓測試通過而去改正式環境的程式碼,會刪掉本該保留行為的測試,會太早收工而留下做到一半的清理;指令一多,它還可能漏掉其中某一條限制。這些語意層面的問題,CI 都抓不到,限縮修復器權限、加入 CodeCourt,都是衝著這些問題而來。
文章沒有提供成功率、平均耗時,也沒有說明被作廢的 diff 占多少比例;範例程式碼是 Go,其他語言的涵蓋情況同樣沒有展開。依作者的描述,人工審查者現在只需回答一個問題:這個開關該不該刪。機械層面的正確性,在前面三段裡已經被攔過一遍了。
參考來源:Uber Engineering 官方部落格、CocoLoop、PolyglotPiranha GitHub 專案頁面;清理數量以 Uber 部落格揭露的累計口徑為準。