最近看了《持續(xù)集成--軟件質(zhì)量改進(jìn)和風(fēng)險(xiǎn)降低之道》和馬丁福勒的博客,看書的時(shí)候感受不是很深,甚至我覺得我都寫不出這篇讀書筆記。我入職時(shí)間不長(zhǎng),進(jìn)入的項(xiàng)目就在實(shí)行CI,很多的CI實(shí)踐雖然一知半解,但是由于一直在用,所以書中很多的內(nèi)容對(duì)我來說并不陌生。后來我又去讀了馬丁福勒的博客,有了一些獨(dú)特的感受,其中最贊同也感觸最深的話,我用在了標(biāo)題里,持續(xù)集成的主要工作是溝通。作為一種溝通方式,持續(xù)集成可以幫助開發(fā)人員快速的交流開發(fā)內(nèi)容,及時(shí)的發(fā)現(xiàn)并且定位問題。
什么是持續(xù)集成
持續(xù)集成是指頻繁的、經(jīng)常性的進(jìn)行代碼的集成構(gòu)建,當(dāng)代碼發(fā)生變更時(shí),無論變更的大小,都要執(zhí)行一次構(gòu)建,進(jìn)行單元測(cè)試,并且與數(shù)據(jù)庫等進(jìn)行一次集成。從我所在的項(xiàng)目來說,我們有4個(gè)環(huán)境,CI環(huán)境,QA環(huán)境,staging環(huán)境,還有生產(chǎn)環(huán)境。
QA環(huán)境主要用于測(cè)試,staging環(huán)境可以理解為一個(gè)beta版的生產(chǎn)環(huán)境,這些環(huán)境在這篇文章里都不想過多介紹,主要想要介紹CI環(huán)境。
關(guān)于CI環(huán)境,我的理解就是這是一個(gè)最低門檻。所有最新提交的代碼都會(huì)最先流入這個(gè)環(huán)境,這個(gè)環(huán)境會(huì)執(zhí)行一次build,跑一遍單元測(cè)試,執(zhí)行一遍代碼審查,查看代碼是否可以構(gòu)建,測(cè)試是否都通過,測(cè)試覆蓋率是否達(dá)標(biāo),是否有過多的code smell。所以這個(gè)環(huán)境也是pipeline掛掉次數(shù)最多的環(huán)境,所有通過這道門檻的代碼,都是沒有集成問題的代碼,可以直接作為產(chǎn)品進(jìn)行測(cè)試。
持續(xù)集成中有一個(gè)很重要的點(diǎn)就是要使用專門的集成構(gòu)建計(jì)算機(jī),這也是我在看前幾頁就帶著的一個(gè)疑問,直到最后才得到了解答。這個(gè)專門的集成構(gòu)建計(jì)算機(jī)就是我們項(xiàng)目中的CI環(huán)境。這個(gè)機(jī)器就是為項(xiàng)目創(chuàng)造一個(gè)共享的干凈的集成環(huán)境。每一個(gè)開發(fā)者所使用的機(jī)器都會(huì)有所不同,有硬件和軟件的各種差異,生產(chǎn)環(huán)境的各種配置也會(huì)與開發(fā)者的本地環(huán)境有一定差異,我們總要保證提交的代碼是可以在生產(chǎn)環(huán)境上工作的,或者是可以在任何一臺(tái)機(jī)器上工作的。這臺(tái)機(jī)器就是去排除掉開發(fā)者本地環(huán)境的種種差異,保證不同的開發(fā)者提交的代碼可以共同工作。
那么為什么CI不能和QA環(huán)境合并呢?如果二者合并,QA的測(cè)試過程可能會(huì)被打斷,因?yàn)檎麄€(gè)環(huán)境在構(gòu)建,整個(gè)程序都被停止,為了保證QA可以正常的工作,需要拆出一臺(tái)機(jī)器或者虛擬機(jī)來進(jìn)行CI的工作。
持續(xù)集成的意義
持續(xù)集成的好處在于:減少風(fēng)險(xiǎn)、減少重復(fù)過程、隨時(shí)生成可部署的軟件、給予團(tuán)隊(duì)構(gòu)建反饋、增強(qiáng)對(duì)產(chǎn)品的信心。這幾點(diǎn)好處相信所有提CI的文章都會(huì)提到,不過多贅述。
說一下個(gè)人的理解,持續(xù)集成的意義就是溝通。剛才提到的幾點(diǎn)好處,我在書中讀到過很多次,然而馬丁的這個(gè)解釋,詮釋了所有這些好處和CI的意義。為什么說持續(xù)集成會(huì)降低風(fēng)險(xiǎn)減少重復(fù)呢?當(dāng)多個(gè)人在同時(shí)開發(fā)的時(shí)候,可能在同一份文件進(jìn)行更改,可能做了同樣的操作。當(dāng)需要對(duì)多個(gè)人做的這些東西進(jìn)行合并的時(shí)候,如何取舍,怎樣合并一定是一件極端痛苦的事情,所以好多人稱之為“地獄”。
我記得我之前做過一個(gè)故事卡,我和另外一組pair的小伙伴做了類似的功能,只是一個(gè)很小的功能,合并的過程痛苦不堪,因?yàn)槲覍?duì)他們的實(shí)現(xiàn)并不了解,解決方案的取舍也是一件艱難的事情,最最痛苦的事情在于花費(fèi)了時(shí)間之后一遍一遍的編譯失敗。
我之所以非常贊同CI的意義就是溝通就在于,當(dāng)我完成一點(diǎn)代碼,我pull一下代碼庫,跑一下測(cè)試,很快就可以知道我的代碼是否與他人有重復(fù),是否可以成功構(gòu)建。CI實(shí)踐讓我不需要隨時(shí)跟我的小伙伴進(jìn)行溝通,就可以快速的知道他們做了什么,我們的代碼是否有沖突、是否有重復(fù),而不是在最后合并的時(shí)候,幾個(gè)人坐在一起聊自己的代碼,然后痛苦不堪的合并。
通過CI實(shí)踐,最后合并的時(shí)間幾乎等于沒有,所有提交到CI環(huán)境上的代碼都是可集成的代碼,即可部署的軟件,可以幫助團(tuán)隊(duì)快速的部署。就我目前的項(xiàng)目來說,我們幾乎沒有經(jīng)歷過大規(guī)模的merge代碼,經(jīng)過CI環(huán)境之后,QA可以快速的部署到測(cè)試環(huán)境,測(cè)試通過后就可以快速的上線。
CI還有一個(gè)很重要的實(shí)踐就是反饋。這一點(diǎn)我感受最深的就是在TWU的時(shí)候,我們團(tuán)隊(duì)有一個(gè)顯示屏,專門用來顯示CI的狀態(tài),當(dāng)CI掛了的時(shí)候,其他人就不會(huì)去pull或者push代碼,最后提交代碼的人也會(huì)快速去修復(fù)。這樣就不會(huì)有人因?yàn)閯e人的代碼而反復(fù)的定位問題,也不會(huì)有多個(gè)人同時(shí)工作在尋找為何無法成功構(gòu)建上而導(dǎo)致做了過多重復(fù)的工作。
CI的實(shí)踐就是一種高效的溝通,不需要言語的表達(dá),也不需要打斷每個(gè)人的工作節(jié)奏,團(tuán)隊(duì)的成員就會(huì)了解到其他人的工作,知道自己接下來應(yīng)該如何去做。
持續(xù)集成與敏捷實(shí)踐
持續(xù)集成是敏捷實(shí)踐的一環(huán),為敏捷實(shí)踐中向客戶持續(xù)進(jìn)行交付打下了一定的基礎(chǔ)。在項(xiàng)目中,持續(xù)集成的使用很大程度上也反映了團(tuán)隊(duì)的敏捷程度。這一陣子我們團(tuán)隊(duì)進(jìn)行了敏捷成熟度的評(píng)估與改進(jìn),有一部分與持續(xù)集成密切相關(guān)的:
- 開發(fā)演示:開發(fā)人員是否在充分完成自測(cè)后,在部署的開發(fā)或測(cè)試環(huán)境下給測(cè)試人員進(jìn)行當(dāng)面演示,在主流程和基本場(chǎng)景都通過的前提下測(cè)試人員再做完整故事測(cè)試
- 代碼評(píng)審:團(tuán)隊(duì)是否建立了每天例行的代碼評(píng)審機(jī)制,對(duì)每天提交代碼的質(zhì)量進(jìn)行集體評(píng)審,并有機(jī)制確保評(píng)審發(fā)現(xiàn)的問題都進(jìn)行了修復(fù)
- 代碼靜態(tài)分析:團(tuán)隊(duì)是否利用了工具頻繁(比如每日代碼提交,或每日多次)對(duì)提交的代碼質(zhì)量進(jìn)行靜態(tài)分析,并且團(tuán)隊(duì)能立即對(duì)發(fā)現(xiàn)的不良問題(嚴(yán)重級(jí)別以上的問題,高重復(fù)率,高復(fù)雜度)進(jìn)行修改,不遺留問題
- 單元測(cè)試:開發(fā)人員是否為新增和修改的代碼創(chuàng)建了單元測(cè)試來驗(yàn)證其正確性,并且這些單元測(cè)試能夠通過持續(xù)集成來頻繁地執(zhí)行,保證持續(xù)有效
- 自動(dòng)化功能測(cè)試:團(tuán)隊(duì)是否創(chuàng)建了有效的自動(dòng)化測(cè)試腳本來對(duì)組件或系統(tǒng)的功能進(jìn)行測(cè)試(包括服務(wù)接口測(cè)試和UI測(cè)試),并且這些測(cè)試腳本能夠通過持續(xù)集成來頻繁地執(zhí)行,保證持續(xù)有效;而且團(tuán)隊(duì)遵循“測(cè)試金字塔”原則,不同層級(jí)的測(cè)試有合適的覆蓋范圍
- 自動(dòng)化非功能管理:團(tuán)隊(duì)是否利用工具模擬對(duì)系統(tǒng)或應(yīng)用的性能,安全性,并發(fā)穩(wěn)定性等非功能性質(zhì)量進(jìn)行了驗(yàn)證,并且這類驗(yàn)證也是盡可能自動(dòng)化的,可頻繁執(zhí)行
- 統(tǒng)一配置管理:團(tuán)隊(duì)是否采用了統(tǒng)一配置管理,即包括應(yīng)用代碼、單元測(cè)試、自動(dòng)化測(cè)試腳本、自動(dòng)構(gòu)建腳本、數(shù)據(jù)庫變更腳本、環(huán)境配置等以合理的目錄結(jié)構(gòu)存放在統(tǒng)一的源代碼庫中,全部進(jìn)行版本化管理
- 單主干開發(fā):開發(fā)團(tuán)隊(duì)是否采用了“單主干+發(fā)布分支”的分支策略:每天新的代碼頻繁提交到唯一主干,沒有特性分支;在迭代結(jié)束時(shí)創(chuàng)建或合并到發(fā)布分支來為發(fā)布提供穩(wěn)定版本;甚至能直接從主干發(fā)布
- 持續(xù)集成:團(tuán)隊(duì)是否建立了有效的持續(xù)集成流水線,頻繁地自動(dòng)化地對(duì)代碼進(jìn)行構(gòu)建,快速獲得反饋;該構(gòu)建過程應(yīng)包括編譯、靜態(tài)分析、執(zhí)行各類測(cè)試、產(chǎn)生包、各環(huán)境自動(dòng)部署等;構(gòu)建成功或失敗能立即通知到團(tuán)隊(duì),一旦失敗團(tuán)隊(duì)能夠立即關(guān)注并解決導(dǎo)致錯(cuò)誤的問題(或回滾代碼)讓構(gòu)建通過
- 分層構(gòu)建:針對(duì)同一個(gè)代碼庫,團(tuán)隊(duì)是否為不同的目的建立了不同層級(jí)的持續(xù)集成流水線以合理的不同頻率執(zhí)行不同的任務(wù)組合,從而平衡執(zhí)行頻率和執(zhí)行效率的矛盾,更快獲得構(gòu)建反饋
- 環(huán)境管理:團(tuán)隊(duì)是否為開發(fā)驗(yàn)證、集成測(cè)試、自動(dòng)化測(cè)試、以及預(yù)生產(chǎn)發(fā)布等各準(zhǔn)備了獨(dú)立的環(huán)境來支持各級(jí)驗(yàn)證環(huán)節(jié),且每個(gè)環(huán)境有明確的目的并隨時(shí)穩(wěn)定可用;最好是這些環(huán)境能夠以腳本來定義和自動(dòng)化變更其配置
其中,開發(fā)演示、代碼評(píng)審、代碼靜態(tài)分析、單元測(cè)試、自動(dòng)化功能管理和自動(dòng)化菲功能管理屬于評(píng)估中質(zhì)量保證的內(nèi)容,質(zhì)量保證的評(píng)估總共8項(xiàng),一半以上都與持續(xù)集成有關(guān)。其他五項(xiàng)屬于敏捷成熟度評(píng)估的持續(xù)交付的內(nèi)容,持續(xù)交付中共有7項(xiàng)評(píng)估內(nèi)容,也是一半與持續(xù)集成有關(guān)。持續(xù)集成是敏捷實(shí)踐中很重要的一項(xiàng)內(nèi)容,我的理解是,持續(xù)集成對(duì)于讓團(tuán)隊(duì)變的敏捷是一個(gè)必要條件。