cover

技術債管理:什麼時候該還、什麼時候該借

技術債跟財務債一樣:有計畫地借是槓桿,無意識地借是災難。

先搞清楚什麼是技術債

Ward Cunningham 最早提出「技術債」的比喻時,他的意思是:

「把不夠完善的程式碼發布出去,就像借了一筆債。只要你後來重構把它還清,利息是可以承受的。危險的是你不還,利息(開發速度下降)會慢慢壓垮你。」

但「技術債」這個詞後來被濫用了。不是所有的爛 code 都叫技術債:

類型這叫什麼怎麼處理
趕時間所以沒寫測試有意識的技術債記下來,排進後續 sprint
用了已知不完美的架構去快速驗證市場策略性技術債驗證成功後立刻還
不知道有更好的做法無意識的技術債透過 code review 和學習來預防
偷懶或缺乏紀律不是技術債,是品質問題改善工程文化和標準

關鍵區分: 技術債是「明知有更好的做法,但有意識地選擇快速方案」。如果你不知道有更好的做法,那不是債,是認知盲區。


技術債的利息長什麼樣

財務債的利息是錢,技術債的利息是時間和風險

         借債時省下的時間
              ↓
         ┌─────────┐
     每次改動  │ 技術債  │  每次改動
     多花的    │         │  多花的
     時間      │         │  時間
         └─────────┘
              ↓
         當利息 > 本金時
         你就開始虧了

利息的具體形式:

  • 改動成本增加 — 本來改一個欄位 5 分鐘,因為耦合嚴重要改 10 個檔案花 2 小時
  • Bug 率上升 — 每次改動都怕壞其他東西,因為沒有測試保護
  • 新人上手變慢 — 「這段 code 為什麼這樣寫?」「不知道,別碰它。」
  • 信心下降 — 團隊開始害怕改東西,能繞就繞,惡性循環
  • 機會成本 — 想加新功能但架構撐不住,被迫先重構

技術債的四象限

Martin Fowler 提出的分類方式,幫你判斷你面對的是哪種債:

           有意識的                 無意識的
  ┌──────────────────┬──────────────────┐
  │                  │                  │
  │  「我們知道這樣   │  「什麼是         │
魯 │   不好,但趕時間  │   Dependency     │
莽 │   先這樣」       │   Injection?」   │
的 │                  │                  │
  │  → 記錄 + 排期還  │  → 需要學習      │
  ├──────────────────┼──────────────────┤
  │                  │                  │
  │  「先發布收集回饋  │  「用了一年才發現  │
謹 │   再來優化架構」  │   這個模式更適合」 │
慎 │                  │                  │
的 │  → 策略正確      │  → 無法避免      │
  │                  │                  │
  └──────────────────┴──────────────────┘

左下角(謹慎 + 有意識)是好的技術債:你知道自己在做什麼,有計畫要還。

右上角(魯莽 + 無意識)是最危險的:你不知道自己在欠債,等發現時利息已經很高了。


什麼時候該借技術債

不是所有技術債都該避免。有些場景下,借債是正確的策略:

場景借債的理由前提
MVP / 市場驗證快速上線比完美架構更重要你有計畫驗證後重構
Deadline 壓力晚一天上線會損失具體的商業價值你記錄了欠的債並排期還
技術探索不確定最好的做法,先做一個版本你願意在學到更好做法後重寫
短期專案專案生命週期只有三個月你確定它真的只活三個月

不該借的情況:

  • 「反正沒人會看這段 code」— 永遠有人會看,通常是三個月後的你
  • 「先 work 就好」但沒有「之後怎麼辦」的計畫
  • 已經在高利息的 code 上繼續疊加

什麼時候該還技術債

訊號偵測 — 這些跡象代表利息太高了:

  1. 改動恐懼 — 團隊說「別碰那塊」或「這很危險」
  2. 相同的 bug 反覆出現 — 修了 A 壞了 B,修了 B 壞了 C
  3. 新功能開發速度明顯下降 — 本來一週能做的,現在要兩週
  4. 新人要花超過兩週才能做第一個 PR — 代表 codebase 太難理解
  5. 你在 workaround 上面疊 workaround — 說明根本問題沒解決

還債的時機點(在這些時候嵌入重構最自然):

  • 做新功能的時候 — 「Boy Scout Rule」:離開時比到達時乾淨一點
  • 修 bug 的時候 — 修完 bug 順便把周圍的壞味道處理掉
  • Sprint planning 時保留 20% 的容量 — 不是整個 sprint 都在還債,而是持續小額還款
  • 大版本之間 — 趁 feature freeze 的空檔做結構性重構

技術債追蹤系統

最簡單可行的做法:

## Tech Debt Registry
 
### TD-001: 使用者驗證沒有 rate limiting
- **位置**: auth/login.ts
- **影響**: 暴力破解風險、每次改 auth 要額外注意
- **利息**: 中(每次安全 review 都會被提出來)
- **還債成本**: 0.5 天
- **優先序**: P1
 
### TD-002: Order model 沒有狀態機
- **位置**: models/order.ts
- **影響**: 狀態轉換靠 if-else,已經有三次因為狀態錯誤出 bug
- **利息**: 高(每次改訂單流程都很怕)
- **還債成本**: 2 天
- **優先序**: P0

不需要華麗的工具。一個 markdown 檔案、一個 Notion 頁面、或是 GitHub Issues 加上 tech-debt label 就夠了。

重點是:讓技術債可見。 看不見的債最危險。


還債策略

策略做法適合場景
持續小額還款每個 PR 順手改善一點(Boy Scout Rule)日常開發,低風險
專項還債 Sprint整個 sprint 只做重構利息已經高到影響開發速度
Strangler Fig新功能用新架構,舊功能逐步遷移大型架構重構
Feature Flag 漸進替換新舊邏輯並行,確認沒問題再切換核心業務邏輯重構
寫測試先行先補測試,再改結構沒有測試覆蓋的遺留代碼

最常見的錯誤:想一次還清所有債。 大型重構風險極高,通常建議用 Strangler Fig 模式漸進替換。


跟非技術人員溝通技術債

PM 或老闆問:「為什麼要花時間重構?功能不是好好的嗎?」

不要說:

  • 「code 太醜了」(他不在乎)
  • 「架構需要改善」(太抽象)

要說:

  • 「現在加一個功能要 3 天,如果重構這塊,以後每個功能只要 1 天」
  • 「這個區域每個月平均出 2 個 bug,重構後可以降到接近 0」
  • 「新人上手這塊要 2 週,重構後只要 3 天」

用數字和商業影響來說話,不要用技術術語。


反思問題

  1. 你的專案裡,哪三塊 code 改動時你最害怕? 那就是利息最高的技術債。
  2. 你有記錄技術債的習慣嗎? 還是都存在腦子裡,換一個人就沒人知道了?
  3. 你上次「有意識地借技術債」是什麼時候? 你後來有還嗎?
  4. 你能跟 PM 用一句話解釋為什麼這次要花時間重構嗎?

延伸閱讀