www.久久久久|狼友网站av天堂|精品国产无码a片|一级av色欲av|91在线播放视频|亚洲无码主播在线|国产精品草久在线|明星AV网站在线|污污内射久久一区|婷婷综合视频网站

當(dāng)前位置:首頁(yè) > 公眾號(hào)精選 > 21ic電子網(wǎng)
[導(dǎo)讀]編譯:伯樂(lè)在線-鄭蕓,英文:HenrikWarne我寫了我是怎樣追蹤這些年遇到的最有趣bug的。最近我重新瀏覽了這所有的194個(gè)條目(歷時(shí)13年),看看我從這些bug中學(xué)到了學(xué)到了那些重要的經(jīng)驗(yàn)教訓(xùn)。我分為編碼、測(cè)試和調(diào)試三大類。編碼這些都是過(guò)去給我?guī)?lái)棘手bug的問(wèn)題:1.事件...


編譯:伯樂(lè)在線 - 鄭蕓,英文:Henrik Warne

我寫了我是怎樣追蹤這些年遇到的最有趣 bug 的。最近我重新瀏覽了這所有的 194 個(gè)條目(歷時(shí) 13 年),看看我從這些 bug 中學(xué)到了學(xué)到了那些重要的經(jīng)驗(yàn)教訓(xùn)。我分為編碼、測(cè)試和調(diào)試三大類。

和各種詭異Bug打交道13年,我總結(jié)了18條經(jīng)驗(yàn)

編碼

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

1.事件順序

當(dāng)處理事件時(shí),問(wèn)以下問(wèn)題富有成效:事件是否可以以不同的順序到達(dá)?如果沒(méi)收到這些事件怎么辦?如果事件在同一行出現(xiàn)兩次怎么辦?即使這通常不會(huì)發(fā)生,在系統(tǒng)的其他部分(或交互系統(tǒng))中的bug也會(huì)導(dǎo)致它發(fā)生。

2.處理太早

這是上述“事件順序”中的一個(gè)特殊情況,但是它已導(dǎo)致了一些棘手的bug,所以它自成一派。例如,如果信令信息接收得過(guò)早,在配置和啟動(dòng)程序完成之前接收,許多奇怪的行為就會(huì)發(fā)生。另一個(gè)例子,當(dāng)一個(gè)連接在被放入空閑列表之前就被標(biāo)記為斷開(kāi)。當(dāng)我們處理這個(gè)問(wèn)題時(shí),我們通常假設(shè)它處在空閑列表狀態(tài)時(shí)被標(biāo)記為斷開(kāi)(但是當(dāng)時(shí)它為什么沒(méi)有從這個(gè)列表上撤下?) 沒(méi)考慮到事情有時(shí)發(fā)生過(guò)早是由于我們沒(méi)有想到。

3.隱蔽故障

例如,一些最難找的的 bug 是由于出現(xiàn)了隱蔽故障而繼續(xù)執(zhí)行而不是給出錯(cuò)誤的代碼導(dǎo)致的。例如,系統(tǒng)調(diào)用(如綁定)返回未檢查的錯(cuò)誤代碼。另一個(gè)例子:當(dāng)遇到一個(gè)錯(cuò)誤元素時(shí),直接返回而不是給出錯(cuò)誤的解析代碼。調(diào)用在故障的狀態(tài)下持續(xù)了一段時(shí)間,使得調(diào)試的難度加大。一旦故障被檢測(cè)出,最好要及時(shí)返回這個(gè)錯(cuò)誤。

4.If 語(yǔ)句

含有多個(gè)條件的If語(yǔ)句(if (a or b),尤其是當(dāng)嵌套時(shí),if (x) else if (y)),給我導(dǎo)致了許多 bug。即使If語(yǔ)句在概念上很簡(jiǎn)單,當(dāng)它有多個(gè)條件需要追蹤時(shí),很容易出錯(cuò)。最近我嘗試重新把代碼寫得簡(jiǎn)潔,避免出現(xiàn)復(fù)雜的If語(yǔ)句。

5.Else

