再論:如何解Bug

來源:互聯網
上載者:User
前言:

這篇文章是基於Android系統定製和維護而寫的,所以裡面的內容與Android相關也就是說系統是Android,語言是Java,特點就是沒有明確的需求行為規格定義,只有代碼,很多行為也比較詭異,代碼架構不是很完美,崩潰,異常比較常見(RuntimeExceptions)。雖然是基於Android的,但是方法是通用的。

什麼是Bug

首先要明白什麼是Bug,這點可能不同的人(測試和開發)有不同的理解,不同的公司也會有不同的標準。但是通俗的來講,Bug就是指未預期的行為(unexpected behaviors),比如系統崩潰(Crashes),發生異常(Exceptions),或功能失常(Malfunctions),比如說點擊了儲存,但實際上沒有儲存,點擊了發送卻沒有發送成功。
那什麼又是預期行為(Expected behaviors)呢?預期行為通常是指需求說明書中規定的行為,但是很多系統(比如Android)完全沒有需求或規格說明書,所以更多的時候判斷的標準就是常識和經驗,或與其他軟體系統進行對比。比如說雖然沒有需求規格書,但是通常意義上儲存應該能把檔案或使用者所編輯的內容寫進磁碟檔案,如果沒有成功,那行就可以認定為Bug。所以說Bug也是受主觀因素影響的。

與Bug打交道的人

軟體的理想情況是程式員所寫的程式(演算法)都是正常的,但是有理論證明這是不可能的,沒有任何一個演算法是完全正確的,另外只要是人就是犯錯誤。所以現代大多數的軟體都這樣來保證它的正確性,開發人員交給測試人員軟體,測試人員來保證它的品質,通過測試Bug,當軟體的Bug在一定的允許的範圍內(小於10個)就可以認定軟體已達到預期了,能正常工作並且發行就緒。
在這一過程中涉及三組人:一個是開發人員,一個是測試人員,另外就是管理層。很多大公司的開發人員與測試人員都分屬不同的部門。開發人員負責開發出可測試的軟體版本,測試人員對軟體進行測試,測試出Bug後提交給開發人員,開發人員再解決Bug。通常他們都有來自管理層的壓力和績效考核的壓力,也就是說管理層對測試人員說:你要儘可能多的提交Bug,無論用什麼方法,或者你每天必須提交3個Bug;另外測試人員的績效也與其所提交的Bug數量直接相關。管理層也會對開發人員說:你要在Milestone前把所有的Bug都解掉,上個星期的Bug怎麼還沒解掉,你想不想幹了?另外開發人員的績效也會與Bug數量有關,如果有Open的Bug會扣新水或獎金等。
這樣一來,原本比較簡單清純的關係變的就有些複雜了,無論是測試人員還是開發人員會把人的本性加進來,把政治和功利也帶了進來,像測試提交了不是Bug的Bug,或是開發人員強行關閉Bug都是常有的事兒。因此,測試與開發人員便有些戰爭:
      開發:你這不是Bug,這個行為就是這樣設計的?
      測試:但是這樣設計很不合理!
      開發:那這個要去找UX設計的人?對於行為的修改我們不能做主
      測試:我不管那麼多,我只管測試
      開發:#%^@&$...
      ....
      測試:你為會麼關我的Bug
      開發:因為它無法複現
      測試:但當時我的確是遇到了
      開發:那你再複現出來吧
      測試:@#$%^...

Bug的常見分類

如前所說Bug就是未預期的行為。所以Bug常見的類型有:崩潰(Crashes),異常(Exceptions),功能失常(Malfunctions),差勁的使用者體驗(Bad user experiences),未實現的行為和功能。

Bug的複現機率

這個是特別是值得注意的,首先Bug描述上面寫的複現機率只是測試人員在當時的現場Bug出現的機率,另外這個也是比較主觀的,比如試了三次出一次,有的人認為是必現的,也有的人認為是有一半機率(Above 50%)。
但是經過這幾年解Bug總結的經驗發現,真正的隨機出現的Bug只有與線程時序有關的邏輯才會有。其他的隨機Bug並不是隨機,只可能是測試不太清楚操作步驟和所有的資料或當時的環境現場。

如何解決Bug

1.弄清楚Bug究竟是什麼樣的問題

拿到Bug後,不要著急去複現,首先要弄明白Bug究竟涉及到哪些行為,哪些操作,當時的現場和環境是什麼樣的,用了什麼樣的資料,操作到哪一步出現了問題等等。因為測試人員對Bug的描述是很主觀的,可能不太清楚,所以就要與測試人員進行溝通,弄明白這些問題:
      當時的配置,環境,現場是什麼樣子的?
      涉及到哪些行為?
      進行了什麼樣的操作?
      操作到哪一步出現了問題?
      出現了什麼問題?
      如果說是功能失常,或差勁的使用者體驗或未實現的行為,那麼測試所期待的行為又是什麼樣子的?
      測試人員有沒有附上日誌,截屏或其他調試資訊。
