怎麼減少程式設計中的 bug?

池建強發表於2016-02-18

  為什麼要程式設計?因為程式碼沒在那裡。創造一個世界是如此讓人著迷,Linux 的創始者 Linus 這樣表述對程式設計的喜愛之情:

對於喜愛程式設計的人來說,程式設計是世界上最有趣的事,比下棋有趣得多!因為你可以自己制訂遊戲規則,而你制定什麼樣的規則,也就會隨之出現與此規則相符合的結果。

在電腦世界中,你就是創世者,你對所發生的一切擁有最終的控制。

你可以建築一個這樣的房子,有一個活板門,既穩固又實用。但是每個人都可以看出一個僅僅以堅固實用為目的的樹上小屋和一個巧妙地利用樹本身特點的美妙小屋之間的差異。這是一個將藝術和工程融為一體的工作。程式設計與造樹上小屋有相似之外……

  每個熱愛程式設計的人都在編寫程式碼的過程中享受著創造的樂趣,但是,伴隨著編碼的快感,bug 總是如影隨形,開發無止境,bug 隨身行。bug 是每個程式設計師沒法繞開的障礙,它們就在那裡,修復一個,增加一個,似乎永不減少,永遠存在。

  遭遇 bug 的時候,理性的程式設計師會說:這個 bug 能復現嗎?
  自負型:這不可能,在我這是好好的。
  經驗型:不應該,以前怎麼沒問題?
  幻想型:可能是資料有問題。
  無辜型:我好幾個星期都沒碰這塊程式碼了!
  樂觀型:只需要改一行程式碼,不會影響其它程式的。
  實踐型:你重啟一下服務試試。

  無論你是哪種型別的程式設計師,遭遇 bug,內心都是崩潰的,尤其是產品經理或測試人員在使用或測試產品的過程中抓到你的一個 bug 之後那種如獲至寶的表情和歡呼聲,會讓我們的心情久久不能平靜。於情於理,防患於未然,減少程式設計中的 bug,對產品和程式設計師,都是最好的結果。

  能不能一次編寫出沒有 bug 的程式呢?一般來說,並不能,除非你寫一輩子 Hello World。我見過一些天才的程式設計師,他們差不多能做到這一點。接到任務之後,思考,冥想,在筆記本上畫出資料結構或某個演算法片段,腹稿打的差不多了就開始程式設計,用 Vim、Emacs 或 IDE 工具,大部分時候能夠一氣呵成,然後構建程式碼,構造測試資料,執行程式,在反覆除錯中修復幾個程式設計過程中沒有考慮到的問題,就可以提交到程式碼庫了。他們的程式碼交給測試和其他開發者,少有人能挑出 bug,因為他們對程式碼有敏銳的感覺,能夠在別人忽略的地方發現程式碼的壞味道,並給出巧妙而優雅的解決方案。他們是天生的程式碼創造者,這樣的人往往效率高而且少有錯誤,以至於會被一些平庸的團隊忽略,因為技術領導總是會下意識的去關注那些最容易出事的環節,但這些人才是團隊真正的脊樑,不是那些四處救火者。如果你擁有這樣的程式設計師,就算撿到寶貝了,要好好珍惜。

  我不是天才的程式設計師,但在年輕時大量產出程式碼的時候,差不多也能做到類似的效果。沒什麼好的辦法,只能下笨功夫,我會在編碼之前儘可能把所有的可能性都想清楚,然後認真做好設計。我常常在工作時間完成程式碼的編寫,下班後帶著筆記本回家逐行 Review 自己的程式碼,對著設計圖檢查是否處理了各種異常和邊界條件,並先於測試人員對自己的程式碼進行白盒測試和黑盒測試。另外,在程式設計方面我奉行不要在同一個地方摔倒兩次的原則,每次自己程式出現的 bug 案例,我都會記錄到 bug 庫裡,檢查程式碼的時候逐一對照,確保不會犯重複的錯誤。

  可能年輕的時候自尊心比較強,我難以忍受自己的程式被別人找出 bug,於是偷偷花費了兩倍的時間來保證程式碼的質量,以至於團隊的人認為我一次就能編寫出高質量的程式碼。現在看來,我當時是個錯覺製造者。

  所以,減少 bug 的第一步,是提升自己的程式設計師素養,努力不給自己和別人找麻煩。

  另外,團隊協作也很重要,前期的技術方案和設計評審、程式碼審查,對減少一些重大的錯誤和弱智的 bug 都非常有好處。

  與幾個有經驗的程式設計師一起評審一個技術方案,常常會發現一些重大的問題,比如為什麼用快取,為什麼做持久化,高併發下怎麼應對,這部分設計支援執行緒重入嗎,這個迴圈為什麼設定成10分鐘,這個超時設定為什麼是60秒,傳輸協議加密了嗎,等等。很多方案可能會僅限於解決當前的問題,但有經驗的程式設計師卻能透過時間的重重迷霧,發現這個方案在未來某個時間點可能爆發的問題。這就是評審的力量。

  技術方案和設計評審一般是先於程式碼的,開始編寫程式碼了,Code Review(程式碼審查)就可以提上議事日程了。國內很多團隊的技術人員內心是牴觸程式碼審查的,他們常常想,在這個國家我們已經被審查的夠多了,就不要再自己審查自己了,然後很多 bug 就產生了。

  我和 Google、Facebook、Twitter、Airbnb 的中國工程師討論過 Code Review,他們覺得沒有程式碼審查是不可思議的。在這些公司的研發流程裡,Code Review 是必不可少的一個環節,只有別人幫你做了 Code Review 並在程式碼上「打了戳」,你的程式碼才能進入 Code Base。在 Facebook,如果你 Review 了別人的程式碼,如果那個人休假了,你就要接手他的程式碼,出了任何問題都要唯你是問。

  事實上,Code Review 才是真正的白盒測試,沒有經過程式碼審查,僅憑測試很難保證程式碼質量。測試通過了但沒有經過程式碼審查的程式碼仍然會出各種問題,這樣的案例比比皆是。只有當另外一個人讀了你的程式碼,並且表明能看懂時,這些程式碼才有真正有了鮮活的意義。程式碼審查的意義就是,在你的程式碼庫合進程式碼庫之前,至少有一個人讀過你的程式碼。

  很多人在做程式碼審查之前會調研大量的程式碼審查工具,就像一個人在跑步之前,要先準備好跑鞋、襪子、壓縮褲、壓縮上衣、鼻貼、眼鏡、口罩、導汗帶、魔術頭巾、各種手錶、冷卻噴霧、肌內效貼布……然後一個月過去了,你問他跑了幾次,他會很扭捏的告訴你,髕骨帶還沒有到!

  沒有工具一樣可以做程式碼審查,你只需要偏轉身體,在另一個程式設計師不忙的時候拍拍他的肩膀說,「來,看看我的程式碼,你能看懂嗎?我準備把它們提交到程式碼庫裡」。然後闡述你的思路,傾聽他的建議,並根據這次討論的結果決定,是修改一下,還是繼續提交到程式碼庫。

  不要小看這短短的20分鐘,它可能會幫你避免的一些隱藏的和弱智的 bug。

  很多團隊都是因為程式碼審查過程或工具過於複雜放棄了Code Review,典型的因噎廢食,其實使用 less、diff 和 git 等工具,基本上就可以做一次完整的程式碼審查了。如果你過於依賴工具和過程,那說明你並沒有抓住問題的核心。

  寫了這麼多,如何減少程式設計中的 bug 呢?不難,也不容易。對內,努力提高自己的程式設計師素養,不去浪費自己和別人的時間。對外,重視團隊協作,進行方案評審和程式碼審查。做到這兩點,你會發現,程式碼中的 bug 會越來越少的。

  沒有 bug 的程式碼,才是好程式碼!

相關文章