Feature Flag 功能发布控制

背景

产品在新功能发布前,可能会采取小流量测试的方式,或者在确定方案前使用A/B测试来衡量。一般开发人员会跟运维同学合作,通过一些现有平台切换机器或者流量来实现。本文介绍了另外一种简便的方式,并解释了其在持续集成上的应用,同时提供了现有的开发框架供快速使用。

Feature Flag VS Feature Branches

Feature Flag(又名 Feature Toggle、Flip等)是一种允许控制线上功能开启或者关闭的方式,通常会采取配置文件的方式来控制。提到Feature Flag一般都会跟Feature Branches进行比较。这两个有什么关联与差别呢?可以通过一个简单的示例来比较:假设产品需要添加一个功能,如果你在主干上进行开发,那么通常的做法是在前端开发人员在界面上添加功能,然后可能会有其他同学来完成后端服务、安全保障,最后测试及Bug修复并发布上线。如下图所示:

640?wx_fmt=png

图中有个明显的问题是主干分支上在功能测试完毕之前是不能进行发布的,因为功能已经在提供在界面中,必须完备之后才能发布给用户使用。

当然解决方法也很简单,例如我们常见的是会使用功能分支(Feature Branches)来解决。在主干上拉取一个分支,然后在分支上开完测试完之后在合并到主干上,这样就不会影响主干的持续发布了。如果有另外的新的功能那么同样拉取新的分支来解决。如下图:

640?wx_fmt=png

这样同样存在问题,如果一个功能比较复杂,开发的周期较长,而在此期间主干上已经多次修改代码,那么等分支上开发完之后合并到主干将是一个比较麻烦的工作。你必须去处理各种冲突,与其他开发人员沟通修改点。这是很多人不愿意做的。

于是有人提供了新的方案来解决这个问题。例如将开发工作拆分成多个小块,在各个分支上开发测试完成后及时合并到主干中,并且可以先隐藏界面功能,直到所有的功能开发完成之后才展现。这样每次合并的难度就小多了;或者每次将主干上的修改都及时同步到分支上,这样分支上开发完成之后合并到主干上就简单多了。

640?wx_fmt=png

如果发布时出现bug怎么办?可能常见的是进行回滚重新上线。有什么方式既能避免分支合并的麻烦、保持主干快速迭代随时发布,又能更好的控制新功能的发布、方便的进行小流量或快速回滚操作呢?答案就是Feature Flag。

Feature Flag允许关闭未完成的功能,你可以在主干上进行迭代开发,新功能即便未开发完成也不会影响发布,因为它对用户是关闭的。当功能开发完成之后,修改配置便可以让功能发布。这种操作甚至可以在线上进行,例如代码已经发布但功能不可见,你可以修改配置让功能对特定的用户(线上测试、小流量或者全量发布等)可见。如果发现新功能存在问题,那么可以通过配置文件来迅速回滚,而必须重新分支上线。Feature Flag原理示意图如下:

640?wx_fmt=png

自的优缺点

选择合适的方案,而不拘泥于方式本身

并没有万能的方案,两种方式都有各自的优缺点。

Feature Branches

优点

  • 同时开发多个功能分支不会影响主干和线上代码

  • 在分支上开发新功能时不用担心对其他在开发的功能的影响

  • 现有很多持续集成系统支持分支的构建、测试、部署等

缺点也很明显,Martin Fowler的文章中已经做了全面的阐述:

  • 分支分出去时间越长往往代码合并难度越大

  • 在一个分支中修改了函数名字可能会引入大量编译错误。这点被称为语义冲突(semantic conflict)

  • 为了减少语义冲突,会尽量少做重构。而重构是持续改进代码质量的手段。如果在开发的过程中持续不断的存在功能分支,就会阻碍代码质量的改进。

  • 一旦代码库中存在了分支,也就不再是真正的持续集成了。当然你可以给每个分支建立一个对应的CI,但它只能测试当前分支的正确性。如果在一个分支中修改了函数功能,但是在另一个分支还是按照原来的假设在使用,在合并的时候会引入bug,需要大量的时间来修复这些bug。

Feature Toggle

优点

  • 避免了分支合并代码冲突的问题,因为是基于主干的开发

  • 每次提交都在主干,迭代速度明显有优势

  • 新功能的整个过程都持续集成

缺点:

  • 未完成的功能可能会部署到线上,如果配置有误可能将未完成的功能开启。当然可以将界面层最后开发避免过早暴露。

  • 主干上担心提交代码影响其他功能。

我们可以根据需要选择合适的方案。Feature Flag在避免分支合并加快迭代上有优势,另外Feature Flag除了主干开发上的支持,还有什么实用功能呢?下面来介绍。

