持續集成之“Everything is code”

本文已發表在 InfoQ中文站的《持續集成》專欄,關於“持續集成”和“持續交付”更多的文章、視頻資源請訪問“持續交付中文站”, http://www.continuousdelivery.info/index.php/resources/


前文《軟件自我識別》中,我們討論瞭如果使軟件做到自我識別,以促進自動化部署和版本檢測等工作。 隨着互聯網的飛速發展,以及基礎設施的改進,越來越多的業務被放在了“雲”端。管理數千臺服務器和各種應用程序的不同版本已經是一種常規事務了。那麼如果管理好這些機器和代碼嗎?本文將介紹一些最佳實踐,來幫助大家更好的完成相關的事務。

一、測試代碼不是二等公民

業務壓力讓團隊人力顯得有點兒緊張。一天下午,大家在緊張的工作着,新的版本即將發佈了。突然,有兩個同事的對話引起了Joe的注意。

“Hi,Sam。過來看一下,我這裏有個自動化測試失敗了。”剛剛加入團隊的測試人員Jared 叫了Sam一聲。

“咦?我本地沒有這個測試,可我更新過我本地的代碼了呀?”Sam一臉茫然地應到。

“哦,是嗎?不會吧。我也是剛剛從SVN上更新了代碼。”Jared說道。

“Jared,你再更新一下,也許是你在我提交之前更新的呢。。。哦,還是一樣的結果。那到我的工作站上看一下吧。”

“噢,原來你把測試放在了這裏。”Sam恍然大悟的樣子,“我們兩個人使用的測試套件版本是不一樣的。根據用戶的反饋,我們重新修改了產品的一個小功能,所以,這部分功能的原有自動化驗收測試邏輯就不對了。”。SVN代碼倉庫的目錄結構如圖1所示。

圖1 產品代碼與測試代碼分離

這時,Joe也湊了過來。“嗯。我們應該修改一下我們的代碼在SVN中的組織結構。把測試代碼和產品代碼放在同一個代碼庫中,做到產品代碼與測試代碼同源。”

Jared 問道:“爲什麼要這麼做呢?我在上一家公司的時候,測試團隊也是把功能測試用例放在公司自行開發的一個測試用例管理平臺上進行管理。當需要做老版本的迴歸測試(比如V1.0)時,我們只要在這個平臺上勾選上該版本對應的測試用例,再點擊‘執行’按鈕,就可以了。當有新版本, 比如V1.1時,只要把 V1.0的所有測試用例複製一份,標記爲V1.1,並在其上修改就可以了。測試代碼的組織方式常常是使用目錄結構來分離版本。”如圖2所示。

圖2 以目錄方式對測試用例進行管理

Joe 回答到:“你剛纔所說的做法,我也在其它公司見過。這種做法常見於使用傳統瀑布開發模式的團隊,即開發階段與測試階段分離。在開發階段,大家並不會頻繁運行相應的自動化測試,這些自動化測試是爲測試人員服務。而在我們這裏,自動化測試是爲所有人服務的,開發人員隨時都會運行測試。其實,我們大部分的測試都已經與產品代碼放在了同一個代碼倉庫中了。只是這一部分是比較老的代碼,需求也一直沒有變化,自動化測試也一直運行成功,所以就沒什麼動力去遷移這部分測試代碼。”

Joe停頓了一下,喝了一口咖啡,接着說道:“當我們做到產品代碼和測試代碼同源時,我們只需要從一個svn代碼倉庫中籤出某個版本的源文件,就同時得到到產品代碼,以及與該版本相對應的測試代碼。所以,不會出現版本不一致,或者需要手工挑選測試用例的問題。現在服務器很多,應用程序使用灰度放量發佈的方式,在生產環境中可能會有多個版本。假如正在運行的某個版本出現了問題,需要修復,那麼,我們很容易就能拿到與其對應的所有代碼。因此,不能把測試代碼作爲代碼中的二等公民,而是應該得到與產品代碼同樣的重視。我們代碼庫中的目錄結構是這樣的。”如圖3所示。

圖3 測試代碼與產品代碼同源

二、配置信息也是代碼

Alex此時也湊了過來,接道:“不只是對代碼需要一視同仁,配置信息也一樣要放到代碼倉庫中。這方面,我們也是有着痛苦經歷的。記得是幾個月前,那時候我們的產品還不大,爲了快速調整,我們經常在生產環境中直接修改配置信息,如數據庫連接,功能開關項或者IP地址什麼的。結果,每次準備上線前的測試時,都要到生產環境上去下載一份配置信息。有一次,生產環境上的一臺機器出了問題,結果那臺機器上的所有信息都丟了,害得我們到處找,花了很長時間才把那臺機器重新配置好。現在都放在代碼倉庫中,就可靠多了。”

