快速失敗#
快速且有效率地重現問題可以大幅提升除錯效率。因此,讓軟體在第一個問題徵兆出現時就立即失敗。這種做法的好處是:失敗的程式碼會在造成問題的程式碼之後很快被執行,甚至就在附近,讓你更容易定位到對應的錯誤。
相反地,如果讓軟體在小問題發生後繼續運行,可能會導致程式進入未知的領域,產生一連串的級聯問題,使 bug 的定位變得更加困難。
快速失敗確實有風險——你可能會聚焦在錯誤的問題上。但如果你修復了那個問題並重新開始除錯,你就永遠消除了一個疑慮來源。透過逐步排除法(gradual elimination),你是在持續進步。
加速失敗的方法#
- 啟用 assertions:驗證函式輸入參數的有效性和 API 呼叫的結果
- Java:使用
-ea選項啟用 runtime assertions - C/C++:不定義
NDEBUGmacro 即可啟用 compile-time assertions
- Java:使用
- 設定 debugging libraries 為嚴格檢查模式(參見 Item 53)
- 使用動態程式分析工具檢查程式運行(參見 Item 59)
- 設定 Unix shell 的
-e選項:讓 shell script 在命令回傳非零 exit status 時立即終止
生產環境的考量#
雖然 fail fast 是除錯自包含程式的有效方式,但對於已經進入維護階段的大型生產系統來說可能不太適合。生產環境的優先考量通常是韌性(resilience):允許系統在小問題發生後繼續運行(例如載入圖示失敗或某個伺服器程序崩潰),可能比讓整個系統停擺更為可取。
這種寬容模式的運作可以透過其他措施來平衡:
- 廣泛的監控(monitoring)
- 完善的日誌記錄(logging)
重點回顧#
- 在除錯時,設置「絆線」(trip wires),讓程式在第一個問題徵兆出現時就立即失敗