有一些bug的產(chǎn)生是由于沒(méi)有恰當(dāng)?shù)乜紤]如果條件為假,什么應(yīng)該發(fā)生。在幾乎所有的情況下,每個(gè)If語(yǔ)句都應(yīng)該有個(gè)else部分。而且,如果你在If語(yǔ)句的一個(gè)分支中設(shè)置了一個(gè)變量,你也許應(yīng)該在其他分支也設(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è)

一開(kāi)始最難預(yù)防的許多bug是由不斷變化的假設(shè)引起的。例如,最初僅僅只有一個(gè)客戶,在這個(gè)假設(shè)下寫了很多代碼。后來(lái)某個(gè)時(shí)候,設(shè)計(jì)發(fā)生了變化,允許每天有多個(gè)客戶事件。當(dāng)這種情況發(fā)生,就很難改變受到新設(shè)計(jì)影響的所有情況。很容易找到顯式依賴該變化的所有項(xiàng),但是難的部分是,找到隱式依賴舊設(shè)計(jì)的所有情況。例如,可能有代碼讀取給定某一天的所有客戶事件。一個(gè)隱式的假設(shè)可能是,結(jié)果集中元素的數(shù)量絕對(duì)不會(huì)大于客戶數(shù)量。我沒(méi)有好的方法可以預(yù)防這類問(wèn)題,歡迎讀者建議。

7.日志記錄

深入了解程序所做的任務(wù)是至關(guān)重要的,尤其是當(dāng)邏輯復(fù)雜的時(shí)候。確保添加足夠的(但也別太多)日志記錄。那樣你就能弄清楚為什么程序在執(zhí)行它執(zhí)行的任務(wù)。讓一切運(yùn)轉(zhuǎn)良好時(shí),它無(wú)關(guān)緊要。但是只要問(wèn)題發(fā)生(這不可避免),你會(huì)很慶幸你添加了合適的日志記錄。

和各種詭異Bug打交道13年,我總結(jié)了18條經(jīng)驗(yàn)

測(cè)試

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

8.零(zero)和空(null)

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

9.添加和刪除

新功能常常需要能夠?yàn)橄到y(tǒng)添加新配置,比如說(shuō)用于電話號(hào)碼翻譯的新配置文件。我們會(huì)自然而然的添加一個(gè)配置文件,來(lái)驗(yàn)證功能是否正常。然而,我發(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ī)輸入

另一種往往能夠發(fā)現(xiàn) bug 的測(cè)試方法是進(jìn)行隨機(jī)輸入。例如,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è)試包括檢查一些需要的行為發(fā)生。但是很容易忽略他的對(duì)立面——檢查不該發(fā)生的事確實(shí)沒(méi)發(fā)生。

13.自制工具

通常,我創(chuàng)建了自己的小工具來(lái)使測(cè)試更簡(jiǎn)易。例如,當(dāng)我處理面向 VoIP 的 SIP 協(xié)議時(shí),我寫了一個(gè)小的腳本可以返回正標(biāo)題和值。這個(gè)工具使得測(cè)試許多個(gè)別場(chǎng)景變得簡(jiǎn)單。另一個(gè)例子是可以調(diào)用 API 的命令行工具。從小的開(kāi)始,逐漸添加一些需要的功能,我最終有許多有用的工具,寫自己的小工具的優(yōu)勢(shì)是我得到我想要的功能。

在測(cè)試中要發(fā)現(xiàn)所有的 bug 幾乎不可能。有一次,我在一種情況下,我對(duì)處理關(guān)聯(lián)號(hào)碼做了改變,包括兩部分:路由地址前綴(總是相同),和從 000 到 999 的動(dòng)態(tài)分配號(hào)碼。問(wèn)題是,當(dāng)查找相關(guān)性時(shí),動(dòng)態(tài)分配的數(shù)字的第一個(gè)數(shù)字在查找之前被錯(cuò)誤地刪除。所以,不是尋找 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)題。

和各種詭異Bug打交道13年,我總結(jié)了18條經(jīng)驗(yàn)

調(diào)試

14.討論

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

15.密切注意

