日常的程式設計,從一個明確連結到客戶所要功能的任務出發,走到測試、走到實作、走到設計,最後走到整合。軟體開發的每一項活動,都被壓縮進每一段歷程(episode)裡。
這一章是 XP 心跳的故事——開發歷程:一位程式設計師實作一項工程任務(排程的最小單位),並把它整合進系統的其餘部分。
一段歷程的實況#
我看著手上那疊任務卡。最上面一張寫著「匯出季初至今的預扣稅額」。今天早上的站立會議上,我記得你說你已經做完季初至今的計算。
我問你(我假想的隊友)有沒有空幫忙做匯出。「沒問題。」你說——規則是:被請求協助時,你必須說「好」。我們就此成為結對程式設計的夥伴。
討論脈絡:我們花幾分鐘聊你昨天做的事。你談到你加的那些 bin、測試長什麼樣子,也許還提一下你昨天發現把螢幕往後推一英尺,結對程式設計會順暢一些。
釐清測試案例:
- 你問:「這個任務的測試案例是什麼?」
- 我說:「跑匯出站時,匯出記錄裡的值應該要和 bin 裡的值相符。」
- 你問:「哪些欄位必須被填入?」
- 我說:「不知道,我們去問 Eddie。」
我們打斷 Eddie 三十秒。他解釋了他所知道的、與季初至今相關的五個欄位。
先重構,再寫測試:我們去看既有匯出測試案例的結構,找到一個幾乎就是我們要的。只要抽出一個超類別,我們就能輕鬆實作自己的測試案例。我們做了這次重構,跑既有測試——全部通過。
我們注意到還有好幾個匯出測試案例可以享用剛做出來的超類別。但我們想先在任務上看到成果,所以只在待辦卡上寫下「回頭改造 AbstractExportTest」。
寫測試:因為超類別剛做好,新測試案例寫起來很容易,幾分鐘就完成。寫到一半我說:「我甚至已經看到要怎麼實作了,我們可以……」你打斷我:「先把測試案例寫完。」寫的過程中我們想到三個變化情境,你把它們記到待辦卡上。
我們寫完測試案例並執行。它失敗了——當然,我們還沒實作任何東西。「等等,」你說,「昨天我和 Ralph 早上在做一個計算器。我們寫了五個以為會壞掉的測試案例,結果第一次跑就過了四個。」
實作:我們對測試案例開起除錯器,看看手上有哪些物件可以運算。我寫程式碼(或你寫,誰的想法最清楚誰寫)。實作途中我們又注意到幾個該寫的測試案例,記到待辦卡上。測試案例通過了。
輪替與重構:我們接著下一個、再下一個測試案例。你注意到程式碼可以更簡單,試著向我解釋怎麼簡化。我一邊聽一邊實作覺得很挫折,於是把鍵盤推給你。你重構程式碼、跑測試案例,全過,接著實作了後面幾個測試案例。
過了一陣子,待辦卡上只剩「重整其他測試案例」。事情進行得很順,於是我們就順手把它們重整了,並確認完成後測試仍能通過。
整合:現在待辦清單空了。我們注意到整合機器沒人用,於是載入最新發布版,再載入我們的變更,然後跑所有測試案例——我們的新測試,加上其他每個人寫過的所有測試。有一個失敗了。「奇怪,我已經快一個月沒在整合時遇到測試壞掉了。」你說。沒關係,我們除錯、修好程式碼,再跑一次整套測試。這次全過。我們發布了我們的程式碼。
這段歷程告訴我們什麼#
以上就是完整的 XP 開發循環。請注意四件事:
- 結對進行——程式設計師成對地一起寫程式。
- 由測試驅動開發——先測試,後寫程式。測試沒全過,你就還沒完成;當所有測試都過、而且你想不出任何還會失敗的測試時,你就完成了這項功能的新增。
- 結對不只讓測試通過,也演化系統設計——變更不侷限於任何特定區域。結對為系統的分析、設計、實作與測試都增添價值,而且是在系統需要的地方增添。
- 整合緊接在開發之後——包含整合測試。