Feature Flag种类与应用

一般Feature Flag可以分为两类,见下所示:

发布开关

  • 在发布代码时关掉未完成的功能

  • 生存期短

  • 功能稳定就马上删除

  • 在整个开发过程中有预定义的值

业务开关

  • 实现A/B测试

  • 针对特定人群发布功能尽早获得反馈

  • 针对特定条件开启或者关闭功能。例如可以设置在指定时间点开启,这样新功能将按照设定自动上线下线,无需手动上线,适合专题等情况

  • 能线上开启或者关闭,实现快速回滚

发布开关主要是为了隐藏未开发完成的功能,而业务开关则可以帮助我们快速满足某些需求。例如A/B测试,Feature Flag可以轻松控制展现哪个功能,提升A/B测试的可维护性。我们也可以通过配置里面的逻辑让新功能针对小部分人群甚至是特定地域的人群发布,尽早获取功能的反馈。甚至是可以在线上开启调试,只让新功能对调试人员可见。而这些都只需要配置文件和简单的标记来实现。

谁在用Feature Flag

功能看起来很酷,但是不是新东西?有谁在用呢,我可不不愿意承担风险

事实上Feature Flag已经在国外互联网公司中获得广泛的使用。例如FaceBook、Google等公司使用基于主干的开发模式来持续集成开发,Feature Flag是其中一个基础技术。下面这幅图展现了FaceBook开发模式转变历程,可以看到几年前facebook就开始使用Feature Toggle,使用了Feature Flag关闭主干上未开发完成的功能来保证快速迭代和高频率的发布。

640?wx_fmt=png

外主干开发中推荐这样一种方式:trunk作为开发主线,所有开发人员完成开发后向及时向主干提交代码,开发人员不允许在主干上拉取分支。在发布的时候由系统拉取分支发布,主干上的bug修复及时同步到发布分支。开发人员可以本地使用git等工具进行版本管理。如下图所示:

640?wx_fmt=jpeg

然基于主干的开发模式已经成为国外的主流,但分支开发并不是不该使用。使用分支不推荐的是让新功能代码在分支上长时间堆积,分支应当是生存周期短的。

实际应用中我们可以根据业务场景来选择是否用功能分支还是Feature Flag,并且这两者可以相互结合。例如在文章前面提到的示例中,可以使用分支来开发细分的子功能保持分支及时合并,同时使用Feature Flag来控制功能的发布,提升工作效率。

最佳实践

除了主干开发,什么情况下选择使用Feature Flag呢?下面是使用Feature Flag的一些典型场景:

  • 在 UI 中隐藏或禁用新功能

  • 在应用程序中隐藏或禁用新组件

  • 对接口进行版本控制

  • 扩展接口

  • 支持组件的多个版本

  • 将新功能添加到现有应用程序

  • 增强现有应用程序中的现有功能

可以看到,由于Feature Flag本身是对业务功能的控制,所以不适于功能大范围的改动等情况。另外使用过程中需要注意一些问题:

  • 只在需要的地方创建开关。美酒虽豪,不可贪杯。滥用任何技术都会出现问题。

  • 控制开关的数量。同上,开关应按需使用并及时清除。

  • 开关之间代码保持独立。如果代码存在依赖就没法删除,最终维护性反而变差

  • 清除发布开关和废弃代码。发布开关应当在功能稳定后删除,旧代码也是。

  • 界面层最后暴露。

如何实现

实现这套东西复杂吗?下面以php和smarty模板为例来介绍。

首先需要一套控制代码逻辑的工具,虽然开源的框架有在后端代码层的支持,但推荐在模板层使用Feature Flag,因为模板直接跟功能挂钩,维护起来更加直观方便。

例如我们会提供一个smarty插件,让你控制相应的展现:

640?wx_fmt=png

个代码的意思是如果common模块的featureA命中,则展现下面代码,否则展现另外一套代码,展现代码由于与功能相关,所以就相当于控制了展现哪个功能。当然你也可以不用featureelse只控制功能的开启或者关闭。

另外我们需要一个配置文件,对应featureA的配置,如下所示:

  {
      "features" : {
          "featureA" : {
              "type" : "switch",
              "value" : "on",
              "desc" : "test switch feature work or not"
          }
      }
  }

featureA配置的value是on,开关类型是switch。也就是说这个功能是开启的。与switch类似的可以实现多个feature类型,例如抽样控制、日期控制、地域控制等,代码逻辑只需要根据value的设定判断是true还是false。例如抽样类型,value设置0.5,那么对应的类型逻辑只需要判断随机数是否在0-0.5范围内而已。

部署中我们只需要修改featureA的配置就可以控制功能的发布,是不是so easy!