往往是當(dāng)調(diào)試一個(gè)問(wèn)題很長(zhǎng)時(shí)間時(shí),是因?yàn)槲易隽隋e(cuò)誤的假設(shè)。例如,我認(rèn)為這個(gè)問(wèn)題發(fā)生在一個(gè)特定的方法中,事實(shí)上,這個(gè)問(wèn)題甚至根本不會(huì)出現(xiàn)在這個(gè)方法中。或者拋出的異常并不是我認(rèn)為的那個(gè)?;蛘呶艺J(rèn)為最新版的軟件在運(yùn)行,但它其實(shí)是較老的版本。因此,一定要驗(yàn)證細(xì)節(jié),而不是假設(shè)。它使你容易看到你所期望看到的問(wèn)題,而不是實(shí)際發(fā)生的問(wèn)題。

16.最近的一次改動(dòng)

本該運(yùn)行的程序停止了,它通常是由最后的一次變動(dòng)導(dǎo)致。有一次,最近的一次變動(dòng)僅僅是日志,但是日志中的一個(gè)錯(cuò)誤導(dǎo)致了更大的問(wèn)題。為了讓諸如此類的回歸更容易找到,有必要在不同的提交代碼中實(shí)行不同的變更,并且要清楚說(shuō)明變更。

17.相信用戶

有時(shí)當(dāng)一個(gè)用戶反饋問(wèn)題時(shí),我的本能反應(yīng)是:這不可能,他們一定搞錯(cuò)了。但是我已經(jīng)意識(shí)到我不應(yīng)該這樣做。我也不想這樣,但更多次,事實(shí)證明他們報(bào)告的問(wèn)題實(shí)際上發(fā)生了。所以這些天,我認(rèn)真對(duì)待他們的反饋。當(dāng)然,我仍然反復(fù)測(cè)試所有的一切被正確地設(shè)置了。但是我碰過(guò)好多情況下,之所以發(fā)生奇怪的問(wèn)題,是由于不同尋常的配置或意料之外的使用,而我的默認(rèn)假設(shè)是他們是對(duì)的,程序是錯(cuò)的。

18.測(cè)試修復(fù)的效果

如果你已經(jīng)修復(fù)了 bug,還需要再測(cè)試。首先運(yùn)行修復(fù)前的代碼,然后觀察 bug。然后運(yùn)用修復(fù)再次測(cè)試?,F(xiàn)在 bug 的問(wèn)題應(yīng)該被消除了。繼續(xù)這些步驟確保它確實(shí)是一個(gè) bug,確保你的修復(fù)已經(jīng)修復(fù)這個(gè)問(wèn)題。簡(jiǎn)單但很必要。

和各種詭異Bug打交道13年,我總結(jié)了18條經(jīng)驗(yàn)

其他心得

過(guò)去 13 年,我一直在記錄我遇到的最棘手的 bug,很多事情發(fā)生了改變。從小的嵌入式系統(tǒng),到大的電信系統(tǒng),網(wǎng)頁(yè)系統(tǒng)都做過(guò)。我使用的語(yǔ)言包括 C 、Ruby、Java 和 Python,若干類的 bug 在我使用 C 的日子里就已經(jīng)不再出現(xiàn)了。像堆棧溢出,內(nèi)存損壞,字符串的問(wèn)題以及某些形式的內(nèi)存泄漏。

其他的問(wèn)題,像回路錯(cuò)誤和極端案例,我見(jiàn)的少得多,因?yàn)槲覇卧獪y(cè)試了更多邏輯,但這并不意味著那里沒(méi)有 bug。這篇文章總結(jié)的經(jīng)驗(yàn)教訓(xùn),幫助我在編碼、測(cè)試和調(diào)試這三個(gè)階段盡量減小破壞。如果你發(fā)現(xiàn)了其他的技巧或者有用的技巧來(lái)預(yù)防或者找到 bug,請(qǐng)?jiān)谠u(píng)論區(qū)留言。



編譯:伯樂(lè)在線 - 鄭蕓版權(quán)歸原作者所有,如有侵權(quán),請(qǐng)聯(lián)系刪除。

21ic電子網(wǎng)

掃描二維碼,關(guān)注更多精彩內(nèi)容

本站聲明: 本文章由作者或相關(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)系本站刪除。
關(guān)閉
關(guān)閉