當(dāng)前位置:首頁(yè) > 芯聞號(hào) > 充電吧
[導(dǎo)讀]我在《從你的bug總結(jié)經(jīng)驗(yàn)教訓(xùn)》一文中寫道,我一直在如何跟蹤遇到的最有意思的bug。我最近回顧了全部194個(gè)bug(時(shí)間跨度達(dá)13年),看看從中學(xué)到了什么經(jīng)驗(yàn)教訓(xùn)。

我一直在如何跟蹤遇到的最有意思的bug。最近回顧了全部194個(gè)bug(時(shí)間跨度達(dá)13年),看看從中學(xué)到了什么經(jīng)驗(yàn)教訓(xùn)。下面是最重要的幾個(gè)經(jīng)驗(yàn)教訓(xùn),分為編碼、測(cè)試和調(diào)試這三大類:

編碼

這些是在過(guò)去給我?guī)?lái)棘手bug的所有問(wèn)題:

1. 事件順序:處理事件時(shí),很有必要提出下列問(wèn)題:事件是否可以以一種不同的順序到達(dá)?如果我們從來(lái)沒有收到該事件,會(huì)怎樣?如果該事件連續(xù)出現(xiàn)兩次,又會(huì)怎樣?即使通常情況下這永遠(yuǎn)不會(huì)出現(xiàn),但系統(tǒng)(或交互系統(tǒng))的其他部分中的bug可能會(huì)導(dǎo)致這出現(xiàn)。

2. 處理太早:這是上述“事件順序”的一種特殊情況,不過(guò)它已引起了一些棘手的bug,所以它自成一類。比如說(shuō),如果信令消息接收太早,在配置和啟動(dòng)過(guò)程完成之前接收,許多奇怪的行為就會(huì)出現(xiàn)。另一個(gè)例子:當(dāng)某個(gè)網(wǎng)絡(luò)連接還沒有被列入空閑列表就被標(biāo)為斷開。調(diào)試這個(gè)問(wèn)題時(shí),我們總是假設(shè)它在處于空閑列表時(shí)被設(shè)為斷開(但為什么它又沒有從列表上撤下?)。沒考慮到有時(shí)動(dòng)作發(fā)生太早要怪我們沒想到。

3. 隱蔽故障:一些跟蹤起來(lái)最棘手的bug(一方面)是由出現(xiàn)隱蔽故障、繼續(xù)執(zhí)行而不是給出錯(cuò)誤的代碼引起的。比如說(shuō),系統(tǒng)調(diào)用(比如綁定)返回未加檢查的錯(cuò)誤代碼。另一個(gè)例子:遇到錯(cuò)誤元素后,直接返回而不是給出錯(cuò)誤的解析代碼。調(diào)用在故障狀態(tài)下繼續(xù)持續(xù)一段時(shí)間,這大大加大了調(diào)試的難度。最好一旦檢測(cè)到故障情況,就返回錯(cuò)誤。

4. if語(yǔ)句:有幾個(gè)條件的if語(yǔ)句給我?guī)?lái)了許多bug。即使if語(yǔ)句概念上很簡(jiǎn)單,有多個(gè)條件需要跟蹤時(shí),它們也很容易搞錯(cuò)。如今我試著重寫代碼,力求更簡(jiǎn)單,避免要處理復(fù)雜的if語(yǔ)句。

5. Else:有幾個(gè)bug是沒有適當(dāng)考慮如果條件為假會(huì)發(fā)生什么而引起的。幾乎無(wú)一例外的是,每個(gè)if語(yǔ)句應(yīng)該有一個(gè)else部分。此外,如果你在if語(yǔ)句的一個(gè)分支中設(shè)置了某個(gè)變量,可能應(yīng)該在另一個(gè)分支也要設(shè)置該變量。與此相關(guān)的是標(biāo)志(flag)被設(shè)定的情況。僅僅添加設(shè)定標(biāo)志的條件很容易,但是容易忘了添加應(yīng)該重新設(shè)定標(biāo)志的條件。任由永久性設(shè)定的標(biāo)志留在那里可能會(huì)在將來(lái)導(dǎo)致bug。

6. 不斷變化的假設(shè):一開始最難預(yù)防的許多bug是由不斷變化的假設(shè)引起的。比如說(shuō),一開始,可能每天只有一個(gè)客戶事件。然后,按照這種假設(shè)編寫了許多代碼。后來(lái)某個(gè)時(shí)候,設(shè)計(jì)發(fā)生了變化,允許每天有多個(gè)客戶事件。出現(xiàn)這種情況后,就很難改變受到新設(shè)計(jì)影響的所有情況。很容易找到顯式依賴該變化的所有項(xiàng),但是難就難在,找到隱式依賴舊設(shè)計(jì)的所有情況。比如說(shuō),可能有代碼讀取某一天的所有客戶事件。隱式的假設(shè)可能是,結(jié)果集從不大于客戶數(shù)量。我沒有好的辦法可以預(yù)防這類問(wèn)題,歡迎讀者建議。

