持續整合(continuous integration, CI),就跟測試一樣,在有時程壓力,以及新功能開發的優先下,常常是被忽略的流程之一。
明明很重要的事,為什麼會被忽略?
這時候我們就要想想為什麼重要,我想很多時候是因為不清楚為什麼要。
說到持續整合,我們就要先從開發的流程開始,一般一個專案開始開發,可以參考下圖:
可以看到每個階段都有其對應要處理的事項,而關於這些不同階段的事項所要解決的事情如下:
- Agile Development: 有效率的溝通,做最有價值的事
- Continuous Integration: 自動化測試,自動化建置,讓重覆的事情可以自動執行
- Continuous Delivery: 讓專案可以自動發布,隨時有穩定版本可以運作,加速 test 驗證
- DevOps: 確保運行環境正常,負責將上述各個機制建置及維護,還有一旦 production deploy 之後的維運。
當然,實際狀況絕對不是 DevOps 這個職位的人單一可以完成上述所有的整合,必須要專案開發人員與及規劃時皆已考慮才有可能順暢的進行。
上述每一個環節都是要避免所有不必要的浪費
- Agile Development: 避免用昂貴的人力(你)無效的溝通
- Continuous Integration: 避免用昂貴的人力(你)進行重覆測試,避免用昂貴的人力(你)進行重覆程式打包
- Continuous Delivery: 避免用昂貴的人力(你)進行 produciton deploy
除了解決不必要的浪費,還有避免人為錯誤,一旦所有程序都自動化後,錯誤將容易被排除驗證。
就像豐田式生產(TPS, lean production)所提倡的理念:杜絕浪費;每一次的浪費一旦被避免,也就表示有更多時間資源可以進行有價值的事!
最終就會像下圖一樣,一步一步改善,一步一步進化,成為專案的魔鬼終結者:)。
知道了持續整合的意義及目的後,我們可以開始來說明企業端如何推動持續整合開發流程。
需要知道的是,軟體開發的進化,其實不像生物進化那樣的漫長,也不是每個步驟都有多大的學問,最重要的是一開始就必須要知道每個步驟以及環節,所要解決的事情,以及要如何達到。
所謂持續整合,其實可以從幾個現在開發方式或工具來說起。
version control system
千萬不要說我們有在用版本控制,不過是用 FTP… 我想那也等於沒有版本控制,隨時都有可能造成檔案覆蓋,只要一不小心刪錯檔案,所有努力都會化為烏有…
目前主流的版本控制有:
花一點時間了解一下相關的使用方式,想要初步了解,網路上都有很多教學資源,這將會是一個專案開始前最重要的準備工作。
one command line build
一旦你的服務開發完成,當然希望可以很方便的進行安裝,如何一行指令完成相關檔案的安裝,是可以努力的方向,任何語言都有對應的工具可以進行。
java:
- maven
- ant
- gradle
javascript:
- grunt
- gulp
- webpack
- npm script
其他語言相信也一定會有相關的 build script,搜尋一下相關的資訊,你將會有更多發現。
在專案一開始,就先把上面兩個基本功先搞定,將可以第一階段節省開發時間,比如一旦開發告一段落要進行 demo 時,就可以在 dev 機器,透過版本控制 command line tool 把專案下載下來,並且透過 one command line build 將 service 運行起來,如此,也就不用傳檔傳半天,安裝相關套件浪費了整天的時間,時間寶貴,不該將生命浪費再重覆的事情上!
有了基本的 build script 以及版本控制後,我們可以在往下一步邁進:auto re-generate data。
auto re-generate data
為什麼我們需要 auto re-generate data,舉例一個情境,假設我們要測試資料的刪除的功能,一般的程序會是:
- 建立資料
- 讀取資料
- 刪除資料
上述三個循環執行多次一點,我相信資料遲早有被刪除完的一天,這時候你要在重建資料以便下次在進行刪除測試,或是將資料庫備份還原?
何不直接一點,一旦專案啟動時,則 reset database,然後透過程式或是執行 sql 語法將測試資料進行建立,如此一來,一旦你的測試資料玩完了,只要重新起動將會是一個新的開始。
通常,這樣的作業也有對應的套件可以處理,又或者,上面介紹的 one command line build 就可以把這程序加進去,在 development mode 的情狀下,執行資料庫 reset,讓每次測試都是新的開始。
當然,讀者一定會想,若我們希望資料可以保留怎麼辦?這時候若你的 environment 是 production 當然就可以 skip 相關的處理,根據不同的情形給予不同的處理,這是可以變通的。
喔!對了,通常要在準備 database server 會是一個大工程,我們可以透過 local storage database 來進行,如:
來進行,都可以很快速的模擬實際資料庫的情形。
想必應該會有另外一個疑問,不同資料庫怎麼相容 sql 語法,可以再搭配 ORM-物件關係對映 技術,同樣以 java,javascript 為例,相關 library 如下:
- java: Hibernate
- javascript: sequelizejs
都可以讓你再用程式操作 database 上有一定的幫助。
有了資料重現的機制,恭喜大家,我們已經有 auto test 的基本要求了!再來我們可以把測試資料建立在啟動 sevice 之前先行建立執行。
bootstrap service/server
想像一下在開發一個 website 網站,一旦我們需要驗證時,通常就是啟動 server 進行測試,在下一個循環開始時,重覆同樣的動作,如果讓這樣的動作利用程式來進行,步驟將會如下:
- 啟動 server
- 建立資料庫
- 建立測試資料
- 開始進行測試
- 確認驗證是否通過
每次測試都會重覆同樣的循環,這個循環有多快,將會影響你的開發速度,可以想像,若每個步驟都需要人力介入是多麽浪費的事,所以,如果我們能夠讓建立資料的部分也能自動化,又是一個更進一步的改善!
接著我們可以在更進階一點,想像另外一個情境,現在專案開發完畢,過程中我們可以很快速的進行專案 deploy 也可以很快速的啟動應用程式,每次啟動都是一個新的開始可以讓我們有全新的資料可以進行測試,但還是有個地方需要一直重覆,那就是整個專案所有細節需要用人工進行驗證。
one command line test
我想,這將會是最難一蹴可幾的地方,因為 test 其實是需要日常累積的,從每日開發養成習慣,一點一點累積,將為有越來越多 test 幫忙驗證相關程式穩定度。
但,常常遇到一個問題就是說既有的專案已經走到一個程度,該如何開始進行 test?我想從新的需求,還有舊有專案比較重要的功能開始補上 spec 將會是比較經濟實惠的開始。
一旦開始有些 test case 才能進行 CI 中的其中一環:auto test。
一般來說每個語言都有其 test framwork,舉例來說:
都可以提供你在測試上必要的功能,相信在進行時可以事半功倍。
有了之前的 one command line build 的經驗,test 也應該要 one command line 作為目標。
而有了之前 auto re-generate data 經驗,auto test 也應該要能夠在測試開始前將測試資料完成建立,如此就可以不停的重覆驗證,日以繼夜的確保專案的健康度。
OK,假設已經做到 one command line build,auto test 短期內可能也還沒辦法,請記得:「念念不忘,必有迴響」,念茲在茲都希望專案可以穩定發展,相信有一天不再擔心受怕不會是夢想,跳過比較需要時間醞釀的部分,我們可以開始架設 CI Server 了!
CI Server
市面上有很多,也有專書介紹,比較主流的有:
其實有很多,只要你有完成 「one command line build」 的實作,進階的「one command line test」,用起來都不太難,就像天下武功出少林一樣,可以以「one command line」貫之。
結論
每一個章節都是一個專門的技術,都是可以專文特別介紹的,在這邊提供相關資訊令讀者可以找到相關關鍵字以及資源進行研讀。
上述所有措施都是為了讓開發者可以專心於開發上,並且將重覆的動作利用程式的方式自動進行,如此每次節省的時間都是賺到的,剩下無法自動化需要創意的部分就是作為人類所需要處理的事,也就是你−最重要的資產。
持續整合,其實就是持續改善,每個自動化的環節,都可以進一步優化,一開始不必追求完美,先求有再求好並不是隨便,而是 lean 的精神的體現。
就像沒有 auto test 只有 auto build 還是可以開始架設 CI server 一樣,先能感受到它的好處,就有動力持續學習,持續改善,希望大家都可以務實的一步一腳印,讓專案運行的更有效率!