技術債務是必然存在的,關鍵是如何管理。
本章聚焦「何時、何處」需要還債;具體「如何」進行重構請見 重構。
什麼是技術債務?#
技術債務和金融債務一樣,不是絕對的壞事。適度的債務可以加速業務發展,但過多的債務會讓系統難以維護。
寶玉對技術債務的定義:
技術債務是為了短期目標而做出的、會在未來增加成本的技術決策。
技術債務的類型#
flowchart TD
subgraph A [🎯 有意識的債務]
A1[為了趕上市場窗口,先用簡單方案]
A2[知道問題在哪,計劃以後修復]
A3[這是「借貸」,需要還]
end
subgraph B [😵 無意識的債務]
B1[不知道自己在製造債務]
B2[缺乏經驗或知識]
B3[這是「無知稅」,代價更高]
end
subgraph C [📅 過時的債務]
C1[技術選型過時]
C2[設計不再適合當前需求]
C3[這是自然演進,難以避免]
end
style A fill:#e8f5e9
style B fill:#ffebee
style C fill:#fff3e0技術債務的表現#
| 表現 | 症狀 |
|---|---|
| 開發變慢 | 改一個小功能需要很長時間 |
| Bug 頻發 | 修一個 Bug 引入新 Bug |
| 難以理解 | 新人需要很長時間上手 |
| 測試困難 | 很難寫測試,或測試經常失敗 |
| 部署風險 | 每次上線都提心吊膽 |
技術債務的成因#
業務壓力#
業務說「先上線再說」,這是技術債務最常見的來源。
喬新亮的觀點:
有時候快速上線是對的決策。問題不在於產生債務,而在於不記錄、不還債。
其他常見原因#
人員問題:
├── 經驗不足
├── 缺乏程式碼規範
├── 溝通不暢
└── 人員流動
流程問題:
├── 缺乏設計評審
├── 缺乏程式碼評審
├── 沒有重構時間
└── 測試不充分
技術問題:
├── 技術選型錯誤
├── 過度設計或設計不足
├── 複製粘貼
└── 文檔缺失量化識別信號與戰術 vs 戰略#
前面的「表現」偏感受層面(變慢、易出 bug)。要讓識別更客觀、讓新人也能判斷,需要一組可量化的信號。
具體識別信號#
| 信號 | 警戒線 | 意涵 |
|---|---|---|
| 類別行數 | > 500 行 | 職責過多,違反 SRP |
| 方法參數個數 | > 5 個 | 概念未抽象、呼叫端易錯 |
| 圈複雜度(Cyclomatic Complexity) | > 15 | 分支過多、難測難懂 |
| 「改一處要改多處」 | 散彈式修改 | 模組邊界沒切對 |
| 新人上手時間 | 明顯偏長 | 認知負荷高、缺文件 |
| 寫測試的難度 | 寫不出/常壞 | 依賴糾纏、可測性差 |
這些指標多數可由 Code Review 提到的工具(SonarQube、PMD、CheckStyle)自動掃出,納入 CI 門檻,讓技術債「看得見」。對照的壞味道見 程式碼壞味道。
戰術型 vs 戰略型思維#
債務累積的根源往往不是時間不夠,而是「思維習慣」的選擇。
| 戰術型思維 | 戰略型思維 | |
|---|---|---|
| 目標 | 讓功能「能跑」就好 | 持續維持好設計 |
| 對複雜度 | 不在意,先過再說 | 視為首要成本,主動控制 |
| 短期 | 看起來更快 | 看起來稍慢 |
| 長期 | 維護成本指數上升 | 維護成本平穩、可持續 |
「能跑」不是品質標準。戰略型投資(多花一點時間把設計做對)在長期維護成本上的回報,遠超短期趕工省下的時間。這不是時間管理問題,而是要不要把「設計品質」當第一公民的取捨。
修復 vs 隔離重建的決策準則#
「重寫往往失敗」已是共識(見下方還債策略),但有些債務確實無法靠小改解決。判準如下:
flowchart TD
A[一筆技術債] --> B{能用小步、有測試保護<br>逐步改善嗎?}
B -->|能| C[修復:持續小改進 + 專項重構]
B -->|不能| D{問題在於過時的<br>第三方依賴/技術選型?}
D -->|是| E[隔離後新建:<br>包一層介面,逐步替換]
D -->|否| F[多半仍應拆解成可小改的步驟]- 可修復:邏輯雖亂,但能在測試保護下小步重構——優先選此路,風險最低。
- 隔離重建:當債務來自無法演進的外部依賴或徹底錯誤的選型,用介面把它隔離,再在背後逐步替換,而非全系統推倒重來。
管理技術債務#
識別和記錄#
第一步是識別和記錄技術債務:
mindmap
root((技術債務管理))
🔍 識別方法
程式碼審查中發現
開發過程中標記(TODO、FIXME)
Bug 分析中發現
團隊討論中提出
技術審計
📝 記錄內容
債務描述:問題是什麼
影響範圍:影響哪些功能
產生原因:為什麼會這樣
修復成本:需要多少資源
不修的代價:不修會怎樣
優先級:什麼時候修把技術債務當成 Issue 來管理。定期回顧,決定什麼時候修復。
優先級評估#
評估技術債務優先級的框架:
| 維度 | 高優先級 | 低優先級 |
|---|---|---|
| 影響範圍 | 影響多個功能 | 只影響一處 |
| 頻繁程度 | 經常遇到 | 很少觸發 |
| 修復成本 | 越拖越難修 | 成本穩定 |
| 業務影響 | 阻礙業務發展 | 對業務無影響 |
| 安全風險 | 有安全隱患 | 無安全問題 |
還債策略#
寶玉介紹的還債方式:
持續小改進:
- 每個迭代安排一定比例的重構時間(如 20%)
- 修改功能時順便改進相關程式碼
- 不追求一次性解決,持續改進
專項重構:
- 對於大的技術債務,安排專項修復
- 需要和業務溝通,獲得支援
- 有明確的目標和計劃
重寫:
- 最後的選擇,風險和成本都很高
- 確保真的無法通過重構解決
- 需要詳細的遷移計劃
「讓我重寫一遍,這次肯定會更好」是危險的想法。重寫往往會製造新的問題,而且會丟失原有程式碼中的隱含知識。
預防技術債務#
預防勝於治療。預防技術債務的四個關鍵手段:
- 編碼規範:詳見 程式碼規範
- 設計評審:大的功能變更前先評審設計,邀請相關人員參與並記錄決策
- 程式碼審查:詳見 Code Review
- 適度重構:詳見 重構
童子軍規則——離開時比來時更乾淨。修改功能時順手改進相關程式碼,是最低成本的還債方式。
與業務溝通技術債務#
為什麼溝通很重要?#
技術債務往往對非技術人員不可見,但它會影響業務:
- 開發速度變慢
- Bug 變多
- 創新能力下降
- 安全風險增加
如何溝通?#
喬新亮的建議:
mindmap
root((與業務溝通))
🗣️ 用業務語言
不說「程式碼耦合」,說「改一個功能要三天」
不說「技術債務」,說「歷史遺留問題」
不說「重構」,說「為新功能做準備」
用資料說話:Bug 數量、開發時間
💪 爭取資源
說明不還債的後果
提出具體的計劃
承諾可見的收益
分階段進行平衡業務壓力#
業務壓力是真實存在的,技術團隊需要在品質和速度之間取得平衡。
平衡的方法:
- 接受有些債務是必要的
- 但要記錄並計劃修復
- 為重大技術債務設置紅線
- 持續和業務溝通
案例:阿里的技術債務#
畢玄分享了阿里處理技術債務的經驗:
淘寶早期為了快速發展,積累了大量技術債務。後來花了很大力氣進行重構和升級。
教訓:
- 債務越積越多,最後不得不付出巨大代價
- 有些債務在當時是必要的(業務優先)
- 還債需要自上而下的支援
- 一邊還債一邊還要支撐業務,很難
本章要點#
- 債務不是壞事:適度債務可以加速發展,關鍵是管理
- 識別和記錄:把債務當 Issue 管理,定期回顧
- 評估優先級:影響範圍、頻繁程度、修復成本
- 多種還債方式:持續小改進、專項重構、(最後)重寫
- 預防勝於治療:規範、評審、審查、持續重構
- 與業務溝通:用業務語言,用資料說話