主干开发,“关上”未完成的功能

来源:互联网 发布:网络服务器图片 编辑:程序博客网 时间:2024/04/30 07:02

软件开发中,“配置开关”根本算不上是一个“新”概念。无论是通过启动时加载配置,还是应用程序运行时动态刷新配置,都可以用来决定或改变应用程序的某种具体行为。比如:

  • 通过配置文件,使用应用程序连接不同的数据库
  • 通过模板配置,达到应用程序“换肤”的目的
  • 通过系统管理员的配置,使不同的用户具有不同的权限

所有这些“开关”都被认为是理所当然的,因为用户的需求就是这样的,“我需要通过xx开关来控制yy”。因此,做为交付团队,也会老老实实地把这些需求实现了。

然而,现在的很多团队,为了能够尽早发布软件,使用主干开发方式,并在程序中加入了另外一种“对用户透明”的开关。这种开关通常有两种使用场景是:

  1. 某些高级(或创新)的特性已经开发完毕,但业务人员根据市场情况,认为不需要投放市场。
  2. 市场需要某些已开发完成的特性,但还有一些特性尚未完成,仍旧处于开发中。

无论哪种情况,都是要求将某些特性进行隐藏后再发布。这种开关常常被认为是不可取的,但现在很多需要“持续交付”的公司都在使用。

(有的同学会说:“这完全可以通过按特性拉分支的方式来解决”。关于这个问题,我会在下一篇中讨论,本次仅限于讨论在使用“主干开发”的情况下,如何正确使用开关。)

开关最容易的地方就是应用程序的用户界面。当为已上线的应用程序重新设计了全新交互界面后,团队无法在一次性在同一发布周期中将其修改完成时,可以 先保留原有页面不变,同时每次仅替换少数的新页面。令所有未开发完成的页面对用户不可见,例如:原有页面的URL是 http://xx.xx.xx.xx/create_user,那么对应的新页面使用http://xx.xx.xx.xx/new_UI /create_user(要对后台逻辑的修改应能够同时响应新旧两个页面的请求)。当新页面完成后,将原来创建用户的页面链接重新指向新页面就可以了。 这样,就能在不破坏原有功能的前提下,做到持续发布。

开关实现形式

另外,对于那些无法在一个发布周期内实现的新功能,我们可以使用下面形式的“开关”:

  • 配置文件,通常在启动时加载

<features>
<feature name="hq.remote_panel_load" />
<feature name="el.enable_asset_library" />
...etc...
</features>

  • 在代码中实现

public function isFeatureOn(featureName:String):Boolean {
var nodes:XMLList = xml.features.feature.
(@name==featureName);
return null != nodes && 0 < nodes.length();
}

  • 设计成API

${core-url}/accounts/featureBits?userUid=&orgUid=&

而在编码中,可以使用不同的实现方式:

  • 最简单的检查

if( registry.config.isFeatureOn( featureName ) ) {
// new implementation ...
} else {
// the old way ...

  • 使用策略模式

if( registry.config.isFeatureOn("ct.analyzer.v2") ) {
service.analyzer = new Analyzer2();
} else {
service.analyzer = new Analyzer();
}

  • 使用工厂模式

public function createMainDisplay():DisplayObject {
if( registry.config.isFeatureOn( "service.panel.v2" ) ) {
return new panel2(); // which extends panel
} else {
return new panel(); // which extends DisplayObject
}
}

  • 使用责任链方式

if( registry.config.isFeatureOn("hq.trickle_reporting") ) {
userActionLogger = userActionLogger.setNext(
new TrickleReportNotifier( .. )
);
}

注意事项:

  • 提前评估是否需要开关,需要的话提前设计,不应该随意在代码中添加。
  • 定义一个开关命名规则,并在团队中达成共识。
  • 尽可能在设计时考虑在哪些层次上加开关。

“开关”在使用中的反模式:

  • 代码中到处都是开关,个数太多;
  • 在开关完成其使命后,未及时清理,使代码变烂。

现在,很多公司的产品都使用这种开关方式。进一步阅读,请参见:

  • Martin Folwer: Feature Toggle
  • Flickr: Flipping out
  • Etsy.com: Go or No-Go
  • Gflag: 针对C/C++的开源开关工具,由Google贡献

代码示例来自于:Erik Sowa,"Feature Bits" on slideshare.net

更多关于"持续交付"的内容请见http://www.continuousdelivery.info。

本文版权归作者乔梁所有,转载请包含作者签名和出处,不得用于商业用途,作者将保留“追究法律责任”的权利!


原创粉丝点击