網際網路時代,人人都在追求産品的快速響應、快速疊代和快速驗證。不論是創業團隊還是大中型企業,都在探索屬于自己的靈活開發、持續傳遞之道。fir.im 團隊也在全面實施靈活,并推出新持續內建服務
— flow.ci ,以幫助企業将開發測試流程自動化,更快速地傳遞産品。
4月15日,fir.im CTO 郭揚在“光環國際·2017靈活春季峰會”帶來了《靈活工程實踐的基石——持續內建》的技術實踐,從靈活方法論的角度分享了持續內建流程的品質實踐與 fir.im 團隊的 CI 技術實踐。演講實錄整理如下,希望能帶給你一些思考。
持續內建的概念出現在 2001 年,它其實是一個 XP 極限程式設計的工程實踐。那麼持續的是什麼,內建是什麼呢,非常簡單就是“一直不停地內建代碼”。
持續內建是把代碼頻繁的合并到主幹,通過自動建構的方式驗證軟體的品質,讓團隊快速的響應品質,快速的修複問題,快速的給客戶解決問題,快速地傳遞更好的軟體品質。
開發人員對下面的軟體開發場景很熟悉,比如:
場景一:開發了新功能,老功能産生新的 bug;
場景二:修好一個 bug,又産生其他 bug,甚至出現連環 bug;
場景三:出現的 bug 比較多,修改代碼要很謹慎,不熟悉的子產品一般不敢動,怕引起問題;
持續內建是如何緩解這個問題,Martin Fowler 大師曾經說過:
“Continuous Integration doesn’t get rid of bugs, but it does make them dramatically easier to find and remove.” — Martin Fowler
如上面所說,持續內建不能消除 bug ,但能更容易地發現 bug,更快速地修複,提升産品品質。那麼,持續內建能給我們帶來哪些價值?