7. 日志:深入了解程序執(zhí)行的任務(wù)至關(guān)重要,尤其是邏輯很復(fù)雜時(shí)。務(wù)必要添加足夠多(但是別太多)的日志,那樣你就能弄清楚為什么程序在執(zhí)行它執(zhí)行的任務(wù)。如果一切正常,日志并不重要,但是一旦出現(xiàn)了問(wèn)題(這不可避免),你會(huì)很高興添加了適當(dāng)?shù)娜罩居涗?。?/p>

測(cè)試

作為一名開發(fā)者,除非進(jìn)行了測(cè)試,否則我不會(huì)說(shuō)搞完了一項(xiàng)功能。至少,這意味著每一行新代碼或更改后的代碼至少執(zhí)行了一次。此外,單元測(cè)試或功能測(cè)試也很好,但還不夠。新功能還必須在類似生產(chǎn)環(huán)境的環(huán)境下加以測(cè)試和探究。下面是bug在測(cè)試方面給予我的一些重要的經(jīng)驗(yàn)教訓(xùn):

8. 零和空:務(wù)必要以零和空(合適的情況下)來(lái)進(jìn)行測(cè)試。對(duì)于字符串而言,這意味著既指長(zhǎng)度為零的字符串,又指內(nèi)容為空的字符串。另一個(gè)例子:在發(fā)送任何數(shù)據(jù)(零字節(jié))之前,測(cè)試TCP連接的斷開。沒有使用這些組合來(lái)測(cè)試是bug悄然出現(xiàn)的頭號(hào)原因,我在測(cè)試時(shí)是原本可以發(fā)現(xiàn)這些bug的。

9. 添加和刪除:新功能常常需要能夠?yàn)橄到y(tǒng)添加新配置,比如說(shuō)用于電話號(hào)碼翻譯的新配置文件。所以測(cè)試它切實(shí)可行、以便添加新的配置文件很自然不過(guò)。然而,我發(fā)現(xiàn)很容易忘了還要測(cè)試配置文件的刪除。

10. 錯(cuò)誤處理:處理錯(cuò)誤的代碼常常很難測(cè)試。最好由自動(dòng)測(cè)試來(lái)檢查錯(cuò)誤處理代碼,但有時(shí)這不可能。這種情況下,我有時(shí)采用的一招就是,臨時(shí)修改代碼,讓錯(cuò)誤處理代碼運(yùn)行。要做到這一點(diǎn),最容易的方法就是反轉(zhuǎn)if語(yǔ)句,比如說(shuō)將if語(yǔ)句由error_count > 0反轉(zhuǎn)為error_count == 0。另一個(gè)例子是誤拼數(shù)據(jù)庫(kù)列名,讓所需的錯(cuò)誤處理代碼運(yùn)行。

11. 隨機(jī)性輸入:常??梢园l(fā)現(xiàn)bug的一種測(cè)試方法就是使用隨機(jī)性輸入。比如說(shuō),H.323協(xié)議的ASN.1解碼可處理二進(jìn)制數(shù)據(jù)。通過(guò)發(fā)送有待解碼的隨機(jī)性字節(jié),我們發(fā)現(xiàn)了解碼器中的幾個(gè)bug。另一個(gè)例子是使用測(cè)試調(diào)用生成腳本,其中調(diào)用持續(xù)時(shí)間、回復(fù)延遲、第一方掛斷等都是隨機(jī)生成的內(nèi)容。這些測(cè)試腳本暴露了無(wú)數(shù)bug,尤其是接踵而至的事件引起的干擾。

12. 檢查什么不該發(fā)生:測(cè)試常常包括檢查所需的動(dòng)作已發(fā)生。但它很容易忽視相反的情況――檢查不該發(fā)生的動(dòng)作確實(shí)沒有發(fā)生。

13. 自行編寫工具:我通常構(gòu)建自己的小工具,好讓測(cè)試更容易。比如說(shuō),我在處理面向VoIP的SIP協(xié)議時(shí),寫了一個(gè)小腳本,就返回我所需要的頭和值。有了這個(gè)工具,許多個(gè)別情況測(cè)試起來(lái)很容易。另一個(gè)例子是可以進(jìn)行API調(diào)用的命令行工具。通過(guò)從小處著手,然后根據(jù)需要逐步添加功能,我最后開發(fā)出了非常實(shí)用的工具。自行編寫工具的好處就是,我獲得了所需的那種功能。

