长期维护的特性分支,这种做法会为每个新的大型特性或项目建立一个分支,仅当准备发布时才合并回到主干上。看似可以独立地开发每个特性,互不干扰。不幸的是,软件系统是如此复杂,随着主干与分支渐行渐远,接下的合并工作本身将会成为一个项目,带来无数的新缺陷,这真是一场噩梦。
当团队需要同时支持多个客户的不同需求时,版本控制仓库中很可能为此存在了许多分支。这显然会造成大量重复浪费以及高昂的维护成本,在临近产品发布时带来巨大风险。
2011年,@申导 进入某银行的网上银行工作。由于各国市场环境、政策法规等原因,以借记卡为例,看似相同的业务和账户,其背后的处理逻辑和外部集成系统可能都是不一样的。
当时的代码库中,多个国家的代码互相拷贝,由不同组维护,各有自己的思路,虽然最早是同一个基础框架发展而来,但短短几年后各自结构和规范差别越来越大。比如,页面login有的在iframe里,有的不在。相同的修改需要到处merge,例如安全性补丁,回归测试工作量大。
秋天,他所领导的敏捷团队开始开发新一代手机银行项目,目标是用同一代码库来支持多个国家的业务需求。
2011秋开始立项,某一个国家的项目率先开始。团队没有一下子设计一个完美的方案,因为当其他国家的需求不明时,根本也不可能有一个完美的方案。只是确定下了基本数据结构和MVC的层次,还有技术栈和构建方案,称之为“可行走的骨架”,随时根据变化来调整架构设计和构建方案,满足对不同国家需求的支持。
首先选定的技术栈是用Maven来管理web工程,采用Jasmine和RobotFramework分别作为单元测试与自动化测试工具。这几个工具都是非常流行,而且易于与Jenkins系统结合,构建持续集成系统。
在这种跨国多团队合作的场景下,好几个国家的项目同时由不同的团队开展,而且打破界限,大家都在SVN主干上进行开发,如果 没有持续集成系统作为反馈和沟通的基础,简直是无法想象的。利用CI,可以快速发现提交测试不完整带来的问题,暴露各人开发环境差异带来的影响,以便尽快修复,避免破窗效应。
在架构的演进过程中,团队充分利用语言和框架的各种多态特性,适时将不同的变种与公共部分剥离出来,将公共代码抽象为”基类”置于单独的软件包中。逐渐地,公共代码演化为“平台”代码,提供公共功能,而每个国家不同的业务逻辑则拼接于”平台”之上。这种通过不断抽象来管理不同分支的方式,称为“以抽象为分支”。(http://martinfowler.com/bliki/BranchByAbstraction.html)
除了代码,单元测试与自动化测试同样也采用单分支策略。
单分支开发(主干开发)的关键注意事项:
”特性开关Feature Toogle“或“以抽象为分支Branch By Abstraction”的架构技术来隔离掉未完成的特性。特性开关是系统中简单的配置开关,使得特性被关闭。以抽象为分支通过在软件内创建新的抽象层,来避免创建新的分支,新老特性得以共存。两种技术都是主干开发的必要条件,以循序渐进的方式进行大规模的软件变化,使你能够在变化进行中仍然可以有节奏地发布软件,同时保证大型特性在有效地完成之前不会被用户使用。
将大型特性分解成细粒度的特性,从而可以增量地发布。这也有助于提高发布管理的可预测性和计划的灵活性。
当测试周期很长时,建议采用”发布分支Release Branch“,在发布到生产环境之前进行版本冻结,仅修复缺陷而不增加任何新特性,从而稳定质量水平。这与传统的SCM策略截然相反。
更多细节,见:苏州开发者大会2013话题 http://softwaresuzhou.org/topic-single-branch-development/
Scrum Gathering 2013候选话题 http://vdisk.weibo.com/s/waw152TRJrC
天津软件沙龙 2013话题 http://vdisk.weibo.com/s/waw152TRJrC