為什麼需要可重現的問題#

能夠可靠且輕鬆地重現問題是高效除錯的關鍵,原因有三:

  • 聚焦根因:一鍵重現問題後,你可以專注追查原因,而非浪費時間隨機嘗試
  • 便於求助:有簡單的重現步驟,就能輕鬆描述問題並向外部求助
  • 驗證修復:修復後再次執行重現步驟,確認問題不再出現

建立精簡範例#

黃金標準是 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 進行作業系統級的虛擬化或容器化
  • 採用組態管理工具如 AnsibleChefPuppetSalt,從高階指令可靠地建立指定的系統組態
  • 維持生產、測試和開發環境的一致性

可靠地複製失敗版本#

  • 將軟體納入版本控制(如 Git
  • 在建置流程中嵌入版本識別碼:
git log -n 1 --format='const string version = "%h";'
  • 在軟體中提供版本顯示功能(command-line option 或 About 對話框)
  • 需要時可以輕鬆取回失敗版本的原始碼:
git checkout 035cd45
  • 別忘了將影響建置結果的所有元素納入版本控制:compiler、第三方 libraries、header files、build specification

重點回顧#

  • 可重現的執行能簡化除錯流程
  • 建立精簡且自包含的範例來重現問題
  • 建立可複製的執行環境
  • 使用版本控制系統來標記和取回軟體版本