开发框架

有哪些相应的开源框架呢?几乎各种语言都有相应的实现。例如FEX FIS小组提供了基于php和node.js的框架。此外还有多种语言的开源实现:

语言Feature Flag框架
php基于smarty的Feature Flag框架
NodeJs基于Node前后端解决方案Yogurt的Feature Flag框架
javaTogglz
.NETFeatureToggle
RubyRollout、Degrade
PythonGargoyle、Nexus admin
GroovyGrailsFeatureToggle

总结

  • Feature Flag与Feature Branches各有优势,结合使用能发挥更大作用

  • 结合业务场景选择合适方案

  • Feature Flag能支持主干开发,并在控制功能发布上有独特优势

参考资料

  • 采用功能切换进行软件开发

  • 使用功能开关更好地实现持续部署

  • FeatureToggle

  • Feature driven development

  • Favor Feature Toggles over Feature Branches

  • What is Trunk Based Development?

  • Decoupling Deployment and Release- Feature Toggles


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/319352.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

P4542-[ZJOI2011]营救皮卡丘【费用流,Floyd】

正题 题目链接:https://www.luogu.com.cn/problem/P4542 题目大意 给出n1n1n1个点mmm条边的无向图,kkk个人开始在000号点,一个人进入iii号点之前必须要有人经过i−1i-1i−1号点,求第一个人进入nnn号点时所有人的最短移动距离和。 1≤n≤150…

【线段树】GSS5 - Can you answer these queries V(luogu-SPOJ 2916)

正题 luogu-SPOJ 2916 题目大意 给你一个序列&#xff0c;有若干询问&#xff0c;每次给出左右端点的区间&#xff0c;问你最大字段和 解题思路 用线段树维护区间信息&#xff0c;询问的区间如果有交则分类讨论求解 code #include<cstdio> #include<cstring> #…

SmartSql 动态代理仓储

SmartSql源码&#xff1a;https://github.com/Ahoo-Wang/SmartSql1|1简介动态代理仓储(SmartSql.DyRepository)组件是SmartSql非常独特的功能&#xff0c;它能简化SmartSql的使用。对业务代码除了配置几乎没有侵入。可以说使用SmartSqlContainer是原始方法&#xff0c;而DyRepo…

HDU 6889 Graph Theory Class(CCPC网络赛)

hdu 6889 传说中的人均min25 题意&#xff1a; n个点的完全图&#xff0c;边权为lcm(i1,j1)&#xff0c;求mst&#xff08;最小生成树&#xff09; 题解&#xff1a; 我一开始以为是推公式&#xff0c;毕竟数据范围这么大&#xff0c;但是自己画图来看看mst的情况 注意求lc…

Ocelot简易教程(六)之重写配置文件存储方式并优化响应数据

本来这篇文章在昨天晚上就能发布的&#xff0c;悲剧的是写了两三千字的文章居然没保存&#xff0c;结果我懵逼了。今天重新来写这篇文章。今天我们就一起来探讨下如何重写Ocelot配置文件的存储方式以及获取方式。作者&#xff1a;依乐祝原文地址&#xff1a;https://www.cnblog…

【线段树】蝴蝶与花(P6859)

正题 P6859 题目大意 给你一个由1,2组成的序列&#xff0c;要求完成写下列操作&#xff1a; 修改一个数查找一段区间&#xff0c;使其区间和为s&#xff08;输出左端点最小的一组&#xff09; 解题思路 用线段树来维护该序列&#xff0c;对于每次查询&#xff0c;先找到从1…

YbtOJ#912-神秘语言【结论,欧拉定理】

正题 题目链接:http://www.ybtoj.com.cn/problem/912 题目大意 给出L,RL,RL,R&#xff0c;求有多少长度在[L,R][L,R][L,R]之间的字符串满足依次取出所有偶数位置的放在最前面后&#xff0c;与原字符串相同。字符集是所有小写字母。 1≤Q≤5,1≤L≤R≤1010,R−L≤51041\leq Q\…

path hdu6705

题意&#xff1a; 一个有向加权图&#xff0c;问所有路径汇中第k小的路径长度是多少&#xff1f; 注意一个边可以反复走多次 题解 做法参考 我们可以利用优先队列来做 利用优先队列实现每次所取为最短边 我们假设一条路是从u—>v,路径和为sum&#xff0c;u->v是u的所以…

.NET Core实践系列之SSO-跨域实现

前言接着上篇的《.net core实践系列之SSO-同域实现》&#xff0c;这次来聊聊SSO跨域的实现方式。这次虽说是.net core实践&#xff0c;但是核心点使用jquery居多。建议看这篇文章的朋友可以先看上篇《.net core实践系列之SSO-同域实现》做一个SSO大概了解。源码地址&#xff1a…