從這張圖上可以看到,持續內建形成一個完美的閉環。通過持續的內建進行不斷地檢查、調整,同時,項目的透明性也得到了最大的展現。
這是一個常見的持續內建流水線:
在日常的開發過程中,程式員在本地送出代碼,持續內建流水線要求先做一次本地內建,在本地進行驗證後送出到源代碼管理倉庫中,之後源代碼工具會發出 webhook 觸發到持續內建系統中。當建構/測試完成後,會及時通過釘釘或郵件通知團隊(測試/研發/boss/産品經理)內建狀态,産品經理或項目經理收到通知後會在測試環境做驗收測試,這是一個比較完美的回報環。
假如測試通過驗收完畢後,持續內建系統會自動觸發部署到類生産環節或測試環境,或由專人手動部署到生産環境。
首先,代碼在遠端進行管理,每個人都會送出代碼,遠端的代碼倉庫會産生變化,是以在本地內建的時候要求進行代碼合并,以免出現分支沖突和代碼沖突。其次,不要依賴于持續內建系統給你結果,可能需要 30 分鐘的時間,不要讓開發人員等待,一定要先做本地內建。
再說一個送出的問題,我們盡量保證每一次送出都是一個完整的送出,也就是原子送出。
當代碼變動你想建立送出時,這個送出應該盡可能的小量,并且包含一個不可分割的特性(feature)、修複(fix)或優化(improved)。
拿每個産品開發都會遇到的 login 功能開發舉例,當填完的使用者名和密碼傳到資料庫,做完驗證後給使用者傳回一個結果。那什麼是一個原子送出?比如,送出驗證一個使用者名,這是一個完整的 feature ;驗證密碼是否符合格式(6位/8位),這也是一個完整的 feature ;當我驗證完使用者名和密碼後再傳到資料庫之後,查詢正确與否,這也是一個完整的 feature ;保證每次送出是一個完整的 feature 或修複了一個 bug,不要代碼寫成半截。
這裡講的是狹義的持續內建系統,通常的 CI 系統收到送出之後會觸發建構,建構會有資訊傳回比如 commit id 、commit 資訊、代碼變更等,收到代碼送出後會觸發自動建構,接着安裝依賴進行編譯,并觸發品質保證流程,也就是說自動化測試集。
自動化測試集包括代碼靜态檢查-單元測試-內建測試-驗收測試-性能測試,也會有壓力測試、回歸測試、monkey test等等一系列的測試。
接下來,我們具體講一下 fir.im 團隊如何進行持續內建實踐的。
fir.im 是一個内測分發平台,我們也做了一個持續內建 CI 産品-flow.ci。先來看一下我們正在使用的靈活環境:
Trello 看闆;
三個環境(類生産環境,測試環境,生産環境);
CI 工具(Jenkins/flow.ci)
我們在應用 3 個分支 —— master/develop/feature 分支,對 feature 命名會有一些要求,持續內建系統一定會回報到 trello 的 kanban 裡,是以對于 feature 分支我們也有這樣的命名 feature/fci-{card number} 以友善區分。
多分支如何做頻繁地持續內建?
master 分支,即線上分支。線上通常會有一些 hotfix, 任何産品都不可能避免線上的 bug ,這些 bug 需要在 master 分支進行修複,修複完成後持續內建系統會告知已上線,收到團隊回報,這些代碼會要求更新在 develop 分支上,之後所有團隊也會收到相關通知,那麼 feature 分支會有變化嗎?答案是肯定的,因為頻繁的內建可以防止代碼偏離。這就是我們多分支建構的政策。
還有一個政策——不同的分支不同的建構,持續內建系統跑完整個流程會很長,是以在 feature 分支頻繁度會比在本地建構要高一些,但是也沒有那麼高。為了保證持續內建系統能快速地收到回報,需要在 feature 分支上做一些定制的 workflow ,是以我們做了代碼靜态分析和單元測試。
當 feature 分支的 card 做完之後(scrum 中 done 的含義是指測試驗收完畢),內建到 develop 分支,develop 分支會自動部署到測試環境,會跑一個整個自動化測試集,為什麼是這樣的建構政策呢?
我們會做代碼 review ,當 feature 分支提 pr 到 develop 分支上,這樣 develop 分支的建構條件是:當收到 pr 之後,開始跑持續內建。假如部署完成整個測試跑過了産品經理驗收之後,沒毛病了,終于可以釋出了到 master 分支。
整個團隊的建構頻率可以看下這張圖:
本地內建的頻率非常高,遠端建構對應的是 feature 分支,會相對低一下。QA 環境對應的是 develop 分支的建構粒度。這樣的建構每天都會産生,是以做完之後不要積壓,一定要保持上線節奏。
kanban + scrum 結合的方式構成我們每日建構,這是一個整體的建構政策和上線頻率。
羅馬不是一天建成的,持續內建不是一開始就是完美的,每個開發者心中都有一個比較理想的自動化工作流——持續部署,大概會經曆這幾個演變階段:
最初階段:送出代碼-自動部署;
一般進階:送出代碼-代碼靜态分析-自動部署,最簡單先再加入代碼靜态分析;
進階進階:送出代碼-代碼靜态分析-自動化測試集-自動部署;
這是我們在用的自動化測試集,下面分别說下靜态檢查分析、單元測試、驗收測試、性能測試的具體用途。
每個公司都會有自己的代碼規範,代碼靜态分析工具能夠保證代碼品質,現成的工具有 java 的 FindBugs,ruby 的 rubocop 等。利用代碼檢查工具可以幫助團隊發現可重構的地方,輸出産出 – HTML 報告,也會發現潛在 bug;有的代碼檢查工具還會檢查出一些安全漏洞。
這三點是代碼靜态分析最重要的作用。這裡也分享一個 GitHub 位址,列出一些主流語言的代碼分析工具,可以參考一下。
這裡的 “單元測試”也加上了內建測試,畢竟創業公司要求資源最大化。程式員一定要寫單元測試,要克服開發的慣性思維,不要甩鍋。下面有一些注意的點和大家分享:
測試異常——不僅僅測試正确情況,也要主動測試異常;
減少耦合——保證獨立的可測試性;
功能分離——單元測試流太長,超過 20 分鐘的話要詳細想一下如何将功能單獨拆開,效率更高;
測試=需求——從測試代碼看到每個 class 是幹什麼的,同時出現 bug 時,第一時間是看測試,想想如何從測試中複現;
驗收測試是端對端的測試,從收到使用者名密碼到傳回結果,是不是我們所期望的一個值,這是驗收 Acceptance Test,其實是驗收了整個功能。代碼靜态檢查和單元測試,保證了我們如何怎麼去寫代碼,驗收測試保證了寫正确代碼,符合開發需求。
flow.ci 做驗收測試比較多,用的是比較流行的架構 Cucumber + Selenium WebDriver,目前支援 3 種資料庫,5 種 git 倉庫,7 種 開發語言跑在 docker 容器雲上,支援 iOS 建構跑在 mac 機器上,要保證這些排列組合正常運作,這是 flow.ci 做驗收測試最核心的價值。
其實,持續內建是一個工作流,當 push 代碼的時候才會 run 起來,但是 flow.ci 本身系統也有外部依賴的特殊性,會依賴一些第三方的 sevice(比如 GitHub/GitLab 等),驗收測試應該一直保持不斷地運作,也可以叫持續測試吧。因為我們永遠不能保證第三方的 api 會不會改變:)
我們的性能測試做的比較簡單,主要測試 api.因為 fir.im 做 app 的内測分發,我們需要性能測試保證 app 上傳下載下傳的正常穩定。性能測試是單使用者的,壓力測試是多使用者的,這是兩者之間的差別。
性能測試會有一些不确定性,有很多系統會産生緩存。flow.ci 的性能測試跑在 docker 上,是一個幹淨獨立的環境,需要讓系統預熱運作一下。Locust/JMeter/LoadRunner是目前比較流行的性能測試工具。
flow.ci 目前用的是 locust,可以參考一下。
我們認為一個好的持續內建系統也要做到項目進度的透明化,最傳統的方式是發送相關的郵件,但實質上有幾個人去看呢?為此我們采購了一個大的螢幕來解決這個問題,用來時刻提醒團隊的某個建構結果。當然也可以用閃爍燈或音頻的方式。
說到資料統計分析,整個 ci 流程跑下來産生的很多資料也非常有挖掘的價值。比如,對于代碼靜态分析有多少 Offence、Risk、Bug,對于單元測試有失敗率、測試覆寫率;對于驗收測試或性能測試有多少的失敗率,這些資料都有可能成為衡量一個程式員的标準。
本文轉自帥氣的頭頭部落格51CTO部落格,原文連結http://blog.51cto.com/12902932/1924585如需轉載請自行聯系原作者
sshpp