fir.im 持續集成技術實踐

互聯網時代,人人都在追求產品的快速響應、快速迭代和快速驗證。不論是創業團隊還是大中型企業,都在探索屬於自己的敏捷開發、持續交付之道。fir.im 團隊也在全面實施敏捷,並推出新持續集成服務 — flow.ci ,以幫助企業將開發測試流程自動化,更快速地交付產品。 這篇文章將以實際開發爲例,從敏捷方法論的角度來講解 CI 技術實踐與演變過程,大概分爲三個部分,希望帶給你一些參考。

fir.im

郭揚,fir.im CTO,曾就職於奔馳戴姆勒創新實驗室,Thoughtworks,索尼移動通信,網易等公司,擔任 DevLead,負責組建技術團隊,管理項目進度與項目風險,軟件及 DevOps 的架構設計、高併發條件下的性能調優、敏捷教練等工作。

持續集成做什麼

持續集成的概念出現在 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,更快速地修復,提升產品質量。那麼,持續集成能給我們帶來哪些價值?

fir.im

從這張圖上可以看到,持續集成形成一個完美的閉環。通過持續的集成進行不斷地檢查、調整,同時,項目的透明性也得到了最大的體現。

fir.im 如何進行持續集成實踐

這是一個常見的持續集成流水線:

fir.im

在日常的開發過程中,程序員在本地提交代碼,持續集成流水線要求先做一次本地集成,在本地進行驗證後提交到源代碼管理倉庫中,之後源代碼工具會發出 webhook 觸發到持續集成系統中。當構建/測試完成後,會及時通過釘釘或郵件通知團隊(測試/研發/boss/產品經理)集成狀態,產品經理或項目經理收到通知後會在測試環境做驗收測試,這是一個比較完美的反饋環。

假如測試通過驗收完畢後,持續集成系統會自動觸發部署到類生產環節或測試環境,或由專人手動部署到生產環境。

爲什麼要做本地集成

首先,代碼在遠程進行管理,每個人都會提交代碼,遠程的代碼倉庫會產生變化,所以在本地集成的時候要求進行代碼合併,以免出現分支衝突和代碼衝突。其次,不要依賴於持續集成系統給你結果,可能需要 30 分鐘的時間,不要讓開發人員等待,一定要先做本地集成。

如何做版本提交

再說一個提交的問題,我們儘量保證每一次提交都是一個完整的提交,也就是原子提交。

當代碼變動你想創建提交時,這個提交應該儘可能的小量,並且包含一個不可分割的特性(feature)、修復(fix)或優化(improved)。

拿每個產品開發都會遇到的 login 功能開發舉例,當填完的用戶名和密碼傳到數據庫,做完驗證後給用戶返回一個結果。那什麼是一個原子提交?比如,提交驗證一個用戶名,這是一個完整的 feature ;驗證密碼是否符合格式(6位/8位),這也是一個完整的 feature ;當我驗證完用戶名和密碼後再傳到數據庫之後,查詢正確與否,這也是一個完整的 feature ;保證每次提交是一個完整的 feature 或修復了一個 bug,不要代碼寫成半截。

持續集成系統

這裏講的是狹義的持續集成系統,通常的 CI 系統收到提交之後會觸發構建,構建會有信息返回比如 commit id 、commit 信息、代碼變更等,收到代碼提交後會觸發自動構建,接着安裝依賴進行編譯,並觸發質量保證流程,也就是說自動化測試集。

fir.im

自動化測試集包括代碼靜態檢查-單元測試-集成測試-驗收測試-性能測試,也會有壓力測試、迴歸測試、monkey test等等一系列的測試。

fir.im

接下來,我們具體講一下 fir.im 團隊如何進行持續集成實踐的。

fir.im 的敏捷環境

