快速失敗#

快速且有效率地重現問題可以大幅提升除錯效率。因此,讓軟體在第一個問題徵兆出現時就立即失敗。這種做法的好處是:失敗的程式碼會在造成問題的程式碼之後很快被執行,甚至就在附近,讓你更容易定位到對應的錯誤。

相反地,如果讓軟體在小問題發生後繼續運行,可能會導致程式進入未知的領域,產生一連串的級聯問題,使 bug 的定位變得更加困難。

快速失敗確實有風險——你可能會聚焦在錯誤的問題上。但如果你修復了那個問題並重新開始除錯,你就永遠消除了一個疑慮來源。透過逐步排除法(gradual elimination),你是在持續進步。

加速失敗的方法#

  • 啟用 assertions:驗證函式輸入參數的有效性和 API 呼叫的結果
    • Java:使用 -ea 選項啟用 runtime assertions
    • C/C++:不定義 NDEBUG macro 即可啟用 compile-time assertions
  • 設定 debugging libraries 為嚴格檢查模式(參見 Item 53)
  • 使用動態程式分析工具檢查程式運行(參見 Item 59)
  • 設定 Unix shell 的 -e 選項:讓 shell script 在命令回傳非零 exit status 時立即終止

生產環境的考量#

雖然 fail fast 是除錯自包含程式的有效方式,但對於已經進入維護階段的大型生產系統來說可能不太適合。生產環境的優先考量通常是韌性(resilience):允許系統在小問題發生後繼續運行(例如載入圖示失敗或某個伺服器程序崩潰),可能比讓整個系統停擺更為可取。

這種寬容模式的運作可以透過其他措施來平衡:

  • 廣泛的監控(monitoring)
  • 完善的日誌記錄(logging)

重點回顧#

  • 在除錯時,設置「絆線」(trip wires),讓程式在第一個問題徵兆出現時就立即失敗