核心概念#
修理電子設備時,第一件事是檢查電源供應是否正常。同樣地,在軟體除錯中,你可以透過檢查 routine 入口處的 preconditions(程式狀態與輸入)和出口處的 postconditions(程式狀態與回傳值)來定位問題。
如果 preconditions 不對,問題在上游設定它們的地方;如果 postconditions 不對,問題就在這個 routine 本身;如果兩者都正確,就需要到其他地方找 bug。
檢查 Preconditions#
在 routine 開頭設置 breakpoint,仔細檢查演算法的參數、呼叫的物件、以及相關的全域狀態。特別注意:
- 不應為
null的值是否為null - 算術值是否在合法的 domain 內(例如傳給
log的值是否大於零) - 物件、結構和陣列的內容是否符合預期(也能幫助找到 invalid pointers)
- 數值是否在合理範圍內(未初始化的變數常會出現像
6.89851e-308或61007410這樣的可疑值) - 資料結構的完整性(例如 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