不過(guò)根本不可能在測(cè)試中發(fā)現(xiàn)所有bug,有一回,我改變了由兩部分組成的處理關(guān)聯(lián)號(hào)碼的機(jī)制:路由地址前綴(始終一樣),以及從000到999的動(dòng)態(tài)分配號(hào)碼。問(wèn)題是,查找關(guān)聯(lián)時(shí),動(dòng)態(tài)分配號(hào)碼的第一位數(shù)字在查詢地址表之前就被誤刪除了。所以,不是尋找637之類的號(hào)碼,你尋找的是37,而這個(gè)號(hào)碼不在表中。這意味著,它一直尋找到100,所以前100個(gè)調(diào)用正常,而之余的所有900個(gè)調(diào)用失效。所以除非我在重新啟動(dòng)之前測(cè)試了100多次,否則在測(cè)試時(shí)發(fā)現(xiàn)不了這個(gè)問(wèn)題。

調(diào)試

14. 討論:在過(guò)去對(duì)我?guī)椭畲蟮恼{(diào)試方法就是與同事討論問(wèn)題。我常常只要向同事描述問(wèn)題,就足以認(rèn)識(shí)到問(wèn)題是什么。此外,即使同事不是很熟悉相應(yīng)代碼,常常也能給出好主意,表明哪里可能有問(wèn)題。我在處理最棘手的bug時(shí),與同事討論這一招來(lái)得尤其管用。

15. 密切關(guān)注:調(diào)試某個(gè)問(wèn)題花很長(zhǎng)時(shí)間時(shí),常常是由于我做了錯(cuò)誤的假設(shè)。比如說(shuō),我以為問(wèn)題出現(xiàn)在某個(gè)方法中,而實(shí)際上這個(gè)問(wèn)題根本不會(huì)出現(xiàn)在這個(gè)方法中?;蛘邟伋龅漠惓2⒉皇俏壹僭O(shè)的那個(gè)異常?;蛘呶乙詾樵谶\(yùn)行軟件的最新版本,實(shí)際上運(yùn)行的是舊版本。因此,一定要核實(shí)這些細(xì)節(jié),而不是犯想當(dāng)然的毛病。很容易看見預(yù)期看見的問(wèn)題,而不是實(shí)際擺在那里的問(wèn)題。

16. 最近的變化:過(guò)去可以運(yùn)行的代碼現(xiàn)在無(wú)法運(yùn)行時(shí),這常常是最后一個(gè)變更的對(duì)象引起的。有一回,最近變化的對(duì)象只是日志,但是日志中的錯(cuò)誤引起了更大的問(wèn)題。為了讓諸如此類的回歸更容易找到,有必要在不同的提交代碼中實(shí)行不同的變更,并且要清楚說(shuō)明變更。

17. 相信用戶:有時(shí)候用戶報(bào)告問(wèn)題時(shí),我的本能反應(yīng)是“這不可能。他們肯定是哪里弄錯(cuò)了。”但是我已學(xué)會(huì)了擯棄這樣的反應(yīng)。結(jié)果往往證明,用戶報(bào)告的正是實(shí)際發(fā)生的問(wèn)題。所以如今,我對(duì)用戶報(bào)告的問(wèn)題信以為真。當(dāng)然,我仍反復(fù)核查各方面已正確設(shè)定。但是我碰過(guò)好多情況下,之所以發(fā)生奇怪的問(wèn)題,是由于不同尋常的配置或意料之外的使用,而我默認(rèn)的假設(shè)是,它們是正確的,程序是錯(cuò)誤的。

18. 測(cè)試修正版:bug的修正版準(zhǔn)備就緒后,它必須進(jìn)行測(cè)試。先在沒有修正版的情況下運(yùn)行代碼,觀察bug。然后打上修正版,重復(fù)測(cè)試用例。現(xiàn)在,錯(cuò)誤行為應(yīng)該消失。遵照這些步驟可以確保它其實(shí)是個(gè)bug,確保修正版確實(shí)解決了問(wèn)題。這很簡(jiǎn)單,又必不可少。

其他意見

這13年來(lái)我一直在跟蹤我遇到的最棘手的bug,這期間發(fā)生了很大的變化。我開發(fā)過(guò)一個(gè)小型嵌入式系統(tǒng)、一個(gè)大型電信系統(tǒng)以及一個(gè)基于Web的系統(tǒng)。我用C 、Ruby、Java和Python編寫過(guò)代碼。我用C 編碼時(shí)期的幾類bug已完全消失,比如堆棧溢出、內(nèi)存損壞、字符串問(wèn)題以及某些形式的內(nèi)存泄漏。

我遇到的其他問(wèn)題(比如循環(huán)錯(cuò)誤和個(gè)別情況)少了很多,那是由于我一直對(duì)更多的邏輯進(jìn)行單元測(cè)試。但是,這并不意味著沒有bug,還是有bug。這篇文章總結(jié)的經(jīng)驗(yàn)教訓(xùn)幫助我在編碼、測(cè)試和調(diào)試這三個(gè)階段盡量減小破壞。

本站聲明: 本文章由作者或相關(guān)機(jī)構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點(diǎn),本站亦不保證或承諾內(nèi)容真實(shí)性等。需要轉(zhuǎn)載請(qǐng)聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請(qǐng)及時(shí)聯(lián)系本站刪除。
換一批
延伸閱讀

9月2日消息,不造車的華為或?qū)⒋呱龈蟮莫?dú)角獸公司,隨著阿維塔和賽力斯的入局,華為引望愈發(fā)顯得引人矚目。

