1.事件順序html
當處理事件時,問如下問題富有成效:事件是否能夠以不一樣的順序到達?若是沒收到這些事件怎麼辦?若是事件在同一行出現兩次怎麼辦?即便這一般不會發生,在系統的其餘部分(或交互系統)中的bug也會致使它發生。數據庫
2.處理太早工具
這是上述「事件順序」中的一個特殊狀況,可是它已致使了一些棘手的bug,因此它自成一派。例如,若是信令信息接收得過早,在配置和啓動程序完成以前接收,許多奇怪的行爲就會發生。另外一個例子,當一個鏈接在被放入空閒列表以前就被標記爲斷開。當咱們處理這個問題時,咱們一般假設它處在空閒列表狀態時被標記爲斷開(可是當時它爲何沒有從這個列表上撤下?) 沒考慮到事情有時發生過早是因爲咱們沒有想到。單元測試
3.隱蔽故障測試
例如,一些最難找的的 bug 是因爲出現了隱蔽故障而繼續執行而不是給出錯誤的代碼致使的。例如,系統調用(如綁定)返回未檢查的錯誤代碼。另外一個例子:當遇到一個錯誤元素時,直接返回而不是給出錯誤的解析代碼。調用在故障的狀態下持續了一段時間,使得調試的難度加大。一旦故障被檢測出,最好要及時返回這個錯誤。命令行
4.If語句翻譯
含有多個條件的If語句(if (a or b),尤爲是當嵌套時,if (x) else if (y)),給我致使了許多 bug。即便If語句在概念上很簡單,當它有多個條件須要追蹤時,很容易出錯。最近我嘗試從新把代碼寫得簡潔,避免出現複雜的If語句。設計
5.Else調試
有一些bug的產生是因爲沒有恰當地考慮若是條件爲假,什麼應該發生。在幾乎全部的狀況下,每一個If語句都應該有個else部分。並且,若是你在If語句的一個分支中設置了一個變量,你也許應該在其餘分支也設置該變量。與此相關的是標誌(flag)被設定的狀況。僅僅添加設定標誌的條件很容易,可是容易忘了添加應該從新設定標誌的條件。任由永久性設定的標誌留在那裏可能會在未來致使 bug。日誌
6.改變假設
一開始最難預防的許多bug是由不斷變化的假設引發的。例如,最初僅僅只有一個客戶,在這個假設下寫了不少代碼。後來某個時候,設計發生了變化,容許天天有多個客戶事件。當這種狀況發生,就很難改變受到新設計影響的全部狀況。很容易找到顯式依賴該變化的全部項,可是難的部分是,找到隱式依賴舊設計的全部狀況。例如,可能有代碼讀取給定某一天的全部客戶事件。一個隱式的假設多是,結果集中元素的數量絕對不會大於客戶數量。我沒有好的方法能夠預防這類問題,歡迎讀者建議。
7.日誌記錄
深刻了解程序所作的任務是相當重要的,尤爲是當邏輯複雜的時候。確保添加足夠的(但也別太多)日誌記錄。那樣你就能弄清楚爲何程序在執行它執行的任務。讓一切運轉良好時,它可有可無。可是隻要問題發生(這不可避免),你會很慶幸你添加了合適的日誌記錄。
做爲一名開發者,除非進行了測試,不然我不會說完成一項功能。起碼這意味着每一行新代碼或更改後的代碼至少執行了一次。此外,單元測試或功能測試也很好,但不夠。新功能還必須在相似產品的環境下進行測試和探究。惟有這樣,我才能夠說完成了一項功能。下面是 bug 在測試方面給予個人一些重要的經驗教訓:
8.零(zero)和空(null)
務必要以零和空(合適的狀況下)來進行測試。對於字符串而言,這意味着既指長度爲零的字符串,又指內容爲空的字符串。另外一個例子:在發送任何數據(零字節)以前,測試 TCP 鏈接的斷開。沒有使用這些組合來測試是 bug 悄然出現的頭號緣由,我在測試時是本來能夠發現這些 bug 的。
9.添加和刪除
新功能經常須要可以爲系統添加新配置,好比說用於電話號碼翻譯的新配置文件。咱們會天然而然的添加一個配置文件,來驗證功能是否正常。然而,我發現很容易忘了還要測試配置文件的刪除。
10.錯誤處理
處理錯誤的代碼經常很難測試。最好由自動測試來檢查錯誤處理代碼,但有時這不可能。這種狀況下,我有時採用的一招就是,臨時修改代碼,讓錯誤處理代碼運行。要作到這一點,最容易的方法就是反轉if語句,好比說將if語句由 error_count > 0反轉爲 error_count == 0。另外一個例子是誤拼數據庫列名,讓所需的錯誤處理代碼運行。
11.隨機輸入
另外一種每每可以發現 bug 的測試方法是進行隨機輸入。例如,H.323 協議的 ASN.1 解碼可處理二進制數據。經過發送有待解碼的隨機性字節,咱們發現瞭解碼器中的幾個 bug。另外一個例子是使用測試調用生成腳本,其中調用持續時間、回覆延遲、第一方掛斷等都是隨機生成的內容。這些測試腳本暴露了無數 bug,尤爲是接踵而至的事件引發的干擾。
12.檢查什麼不應發生
一般測試包括檢查一些須要的行爲發生。可是很容易忽略他的對立面——檢查不應發生的事確實沒發生。
13.自制工具
一般,我建立了本身的小工具來使測試更簡易。例如,當我處理面向 VoIP 的 SIP 協議時,我寫了一個小的腳本能夠返回正標題和值。這個工具使得測試許多個別場景變得簡單。另外一個例子是能夠調用 API 的命令行工具。從小的開始,逐漸添加一些須要的功能,我最終有許多有用的工具,寫本身的小工具的優點是我獲得我想要的功能。
14.討論
在過去對我幫助最大的調試方法就是與同事討論問題。我經常只要向同事描述問題,就足以認識到問題是什麼。此外,即便同事不是很熟悉相應代碼,經常也能給出好主意,代表哪裏可能有問題。
15.密切注意
每每是當調試一個問題很長時間時,是由於我作了錯誤的假設。例如,我認爲這個問題發生在一個特定的方法中,事實上,這個問題甚至根本不會出如今這個方法中。或者拋出的異常並非我認爲的那個。或者我認爲最新版的軟件在運行,但它實際上是較老的版本。
16.最近的一次改動
本該運行的程序中止了,它一般是由最後的一次變更致使。有一次,最近的一次變更僅僅是日誌,可是日誌中的一個錯誤致使了更大的問題。
17.相信用戶
有時當一個用戶反饋問題時,個人本能反應是:這不可能,他們必定搞錯了。可是我已經意識到我不該該這樣作。我也不想這樣,但更屢次,事實證實他們報告的問題實際上發生了。
18.測試修復的效果
若是你已經修復了 bug,還須要再測試。首先運行修復前的代碼,而後觀察 bug。而後運用修復再次測試。如今 bug 的問題應該被消除了。繼續這些步驟確保它確實是一個 bug,確保你的修復已經修復這個問題。簡單但很必要。