Civilization advances by extending the number of important operations we can perform without thinking.
— Alfred North Whitehead
核心概念#
在第一版《The Pragmatic Programmer》出版後,作者們想要創作更多幫助團隊開發軟體的書籍。他們決定從最基礎的開始:每個團隊都需要的最基本、最重要的元素,無論方法論、語言或技術棧如何。於是 Pragmatic Starter Kit 的概念誕生了,涵蓋三個關鍵且相互關聯的主題:
- 版本控制(Version Control)
- 回歸測試(Regression Testing)
- 完全自動化(Full Automation)
這是支撐每個專案的三條腿。
以版本控制驅動#
如同 Topic 19 Version Control 所說,你要把建構專案所需的一切都放在版本控制之下。這個概念在專案層級變得更加重要。
首先,它讓建構機器變成臨時的。建構機器和叢集可以在雲端按需建立為即時實例。部署配置也在版本控制之下,所以發布到生產環境可以自動處理。
在專案層級,版本控制驅動建構和發布流程。
Tip 89 - Use Version Control to Drive Builds, Tests, and Releases(使用版本控制來驅動建構、測試和發布)
也就是說,建構、測試和部署都由推送到版本控制的操作觸發,並在雲端的容器中建構。發布到預備環境或生產環境則由版本控制系統中的標籤來指定。發布因此成為日常生活中低儀式感的一部分——真正的持續交付,不依賴任何一台建構機器或開發者的機器。
無情且持續的測試#
許多開發者小心翼翼地測試,潛意識裡知道程式碼會在哪裡崩潰,避開弱點。務實的程式設計師不同。我們被驅使著現在就找到我們的 bug,這樣就不必忍受別人以後找到我們的 bug 的恥辱。
找 bug 有點像用網捕魚:我們用細網(單元測試)來抓小魚,用粗網(整合測試)來抓大鯊魚。
Tip 90 - Test Early, Test Often, Test Automatically(早測、常測、自動測)
我們希望在有程式碼後就開始測試。那些小 bug 有一個可怕的習慣——快速成長為巨大的食人鯊。所以我們寫大量的單元測試。
事實上,一個好的專案可能有比生產程式碼更多的測試程式碼。這些測試程式碼的投入是值得的,長期來看會便宜得多。
Tip 91 - Coding Ain’t Done ‘Til All the Tests Run(測試沒跑完,程式碼就沒完成)
測試的類型#
建構可能涵蓋幾種主要的軟體測試類型:
| 測試類型 | 英文名稱 | 說明 |
|---|---|---|
| 單元測試 | Unit Testing | 測試個別模組的程式碼,是所有其他測試形式的基礎。如果零件本身不能運作,組合在一起也不太可能順利運作 |
| 整合測試 | Integration Testing | 展示構成專案的主要子系統能協同工作。整合測試其實是單元測試的延伸——你只是在測試整個子系統如何遵守它們的契約 |
| 驗證與確認 | Validation and Verification | 使用者告訴你他們想要的東西,確實是他們需要的嗎?系統是否滿足功能需求? |
| 效能測試 | Performance Testing | 軟體是否在真實世界條件下——預期的使用者數量、連接數或每秒交易數——滿足效能需求? |
測試測試#
因為我們無法寫出完美的軟體,所以我們也無法寫出完美的測試軟體。我們需要測試測試本身。
寫完一個用來偵測特定 bug 的測試後,故意製造那個 bug 並確保測試會報警。這確保了測試在 bug 真正發生時能抓到它。
Tip 92 - Use Saboteurs to Test Your Testing(用破壞者來測試你的測試)
如果你真的認真看待測試,取一個原始碼樹的獨立分支,故意引入 bug,驗證測試會抓到它們。更高層級上,你可以使用像 Netflix 的 Chaos Monkey 這樣的工具來中斷服務,測試你的應用程式的韌性。
徹底測試#
即使你碰巧執行了每一行程式碼,那也不是全貌。重要的是你的程式可能有的狀態數量。狀態不等同於程式碼行數。
Tip 93 - Test State Coverage, Not Code Coverage(測試狀態覆蓋,而非程式碼覆蓋)
使用基於屬性的測試(property-based testing)技術來根據被測程式碼的契約和不變量生成測試資料,探索程式碼如何處理意外狀態。
收緊漁網#
測試中最重要的概念:如果一個 bug 穿過了現有測試的網,你需要加一個新測試,下次把它網住。
Tip 94 - Find Bugs Once(每個 Bug 只找一次)
一旦人工測試者發現一個 bug,那應該是最後一次人工測試者發現那個 bug。從那時起,自動化測試應該每次都檢查那個特定的 bug——毫無例外,無論多瑣碎,無論開發者怎麼抱怨說「噢,那不會再發生了」。因為它會再發生。
完全自動化#
現代開發依賴腳本化的自動程序。無論你使用簡單的 shell 腳本搭配 rsync 和 ssh,還是完整的解決方案如 Ansible、Puppet、Chef 或 Salt,就是不要依賴任何手動介入。
Tip 95 - Don’t Use Manual Procedures(不要使用手動程序)
人就是不像電腦那樣可重複。shell 腳本或程式會以相同的順序執行相同的指令,一次又一次。它本身就在版本控制之下,所以你可以檢查建構/發布程序隨時間的變化。
一切都取決於自動化。你無法在匿名的雲端伺服器上建構專案,除非建構完全自動化。你無法自動部署,如果有手動步驟參與。一旦你引入手動步驟(「就這一個部分而已…」),你就打破了一扇非常大的窗。
有了版本控制、無情測試和完全自動化這三條腿,你的專案將擁有堅固的基礎,讓你可以專注於真正困難的部分:取悅使用者。
相關章節#
- Topic 11,可逆性
- Topic 12,曳光彈
- Topic 17,Shell 遊戲
- Topic 19,版本控制
- Topic 41,測試以編碼
- Topic 49,務實的團隊
- Topic 50,不要切開椰子