🎯 什麼情境該想到我

當你想「先湊合一下、之後再修」,或看到程式碼已經很亂而放任它繼續爛時。

⚙️ 怎麼用

一扇破窗(沒修的爛程式碼、爛設計、爛決策)會招來更多破窗。 一旦「反正已經很亂」的心態蔓延,系統會加速腐爛(軟體熵增)。

  1. 看到破窗就修,或至少擋起來:立刻修小問題,或加 TODO/工單追蹤,別放著不管。
  2. 維持乾淨的基準線:呼應童子軍規則(工具-註解是必要之惡 所屬的整潔紀律)——離開時比來時更乾淨。
  3. 別破第一扇窗:你自己也別為了趕而留下「反正只有一個」的爛攤子。

★ 為什麼「一扇破窗」會擴散:機制

這不是道德勸說,是團隊常規(norm)的形成機制:

  1. 工程師寫新程式碼時,會參考周圍的程式碼決定「這裡的標準是什麼」。
  2. 周圍都是乾淨的 → 「我也該寫乾淨」;周圍有 3 個 // TODO: fix later 和 1 個被註解掉的區塊 → 「這裡的標準是能跑就好」。
  3. 每個人都做出局部合理的決定,整體品質就單向往下。

所以破窗的代價不是那一扇窗本身,而是它改變了下一個人對標準的判斷。這也是為什麼修小問題的回報比看起來大。

★ 讓「不再破窗」自動化:棘輪(ratchet)

對舊專案,「一次修好所有問題」不可能;但「不准變得更糟」可以做到,而且可以用 CI 強制:

做法怎麼實作
只檢查新程式碼golangci-lint 的 --new-from-rev=origin/main:只回報這次變更新增的問題,舊問題先不管
數字只能降不能升把目前的警告數/覆蓋率存進 repo,CI 比對:警告數 > 基準 → 失敗;< 基準 → 更新基準
碰到哪修到哪童子軍規則:你改的那個函式,離開時比進來時乾淨一點(改個名、刪個死程式碼)
明確標記技術債// TODO(#482) 必須帶 issue 編號;沒編號的 TODO 在 review 擋下

棘輪的好處:不需要排一個「清理 sprint」,品質靠日常的每個 PR 單調往上爬。

★ 哪些「破窗」要立刻修,哪些可以登記

立刻修(修的成本 < 5 分鐘 或 會擴散)登記成債(修的成本高、不會擴散)
編譯警告、lint 警告模組邊界畫錯
被註解掉的程式碼缺整合測試的舊模組
誤導的名字、過時的註解需要資料遷移的 schema 問題
不穩定(flaky)的測試——它教會大家「紅燈可以忽略」效能問題(有量測數據佐證的)

flaky test 是最危險的破窗:一旦團隊習慣「CI 紅了就重跑」,真正的紅燈也會被重跑掉。發現就要隔離(標記跳過並開單)或修掉,不能放著。

🧪 我實際套用的紀錄

  • 2026-07-15:(待填)

⚠️ 注意

  • 緊急時可暫時妥協,但要明確記錄為技術債並排程償還,不能無聲無息地累積。

  • 破窗理論在犯罪學上的證據有爭議(原始的都市治安政策效果至今仍有爭論);《程式設計師修煉之道》借用的是它的比喻,而軟體團隊中的常規擴散,靠 code review 和 CI 的經驗就能觀察到,不依賴那份犯罪學結論。

  • 別把「修破窗」變成拒絕上線的藉口:目標是不讓品質單向下滑,不是每次上線前把整個 repo 擦亮。

🔗 相關工具