關(guān)鍵字: 阿維塔 塞力斯 華為

倫敦2024年8月29日 /美通社/ -- 英國(guó)汽車技術(shù)公司SODA.Auto推出其旗艦產(chǎn)品SODA V,這是全球首款涵蓋汽車工程師從創(chuàng)意到認(rèn)證的所有需求的工具,可用于創(chuàng)建軟件定義汽車。 SODA V工具的開發(fā)耗時(shí)1.5...

關(guān)鍵字: 汽車 人工智能 智能驅(qū)動(dòng) BSP

北京2024年8月28日 /美通社/ -- 越來(lái)越多用戶希望企業(yè)業(yè)務(wù)能7×24不間斷運(yùn)行,同時(shí)企業(yè)卻面臨越來(lái)越多業(yè)務(wù)中斷的風(fēng)險(xiǎn),如企業(yè)系統(tǒng)復(fù)雜性的增加,頻繁的功能更新和發(fā)布等。如何確保業(yè)務(wù)連續(xù)性,提升韌性,成...

關(guān)鍵字: 亞馬遜 解密 控制平面 BSP

8月30日消息,據(jù)媒體報(bào)道,騰訊和網(wǎng)易近期正在縮減他們對(duì)日本游戲市場(chǎng)的投資。

關(guān)鍵字: 騰訊 編碼器 CPU

8月28日消息,今天上午,2024中國(guó)國(guó)際大數(shù)據(jù)產(chǎn)業(yè)博覽會(huì)開幕式在貴陽(yáng)舉行,華為董事、質(zhì)量流程IT總裁陶景文發(fā)表了演講。

關(guān)鍵字: 華為 12nm EDA 半導(dǎo)體

8月28日消息,在2024中國(guó)國(guó)際大數(shù)據(jù)產(chǎn)業(yè)博覽會(huì)上,華為常務(wù)董事、華為云CEO張平安發(fā)表演講稱,數(shù)字世界的話語(yǔ)權(quán)最終是由生態(tài)的繁榮決定的。

關(guān)鍵字: 華為 12nm 手機(jī) 衛(wèi)星通信

要點(diǎn): 有效應(yīng)對(duì)環(huán)境變化,經(jīng)營(yíng)業(yè)績(jī)穩(wěn)中有升 落實(shí)提質(zhì)增效舉措,毛利潤(rùn)率延續(xù)升勢(shì) 戰(zhàn)略布局成效顯著,戰(zhàn)新業(yè)務(wù)引領(lǐng)增長(zhǎng) 以科技創(chuàng)新為引領(lǐng),提升企業(yè)核心競(jìng)爭(zhēng)力 堅(jiān)持高質(zhì)量發(fā)展策略,塑強(qiáng)核心競(jìng)爭(zhēng)優(yōu)勢(shì)...

關(guān)鍵字: 通信 BSP 電信運(yùn)營(yíng)商 數(shù)字經(jīng)濟(jì)

北京2024年8月27日 /美通社/ -- 8月21日,由中央廣播電視總臺(tái)與中國(guó)電影電視技術(shù)學(xué)會(huì)聯(lián)合牽頭組建的NVI技術(shù)創(chuàng)新聯(lián)盟在BIRTV2024超高清全產(chǎn)業(yè)鏈發(fā)展研討會(huì)上宣布正式成立。 活動(dòng)現(xiàn)場(chǎng) NVI技術(shù)創(chuàng)新聯(lián)...

關(guān)鍵字: VI 傳輸協(xié)議 音頻 BSP

北京2024年8月27日 /美通社/ -- 在8月23日舉辦的2024年長(zhǎng)三角生態(tài)綠色一體化發(fā)展示范區(qū)聯(lián)合招商會(huì)上,軟通動(dòng)力信息技術(shù)(集團(tuán))股份有限公司(以下簡(jiǎn)稱"軟通動(dòng)力")與長(zhǎng)三角投資(上海)有限...

關(guān)鍵字: BSP 信息技術(shù)
關(guān)閉
關(guān)閉