AI 的程式重構:為什麼它不敢動舊碼
舉個很常見的例子:一個看似無用的 `getUserLevel()` 方法,你可能會覺得它只是回傳一個等級,刪掉也沒差。但實際上,某個報表排程會透過反射去呼叫它,或者某個前端透過 API 名稱的命名慣例去猜測端點。AI 在沒有完整呼叫圖的情況下,最理性的策略就是「不動」。因為它知道,自己無法證明「刪掉是安全的」,而在無法證明的情況下動手,就是在賭。
副作用也是同樣的道理。舊系統裡的方法常常同時做三件事:查資料、算東西、順便寫 log 或更新快取。你請 AI 把「計算」抽出來,它會擔心抽出來之後,快取更新的時機改變了,log 的順序改變了,於是整個系統的行為就跟著變了。這種「方法不只做一件事」的設計確實不好,但要重構它,需要的不只是程式能力,還需要對執行時行為的完整掌握。
測試覆蓋率是真實的安全網
第二個關鍵是測試。AI 重構本質上是一種「機率性編輯」:它根據上下文預測下一步該怎麼改,然後產出候選答案。這種工作模式極度需要快速回饋——改完之後跑一次測試,綠燈就繼續,紅燈就修正。測試就是 AI 的安全網,也是它敢不敢放手動手的關鍵指標。
問題是,多數遺留系統的測試覆蓋率低得可憐。不是工程師不想寫,而是這些系統通常在「先求有」的壓力下長大,測試被視為奢侈品;等到系統變大、邏輯變複雜,想補測試又會發現每個方法都牽扯一堆外部相依,光是 mock 就要寫半天。於是形成一個惡性循環:沒有測試,所以不敢重構;不敢重構,所以程式碼越來越難懂;越來越難懂,所以更寫不出測試。
在這種環境下,AI 的表現其實非常「誠實」。它會告訴你「建議先建立測試」,因為它內部的推理也知道:沒有測試的重構,等於在沒有防護網的情況下走鋼索。這一點其實值得我們反過來思考——AI 不願意動,很多時候不是能力不足,而是它在提醒我們「這個專案的工程基礎還不到位」。
上下文窗口與全域理解的極限
第三個限制是上下文。不管模型的窗口多大,一個中型專案的程式碼量往往還是遠超它能一次讀完的範圍。AI 只能看到被餵進去的檔案、被檢索出來的片段、被摘要過的說明。它看不到完整呼叫鏈、看不到歷史 commit 的脈絡、看不到那些「為什麼當初要這樣寫」的討論。
這會造成一種很微妙的現象:AI 對單一檔案的理解可能比多數人還深,但對整個系統的理解卻非常片段。當你請它重構一個方法,它可能改得很漂亮,但改完之後那個方法在整體架構中的位置卻錯了——本來應該是核心邏輯,被它當成工具函式搬到 utils;本來應該是外圍的格式轉換,被它併進 domain model。這種「局部正確、全域錯誤」的風險,是 AI 重構目前最難克服的技術障礙之一。
三、不敢動的經濟原因:風險與報酬極度不對稱
除了技術限制,還有一個更現實的原因:對 AI 而言,重構遺留系統是一件「風險與報酬極度不對稱」的事。這一點常常被忽略,但它其實是理解 AI 行為的關鍵。
重構失敗的成本由誰承擔
對人類工程師來說,重構成功可以帶來成就感、可以讓程式碼更好維護、可以在考核裡寫一筆「技術債下降」。但對 AI 來說,這些收益它一項都拿不到。它不會因為重構成功而升遷,也不會因為程式碼變漂亮而開心。它能「感受到」的,只有一件事:如果它改錯了,會發生什麼事。
而改錯的後果是明確且嚴重的:系統掛掉、客訴進來、工程師半夜被叫起來、事後檢討會上被點名「是誰讓 AI 直接改 production 邏輯的」。在這種風險結構下,最理性的策略當然是保守。這不是模型「不會」,而是模型在一個風險不對稱的環境裡,選擇了對自己最安全的路徑。
驗證成本高於生成成本
還有一個經濟學上的問題:生成很便宜,驗證很貴。AI 產生一個重構版本可能只要幾秒鐘,但驗證這個版本是否正確,卻需要跑完整測試、需要人工 review、需要 QA 回歸、需要 staging 環境驗證、需要觀察線上指標。整個流程加起來可能是好幾個人日。
當驗證成本遠高於生成成本時,會出現一個很奇特的現象:大家會傾向「多生成幾個版本來比較」,但實際上根本沒有足夠的驗證資源去評估這些版本。最後變成一種心理負擔——「AI 給了我三個重構方案,但我不知道哪個對,於是我一個都不敢用」。這種情況下,AI 越是積極產出,使用者的焦慮反而越高,最後雙方都退回保守路線。
四、不敢動的知識原因:業務邏輯不在程式碼裡
如果說技術限制與經濟誘因是「表面原因」,那知識結構就是「根本原因」。遺留系統最難重構的部分,往往不是程式碼本身,而是程式碼背後那些沒有被寫下來的知識。
文件缺失與口耳相傳的規則
你一定遇過這種情況:某個欄位明明型別是 string,但長度永遠不會超過 20;某個金額欄位明明允許負數,但業務上永遠不該是負的;某個狀態機明明有六個狀態,但實際上只會用到其中四個。這些規則去哪裡找?通常不在程式碼裡,而是在某個已經離職的 PM 的腦袋裡,在某次會議紀錄的角落,在某個客戶的合約附件裡。
AI 讀程式碼,它會看到「這個欄位沒有長度限制」,於是它可能很合理地建議「那我們把它放寬吧」。但真正的問題是:那個限制不是技術限制,而是業務限制。這種「程式碼沒說、但大家都知道」的規則,是 AI 重構遺留系統時最大的盲區。
歷史包袱與「不能問的為什麼」
更麻煩的是,有些程式碼之所以長成那樣,是因為它曾經修過一個很嚴重的 bug,而那個修法本身很醜,但它有效。這種「用醜方法解決真實問題」的痕跡,在遺留系統裡到處都是。AI 看到這種程式碼,第一反應通常是「這段邏輯很奇怪,建議重寫」;但重寫之後,那個當年的 bug 可能就回來了。
這也是為什麼資深工程師在重構舊系統時,常常會有一種「敬畏感」——不是因為程式碼寫得好,而是因為你知道每一段醜程式碼背後,可能都有一個故事。AI 沒有這種敬畏感,但它也沒有承擔後果的能力,於是最終還是只能選擇不動。
五、AI 自身的限制:訓練資料、獎勵機制與自我懷疑
除了外部環境,AI 本身也有一些內建的限制,讓它在面對舊碼時特別保守。
訓練語料的偏誤
目前主流模型在訓練時,看最多的程式碼是開源專案、教學範例、現代框架的官方文件。這些語料有一個共同特徵:它們都是「理想狀況下的程式碼」。開源專案會重構、會清理技術債、會遵循最佳實踐;教學範例更是乾淨到不行。模型從這些語料裡學到的,是一種「現代化、結構化、型別安全」的程式碼審美。
但企業遺留系統不是這樣長大的。它是在預算壓力、時程壓力、人員流動中被硬擠出來的。於是模型看到舊碼時,會產生一種「這寫法不對」的直覺,可是它同時也知道「這是 production 系統,不能亂改」。這兩種訊號互相衝突,最後的結果就是它會給你一堆「建議」,但不太敢真的動手。
被訓練成保守與討好
還有一個很現實的因素:現在的模型在對齊訓練中,被教導要「避免高風險建議」。這本身是好事,但也造成一種副作用——模型會過度傾向給出「安全牌」。你會發現它很愛說「建議先諮詢團隊成員」、「這部分可能需要更多上下文」、「在正式環境請謹慎評估」。這些話當然沒錯,但當每一句都是這種話時,你就會覺得它根本沒有在幫你解決問題。
這種「討好式保守」其實是 AI 重構工具目前最大的體驗痛點。使用者要的不是一個一直說「小心」的助手,而是一個能判斷「哪裡可以動、哪裡不能動」的夥伴。而這種判斷能力,目前模型還不夠穩定。
六、實務上怎麼讓 AI 敢動手:把重構拆成可驗證的小步
講了這麼多限制,不是要說 AI 不能重構舊碼,而是要說:想讓它敢動,必須先把環境準備好。以下幾個做法,是目前實務上比較有效的策略。
先建安全網:測試、型別、可觀測性
第一步永遠是安全網。在請 AI 重構之前,先確認你要動的那個模組有基本的測試覆蓋。如果沒有,那就先讓 AI 幫你補測試——注意,是「幫你補測試」,不是「幫你重構」。補測試這件事風險低、報酬高,而且測試本身就是重構的前置作業。有了測試,AI 才有辦法在每次修改後驗證自己的假設。
型別也是另一種安全網。如果專案有 TypeScript、有強型別、有 lint 規則,AI 改壞東西的機率就會大幅下降,因為它會被編譯器擋下來。可觀測性也一樣:如果每次改動都能在 staging 環境看到 log、指標、trace,那驗證成本就會下降,AI 也就更敢動手。
餵對上下文:把隱形契約寫出來
第二步是補充上下文。AI 看不到的東西,你要主動告訴它。比如說:這個欄位的長度限制是業務規則、這個方法的呼叫者是誰、這個模組不能依賴外部的時間來源、這個排序結果被前端依賴。這些資訊可以寫在 README、寫在註解、寫在 prompt 裡,重點是要讓 AI 知道「哪些東西不能碰」。
更進一步的做法,是建立一份「重構禁區清單」。哪些檔案不能動、哪些函式不能改簽名、哪些資料表不能改結構,全部列出來。這份清單不只是給 AI 看,也是給人看的。很多時候,團隊自己也沒搞清楚禁區在哪,透過這個過程反而能把隱性知識顯性化。
把重構拆成可回滾的小步
第三步是拆分。不要讓 AI 一次重構整個模組,而是拆成一系列「可驗證、可回滾」的小步驟。例如:先加測試、再抽出常數、再抽出方法、再搬移類別、最後才調整架構。每一個步驟都應該是可以獨立合併、獨立回滾的。這樣即使某一步出錯,也不會讓整個系統陷入混亂。
這種做法其實就是把「重構」從一個大冒險,變成一連串低風險的小實驗。對 AI 來說,小步驟的上下文需求較低、驗證成本較低、失敗成本也較低,它自然就比較敢動手。對人類來說,小步驟也比較容易 review,不會出現「這個 PR 改了 3000 行,我不知道從哪裡看起」的窘境。
建立 AI 重構的驗收流程
最後,要建立明確的驗收流程。什麼樣的改動可以直接合併?什麼樣的改動需要人工複查?什麼樣的改動一定要跑完整回歸?這些規則要先講清楚。有了明確的規則,AI 才知道自己的邊界在哪,人類也才知道什麼時候可以信任它。
實務上,一個常見的做法是「分級信任」:純格式調整、註解補充、變數重新命名這類改動,可以讓 AI 直接處理;抽出方法、調整結構這類改動,需要人工 review;涉及業務邏輯、資料庫結構、外部介面的改動,則必須人工主導,AI 只能當輔助。這種分級不是歧視 AI,而是承認不同類型的改動有不同的風險係數。
七、結語:不敢動不是缺陷,是誠實
回到最初的問題:為什麼 AI 不敢動舊碼?答案其實不是單一的。它是技術限制(看不到隱性依賴、上下文不足)、經濟誘因(風險不對稱、驗證成本高)、知識結構(業務規則不在程式碼裡)、以及模型自身訓練偏誤共同作用的結果。
但換個角度想,這種「不敢動」其實是一種誠實。它誠實地反映出遺留系統的真實狀態:測試不足、文件缺失、隱性契約太多、知識集中在少數人身上。這些問題本來就存在,只是過去被「能跑就好」的文化掩蓋了。AI 的保守,反而像一面鏡子,讓我們看見自己專案的工程基礎有多薄弱。
所以,與其抱怨 AI 不敢重構,不如把這件事當成一個契機:先把測試補起來、把隱性知識寫下來、把重構拆成小步、把驗收流程建立起來。當這些基礎到位,AI 自然就會從「只肯加註解」變成「敢於動手」的夥伴。毕竟,一個真正可靠的工程環境,本來就不該依賴某個天才工程師的記憶,也不該依賴某個 AI 的勇氣,而是該依賴一套讓所有人都能安全修改系統的機制。
對雅寶社區的開發者來說,這或許也是個值得分享的經驗:AI 不是來取代我們的判斷,而是來放大我們的工程紀律。你給它什麼樣的環境,它就回饋什麼樣的能力。舊碼不是不能動,而是需要先把動它的條件準備好——這件事,目前還是得由人來做。