新聞中心
背景

為懷化等地區(qū)用戶(hù)提供了全套網(wǎng)頁(yè)設(shè)計(jì)制作服務(wù),及懷化網(wǎng)站建設(shè)行業(yè)解決方案。主營(yíng)業(yè)務(wù)為成都網(wǎng)站制作、成都網(wǎng)站設(shè)計(jì)、懷化網(wǎng)站設(shè)計(jì),以傳統(tǒng)方式定制建設(shè)網(wǎng)站,并提供域名空間備案等一條龍服務(wù),秉承以專(zhuān)業(yè)、用心的態(tài)度為用戶(hù)提供真誠(chéng)的服務(wù)。我們深信只要達(dá)到每一位用戶(hù)的要求,就會(huì)得到認(rèn)可,從而選擇與我們長(zhǎng)期合作。這樣,我們也可以走得更遠(yuǎn)!
產(chǎn)品在新功能發(fā)布前,可能會(huì)采取小流量測(cè)試的方式,或者在確定方案前使用A/B測(cè)試來(lái)衡量。一般開(kāi)發(fā)人員會(huì)跟運(yùn)維同學(xué)合作,通過(guò)一些現(xiàn)有平臺(tái)切換機(jī)器或者流量來(lái)實(shí)現(xiàn)。本文介紹了另外一種簡(jiǎn)便的方式,并解釋了其在持續(xù)集成上的應(yīng)用,同時(shí)提供了現(xiàn)有的開(kāi)發(fā)框架供快速使用。
Feature Flag VS Feature Branches
Feature Flag(又名 Feature Toggle、Flip等)是一種允許控制線上功能開(kāi)啟或者關(guān)閉的方式,通常會(huì)采取配置文件的方式來(lái)控制。提到Feature Flag一般都會(huì)跟Feature Branches進(jìn)行比較。這兩個(gè)有什么關(guān)聯(lián)與差別呢?可以通過(guò)一個(gè)簡(jiǎn)單的示例來(lái)比較:
假設(shè)產(chǎn)品需要添加一個(gè)功能,如果你在主干上進(jìn)行開(kāi)發(fā),那么通常的做法是在前端開(kāi)發(fā)人員在界面上添加功能,然后可能會(huì)有其他同學(xué)來(lái)完成后端服務(wù)、安全保障,最后測(cè)試及Bug修復(fù)并發(fā)布上線。如下圖所示:
上圖中有個(gè)明顯的問(wèn)題是主干分支上在功能測(cè)試完畢之前是不能進(jìn)行發(fā)布的,因?yàn)楣δ芤呀?jīng)在提供在界面中,必須完備之后才能發(fā)布給用戶(hù)使用。
當(dāng)然解決方法也很簡(jiǎn)單,例如我們常見(jiàn)的是會(huì)使用功能分支(Feature Branches)來(lái)解決。在主干上拉取一個(gè)分支,然后在分支上開(kāi)完測(cè)試完之后在合并到主干上,這樣就不會(huì)影響主干的持續(xù)發(fā)布了。如果有另外的新的功能那么同樣拉取新的分支來(lái)解決。如下圖:
但這樣同樣存在問(wèn)題,如果一個(gè)功能比較復(fù)雜,開(kāi)發(fā)的周期較長(zhǎng),而在此期間主干上已經(jīng)多次修改代碼,那么等分支上開(kāi)發(fā)完之后合并到主干將是一個(gè)比較麻煩的工作。你必須去處理各種沖突,與其他開(kāi)發(fā)人員溝通修改點(diǎn)。這是很多人不愿意做的。
于是有人提供了新的方案來(lái)解決這個(gè)問(wèn)題。例如將開(kāi)發(fā)工作拆分成多個(gè)小塊,在各個(gè)分支上開(kāi)發(fā)測(cè)試完成后及時(shí)合并到主干中,并且可以先隱藏界面功能,直到所有的功能開(kāi)發(fā)完成之后才展現(xiàn)。這樣每次合并的難度就小多了;或者每次將主干上的修改都及時(shí)同步到分支上,這樣分支上開(kāi)發(fā)完成之后合并到主干上就簡(jiǎn)單多了。
但如果發(fā)布時(shí)出現(xiàn)bug怎么辦?可能常見(jiàn)的是進(jìn)行回滾重新上線。有什么方式既能避免分支合并的麻煩、保持主干快速迭代隨時(shí)發(fā)布,又能更好的控制新功能的發(fā)布、方便的進(jìn)行小流量或快速回滾操作呢?答案就是Feature Flag。
Feature Flag允許關(guān)閉未完成的功能,你可以在主干上進(jìn)行迭代開(kāi)發(fā),新功能即便未開(kāi)發(fā)完成也不會(huì)影響發(fā)布,因?yàn)樗鼘?duì)用戶(hù)是關(guān)閉的。當(dāng)功能開(kāi)發(fā)完成之后,修改配置便可以讓功能發(fā)布。這種操作甚至可以在線上進(jìn)行,例如代碼已經(jīng)發(fā)布但功能不可見(jiàn),你可以修改配置讓功能對(duì)特定的用戶(hù)(線上測(cè)試、小流量或者全量發(fā)布等)可見(jiàn)。如果發(fā)現(xiàn)新功能存在問(wèn)題,那么可以通過(guò)配置文件來(lái)迅速回滾,而必須重新分支上線。Feature Flag原理示意圖如下:
各自的優(yōu)缺點(diǎn)
選擇合適的方案,而不拘泥于方式本身
并沒(méi)有萬(wàn)能的方案,兩種方式都有各自的優(yōu)缺點(diǎn)。
Feature Branches
優(yōu)點(diǎn):
同時(shí)開(kāi)發(fā)多個(gè)功能分支不會(huì)影響主干和線上代碼
在分支上開(kāi)發(fā)新功能時(shí)不用擔(dān)心對(duì)其他在開(kāi)發(fā)的功能的影響
現(xiàn)有很多持續(xù)集成系統(tǒng)支持分支的構(gòu)建、測(cè)試、部署等
缺點(diǎn)
Martin Fowler的文章中已經(jīng)做了全面的闡述:
分支分出去時(shí)間越長(zhǎng)往往代碼合并難度越大
在一個(gè)分支中修改了函數(shù)名字可能會(huì)引入大量編譯錯(cuò)誤。這點(diǎn)被稱(chēng)為語(yǔ)義沖突(semantic conflict)
為了減少語(yǔ)義沖突,會(huì)盡量少做重構(gòu)。而重構(gòu)是持續(xù)改進(jìn)代碼質(zhì)量的手段。如果在開(kāi)發(fā)的過(guò)程中持續(xù)不斷的存在功能分支,就會(huì)阻礙代碼質(zhì)量的改進(jìn)。
一旦代碼庫(kù)中存在了分支,也就不再是真正的持續(xù)集成了。當(dāng)然你可以給每個(gè)分支建立一個(gè)對(duì)應(yīng)的CI,但它只能測(cè)試當(dāng)前分支的正確性。如果在一個(gè)分支中修改了函數(shù)功能,但是在另一個(gè)分支還是按照原來(lái)的假設(shè)在使用,在合并的時(shí)候會(huì)引入bug,需要大量的時(shí)間來(lái)修復(fù)這些bug。
Feature Toggle
優(yōu)點(diǎn):
避免了分支合并代碼沖突的問(wèn)題,因?yàn)槭腔谥鞲傻拈_(kāi)發(fā)
每次提交都在主干,迭代速度明顯有優(yōu)勢(shì)
新功能的整個(gè)過(guò)程都持續(xù)集成
缺點(diǎn):
未完成的功能可能會(huì)部署到線上,如果配置有誤可能將未完成的功能開(kāi)啟。當(dāng)然可以將界面層最后開(kāi)發(fā)避免過(guò)早暴露。
主干上擔(dān)心提交代碼影響其他功能。
我們可以根據(jù)需要選擇合適的方案。Feature Flag在避免分支合并加快迭代上有優(yōu)勢(shì),另外Feature Flag除了主干開(kāi)發(fā)上的支持,還有什么實(shí)用功能呢?下面來(lái)介紹。
Feature Flag種類(lèi)與應(yīng)用
一般Feature Flag可以分為兩類(lèi),見(jiàn)下所示:
發(fā)布開(kāi)關(guān):
在發(fā)布代碼時(shí)關(guān)掉未完成的功能
生存期短
功能穩(wěn)定就馬上刪除
在整個(gè)開(kāi)發(fā)過(guò)程中有預(yù)定義的值
業(yè)務(wù)開(kāi)關(guān):
實(shí)現(xiàn)A/B測(cè)試
針對(duì)特定人群發(fā)布功能盡早獲得反饋
針對(duì)特定條件開(kāi)啟或者關(guān)閉功能。例如可以設(shè)置在指定時(shí)間點(diǎn)開(kāi)啟,這樣新功能將按照設(shè)定自動(dòng)上線下線,無(wú)需手動(dòng)上線,適合專(zhuān)題等情況
能線上開(kāi)啟或者關(guān)閉,實(shí)現(xiàn)快速回滾
發(fā)布開(kāi)關(guān)主要是為了隱藏未開(kāi)發(fā)完成的功能,而業(yè)務(wù)開(kāi)關(guān)則可以幫助我們快速滿足某些需求。例如A/B測(cè)試,F(xiàn)eature Flag可以輕松控制展現(xiàn)哪個(gè)功能,提升A/B測(cè)試的可維護(hù)性。我們也可以通過(guò)配置里面的邏輯讓新功能針對(duì)小部分人群甚至是特定地域的人群發(fā)布,盡早獲取功能的反饋。甚至是可以在線上開(kāi)啟調(diào)試,只讓新功能對(duì)調(diào)試人員可見(jiàn)。而這些都只需要配置文件和簡(jiǎn)單的標(biāo)記來(lái)實(shí)現(xiàn)。
誰(shuí)在用Feature Flag
功能看起來(lái)很酷,但是不是新東西?有誰(shuí)在用呢,我可不不愿意承擔(dān)風(fēng)險(xiǎn)
事實(shí)上Feature Flag已經(jīng)在國(guó)外互聯(lián)網(wǎng)公司中獲得廣泛的使用。例如FaceBook、Google等公司使用基于主干的開(kāi)發(fā)模式來(lái)持續(xù)集成開(kāi)發(fā),F(xiàn)eature Flag是其中一個(gè)基礎(chǔ)技術(shù)。下面這幅圖展現(xiàn)了FaceBook開(kāi)發(fā)模式轉(zhuǎn)變歷程,可以看到幾年前facebook就開(kāi)始使用Feature Toggle,使用了Feature Flag關(guān)閉主干上未開(kāi)發(fā)完成的功能來(lái)保證快速迭代和高頻率的發(fā)布。
國(guó)外主干開(kāi)發(fā)中推薦這樣一種方式:trunk作為開(kāi)發(fā)主線,所有開(kāi)發(fā)人員完成開(kāi)發(fā)后向及時(shí)向主干提交代碼,開(kāi)發(fā)人員不允許在主干上拉取分支。在發(fā)布的時(shí)候由系統(tǒng)拉取分支發(fā)布,主干上的bug修復(fù)及時(shí)同步到發(fā)布分支。開(kāi)發(fā)人員可以本地使用git等工具進(jìn)行版本管理。如下圖所示:
雖然基于主干的開(kāi)發(fā)模式已經(jīng)成為國(guó)外的主流,但分支開(kāi)發(fā)并不是不該使用。使用分支不推薦的是讓新功能代碼在分支上長(zhǎng)時(shí)間堆積,分支應(yīng)當(dāng)是生存周期短的。
實(shí)際應(yīng)用中我們可以根據(jù)業(yè)務(wù)場(chǎng)景來(lái)選擇是否用功能分支還是Feature Flag,并且這兩者可以相互結(jié)合。例如在文章前面提到的示例中,可以使用分支來(lái)開(kāi)發(fā)細(xì)分的子功能保持分支及時(shí)合并,同時(shí)使用Feature Flag來(lái)控制功能的發(fā)布,提升工作效率。
最佳實(shí)踐
除了主干開(kāi)發(fā),什么情況下選擇使用Feature Flag呢?下面是使用Feature Flag的一些典型場(chǎng)景:
在 UI 中隱藏或禁用新功能
在應(yīng)用程序中隱藏或禁用新組件
對(duì)接口進(jìn)行版本控制
擴(kuò)展接口
支持組件的多個(gè)版本
將新功能添加到現(xiàn)有應(yīng)用程序
增強(qiáng)現(xiàn)有應(yīng)用程序中的現(xiàn)有功能
可以看到,由于Feature Flag本身是對(duì)業(yè)務(wù)功能的控制,所以不適于功能大范圍的改動(dòng)等情況。另外使用過(guò)程中需要注意一些問(wèn)題:
只在需要的地方創(chuàng)建開(kāi)關(guān)。美酒雖豪,不可貪杯。濫用任何技術(shù)都會(huì)出現(xiàn)問(wèn)題。
控制開(kāi)關(guān)的數(shù)量。同上,開(kāi)關(guān)應(yīng)按需使用并及時(shí)清除。
開(kāi)關(guān)之間代碼保持獨(dú)立。如果代碼存在依賴(lài)就沒(méi)法刪除,最終維護(hù)性反而變差
清除發(fā)布開(kāi)關(guān)和廢棄代碼。發(fā)布開(kāi)關(guān)應(yīng)當(dāng)在功能穩(wěn)定后刪除,舊代碼也是。
界面層最后暴露。
如何實(shí)現(xiàn)
實(shí)現(xiàn)這套東西復(fù)雜嗎?下面以php和smarty模板為例來(lái)介紹。
首先需要一套控制代碼邏輯的工具,雖然開(kāi)源的框架有在后端代碼層的支持,但推薦在模板層使用Feature Flag,因?yàn)槟0逯苯痈δ軖煦^,維護(hù)起來(lái)更加直觀方便。
例如我們會(huì)提供一個(gè)smarty插件,讓你控制相應(yīng)的展現(xiàn):
這個(gè)代碼的意思是如果common模塊的featureA命中,則展現(xiàn)下面代碼,否則展現(xiàn)另外一套代碼,展現(xiàn)代碼由于與功能相關(guān),所以就相當(dāng)于控制了展現(xiàn)哪個(gè)功能。當(dāng)然你也可以不用featureelse只控制功能的開(kāi)啟或者關(guān)閉。
另外我們需要一個(gè)配置文件,對(duì)應(yīng)featureA的配置,如下所示:
- {
- "features" : {
- "featureA" : {
- "type" : "switch",
- "value" : "on",
- "desc" : "test switch feature work or not"
- }
- }
- }
featureA配置的value是on,開(kāi)關(guān)類(lèi)型是switch。也就是說(shuō)這個(gè)功能是開(kāi)啟的。與switch類(lèi)似的可以實(shí)現(xiàn)多個(gè)feature類(lèi)型,例如抽樣控制、日期控制、地域控制等,代碼邏輯只需要根據(jù)value的設(shè)定判斷是true還是false。例如抽樣類(lèi)型,value設(shè)置0.5,那么對(duì)應(yīng)的類(lèi)型邏輯只需要判斷隨機(jī)數(shù)是否在0-0.5范圍內(nèi)而已。
部署中我們只需要修改featureA的配置就可以控制功能的發(fā)布,是不是so easy!
開(kāi)發(fā)框架
有哪些相應(yīng)的開(kāi)源框架呢?幾乎各種語(yǔ)言都有相應(yīng)的實(shí)現(xiàn)。例如FEX FIS小組提供了基于php和node.js的框架。此外還有多種語(yǔ)言的開(kāi)源實(shí)現(xiàn):
語(yǔ)言 Feature Flag框架
php 基于smarty的Feature Flag框架
NodeJs 基于Node前后端解決方案Yogurt的Feature Flag框架
java Togglz
.NET FeatureToggle
Ruby Rollout、Degrade
Python Gargoyle、Nexus admin
Groovy GrailsFeatureToggle
總結(jié)
Feature Flag與Feature Branches各有優(yōu)勢(shì),結(jié)合使用能發(fā)揮更大作用
結(jié)合業(yè)務(wù)場(chǎng)景選擇合適方案
Feature Flag能支持主干開(kāi)發(fā),并在控制功能發(fā)布上有獨(dú)特優(yōu)勢(shì)
本文鏈接:http://blog.jobbole.com/73930/
【責(zé)任編輯: chenqingxiang TEL:(010)68476606】
分享名稱(chēng):FeatureFlag功能發(fā)布控制
網(wǎng)頁(yè)路徑:http://m.fisionsoft.com.cn/article/dhcgsjp.html


咨詢(xún)
建站咨詢(xún)
