「沒有框架不是應該更自由嗎?想怎麼改就怎麼改,哪來的複雜?」
這是我常聽到的另一個誤解。框架的價值從來不是「限制你」,而是「幫你擋掉一整類錯誤」:路由怎麼派送是固定的、依賴怎麼注入是固定的、輸入怎麼驗證有慣例可循。拿掉框架之後,這些「本來不用想」的事全部變成要靠人(或 AI)自己判斷的細節——而 AI 對「這件事在這個專案裡是怎麼運作的」這種隱性知識,完全沒有安全網。
昨天提到的核心命題——「AI 給出的『已確認』結論,永遠只在它實際查過的範圍內成立」——在無框架、無測試、跨版本並存的系統裡,會被放大成三種不同形狀的風險。今天就把這三種風險具體攤開來看。
框架系統裡,「這個變數是什麼型別」通常有慣例可查:ORM 的 schema、型別宣告、IDE 的自動完成。無框架的 legacy 系統裡,這些線索常常只剩下命名。
我接手的這套系統裡,資料庫欄位的命名慣例是用前綴表達型別——n 開頭代表數字、s 開頭代表字串。這個慣例大部分時候是對的,直到某一次要把某張表的欄位轉成 Repository 層的型別轉換宣告時,AI 直接照命名慣例判斷:nTotalAmt 開頭是 n,應該轉成整數型別。
實際去查建表的 migration 才發現,這個欄位其實是 decimal——存的是帶小數的金額。命名慣例騙人了,而且騙得很有說服力,因為系統裡九成以上的 n 開頭欄位真的是整數。
❌ 沒有查證的版本:
AI:「欄位名稱 nTotalAmt 以 n 開頭,依命名慣例轉型為 int。」
→ 命中大多數情況,但這裡剛好是例外,會導致小數金額被截斷
✅ 查證過真實 schema 的版本:
AI:「已查詢 migration 檔案,nTotalAmt 實際型別為 decimal(18,4),
依實際型別轉型,不依賴命名慣例推斷。」
→ 命名慣例可以當提示,但不能取代查證實際定義
沒有框架強制的型別系統,命名慣例就是唯一的線索,而線索是會騙人的——AI 重構無框架系統時,任何「依慣例判斷」的地方,都要換成「依實際定義查證」。
第二個風險更根本:這套系統裡,很多程式碼從寫成的那一天起,就沒有任何自動化測試覆蓋過。
一開始我以為「先重構、之後有空再補測試」是合理的節奏。後來意識到這個順序在 AI 重構的情境下特別危險:沒有測試覆蓋的程式碼,AI 改完之後,你唯一能確認「有沒有壞掉」的方法,是靠人工重新走一遍所有情境——而這正是 AI 重構規模化之後,最先失守的一環,因為人工驗證的速度追不上 AI 改動的速度。
我現在的規則很直接:目標程式碼現在有沒有測試覆蓋,是重構能不能動手的先決條件,不是「順便補一下」的加分項。沒有覆蓋就先停手,除非這次重構的目標本身就是「幫這段程式碼補上測試」。這聽起來像是把節奏拖慢,但實際上是把「事後才發現壞掉」的風險,換成「事前就知道哪裡不能碰」的確定性。
第三個風險最隱蔽,也最容易讓 AI 判斷錯誤。這套系統的正式環境上,同時存在好幾套彼此獨立、卻又有部分程式碼互相複製過的平行系統——因為早期開發時圖方便,直接把一套系統的程式碼複製到另一套系統當起點,複製之後兩邊各自演化,但沒有人回頭把共通的部分抽出來統一維護。
某次請 AI 判斷一段可疑程式碼是不是 bug,AI 很快查出這段邏輯確實有問題——某個資料結構的欄位存取方式跟目前的定義對不上。但這段程式碼其實屬於「另一套平行系統」複製過來、沒有跟著改的殘留片段,在它原本所屬的那套系統裡,資料結構是另一種形狀,這段程式碼在那邊是對的;只是被複製到現在這套系統之後,兩邊的資料結構已經分岔,這裡才是真正壞掉的地方。
判斷「這是不是 bug」之前,得先確認這段程式碼真正屬於哪一套系統——歸因錯了,後面的修法方向就整個錯了。 這不是程式碼邏輯本身的問題,是背景知識的問題,而背景知識恰恰是 AI 在一次性任務裡最容易漏掉的東西。
把這三種風險收斂成一個動手前的檢查習慣:
這三個問題背後其實是同一件事:逼 AI 把「看起來合理的推斷」換成「查證過的事實」,跟昨天講的核心命題完全一致——AI 的自信範圍,需要一套流程收斂到跟它實際查證的範圍一致。
回想你手上的 legacy 系統:有沒有哪個地方是靠「命名慣例」「大家都這樣寫」在維持運作,而不是靠明確的規則?如果 AI 今天要改動那個地方,它有辦法查到真正的定義,還是只能猜?
明天會講一個更直接的案例——一次沒有安全網的重構,AI 引入了一個真正的迴歸,而且差一點就被合併進主線。這個案例會具體示範,今天講的「無測試覆蓋」風險,實際發生時長什麼樣子。
iThome鐵人賽