拒絕修復(fù)bug的幾個正當(dāng)理由
當(dāng)某些功能沒有按預(yù)期運(yùn)行時,bug 就出現(xiàn)了。一次 bug 修復(fù)基本上是給現(xiàn)有代碼打一個補(bǔ)丁,它應(yīng)該解決當(dāng)前問題,以確?!冈摴δ堋拱搭A(yù)期運(yùn)行??墒?,這個補(bǔ)丁修復(fù)了一個地方,卻常常破壞了很多地方。我相信有必要時不時地拒絕 bug 修復(fù),并要求其作者重新制作補(bǔ)丁,以保護(hù)項(xiàng)目避免遭受更大的問題。根據(jù)我的經(jīng)驗(yàn),對于這種拒絕,存在著一些正當(dāng)理由。
《***犯罪(El Crimen Perfecto)》,導(dǎo)演:Alex de la Iglesia
它降低了代碼覆蓋率
這是非常常見的情景:在某個地方做了修改之后,單元測試在其它地方失敗了。bug 被修復(fù)了,但是一些可能不相關(guān)的單元測試開始報告失敗。由于壓力或僅僅因?yàn)槲覀兊膽卸瑁覀儧]有修復(fù)它們;我們只是刪除了測試、或?qū)⑺鼈儤?biāo)注為臨時的「跳過」。問題被解決了,構(gòu)建是干凈的,那么合并該補(bǔ)丁,收工,對嗎?錯!
即使我喜歡盡可能的偷工減料,但是對于這種問題,我不推薦你那樣做。
單元測試的存在恰恰是為了防止我們在面臨壓力時去破壞代碼。
很明顯,存在著一些情景,比如單元測試錯了,我們不得不刪除它們。對于這種情況,記得要創(chuàng)建新的單元測試。
還有一些情景,比如 bug 必須盡快修復(fù),保證系統(tǒng)線上運(yùn)行,而修復(fù)所有單元測試將花費(fèi) 1 個小時。這種情況強(qiáng)烈預(yù)示著,你已經(jīng)處于一種可怕的潛在情景,那就是產(chǎn)品中的測試覆蓋率。毫無疑問,我們不得不做出修復(fù),并在一段時間后讓測試通過。但是,對于這種情況,要確保團(tuán)隊(duì)在修復(fù)該 bug 之后的下一個任務(wù)就是糾正那些不好使的單元測試。我推薦閱讀 Michael Feathers 編寫的《修改代碼的藝術(shù)》,本書為該主題提供了正解。
Michael Feathers 編寫的《修改代碼的藝術(shù)》
它不會重現(xiàn)問題
有時候整個系統(tǒng)掛掉,僅僅是因?yàn)槟承写a里的一個小拼寫錯誤。明顯的 bug 修復(fù)就是刪除這個拼寫錯誤,如果我們關(guān)心項(xiàng)目質(zhì)量,這就不是項(xiàng)目期望我們做的操作。問題不在于拼寫錯誤,而在于缺乏單元測試,單元測試在部署階段是可以捕捉到這個錯誤的。
真正問題在于,測試代碼覆蓋率在代碼的這個部分是缺失的。單純地刪除拼寫錯誤,無助于整個項(xiàng)目。而且,我們在傷害它——我們正在掩蓋真正的問題。
不管問題多么小、不管其表現(xiàn)形式是多么地迷惑人,bug 修復(fù)必須包含可以首先重現(xiàn)該 bug 的額外測試。沒有這樣的測試,所謂的 bug 修復(fù)只是在浪費(fèi)項(xiàng)目的金錢。
進(jìn)一步講,沒有重現(xiàn)問題的單元測試,就無法保證 bug 修復(fù)不會帶來更多的 bug。我甚至敢說,我們的 bug 修復(fù)越多,引起的熵【注1】就越高。減少這種不確定性的唯一方式就是用單元測試覆蓋代碼。沒有測試,bug 修復(fù)將給代碼庫帶來更多的無序。
它太大了
bug 修復(fù)不是功能;它們必須小而專注。在修復(fù) bug 時,引入了某些重構(gòu),這是程序員自我陶醉時經(jīng)常要犯的錯誤。結(jié)果,補(bǔ)丁大得難以理解。我不是反對重構(gòu);重構(gòu)對于項(xiàng)目非常重要,屬于積極的舉動,但要在 bug 被修復(fù)、合并之后,專門來做重構(gòu)。
請?jiān)谛迯?fù) bug 的時候,不要重構(gòu)代碼!
創(chuàng)建一個新的單元測試,重現(xiàn) bug,并提交。在現(xiàn)有的代碼庫里修復(fù) bug,不管它是多么丑陋。創(chuàng)建新 bug,要求團(tuán)隊(duì)改善丑陋代碼庫的狀況。如果感興趣,就把這些 bug 分配給你自己?;蛟S其他人只是對修復(fù)它們以及重構(gòu)代碼感興趣。不過所有這些都會在其它的 pull request 里發(fā)生,也帶著新的代碼審查和新的合并。
修復(fù)那些糟糕的代碼,和懶惰、不愿意沒有關(guān)系。這是一項(xiàng)紀(jì)律,比良好意圖更加重要。
它不只解決一個問題
每次總是修復(fù)一個問題——就這么簡單,沒有例外。當(dāng)一個 bug 修復(fù)的補(bǔ)丁包含了修復(fù)多個問題的代碼修改時,就很難理解哪個問題被測試到了,哪個是可重現(xiàn)的、以及它們彼此有何關(guān)聯(lián)。把多個 bug 修復(fù)整合到一次 pull request 是一種非常糟糕的實(shí)踐。
不管這次修復(fù)多么簡單,要確保它和其它修復(fù)分開。逐個審查代碼、測試以及合并。這也增加了追溯代碼修改的便利性,很容易理解誰做的此次修復(fù)、誰審查的代碼、以及什么時候被合并(和部署)。
-
注1:在信息論中,熵是接收的每條消息中包含的信息的平均量,又被稱為信息熵、信源熵、平均自信息量。這里, 消息代表來自分布或數(shù)據(jù)流中的事件、樣本或特征。(熵***理解為不確定性的量度而不是確定性的量度,因?yàn)樵诫S機(jī)的信源的熵越大。)https://zh.wikipedia.org/wiki/%E7%86%B5_(%E4%BF%A1%E6%81%AF%E8%AE%BA)