為了快速發布開發完成的功能,現代的互連網企業通常會以比較快的迭代周期來持續的發布。但是有時候因為技術或者 業務上的原因,需要在發布的時候將某些功能隱藏起來。一種解決方案是,在獨立的分支上開發新功能,全部開發測試完成 之後,才合并回主幹,準備發布。這也就是我們經常提到的功能分支(feature branch)。本文將介紹如何使用功能開關( feature toggle)來更好地解決這個問題,及其在一個典型Spring web應用程式中的具體實現,最後討論了功能開關和持續 整合如何協同工作。
功能分支的問題
功能分支可以協助我們同時開發多個新功能,而不對發布的節奏造成影 響,這解決我們一開始提到的那個持續發布的需求,但是它也會引入很多問題。在Martin Fowler的文章中已經很全面的闡 述了這些問題,簡單總結如下:
分支分出去時間長了往主幹合并的時候會出現很多的代碼衝突。
在一個分支中修改了函數名字,但是如果在其它分支中大量使用修改前的函數名,則會引入大量編譯錯誤。這點被稱為 語義衝突(semantic conflict)
為了減少語義衝突,會盡量少做重構。而重構是持續改進代碼品質的手段。如果在開發的過程中持續不斷的存在功能分 支,就會阻礙代碼品質的改進。
一旦程式碼程式庫中存在了分支,也就不再是真正的持續整合了。當然你可以給每個分支建立一個對應的CI,但它只能測試當 前分支的正確性。如果在一個分支中修改了函數功能,但是在另一個分支還是按照原來的假設在使用,在合并的時候會引入 bug,需要大量的時間來修複這些bug。
功能開關
下面我們來看看功能開關是如何解決上述的問題的。
第一原則,程式碼程式庫中不再引入任何分支, 所有的代碼都提交到同一個主線(mainline),在開始開發一個新功能的時候,引入一個布爾值的配置項,使得在該配置項 為假時,應用程式的外部行為和沒有引入該功能之前保持一致;而在配置項為真時,應用程式才展現出那些新開發的功能。
實現的方式也很直觀。在所有跟該功能相關的代碼中都會讀取該配置項的值,如果配置項值為真,則使用新功能, 如果為假,則保持以前的邏輯。我們把在某處代碼使用到該布爾配置項稱為該處代碼使用了該開關。
對於一個典型 的Spring的web項目,程式碼程式庫中會包括Java代碼、JSP代碼,IOC設定檔,還有CSS和JS檔案。這些都是代碼,根據不同的業 務需求,這些代碼都有可能會用到開關。為了能夠在這些代碼中方便地擷取開關的值,使用開關,我們需要一些基礎設施來 支援。
如上圖所示。需要在“功能開關”的模組中實現所需要的基礎設施,然後配合設定檔的內容來對應用程式的行為進行 控制。下面我們就設定檔和基礎設施做一些討論。