為什麼需要可重現的問題#
能夠可靠且輕鬆地重現問題是高效除錯的關鍵,原因有三:
- 聚焦根因:一鍵重現問題後,你可以專注追查原因,而非浪費時間隨機嘗試
- 便於求助:有簡單的重現步驟,就能輕鬆描述問題並向外部求助
- 驗證修復:修復後再次執行重現步驟,確認問題不再出現
建立精簡範例#
黃金標準是 minimal example——能重現問題的最短範例。白金標準是 SSCCE(Short, Self-Contained, Correct, Compilable Example)。
精簡範例的好處:
- 排除不相關的程式碼路徑
- 產生的 log 和 trace 不會過長
- 執行速度快,在 debug mode 下尤其重要
縮減範例的兩種策略#
Bottom-up(由下而上):假設問題根因(例如某個 API 呼叫),建構一個最小測試案例來驗證假設。適合依賴關係多、從零開始較容易的情況。
Top-down(由上而下):從完整的問題場景開始,逐步移除元素直到找到最小重現條件。Binary search 技巧特別有用——例如一個有問題的 HTML 檔案,先移除 head,再移除一半 body,反覆縮小範圍。
讓範例自包含(Self-Contained)#
讓範例不依賴外部資源(libraries、headers、CSS、web services):
- 使用相對路徑(
../resources/file.css)而非絕對路徑 - 使用 localhost 而非硬編碼 IP
- 如果需要外部元素,打包在一起
自包含的範例便於在不同環境重現、發佈到 Q&A 論壇、或寄給廠商分析。
建立可複製的執行環境#
使用 virtual machine image 來維持乾淨的系統狀態。例如除錯軟體安裝程式時,每次失敗安裝後都能從乾淨映像重新開始。
更進一步的做法:
- 使用 Docker 進行作業系統級的虛擬化或容器化
- 採用組態管理工具如 Ansible、Chef、Puppet、Salt,從高階指令可靠地建立指定的系統組態
- 維持生產、測試和開發環境的一致性
可靠地複製失敗版本#
- 將軟體納入版本控制(如 Git)
- 在建置流程中嵌入版本識別碼:
git log -n 1 --format='const string version = "%h";'- 在軟體中提供版本顯示功能(command-line option 或 About 對話框)
- 需要時可以輕鬆取回失敗版本的原始碼:
git checkout 035cd45- 別忘了將影響建置結果的所有元素納入版本控制:compiler、第三方 libraries、header files、build specification
重點回顧#
- 可重現的執行能簡化除錯流程
- 建立精簡且自包含的範例來重現問題
- 建立可複製的執行環境
- 使用版本控制系統來標記和取回軟體版本