核心概念#

修理電子設備時,第一件事是檢查電源供應是否正常。同樣地,在軟體除錯中,你可以透過檢查 routine 入口處的 preconditions(程式狀態與輸入)和出口處的 postconditions(程式狀態與回傳值)來定位問題。

如果 preconditions 不對,問題在上游設定它們的地方;如果 postconditions 不對,問題就在這個 routine 本身;如果兩者都正確,就需要到其他地方找 bug。

檢查 Preconditions#

在 routine 開頭設置 breakpoint,仔細檢查演算法的參數、呼叫的物件、以及相關的全域狀態。特別注意:

  • 不應為 null 的值是否為 null
  • 算術值是否在合法的 domain 內(例如傳給 log 的值是否大於零)
  • 物件、結構和陣列的內容是否符合預期(也能幫助找到 invalid pointers)
  • 數值是否在合理範圍內(未初始化的變數常會出現像 6.89851e-30861007410 這樣的可疑值)
  • 資料結構的完整性(例如 map 是否有預期的 key/value,doubly linked list 是否能正確遍歷)

檢查 Postconditions#

在 routine 結尾設置 breakpoint,檢查執行結果:

  • 計算結果是否合理?是否在預期範圍內?
  • 如果看似合理,結果是否真的正確?(可以手動計算驗證,或與已知的正確值比對)
  • routine 的 side effects 是否正確?有沒有資料被意外修改或設為錯誤的值?
  • 演算法取得的資源(如 file handles 或 locks)是否正確釋放?

應用於更高層次#

同樣的方法適用於更高層次的操作與環境:

  • 驗證 SQL 語句掃描的 table 和建構的結果
  • 檢查 file-based 處理的輸入與輸出檔案
  • 檢視 web service 各節點的輸入與輸出
  • 排查整個 data center,檢查 networking、DNS、shared storage、database、middleware 等各元素

在所有情況下,verify, don’t assume(驗證,不要假設)。

重點回顧#

  • 仔細檢查 routine 的 preconditions 和 postconditions