1. 程式人生 > >當你的系統依賴於某個bug...

當你的系統依賴於某個bug...

標題粗略看是有點違反常識的,bug通常是指某些程式碼存在問題導致系統沒有按照期望方式工作,應該是需要儘可能被修復的,這樣系統才會正常工作。但是,開發實踐中會發現在某些情況下,本來功能沒有問題,在你信心滿滿的修復了某個bug之後,某項功能反倒變成有問題了。這是怎麼回事呢?在bug fix本身沒有問題的情況,最可能的原因是你的某些上層模組依賴於這個被修復bug的行為,當bug修復之後,這個被依賴的bug行為不存在了,所以導致這些上層模組不工作。下面舉一個來自實踐中的真實的案例。

有一個函式isdigitstring,它負責檢查輸入字串是否是數字字串。我們在對這個函式做單元測試的時候,發現它存在一個明顯的bug。如果輸入字串為空,這個函式會判斷這個空字串為數字字串,很明顯這個判斷是不正確的。在單元測試中發現這種bug是非常鼓舞人心的,而且解決這個bug是非常容易的,只需要在函式裡面增加一個空字串的判斷處理即可。像預料的那樣,我們接下來應該是立即修復這個bug, 然後自豪的宣稱程式碼質量又得到了極大的改善。

意外的是某個資深的軟體工程師對此提出一個奇怪而強烈的意見,這個bug現在不能被修復!什麼?這是一個毫無疑問的低階錯誤,修復它看起來完全不存在side effect, 因為它看起來是如此的簡單和直接。作為合格的軟體工程師來說,我們的職責難道不是儘可能的發現bug和修復bug? 這位提出意見的工程師隨即解釋了他的理由,原來這個bug在不久前已經被發現,但是同時也發現存在這個bug的函式在程式碼中被大量使用,程式碼裡所有的現有呼叫者都已經假定空字串就是一個數字字串!所以,如果我們修復了這個bug, 所有呼叫這個函式的地方都會有問題(因為它們都依賴於這個錯誤的假定)。這個專案已經臨近結束,我們可以修復isdigitstring的bug, 但是我們基本上已經不能負擔修改此函式的caller程式碼的時間成本。也就是說,我們暫時最好的決定居然是不修復這個bug。很明顯在新的專案程式碼裡,我們必然會修復這個bug和修復所有的caller程式碼(不再依賴於錯誤的假定)。但是對一個低階錯誤bug的解決方案是"won't fix", 的確會令一個熱情的軟體工程師內心感覺到挫敗。

那麼經驗教訓是什麼呢?在專案早期就必須開始單元測試,否則在後期修復一個簡單bug的成本可能都會變得非常巨大;低層&公用的程式碼的修復成本通常會比較高;整體系統工作正常並不一定表示區域性模組不存在bug。