“配置信息是指哪些呢?”Jared問道。

Joe回答道:“配置信息包括應用程序相關的配置,以及程序部署時的相關配置。應用程序相關的配置是指影響應用程序行爲的配置項,比如某個功能的開關、數據庫連接、緩存的大小等等。程序部署時的相關配置是指部署在不同機器上的程序組件是如何相互連接的,如IP地址等等。”

“那有些配置信息是動態生成的,那怎麼把它放到SVN中呢?”Jared接着問道。

“我們首先要把動態信息與靜態信息分開。一般對於動態信息來說,只要把其變動的規則保存在SVN中就可以了。”Alex答道。“比如,某些 IP地址或內部域名是自動配置的,那麼就把自動配置的腳本放到 SVN中就行了。這樣,一旦出了問題,我們也可以確切地知道,所用的分配規則是什麼樣的。”

“那生產環境的配置與測試環境的配置不同,與開發環境的配置也不同,怎麼辦呢?”Jared窮追不捨。

“這個好辦,只要存三份配置,對應三種不同的環境就可以了。”Joe笑道,“所以,我們代碼目錄結構是這樣的。”他拿起筆,在紙上畫了一下,如圖4所示。

圖4 以業務爲核心組織產品結構

三、腳本文件也是源代碼

“嗨,Joe。這裏的 script目錄裏面放什麼的呢?”Jared問道。

“哦,這個目錄是放所有我們用到的腳本的。”Alex笑着說,“以前大家在測試、部署等工作中寫了很多腳本,用在各自的工作中。現在我們統一放在這個目錄中,這樣所有人都可以使用相同的腳本做相同的事情。比如,當開發人員在自己調試時,只要執行部署腳本autodeploy,它就會從開發配置目錄 (conf/dev)中讀取相關配置,部署好開發調試環境。而測試人員使用同一個部署腳本autodeploy,它就會從測試配置目錄(conf/test)目錄中讀取相關配置,部署好測試環境,生產環境部署也運行同一個腳本,只不過說生產環境配置而已。”

“這樣不錯。我們的腳本在最終向生產環境部署之前就已經被測試過很多次啦。”Jared笑道。

四、數據也是代碼嗎?

“我們有點跑題了,回到我們最開始遇到的那個測試問題上吧。”Jared說,“那個測試失敗,除了功能的小改動以外,log裏還有一些異常,好象是數據格式問題。”

“嗯,這部分測試用到的數據放在一個固定的共享目錄中了。可是,雖然文件名沒有變化,但其中的數據格式已經改了。也就是說,這份測試代碼與測試數據存在不一致性。”Joe說道。

Alex接道,“嗯,我們現在把數據也放到了代碼倉庫中。”

Jared一臉狐疑,問道:“數據那麼大,怎麼放到代碼倉庫中呢?SVN保存大數據並不高效,而且佔用空間也比較大呀。”

“Alex 只說了完了一半。其實,我們是把大數據放在了一個我們自行開發的版本控制系統中了。當把一份大數據放在其上時,該系統會返回唯一的一個標識ID,我們把它放在了這個產品代碼的conf目錄中。這樣,當簽出某個版本的代碼時,你就可以直接拿到對應的大數據了。如果大數據修改了,那隻要把放再次放到那個大數據存儲系統中,然後把返回的唯一標識更新到對就應的conf目錄中就行了。”Joe補充道。“如果沒有這樣一個大數據庫版本管理系統,也可以使用共享目錄,只不過,每個子目錄下保存一份數據,把這個子目錄地址放在SVN裏,也就行了。”

“對於數據庫結構的修改,我們還有另外一種方法,就是利用類似於DBmaintain或是DBDeploy這樣的工具。把每一次數據庫結構的變更都寫到一個數據庫腳本,並把它們和代碼放到一起。這樣,升級過程就由這些工具就完成了。”

五、Everything is code

“哦,我明白了。”Jared說道,“就是圍繞我們的服務或產品,將所有的東西進行版本管理。這樣,所有的內容都只有唯一的一個源,所有人都可以拿到同樣的信息,而且自動化工作也非常容易了。”

“是的。而且,當完成這一步以後,所有的事情自然都成爲可跟蹤可追溯的了。”Joe笑道:“這也算是一個額外的收益吧。”

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