2.如果Bug是崩潰或異常
先不要忙著去複現,因為對於崩潰和異常,日誌當中肯定會有崩潰和異常的直接相關資訊,通常這就能定位出問題,比如對於Java語言來說如果出現未Handle的異常,那麼日誌中肯定會有異常相關的資訊調用棧等。所以通過記錄檔就可以定位出問題出現的原始碼。這樣就多了一個線索,因為你可以通過原始碼來推測是什麼導致了這個異常,可能做了什麼操作,環境現場發生了什麼變化等,通常來講這比測試人員提供的資訊更有參考性。
3.如果是差勁的使用者體驗或是未實現的功能
這個要與測試人員進行溝通,甚至是與管理層和設計者進行溝通,如何修改行為或如何?行為,並且什麼時候進行修改等,通常這個開發人員是沒有決定權的。
4.嘗試複現Bug
這個步驟也是很有必要的,因為即使你修複了Bug,也是需要複現Bug來進行驗證以保證你真正的修複了。所以,如果無法複現Bug那麼就說不清是因為一直都沒有複現還是被你修複了。
如前所述,如果你完全掌握了Bug所發生的條件,相關的操作步驟,那麼複現Bug應該很容易,相關的操作步驟應該Bug描述都會有,但是Bug的相關條件(環境,配置,上下文和資料)這些東西可能要去挖掘才能知道,因為測試可能沒有注意,也可能忘記添加到Bug描述中去,所以為什麼第一步是弄清楚問題。
如果是真正的隨機問題,那肯定是與線程時序相關的,對於這類問題,發生的原因通常是線程應用不當,產生的Bug也相當的隱蔽。對於這類問題的複現方法是,找到相關的代碼邏輯和線程,進行人為的幹預,以加大問題出現的機率,比如可以用Thread.sleep()來阻塞線程,以讓其以某種特定的時序來運行,以加大Bug複現的機率。
另外,如果難以完全複製Bug出現的條件,比如特定資料或特定的條件等,也可以通過修改代碼來實現,比如某一邏輯只有當對象為空白的時候才會進,但是99%的情況下它都不為空白,且沒有合資料讓它為空白,那麼就在代碼中直接用空的對象,以複現Bug。
5.迭代:猜測問題並定位問題
這一步的目的就是定位出問題究竟出現在哪一個源檔案,哪一行或哪一邏輯中。當然,這一步要建立在Bug能複現的基礎上。
定位問題也有很多方法,比如設斷點調試,添加日誌,一個很常用的方法是加上Thread.dumpStack(),以瞭解函數的邏輯調用關係。這個主要與軟體的類型和開發環境有關,很多軟體系統無法進行即時的調試。所以添加記錄檔是最通用的方式。
6.迭代:修複問題並進行驗證
如果定位出問題了,就可以進行修複,有些問題可能容易修複,有些問題可能比較複雜,這要視具體的軟體和具體的問題而定。還有可能是,特別是那些沒有需求規格的軟體,會發現代碼本來就是這樣子工作的,這時就要與管理層和測試和設計者討論這到底算不算Bug且要不要修複。當然最悲劇的就是發現引發這個Bug的原因是系統的架構設計不合理導致的,這個時候就只能用其他方法而不是修改整體架構設計了,當然這個是前期設計造的孽,是否要改要看管理層了和時間預算允許不允許了。
這也是一個迭代過程,進行修複和驗證,直到Bug被完美的修複。也就是說Bug被修複,所做的修改最小,且不會引發其他的Bug。
7.提交CodeReview並進行CodeReview
像開發一樣,解Bug也是開發週期的一個部分,所以為了品質最好還是要進行CodeReview。
Review的目的就是讓修改達到最小,且不會引發其他問題。為什麼讓修改最小,因為你改的越多,產生的影響也就越多,如果沒有足夠的單元測試來驗證,那麼引發其他問題的可能性就越大,所以對於修複Bug來講,修改越少越好,改動的代碼越少越好,修改的檔案越少越好。(當然,最理想的情況是不用修改代碼也能把Bug給解了^_^)。
8.提交Patch和關閉Bug
這個是解Bug的最後一步,但是也要小心,特別是對於公司所用的開發工具和版本管理工具不熟悉的人,一定要小心,因為即使你的Patch已達到最佳化,但是如果在Checkin代碼時發生了問題,那就是悲劇中的悲劇,如果引起了Build error那就等著挨罵吧!
要注意的是把所有的改動都提交到版本控制中去,為了以防萬一,在提交之後最好再從版本中拉出來編譯驗證,一是看是否有Build error(通常是由於提交不全導致的),二是看是否有漏提交(結果就是Bug沒有解掉)。

總結

在《The Practice of Programming》(《程式設計實踐》)有一句關於解Bug的話說的很好:Debugging involves backwards reasoning, like solving murder mysteries. Something impossible occurred, and the only solid information is that it really did occur.(解Bug/調試需要逆向推理,就像偵破離奇的謀殺案。貌似不可能的事情發生了,而且唯一確定的線索是它的確發生了)。仔細品味這句話,解決Bug的過程的確是這樣。我們拿到是就是Bug---一個結果,不斷的嘗試尋找線索,推敲去尋找它的原因,找到了原因了後再想辦法修複它,我們是二十一世紀的福爾摩斯,我們是軟體工業中的柯南。回頭再看那些解決掉的神奇的Bug,與福爾摩斯破案後的感覺類似,也有相當的成就感和自豪感。

後記:

關於解Bug有一本經典的書《The Science of Debugging》(《程式調試思想與實踐》),這本書寫的相當的實在,內容以Bug為主題,覆蓋瞭解Bug所需要的所有話題,內容詳實,完全是作者幾十年作為Debugger的總結。在我看來這本應該與《代碼大全》之類的平起平坐。感興趣的朋友不妨讀一讀。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.