1. 程式人生 > >軟體除錯的一般思路

軟體除錯的一般思路

解決軟體的Bug就像警察破案一樣。警察在掌握了案件發生的時間地點和相關人物後進行分析推理,採訪相關人員,排除嫌疑人,最終找到凶手。同樣的,軟體開發人員在接到Bug時,也是分析Bug發生的背景,然後在運用各種方法來找出問題的原因。並不是所有的Bug都能一眼看出問題發生在哪個地方。雖然Bug發生的原因千差萬別,但是我們還是有一些比較通用的方法來逐步縮小bug的根源的範圍。在水缸裡面抓魚要比在河裡面抓魚要容易,同樣的如果能把問題的根源縮小到一個類,一個函式,那麼我們就能更容易找出Bug是如何發生的了。本文結合最近的一些經驗以及閱讀的一些資料,簡單談談如何有效地找出問題的根源。

1. 哪些因素可能導致軟體出現問題

簡單來講,導致軟體出現問題的因素有如下幾個方面:
  • 軟體自身的問題
  • 第三方的問題,比如作業系統,第三方系統
  • 使用者的輸入

但最終來講都是軟體的問題,是軟體本身沒有處理好這些變化的因素。因此,在剛接到Bug的時候,我們可能無法立刻判斷問題是由哪個因素引起的,誰都可能是凶手,因此我們要逐漸縮小懷疑的範圍。

2. 利用實證來分析Bug

當問題出現了,我們可以根據看到的現象,結合問題發生的環境以及我們對軟體邏輯的理解來分析推斷出問題的原因。這當然是一種可行的方法,但是隨著軟體變得更加複雜,這並不是最有效的辦法。軟體除錯相對於其他領域來講還是比較容易的。比如,發生一起車禍以後,找出事故的原因只能靠分析,交警不能說事故現場沒有發動機的日誌,要求重現這個事故後再來分析事故的原因。而軟體的優勢就在於能做各種實驗來證明你的想法。比如你懷疑是某個地方的問題,那麼就去做個實驗來看看。這就是利用實證的手段來分析Bug。它的一般步驟為:

  • 根據你對問題和軟體的瞭解,提出一個假設,比如你懷疑問題可能是Windows 2012上特有的。
  • 根據你的假設,去構建實驗來驗證你的假設。同樣,如果你懷疑問題是Windows 2012上特有的,那麼可以做的實驗之一就是到Windows 2008上去試一下,如果問題還是發生了,那就不能證明問題是2012上特有的。
  • 根據實驗的結果,你能對問題有進一步的認識,從而能將問題的範圍縮小。
需要注意的是:
  • 每次實驗只能改變一個因素。假如某次實驗和上個實現相比,你改變兩個因素(比如既換了作業系統,又換了另外一個版本的軟體),那麼你就不知道這次實現的結果是由哪個因素引起的。
  • 每次做實驗都要有個明確的目的,並且要有記錄,包括變化了什麼,結果是什麼。要不然,過了一陣可能就忘記了。

3. 利用差異來縮小問題根源的範圍

假如有兩個“同樣”配置的機器,一臺有問題,另外一臺沒有問題,那麼要找出那臺有問題機器出問題的原因,可以關注一下兩臺機器有什麼差別。雖然配置看起來一樣,但他們肯定有差別。找出這些可能和問題相關的差別,利用上一節介紹的實證性分析的方法來證明你的假設。

另外一個例子,如果你開發中的軟體,版本001沒有問題,而版本002有問題,那麼就看看這兩個版本之間有什麼差異,比如通過SCM來看看都改動了哪些檔案,或者使用的第三方庫是否發生了變化等。

4. 利用二分法

我們都知道二分查詢的效率很高。同樣我們也可以利用二分法的一般原理來縮小問題的範圍。還是以上面的那個例子,假如版本001沒問題,而版本008有問題,那麼怎麼快速找到問題是在哪個版本里面引入的呢。最直接的辦法,從版本002一直試到008,但是這樣效率就太低了。我們假設問題被引入後就不會自動消失,這樣就可以利用二分法來找到查詢問題被引入的第一個版本。我們先看版本005有沒有同樣的問題,如果有,那麼問題就在版本002-004之間引入的,然後在繼續用同樣的方法找下去,最多找3次就能找到首次引入這個問題的版本,然後就可以看看那個版本里面有什麼改動,就可以把問題的根源縮小到這些改動上了。

這也是持續整合的思想了,每次提交程式碼都會觸發一次構建和單元測試。如果構建或者測試失敗了,問題的的根源就是上一次程式碼提交造成的,在問題被引入的第一時間修復這個問題要比過了幾個版本後再修復要容易一些。

5. 寫出能重現問題的最短程式碼

如果軟體的問題是由於第三方的庫導致的,在向第三方庫報告問題的時候,最好是能寫出一個簡單的程式來向其說明問題的發生條件,而不是把直接把你的軟體的問題扔給第三方。

同樣的,如果問題就是軟體內部造成的,如果能寫一個單元測試來重現問題,那麼也能提高你測試和除錯的速度,因為單元測試啟動和執行的速度肯定比把整個系統啟動起來的速度要快。任何時候,我們都要提高反饋的速度。

6. 小結

在遇到問題的時候要先分析以縮小問題根源的範圍,而不是直接就跳到程式碼裡面去看哪裡出錯了(那些一眼就看出問題出錯的地方除外)。如果問題在某個環境(這裡的環境是各種可能因素的組合,比如OS,軟體,第三方庫或者系統)發生了,而在另外的環境沒有發生,利用這兩個環境的差異來找出可能導致問題的因素。利用實證的方法來逐漸縮小問題根源的範圍,利用二分法或者其他策略來快速排除一些干擾因素。在找到問題的根源後,最好能寫出一個單元測試來重現問題,它能提高測試和除錯的反饋速度,也有助於向第三方描述問題。我相信本文介紹的方法大家都曾經使用過,我只是將大家都知道的內容簡單總結了一下,希望能有些幫助。