持續整合
個人實踐主幹開發,團隊實踐持續整合
— Agile Steve Smith持續整合——如同定義
多年來,不論是使用哪一種分支模型,持續整合已經被一部份的軟體社群接受為一個用來監看程式碼倉庫的變化並且驗證其正確性的常駐程式。
然而,最初的目的是專門為開發團隊提供單一整合點的驗證。並且每天進行一次甚至更多次。這個想法是讓開發者自己去養成習慣,確保每天提交到共享位置的程式品質是足夠高的,並且讓持續整合的伺服器每晚進行驗證。
我們今天所知的持續整合是由 Kent Beck 所倡導,做為他在九十年代中期包含在「極限開發」(Extreme Programming) 中的實踐之一。可以肯定的是,在 1996 年,在著名的 Chrysler Comprehensive Compensation System(C3) 專案中,Kent 讓所有開發者都體驗和享受這種方法論——包括持續整合方面。該專案的語言是 Smalltalk,單一整合點是一個 Smalltalk image(一種比今天「僅僅」程式碼控制系統更先進的技術)。
因此,根據定義,持續整合的意圖幾乎與在其他地方出現的主幹開發完全相同。主幹開發並沒有直接或間接提到持續整合常駐程式,但如今兩者之間存有重疊之處——圍繞簡單分支模型(以及一堆技術)的安全網非常有價值。
Martin Fowler 與 Matt Foemmel 在 2000 年的一篇文章中提到了持續整合(重寫於 2006 年) ,而 ThoughtWorks 的同事們隨後建立了當時主導的 “Cruise Control”(在 2001 年初)。Cruise Control 將持續整合配置與下一個建置腳本放在一起,這樣做是正確的。
整合:人為行為
需要注意的是,開發者在提交程式碼之前運行的建置腳本與持續整合服務使用的腳本完全相同(請參閱下文)。建置過程被分解為多個步驟,以確保與開發者以及團隊成員之間的溝通簡潔清楚。經典的步驟包括:編譯產品程式碼、編譯測試程式碼、單元測試、服務測試與功能測試。最後兩項是整合測試的一部分。
如果建置在開發者的個人電腦上通過了,並且程式碼與團隊所看到的主幹版本(HEAD)保持同步,那麼開發者就可以提交工作(對於 Git 來說是提交和推送)。具體提交到何處取決於團隊採用的工作方式。一些較小的團隊可能會直接推送到主幹,有些甚至可能一天多次進行推送(請參閱直接提交到主幹)。較大的團隊可能會推送到一個提交修改審查系統,或者使用短期功能分支,儘管這可能會影響開發速度。
持續整合服務: 機器人驗證人為的活動
每個大於三人的開發團隊都需要一個持續整合常駐程式來保護程式碼倉庫受壞的提交和時間錯誤的影響。團隊已經設計了可以快速執行的建置腳本。這應該從編譯到功能測試(也許在多個層次上利用模擬)和打包都適用。然而,不能保證開發者在提交之前運行建置腳本。持續整合常駐程式透過在提交後驗證提交來履行這一角色。企業可能會搭建了一個更大規模的持續整合技術架構,以便跟上整個團隊的提交或推送,或是使用批次提交,使用更少的計算資源來執行追蹤和驗證工作。
Radiator
一種流行的 Radiator 風格視覺化指標是以左至右排列的一系列綠色(通過)或紅色(失敗)的圖標或按鈕,並配有適當簡短的標題:
如果開發者在同一個地方,應該把儀表板顯示在電視牆上。也應該提供可以直接從儀表板發送通知信的功能。
快速建置通知
從提交到「這個提交讓建置失敗」之間,通知消耗的時間很重要。這是因為在建置中斷的情況下,隨著額外的提交被推送到分支,修復問題的成本會增加。我們希望減少其中一個面向是從分支建置被破壞到修復的距離(參考五分鐘概述)。
流水線——進階閱讀
註記: 持續整合流水線在《Continuous Delivery》 這本暢銷書中有更詳細被描述與說明。該書籍還包含許多受精實(lean)所啟發的概念,適合那些力求更進一步的團隊。
進階的持續整合議題
持續整合服務是按提交建置還是按批次建置?
直接提交或是推送到共享主幹對於每天僅有少量提交的團隊可能是可以接受的。對於只有少數開發者且彼此信任在提交之前在其個人電腦上嚴謹執行的團隊來說,這也是可以接受的(就像在 90 年代的所有人都一樣)。
在持續整合伺服器上設置單執行緒進行建置和通過或是失敗通知週期,有時會導致持續整合作業中的批次處理。對於小團隊來說,這不是一個大問題。批次處理是指一次建置驗證兩個或更多的提交。對於分析兩個或三個提交中導致失敗的是哪一個並不困難。你可以放心相信這一點,因為這兩個提交很有可能位於基準程式碼的不同部分,幾乎從沒有交集。
然而,如果團隊更大,每天有更多的提交,那麼將不正確或是有問題的內容推送到主幹可能會對團隊造成干擾。理想上如果能夠讓持續整合伺服器針對每個提交獨立處理是最好的方式。如果持續整合伺服器是使用單執行緒的方式處理驗證工作,則有可能處理驗證的速度會趕不上提交的速度。
控制器以及持續整合架構的代理處理程式
更加進階的持續整合伺服器設定具有一個單一的控制器與許多的代理處理程式,能夠讓建置工作能夠平行處理。這比基礎的設置還要投入更多的資源,但隨著現代持續整合技術和服務的演化,這越來越容易實現。
例如 Docker 等技術使團隊能夠擁有與測試目的相符的完整小型正式環境。
測試永遠不會錯誤地變綠色
撰寫良好的測試,有傳言說在 2000 年代初期,有些測試套件的單元測試通過率為 100%,但完全沒有做任何狀態的檢測。
有些團隊會專注於在達到 99% 的自動化檢測功能正確性。你可能會注意到,對於一個並行由持續整合產生出來的臨時測試架構,頁面的回應時間大約是 500 毫秒,而實際上在正式環境的目標時間是 100 毫秒。你的功能測試將不會捕捉到這個失敗——這將會通過功能測試。如果你也有非功能性測試(那 0.1% 的狀況),那你有可能會捕捉到這個問題。也許將這樣的非功能性自動化測試移至後續的流水線階段是最好的,而在這個彈性(暫時的)持續整合架構下可以快速、簡單且並且經常運行多個功能性測試,你會感到滿意。
有一句話這樣說:測試永遠不會錯誤地變成綠色。反過來說,一個測試很常失敗但在正式環境程式碼卻是驗證正確。品質分析自動化工程師永遠在修復少量不穩定的測試。
一個經常紅色或是失敗的持續整合建置,或是一個消耗整晚的測試當天所有一切的持續整合工作並且總是具有一定比例的失敗,將會將低持續整合驗證的價值。
一個定期的持續整合建置透過某個定義完整,妥善撰寫並且除非具有問題之外都是綠色是非常有價值的。
一旦你達到值得信賴且總是綠色的狀態,這將會很自然去儘可能運行持續整合。
持續整合應該在提交變更前或是後執行?
對於損壞或是錯誤(比如說是格式錯誤)或是真正的損壞而言,在提交變更之後發現是不理想的。修復損壞讓其他團員只能觀望或是等待是一個降低團隊生產力的不好作法。
黃色的部份代表自動化步驟。紅色代表有可能讓所有人建置損壞。
註:對於直接提交或是推送變更到共享主幹作法,程式碼審查與持續整合驗證能夠同時進行。不過,最可能的情況是持續整合常駐程式驗證完程式品質後再來進行審查。
更好的設置是在提交進入主幹供所有人查看之前進行程式碼審查和持續整合驗證:
最好的方式是在提交的變更進入主幹之前執行程式碼審查與持續整合驗證。基於時間差的關係仍然有可能有發生錯誤的機會,因此持續整合驗證需要在提交的變更進入主幹之後再度執行一次,雖然在第二次建置失敗的機會很小,當發生建置失敗時自動恢復或是回滾並且發送通知是最佳處理方式。
今天的標準
高效率的團隊具有持續整合伺服器,可以避免主幹被破壞。這代表在提交的變更進入主幹之前都會被驗證,整個團隊的人都可以安心的對主幹進行更新或同步以及拉取最新的提交。
要解決的問題是,當提交變更到主幹速度太快時,無法在建置失敗時自動回復到原本成功的狀態。在 Google,每 30 秒就有一個提交會進入主幹。很少有持續整合技術(與程式碼版本管理系統)可以跟上這種速度,而不是批次處理(在某種程度上)。你將會停止整個產線太多次導致人們無法理解一連串失敗建置的意義,而其中只有一兩個是真正的失敗建置,而不是因為過短時間提交導致的失敗。
重新建立在一個最新建置成功提交加上一個提交的虛擬 HEAD 來驗證這個提交與其他 20 個在十分鐘獨立提交的變更並不難,但這需耗費大量的計算資源。最好的方式是把等待驗證的提交集中整理到一個地方,這個地方放置的提交都是緊隨著上一個成功建置的提交但還沒放入主幹。
這個地方有一個名字——分支(或是在 GitHub 中所謂的一個複製出來的分支)。這是最適合用來在自動合併提交到主幹之前執行持續整合驗證提交變更的地方(如果你希望在程式碼審查通過後做自動合併)。
新的問題是如何防止這個短期功能分支演化成一個由六人以上的開發者處理由於某些因素無法完成的長期功能分支並且想要合併回主幹。現有的工具無法做到這一點,但如果你可以在建立分支時有一個倒計時或計數器,以強制執行其「暫時」的意圖,那將是很酷的。
有關於高效率的提交變更與持續整合驗證的議題,可以參考 變革推動者 - 自家開發的持續整合(CI)與工具 這篇文章。請注意到在文章中沒有設置臨時分支來支持這一點。
業界持續整合常駐程式的分歧
ThoughtWorks 被委託進行了一項調查——「沒有人知道該如何去定義持續整合或是持續交付」。不幸地是,除了主幹開發之外這項假設已經在所有相容於持續整合的分支模型上證實為真。他們的首席科學家 Martin Fowler 在 “Semantic Diffusion" 這篇文章有談到了這一普遍影響。
Martin 還特別寫到使用多個活躍分支模型的團隊為了其中一個分支或是全部分支設置了一個持續整合常駐程式,使得分支能夠具有自我回復的功能:在「Continuous Integration Certification」中提到了這一效果,其中還包括了「常駐式持續整合」的描述。
這個網站關於持續整合以及主幹開發的使用
基於其他流行的非主幹開發分支模型也受益於持續整合伺服器持續監測並且驗證提交的變更。所以本網站也將會把強制限制變更提交到單一程式碼控制分支的練習稱為主幹開發。現在有許多可用的持續整合的技術與服務可以讓團隊來使用。有些是免費,有些是開源。有些則需要儲存關於持續整合程式的設定在版本控制系統上,另外有些則是儲存再其他地方。為了更方便能夠做到為發布建立分支,最好的方法是相關持續整合程式的設定儲存在同一個分支。
持續整合伺服器或常駐程式的實作
- Jenkins 商業服務, 由 Jenkins 開源 - 可以在本機安裝
- Travis-CI - 雲端服務
- Circle-CI - 雲端服務
- ThoughtWorks' Go CD - 雲端服務以及可以在本機安裝
- Codeship - 雲端服務
- Atlassian’s Bamboo - 可以在本機安裝
- JetBrains' TeamCity - 可以在本機安裝
- Microsoft’s TFS platform - 可以在本機安裝(被建置在一個大平台上)
- Codefresh - 雲端服務,可以在本機安裝以及混合型(自行配置自己的執行程式)安裝
特別注意的是,對於 Jenkins,可以使用 Pipeline DSL 腳本(或 Groovy) (原名 Workflow),或者你可以使用 GroupOn 的 DotCI 來配置設定來驗證以及建置在版本控制系統中的每個提交更新。
其他參考資料
10 Sep 2000, MartinFowler.com Article |
Continuous Integration - original version |
18 May 2006, MartinFowler.com Article |
Continuous Integration |
18 May 2015, Hangout Debate |
Branching strategies and continuous delivery |
02 Sep 2015, Conference Presentation |
The Death of Continuous Integration |