如何修改bug(二)-bug的修改流程
一.前言
我發現很多程序員都在改bug,總在改bug。但是很多人沒有思考過什么是修改bug的正確方法,如何高效率的修改bug,如何避免改了一個bug又被測出另外一個bug(我稱為連環bug);還有就是,為什么我們的系統越做越不穩定了,bug越改越多了。
我總結了一下經驗和大家分享。(本人一直在做windows平台下C++系統的工作,文章對C++更有針對性)
作為一個程序員,少不了要修改bug,甚至每天都要修改bug。也許你在維護一個老系統,也許你的專職就是修改bug或者你自己寫的代碼總是被測試人員測出問題,bug總是伴隨在程序員的身邊。
有的人對修改bug有抵觸情緒,說:這么爛的系統,還不如重寫了,要是我來寫代碼,哪里會有這些爛bug。
有的人麻木了,說:反正bug改不完,干一天算一天。
還有的人輕蔑的說:有bug,就改唄,哪有軟件沒bug的,立馬動手改!
修改bug是一件非常能鍛煉人的工作,一般不需要一個團隊去修改一個具體的bug,所以修改bug更能提現一個人的綜合能力。希望這個系列的文章能對那些天天和bug做伴的朋友有一些幫助。
二.bug的定義和分類
站在能改掉bug的角度上,我對bug做了如下分類:
我把bug分為三大類:
1.邏輯錯誤(有出現,不能重現)
只要是有出現的bug,不管是功能錯誤,內存錯誤的crash等,基本都是邏輯錯誤。那些不能輕易再現的錯誤都屬於這一類。
要想正真改掉一個bug,請你重現它。不論用什么手段,重現它。否則,你不能對比驗證你在之后修改的結果。不能驗證修改的結果,你敢說你一定改對了嗎。
這個系列的文章一個基本前提就是:bug一定能重現。
至於如何重現一個詭異的bug,我在以后其他系列的文章專門寫點東西。
2.邏輯錯誤(有出現,能重現)
a.明確原因:
bug拿到手,就非常清晰的理解上下文邏輯,知道需要在哪里做什么樣的修改;正確估計所做的修改對他相關模塊、邏輯的影響(做到這點不容易)。
或者bug非常簡單,比如:筆誤、字符串拼寫錯誤,界面圖片對齊等。
b.不明原因:
這種bug的修改也是我在后面文章要大書特書的。
不明確bug產生的真正原因,只知道一個判斷或者調用就有bug了,或者誤解了bug產生的原因。看圖中誤改的箭頭,這種情況下做的修改是工作效率低下的主要因素,連環bug也是這么誕生的。
一個不明確產生bug正真原因的修改,會造成無法預計的風險(看箭頭)。
知道導致bug的表面調用,但是不理解代碼上下文,對於直接修改表面調用造成的其他隱患沒有正確估計的bug,也屬於不明原因的bug。
一個只對bug表面調用邏輯做修改,不思考所有相關邏輯的行為,是要付出沉重代價的。
修改bug是非常簡單的,但是明確一個bug的原因有時是很難的。
c.內存錯誤導致的邏輯錯誤:
內存錯誤是C++老生常談的問題了:泄露,越界等。
由於A處的內存錯誤導致,即使本來正確的B處邏輯,也會出現異常狀態。(有些新手可能不太理解這句話,有什么問題就問吧)
特別是那些檢測不出來的內存錯誤:B處邏輯被你改穿了,A處還是有越界,等B處邏輯被你保護死了,又發現C處邏輯又壞了,多么可怕啊。嚴重影響工作效率。
內存錯誤的難點在於,如何認識到你手頭的這個邏輯錯誤是由一個毫不相關的內存錯誤導致的。
內存錯誤最怕的是誤改。
后面的文章我會談到怎么修改內存錯誤。
3.泄漏和越界,資源釋放問題
a.能檢測出內存錯誤:
有些泄露用IDE能檢測出來,還可以借助boundschecker等工具。這些問題,在調試過程中就能體現。
b.不能檢測出內存錯誤:
C++的數組越界。除非你用STL或者Boost庫的數組來寫代碼。
C風格的數組的性格,我們改變不了。
一句話,C++是給明白人用的。
不明白的人拿起你的vc,建一個Dialog工程,定義一個成員int m_test[16];在構造函數寫m_test[16] = 1;跑跑看吧。
三.修改bug的前提
再次強調,一定要重現bug,無論是誰反饋的,你要能親眼見到bug。
有些特例:比如,前方做實施半夜1點電話你,說:重大事故啦,快改下什么什么的類型,不然人家數據要全沒啦,你快改!!有經驗的人,第一時間會利用vpn或者其他方式連到現場,親眼看看。實在看不到現場的,除非你非常明確前方人員表達的意思;除非你對代碼熟悉的能背誦了,早就預料到會有這一天,那你敢改就改吧。
2009-03-14
-------------------------------------------------------(未完待續,下篇:bug的修改流程)
上篇中我對bug做了3大分類:能重現的邏輯錯誤,不能重現的邏輯錯誤和潛在的內存錯誤。
這篇文章是我總結關於邏輯錯誤的修改流程,也算是后面文章的一個總領。
流程如圖:
1 重現
再次強調這個是修改bug的前提。
2 明確事發點
就是明確導致一個bug產生最直接的一個調用或者一個判斷。 明確了事發點后有兩種情況,就是上圖中的分支。 有些bug,在明確了事發點后就立刻知道原因了,這個大家都有體會;有些就不是這么簡單了。 定位事發點的方法下篇文章有詳細介紹。
3 整理代碼
有些事發點邏輯錯綜復雜,一點注釋也沒有,也沒有文檔,或者代碼風格很差。整理下代碼,能減縮進就減點,太長的函數分割一下。。。就是為了提高閱讀性。
因人而異,如果你覺得你的閱讀能力超強,不整理也無所謂。 但是千萬不要自作聰明的就開始做點“保護”,這個步驟不要讓邏輯受一點影響。
4 分析原因
具體情況具體分析。這個步驟有時候是最難的,但是一定要明確原因。不明原因或者誤解原因bug的修改后果是有極大風險的。 可參考《如何修改bug(一)-bug的分類和定義》。
5 確定方案
可行性、所做修改對其他模塊和邏輯的影響需要周密思考、測試和驗證。有些方案看上去很好,正真做進去了才發現時間白花了。在解決一些關於性能方面問題的時候往往會發生拿錯方案的慘案。 有時候方案很多,都可行,難以抉擇,那就具體情況具體分析了。
6 修改代碼
這一步,是所有步驟中最簡單的,就是碼字。
7 驗證
程序員保證自己工作效率和質量的關鍵步驟。你不想總被別人測出問題吧,或者你也不想問題最多的模塊總是你在改的吧。
小結
bug千奇百怪,不是每個bug都需要經歷所有流程的。每個步驟都有它的難點。 有些bug難在事發點的定位,比如多線程,異步邏輯中的bug; 有些bug難在原因很難分析,多數是你看不懂代碼; 有些bug難在你不敢改,那是你的修改方案沒有做好充分的分析。 。。。 其實會者不難,后面我會細細道來,和大家一起分享。