Allan Kelly

程式碼不會說謊,但可以自相矛盾#

程式碼不會說謊,但它可以自相矛盾。某些矛盾會導致令人困惑的「這怎麼可能運作?」的時刻。

Apollo 11 的故事#

在一次訪談中,Apollo 11 登月艙的首席設計師 Allan Klumpp 透露,控制引擎的軟體包含一個本應使著陸器不穩定的 bug。然而,另一個 bug 補償了第一個 bug,而該軟體在 Apollo 11 和 Apollo 12 登月任務中都被使用,直到兩個 bug 都未被發現。

互相補償的缺陷#

考慮以下情境:

  • 一個函式在應該回傳 false 時回傳 true,而呼叫端剛好忽略了回傳值的檢查——一切正常運作,直到有人加入了缺少的檢查
  • 一個儲存狀態為 XML 的應用程式,某個節點被錯誤命名為 TimeToLive 而非 TimeToDie——寫入端和讀取端都包含相同的錯誤,所以一切正常。但修復其中一個或新增另一個讀取程式,對稱性就被打破了

修復的困難#

當兩個缺陷互相補償而只產生一個可見的錯誤時,修復過程會變成一場噩夢:開發者找到一個缺陷並修復,但錯誤仍然存在(因為第二個缺陷);於是撤回第一個修復,找到並修復第二個缺陷,但第一個缺陷又浮現了;最終開發者已經排除了兩個正確的修復,正在尋找不存在的第三個修復。

這種問題不僅出現在程式碼中——也存在於書面需求文件中。錯誤可以像病毒一樣從一處傳播到另一處,程式碼中的錯誤恰好補償了文件中的錯誤。

甚至會傳播到使用者:當應用程式顯示 Left 但實際意思是 Right,使用者會學會相應調整行為。修復這個 bug 後,使用者反而需要重新適應。

單一錯誤容易發現和修復。真正棘手的是多重原因造成的問題,需要多處修改才能解決。容易修的問題往往被快速解決,而困難的問題則被擱置。對於這類互相補償的缺陷(sympathetic defects),沒有簡單的建議——唯有保持警覺、保持清醒的頭腦,以及願意考慮所有可能性。