所屬文章系列及序號(hào):尋找塵封的銀彈:bug修理廠(一)
看似沒(méi)有什么營(yíng)養(yǎng)的bug描述里,其實(shí)蘊(yùn)含著兩個(gè)關(guān)鍵要素晴及,往往被我們忽略。開發(fā)者一旦掌握了這兩個(gè)要素,靈感會(huì)被瞬間激發(fā)出來(lái)戴质,立刻想到解決方案,而且是正確的方案踢匣!筆者之所以要在這里強(qiáng)調(diào)“正確的方案”告匠,原因就在下邊對(duì)這兩個(gè)要素的講述之中。
【一個(gè)要素是條件】
Bug描述里一般會(huì)列出這些條件:操作系統(tǒng)的版本號(hào)离唬,環(huán)境變量配置了什么值(這些變量也許會(huì)是一個(gè)長(zhǎng)長(zhǎng)的列表)后专,發(fā)生bug之前做了什么操作(這些操作也許會(huì)是一個(gè)長(zhǎng)長(zhǎng)的列表)。
我們需要從這個(gè)描述中找出導(dǎo)致bug的“條件要素”输莺,才能更好的理解bug發(fā)生的原因行贪,從而可以找到解決方案。這里提到的“條件要素”是指模闲,如果不執(zhí)行某個(gè)測(cè)試步驟建瘫,就不會(huì)發(fā)生這個(gè)bug,那么這個(gè)步驟就是“條件要素”尸折。
對(duì)于能夠100%重現(xiàn)bug(或叫必現(xiàn))啰脚,我們既可以用下邊的方法去找“條件要素”,又可以直接用設(shè)置斷點(diǎn)的方式去發(fā)現(xiàn)代碼錯(cuò)誤实夹,不過(guò)設(shè)置哪個(gè)斷點(diǎn)也有很多可討論的地方橄浓,這些復(fù)雜的討論需要在開發(fā)者“做bug重現(xiàn)”時(shí)再去解決(參見后續(xù)文章)。在這兩種方法的具體選擇上亮航,要看哪個(gè)方法更快荸实、自己更熟悉等因素。
對(duì)于重現(xiàn)概率較低的bug缴淋,作為一個(gè)開發(fā)者准给,如何在這些海量信息面前泄朴,迅速找出那個(gè)決定性的條件?這絕對(duì)是個(gè)能力露氮,而且有時(shí)很像智商測(cè)試題祖灰。這是程序員必備的技能,具體的方法有很多畔规,其中一個(gè)方法是“對(duì)比”局扶。
現(xiàn)代版的俗話說(shuō):“沒(méi)有對(duì)比就沒(méi)有傷害”。
當(dāng)開發(fā)者或測(cè)試者修改了某一個(gè)測(cè)試步驟叁扫,例如改變了一個(gè)環(huán)境變量的值三妈、減少了一個(gè)測(cè)試步驟、改變了兩個(gè)測(cè)試步驟的順序莫绣,等等畴蒲,有時(shí)就會(huì)發(fā)現(xiàn)bug沒(méi)有了,那就證明是這次的測(cè)試步驟改變導(dǎo)致bug消失的兔综,條件要素也就找到了饿凛。
這里有兩個(gè)變化需要注意:
一、無(wú)論是必現(xiàn)的bug還是不必現(xiàn)的bug软驰,修改一個(gè)步驟后bug消失了涧窒,一般情況下就能判斷出是這次修改步驟導(dǎo)致的,但僅限于一般情況锭亏,還有其他情況導(dǎo)致bug發(fā)生纠吴,例如多線程,這些復(fù)雜的討論需要在開發(fā)者“做bug重現(xiàn)”時(shí)再去解決(參見后續(xù)文章)慧瘤,這個(gè)階段只是為了讓項(xiàng)目經(jīng)理戴已、開發(fā)者、測(cè)試者看懂bug就足夠做決策用了锅减。
二糖儡、一次只能改變一個(gè)測(cè)試步驟,否則我們就無(wú)法準(zhǔn)確知道是哪個(gè)改變導(dǎo)致的怔匣。
到此為止握联,方法是有了,但是方法還不夠有力每瞒。一旦測(cè)試步驟非常多金闽,那么需要對(duì)比的測(cè)試用例就多,有時(shí)會(huì)達(dá)到100條以上剿骨,這樣的效率就太低了代芜,而且操作起來(lái)讓人心煩,根本找不到工作中的快樂(lè)浓利。
好在我們還有更好的方法:谷歌搜索的“手氣不錯(cuò)”挤庇!也就是說(shuō)钞速,在把所有情況羅列出來(lái)以前,先用自己的直覺(jué)試驗(yàn)一個(gè)最有可能的用例罚随,往往就能找到那個(gè)關(guān)鍵的條件要素玉工。不過(guò)直覺(jué)需要知識(shí)和經(jīng)驗(yàn)的積累羽资,更需要對(duì)經(jīng)驗(yàn)的“反芻”淘菩。
【另一個(gè)要素是“錯(cuò)誤是什么”】
有人會(huì)說(shuō),“錯(cuò)誤是什么”不是明擺著的嗎屠升?看完下邊這個(gè)例子潮改,他就能體會(huì)到“明擺著”只是一種奢望:
有一個(gè)Bug的標(biāo)題是:用戶打開某個(gè)界面時(shí),得到的人員列表不符合預(yù)期腹暖。
Bug的細(xì)節(jié)描述是:當(dāng)用戶打開應(yīng)用程序的一個(gè)界面時(shí)汇在,得到了一個(gè)如下這個(gè)不符合預(yù)期的人員列表:
002 B先生
003 C小姐
001 A先生
而期望值是:
001 A先生
002 B先生
003 C小姐
理解錯(cuò)誤的壞結(jié)果
如果這個(gè)列表比較長(zhǎng),那么靠人眼去對(duì)比期望值和實(shí)際結(jié)果脏答,需要多花一點(diǎn)時(shí)間糕殉。不要小看多花的這一點(diǎn)時(shí)間,一方面殖告,人的大腦看到瑣碎的東西一定會(huì)比較累阿蝶。
另一方面,如果是產(chǎn)品經(jīng)理或項(xiàng)目經(jīng)理在看這個(gè)列表黄绩,他不可能去看每一個(gè)bug的細(xì)節(jié)羡洁,因?yàn)樗枰驹谝粋€(gè)更高的視角去看待整個(gè)項(xiàng)目。所以他看到這種模糊不清的問(wèn)題爽丹,要么多花一些時(shí)間去仔細(xì)理解這個(gè)bug筑煮,要么是認(rèn)為自己理解清楚了,從而讓這個(gè)bug在整個(gè)開發(fā)鏈條中的多個(gè)人之間流轉(zhuǎn)一圈粤蝎,最后bug仍然沒(méi)有解決真仲,這樣一來(lái),多花的時(shí)間就有些可觀了初澎。
導(dǎo)致理解錯(cuò)誤的淺層原因
下面就是一個(gè)導(dǎo)致bug無(wú)效流轉(zhuǎn)的“坑”秸应。
開發(fā)者看到這個(gè)結(jié)果對(duì)比的直覺(jué)是:一定是第一列的顯示順序錯(cuò)了。之后谤狡,開發(fā)者就去改代碼灸眼,改完之后,測(cè)試者又發(fā)現(xiàn)了另外一個(gè)bug:
當(dāng)用戶打開應(yīng)用程序的一個(gè)界面時(shí)墓懂,得到了一個(gè)如下列表:
001 A先生
002 B先生
003 C小姐
004 A小姐
而期望值是:
001 A先生
004 A小姐
002 B先生
003 C小姐
實(shí)際上只是因?yàn)樵谶@個(gè)列表中又加入一條數(shù)據(jù)而已焰宣,卻觸發(fā)了開發(fā)者改上一個(gè)bug時(shí)的理解錯(cuò)誤,導(dǎo)致修改bug的成本翻倍捕仔。
經(jīng)過(guò)分析匕积,終于得出結(jié)論:應(yīng)該按照第二列排序盈罐,而不是第一列!
這還只是一個(gè)最簡(jiǎn)單的例子闪唆,大部分人還是能一眼就能看出來(lái)盅粪,但是,實(shí)際的工作中遠(yuǎn)比這個(gè)情況復(fù)雜悄蕾,想不“中招”就需要去蕪取精的能力了票顾。
正確的做法是:
開發(fā)者看到這個(gè)問(wèn)題,如果邏輯清晰的話帆调,應(yīng)該能想到有很多種情況導(dǎo)致這種錯(cuò)誤奠骄,上文提到的只是其中的兩種情況,他想到之后要去找測(cè)試者確認(rèn)番刊,有時(shí)甚至要找到需求文檔編寫者和產(chǎn)品經(jīng)理含鳞。
導(dǎo)致理解錯(cuò)誤的深層原因
表面上看起來(lái)這是個(gè)溝通問(wèn)題,其實(shí)不是芹务,這是因?yàn)椋簻y(cè)試者確切地知道需求是什么蝉绷,只是他認(rèn)為沒(méi)必要寫出來(lái),而開發(fā)者也認(rèn)為自己理解對(duì)了枣抱,也就沒(méi)必要再問(wèn)熔吗,導(dǎo)致了bug的無(wú)效流轉(zhuǎn)。當(dāng)大家都認(rèn)為沒(méi)有分歧時(shí)沃但,自然就不需要溝通磁滚,所以邏輯能力的欠缺才是深層原因!
解決邏輯能力欠缺的有效方法有兩個(gè):長(zhǎng)期來(lái)看宵晚,應(yīng)該去學(xué)習(xí)垂攘、思考。短期來(lái)看淤刃,用最準(zhǔn)確的語(yǔ)言去描述晒他,例如上文的bug描述應(yīng)改為:用戶打開某個(gè)界面時(shí),得到的人員列表應(yīng)該按照第二列排序逸贾。
導(dǎo)致理解錯(cuò)誤的知識(shí)原因
行文至此陨仅,如果讀者認(rèn)為這就是“第二個(gè)要素:錯(cuò)誤是什么”的全部了,“也不過(guò)如此嘛”铝侵,那有時(shí)還會(huì)掉到下邊這個(gè)更深的“坑”里:
對(duì)于使用分布式數(shù)據(jù)庫(kù)的系統(tǒng)灼伤,程序中傳給數(shù)據(jù)庫(kù)的SQL中,如果沒(méi)有包含order by咪鲜,那得到數(shù)據(jù)的順序是不會(huì)得到保證的狐赡!因?yàn)榉植际綌?shù)據(jù)庫(kù)為了提高性能,是用并發(fā)的方式從多個(gè)數(shù)據(jù)庫(kù)節(jié)點(diǎn)獲得數(shù)據(jù)疟丙,既然是并發(fā)颖侄,那就無(wú)法確定哪個(gè)節(jié)點(diǎn)的數(shù)據(jù)先傳到鸟雏。
如果開發(fā)者沒(méi)有這個(gè)知識(shí),或即便有這個(gè)知識(shí)而忘記了在這里運(yùn)用它览祖,就會(huì)掉到上邊這個(gè)“深坑”里孝鹊。結(jié)果就是:讓一個(gè)bug衍生出另外一個(gè)bug,再衍生出第三個(gè)bug展蒂,讓這些“臭蟲”在開發(fā)者又活、測(cè)試者、項(xiàng)目經(jīng)理玄货、產(chǎn)品經(jīng)理皇钞,甚至客戶那里轉(zhuǎn)啊轉(zhuǎn)悼泌,創(chuàng)造出的GDP是很多了松捉,但都是無(wú)價(jià)值甚至是負(fù)價(jià)值的GDP。
作于2018-3-10