從今天的文章開始,會開始注重在一些技術的層面,不過,雖然都是技術相關的知識,我還是希望能讓大家了解到為什麼要用這項技術或概念,才能真正的激勵讀大家開始看中和實踐這些事
所以,我後續系列的文章,都還是會採用前述說到的黃金圈思維(Golden circle),也就是 Why -> How -> What 的方式來撰寫,讓大家可以真正了解和應用這些軟體上的概念
所以呢,本系列的文章就會從 "為什麼要測試" 的主題開始,希望讓大家可以更瞭解我們測試的目的
而為了讓 "為什麼要測試" 這件事更有說服力,我會利用 Google 的經驗跟大家說明「為什麼要做測試」、「測試的重要性」
畢竟 Google 的工程師是被認為最優秀的工程師的所在地之一,那這些聰明人的思維我們當然要來效仿一下啦~
那以下就會以 Sofeware engineering at Google、單元測試的藝術,和一些我的想法和經驗來述說「為什麼要做測試」
先來講一些歷史,讓大家感覺一下測試到底為什麼那麼重要
其實在早時,連 Google 都不認為測試是重要的,他們總是靠聰明人把軟體寫正確,直到有一個核心產品受到了最嚴重的影響,人稱 Google Web Server,簡稱 GWS
GWS 是負責為谷歌搜尋查詢提供服務的網路伺服器,它對谷歌搜尋的重要性就像空中交通管制對機場的重要性一樣。早在 2005 年,隨著專案規模和複雜性的增加,生產效率急劇下降。上線的版本越來越多的錯誤,推送的時間也越來越長。團隊成員在對服務進行修改時信心不足,往往是在功能停止工作時才發現有問題。(有一次,超過80%的生產推送包含了影響使用者的bug,不得不 rollback )
為了解決這些問題,GWS 的 Tech lead 決定建立一項由工程師驅動的自動化測試策略。作為這項策略的一部分,所有新的程式碼修改都需要包括測試,而且這些測試將被持續執行。在實行這一策略的一年內,緊急推送的數量下降了一半。儘管該專案每季度都有創紀錄的新改動,但還是出現了這種下降。即使面對前所未有的增長和變化,測試也給谷歌最關鍵的專案之一帶來了新的生產力和信心。如今,GWS 幾乎每天都有數萬個測試和釋出,幾乎沒有客戶可見的故障
在書中,給我們一個重要啟示
你不能僅僅依靠程式設計師的能力來避免產品缺陷。即使每個工程師只是偶爾寫一些bug,當你有足夠多的人在同一個專案上工作時,你也會被不斷增長的缺陷列表所淹沒
想象一下,一個假設的100人的團隊,其工程師非常優秀,他們每個人每月只寫一個bug。而這群了不起的工程師在每個工作日仍然會產生5個新的bug
更糟糕的是,在一個複雜的系統中,修復一個錯誤往往會導致另一個錯誤,因為工程師們會適配已知的bug並圍繞它們編寫程式碼
所以,不要妄想只靠優秀的程式設計能力來完成軟體上的任務,在我剛進公司時,就算身邊都是優秀的資深工程師們,我的經理卻跟我說,產品總是會有 bug 的,就算你再有自信自己做得很好,尤其當你的產品有一定的規模,但是,我們可以透過測試,盡可能的大幅降低可見的 bugs,讓產品持續健康的成長
在 Sofeware engineering at Google 一書中,提到了做測試能帶來非常多的好處,我們就來簡單介紹一下
正如我們所想的那樣,經過測試的程式碼在提交時有更少的 bug。重要的是,它在整個產品的生命週期中也有較少的缺陷,大多數缺陷在程式碼提交之前就會被發現
在谷歌,一段程式碼在其生命週期內預計會被修改幾十次。它將被其他團隊甚至是自動程式碼維護系統所改變。一次寫好的測試會繼續帶來紅利,並在專案的生命週期中防止昂貴的缺陷和惱人的除錯過程。對專案或專案的依賴關係的改變,如果破壞了測試,可以被測試基礎設施迅速發現,並在問題被發佈到生產中之前回滾
有了健康的自動化測試,團隊可以放心地發布新版本
所有的軟體變更。具有良好測試的團隊可以滿懷信心地審查和接受專案的變更,因為他們的專案的所有重要行為都得到了持續驗證。這樣的專案鼓勵重構。在保留現有行為的情況下,重構程式碼的變化應該(最好)不需要改變現有的測試
我覺得這件事非常重要,尤其當團隊產品在做 Code scan,或遇到 ISO audit 迫不得已需要升級套件版本時,就會擔心產品是不是會 crash,導致我們又要花非常多的時間修補,但有了測試,我們就不會遇到那麼多的問題,且讓每次新功能的開發和推送更有信心
軟體文件是出了名的不可靠。從過時的需求到缺失的邊緣案例,文件與程式碼的關係很脆弱,這很常見。清晰的、有針對性的測試,一次行使一個行為的功能是可執行的文件。如果你想知道程式碼在某一特定情況下做了什麼,看看該情況的測試。更好的是,當需求發生變化,新的程式碼破壞了現有的測試時,我們會得到一個明確的訊號,"文件 "現在已經過時了。請注意,只有在注意保持測試的清晰和簡潔的情況下,測試才能作為文件發揮最佳效果
根據我的經驗,我強烈的同意這段敘述,我自己也有撰寫軟體文件的習慣,希望在我們的產品開發都能詳細記錄清楚的流程、每個開發的細節、為什麼我們做這些決定,但是在公司,最被重視的還是功能的交付,所以我只能用非常有限的時間來撰寫文件,而且也常常會遇到開發流程變更的問題,我就需要定期更新這些文件,很難靠一己之力來維護文件,通常也非常少人願意幫忙撰寫和維護文件
如果我們有辦法撰寫「好的測試」,就會比這些文件可靠得多,且當我們更改功能時,也會被舊測試阻擋,告訴我們「你該更新你的測試囉」,讓測試扮演好的文件的角色
(我們可以透過 單元測試的藝術 一書中提到的 pattern 來撰寫好的測試,利用 U.S.E 來撰寫測試描述,利用 3A pattern 來撰寫測試程式,後續文章會再詳述介紹)
我自己的小撇步
當我們在研究 source code 時,既然知道測試可以當文件,我們可以利用測試程式來幫我們了解開源者的想法,讓我們可以更容易的瞭解 source code
在谷歌,所有的程式碼在提交之前都要經過至少一名其他工程師的審查。如果程式碼審查包括徹底的測試,證明程式碼的正確性、邊緣情況和錯誤情況,那麼程式碼審查員花在驗證程式碼是否按預期執行的精力就會減少。審查員可以驗證每個案例都有一個合格的測試,而不必費心費力地在程式碼中對每個案例進行解讀
我們可以藉由看 PR 的測試程式碼,來快速瞭解同事到底做了什麼功能,而且這些功能是「可信的」,因為已經有測試的驗證
為新程式碼編寫測試是鍛鍊程式碼本身的API設計的一種實用手段。如果新程式碼難以測試,往往是因為被測試的程式碼有太多的職責或難以管理的依賴關係。設計良好的程式碼應該是模組化的,避免緊密耦合,並專注於特定的責任。儘早修復設計問題往往意味著以後的返工更少
在單元測試的藝術也有提到,當你的程式碼不方便測試,其實你就要想想你的程式碼是不是需要重新設計,再更模組化一些
在指導新員工時,我們經常被問到,究竟哪些行為或屬性需要被測試?直截了當的回答是:測試所有你不想破壞的東西。換句話說,如果你想確信一個系統表現出一個特定的行為,唯一能確保它會表現出這種行為的方法就是為它編寫一個自動測試。這包括所有常見的可疑因素,如測試效能、行為正確性、可及性和安全性。它還包括不太明顯的屬性,如測試系統如何處理故障
我們對這一總體理念有一個名稱:我們稱之為碧昂斯規則。簡而言之,它可以被陳述如下。"如果你喜歡它,那麼你就應該對它進行測試"。碧昂斯規則通常由負責在整個程式碼庫中進行更改的基礎架構團隊參考。如果不相關的基礎設施變化通過了你所有的測試,但仍然破壞了你的團隊的產品,你就得負責修復它並增加額外的測試
我當初看到這段時覺得非常有趣,Google 工程師們居然這麼跟的上流行,我也同時去找了一下這首歌,原來是碧昂絲一首叫做 Single ladies 的歌
歌詞內容差不多就是說前男友應該要好好珍惜她,其中有一段歌詞是:
If you liked it then you should have put a ring on it
假如你喜歡它的話,那麼你早該為它戴上戒指
就是說,如果我們喜歡一個女孩,就應該好好愛護他,同樣的道理我們也可以應用在產品程式碼上,「如果你喜歡他,那們你就應該對他進行測試」,表示對產品的責任心