P2150-[NOI2015]寿司晚宴【dp】

正题 题目链接:https://www.luogu.com.cn/problem/P2150 题目大意 将2∼n2\sim n2∼n选出一些分成两个集合&#xff0c;要求这两个集合中没有一对数不是互质的。求方案数对ppp取模 2≤n≤500,1≤p≤10102\leq n\leq 500,1\leq p\leq10^{10}2≤n≤500,1≤p≤1010 解题思路 数…

ABC181——F - Silver Woods

现在时间太少了&#xff0c;只能把自己不会的题补一下&#xff0c;会的题就不写了 F - Silver Woods 显然可以二分圆的半径&#xff0c;那么现在问题转化成判断半径为rrr的圆是否能够满足题意。 考虑什么情况下该半径的圆不能通过这些点。尝试用并查集维护一些关系 如果两个…

【树链剖分】洛谷树(P3401)

正题 P3401 题目大意 给你一棵树&#xff0c;让你进行以下操作 修改一条边的边权查询一条路径的所有子路径异或值的和 解题思路 记下所有点到根节点的路径亦或值&#xff0c;那么查询就是所有点对的异或值之和 因为边权<1024&#xff0c;最多只有10位&#xff0c;所以可…

牛客练习赛70 重新排列

来源&#xff1a;牛客网&#xff1a; 文章目录重新排列题解&#xff1a;代码&#xff1a;重新排列 时间限制&#xff1a;C/C 1秒&#xff0c;其他语言2秒 空间限制&#xff1a;C/C 262144K&#xff0c;其他语言524288K 64bit IO Format: %lld 题目描述 牛牛有个很喜欢的字符串”…

.NET 源代码库指南

微软.NET开发团队在博客上&#xff08;https://blogs.msdn.microsoft.com/dotnet/2018/10/15/guidance-for-library-authors/&#xff09;发布了.NET Library Guidance的第一个版本。这是一系列全新的文章&#xff0c;指导你为.NET创建高质量代码库。该指南包含我们已确定的适用…

P4774-[NOI2018]屠龙勇士【EXCRT】

正题 题目链接:https://www.luogu.com.cn/problem/P4774 题目大意 nnn个龙血量为aia_iai​&#xff0c;回复能力为pip_ipi​&#xff0c;死亡后掉落剑的攻击力tit_iti​&#xff0c;mmm把剑&#xff0c;攻击力为bib_ibi​。 从111开始打&#xff0c;每次使用不大于当前龙血量…

ARC107——D - Number of Multisets

D - Number of Multisets 之前写过一个类似表示的题&#xff08;2018CCPC吉林赛区——C - Justice&#xff09;&#xff0c;也是让用12,14,18…\frac1 2 ,\frac 14,\frac1 8 \dots21​,41​,81​…凑数&#xff0c;我效仿之前的思路写了个复杂度不清楚的东西&#xff08;非常爆…

【树链剖分】春季大扫除(P6805)

正题 P6805 题目大意 给你一棵树&#xff0c;每次可选择两个叶子结点&#xff0c;然后覆盖路径上的边&#xff0c;代价为其长度&#xff0c;每个叶子结点只能选一次。 对于每次询问&#xff0c;加入若干新点&#xff08;只会连接原树的点&#xff09;&#xff0c;问你覆盖所…

序列自动机

介绍 子串&#xff1a;串中任意个连续的字符组成的子序列称为该串的子串 子序列&#xff1a;子序列中的字符在字符串中不一定是连在一起的&#xff0c;而是删除其中若干个&#xff0c; 但子序列一定是单调的 简单说就是子序列不连续&#xff0c;子串连续 序列自动机可以在复杂…

基于gRPC服务发现与服务治理的方案

重温最少化集群搭建&#xff0c;我相信很多朋友都已经搭建出来&#xff0c;基于Watch机制也实现了出来&#xff0c;相信也有很多朋友有了自己的实现思路&#xff0c;但是&#xff0c;很多朋友有个疑问&#xff0c;我API和服务分离好了&#xff0c;怎么通过服务中心进行发现呢&a…

YbtOJ#723-欧拉之树【莫比乌斯反演,虚树】

正题 题目链接:http://www.ybtoj.com.cn/contest/121/problem/2 题目大意 给出nnn个点的一棵树&#xff0c;每个点有一个权值aia_iai​&#xff0c;求 ∑i1n∑j1ndis(i,j)φ(aiaj)\sum_{i1}^n\sum_{j1}^ndis(i,j)\times \varphi(a_i\times a_j)i1∑n​j1∑n​dis(i,j)φ(ai​…