fir.im 是一個內測分發平臺,我們也做了一個持續集成 CI 產品- flow.ci 。先來看一下我們正在使用的敏捷環境:
fir.im

  • Trello 看板;
  • 三個環境(類生產環境,測試環境,生產環境);
  • CI 工具(Jenkins/ flow.ci

說一下 Git 分支管理

我們在應用 3 個分支 —— master/develop/feature 分支,對 feature 命名會有一些要求,持續集成系統一定會反饋到 trello 的 kanban 裏,所以對於 feature 分支我們也有這樣的命名 feature/fci-{card number} 以方便區分。

fir.im

多分支如何做頻繁地持續集成?

master 分支,即線上分支。線上通常會有一些 hotfix, 任何產品都不可能避免線上的 bug ,這些 bug 需要在 master 分支進行修復,修復完成後持續集成系統會告知已上線,收到團隊反饋,這些代碼會要求更新在 develop 分支上,之後所有團隊也會收到相關通知,那麼 feature 分支會有變化嗎?答案是肯定的,因爲頻繁的集成可以防止代碼偏離。這就是我們多分支構建的策略。
fir.im
還有一個策略—— 不同的分支不同的構建 ,持續集成系統跑完整個流程會很長,所以在 feature 分支頻繁度會比在本地構建要高一些,但是也沒有那麼高。爲了保證持續集成系統能快速地收到反饋,需要在 feature 分支上做一些定製的 workflow ,所以我們做了代碼靜態分析和單元測試。

當 feature 分支的 card 做完之後(scrum 中 done 的含義是指測試驗收完畢),集成到 develop 分支,develop 分支會自動部署到測試環境,會跑一個整個自動化測試集,爲什麼是這樣的構建策略呢?

我們會做代碼 review ,當 feature 分支提 pr 到 develop 分支上,這樣 develop 分支的構建條件是:當收到 pr 之後,開始跑持續集成。假如部署完成整個測試跑過了產品經理驗收之後,沒毛病了,終於可以發佈了到 master 分支。

整個團隊的構建頻率可以看下這張圖: fir.im
本地集成的頻率非常高,遠程構建對應的是 feature 分支,會相對低一下。QA 環境對應的是 develop 分支的構建粒度。這樣的構建每天都會產生,所以做完之後不要積壓,一定要保持上線節奏。 fir.im
kanban + scrum 結合的方式構成我們每日構建,這是一個整體的構建策略和上線頻率。

fir.im 的持續集成系統演變過程

羅馬不是一天建成的,持續集成不是一開始就是完美的,每個開發者心中都有一個比較理想的自動化工作流——持續部署,大概會經歷這幾個演變階段:

  • 最初階段:提交代碼-自動部署;
  • 一般進階:提交代碼-代碼靜態分析-自動部署,最簡單先再加入代碼靜態分析;
  • 高級進階:提交代碼-代碼靜態分析-自動化測試集-自動部署; fir.im

這是我們在用的自動化測試集,下面分別說下靜態檢查分析、單元測試、驗收測試、性能測試的具體用途。

Step 1. 靜態代碼分析

每個公司都會有自己的代碼規範,代碼靜態分析工具能夠保證代碼質量,現成的工具有 java 的 FindBugs,ruby 的 rubocop 等。利用代碼檢查工具可以幫助團隊發現可重構的地方,輸出產出 – HTML 報告,也會發現潛在 bug;有的代碼檢查工具還會檢查出一些安全漏洞。

這三點是代碼靜態分析最重要的作用。這裏也分享一個 GitHub 地址 ,列出一些主流語言的代碼分析工具,可以參考一下。

Step 2. “單元測試”

這裏的 “單元測試”也加上了集成測試,畢竟創業公司要求資源最大化。程序員一定要寫單元測試,要克服開發的慣性思維,不要甩鍋。下面有一些注意的點和大家分享:

  • 測試異常——不僅僅測試正確情況,也要主動測試異常;
  • 減少耦合——保證獨立的可測試性;
  • 功能分離——單元測試流太長,超過 20 分鐘的話要詳細想一下如何將功能單獨拆開,效率更高;
  • 測試=需求——從測試代碼看到每個 class 是幹什麼的,同時出現 bug 時,第一時間是看測試,想想如何從測試中復現;
Step 3. 驗收測試

驗收測試是端對端的測試,從收到用戶名密碼到返回結果,是不是我們所期望的一個值,這是驗收 Acceptance Test,其實是驗收了整個功能。代碼靜態檢查和單元測試,保證了我們如何怎麼去寫代碼,驗收測試保證了寫正確代碼,符合開發需求。

flow.ci 做驗收測試比較多,用的是比較流行的框架 Cucumber + Selenium WebDriver,目前支持 3 種數據庫,5 種 git 倉庫,7 種 開發語言跑在 docker 容器雲上,支持 iOS 構建跑在 mac 機器上,要保證這些排列組合正常運行,這是 flow.ci 做驗收測試最核心的價值。 fir.im
其實,持續集成是一個工作流,當 push 代碼的時候纔會 run 起來,但是 flow.ci 本身系統也有外部依賴的特殊性,會依賴一些第三方的 sevice(比如 GitHub/GitLab 等),驗收測試應該一直保持不斷地運行,也可以叫持續測試吧。因爲我們永遠不能保證第三方的 api 會不會改變:)

Step 4. 性能測試

我們的性能測試做的比較簡單,主要測試 api.因爲 fir.im 做 app 的內測分發,我們需要性能測試保證 app 上傳下載的正常穩定。性能測試是單用戶的,壓力測試是多用戶的,這是兩者之間的區別。

性能測試會有一些不確定性,有很多系統會產生緩存。 flow.ci 的性能測試跑在 docker 上,是一個乾淨獨立的環境,需要讓系統預熱運行一下。Locust/JMeter/LoadRunner是目前比較流行的性能測試工具。 flow.ci 目前用的是 locust,可以參考一下。

持續集成的可視化、數據分析

我們認爲一個好的持續集成系統也要做到項目進度的透明化,最傳統的方式是發送相關的郵件,但實質上有幾個人去看呢?爲此我們採購了一個大的屏幕來解決這個問題,用來時刻提醒團隊的某個構建結果。當然也可以用閃爍燈或音頻的方式。

fir.im

說到數據統計分析,整個 ci 流程跑下來產生的很多數據也非常有挖掘的價值。比如,對於代碼靜態分析有多少 Offence、Risk、Bug,對於單元測試有失敗率、測試覆蓋率;對於驗收測試或性能測試有多少的失敗率,這些數據都有可能成爲衡量一個程序員的標準。

fir.im

結語

CI 就像蓋樓房的腳手架一樣,沒有腳手架就沒辦法蓋出一個足夠高的樓,沒有 CI 就無法交付質量足夠好的軟件!

歡迎分享你的觀點。


P.S.想要現場 slide 的同學,請掃碼下圖關注公衆號flow_ci,並回復關鍵詞「ci實踐」即可獲得 :)
fir.im

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章