版本管理 Branch By Abstraction

liuxue.gu@hotmail.com · 2008年11月17日 · 27 次阅读

Branch By Abstraction A [b] lesser-known source-control best practice[/b] I'vebeen pushing for a number of years is Branch by Abstraction. The suggestion is that you can convene large sets of developersin a single trunk and get then to continue to commit to a single placewithout having to spawn "short lived feature branches" when some largechange could mean that the build is going to be hosed for a number ofweeks while the team gets it right. Those branches just end uprunning and running.... ProvisosThere are some generalprovisos for the single as opposed to composite trunk design, thatcoincide with hard-core Agile development: [list][] You've broken your application into multiple components.[] Each component into a directory inside the trunk (possibly hierarchical).[] Each directory its own source self-contained and its own build (possibly hierarchical).[] You have a good set of unit tests and consider them important enough to illustrate snippets of example usage.[] Continuous Integration drives things, even for hundreds of components, that drops items into a Maven-like repository. [url=http://cruisecontrol.sourceforge.net/CruiseControl[/url]] has a nice [url=http://cruisecontrol.sourceforge.net/main/configxml.html#httpfile][/url] directive that with the [url=http://cruisecontrol.sourceforge.net/main/configxml.html#include.projects][/url] directive that allows you to set up the killer CI installation that isbranch-ready meaning you can run without a dedicated CI administrator.[] Your management are good at release planning.[*] Developers are in the habit of never breaking the build :-)[/list] Your trunk may look like:

trunk/ foo-components/ foo-api/ foo-beans/ foo-impl/ build.xml src/ java/ test/ cruisecontrol-config-snippet.xml remote-foo/ bar-services/ bar/ build.xml src/ java/ test/ cruisecontrol-config-snippet.xml bar-web-service/

[b] So back to the problem[/b].. What to do when (if) your team says they wantneed to shift from Hibernate to iBatis (hypothetical case). Therecould be thousands of classes that depend on Hibernate. Thearchitects might suggest that the build will be broken for weeks so aseparate branch is the best place for this change. Instead, letstry [b] Branch by Abstraction/b instead of the traditional "Branch by Source Control" ([url=http://digital-compulsion.blogspot.com/Stacy] Curl[/url] coined the name by the way - I'm trying to shame him into writing a better blog article than this one). The steps to living Branch By AbstractionWith your most responsible developers - [list=1][] Introduce an abstraction over the core bits of the big thing you're going to change.[] Update all the bits of code that were formerly using the thing directly to use it via the new abstraction.[] Make a second implementation of the abstraction, with unit tests that specifically test its core functionality.[] Update all the code from (2) to use the new implementation (still via the abstraction)[] Deprecate the first implementation (or skip to 6 if you don't want a respectful grace period).[] Delete the first implementation (its proven there is no need for you to go back).[] Remove the abstraction (if it is inelegant).[/list] Benefits[list][] Only a small team is even bothered by the change.[] You can go live at any stage - because the larger application works at all times.[] Management can be adaptive about scheduling.[] Avoids merge hell.[*] Introducing Abstraction helps increase understanding/modeling of piece - which is useful in itself.[/list] Of course, BBA [u] is not a panacea[/u].It is just a practice that developers/architects can often do it whenarchitects with less nerve are suggesting yet another long runningfeature branch. Architects should strive to do BBA instead of newfeature branches - Architects should not hope to reach a situationwhere they can declare at the outset that a new branch is the "onlyway" to achieve something.

A buddy last week was telling me of21 significant branches who's merge order was uncertain in his namelessclient. Sucks. He smiled wryly when I guessed Clearcase astheir SCM choice. Clearcase whether in dynamic, static or UCMmodes has no place in Agile development efforts. It is a selffulling prophesy that requires dozens of administrators a fewblack-belt merge-meisters and multiple branches and causes longdevelopment cycles, waterfall thinking and high staff turnover. The only thing worse that it is PVCS (who owns it now?). Anyone wanting a good tool for Agile development should belooking at [url=http://www.perforce.com/Perforce[/url]] (still my favorite cos Intellij works very well with it) or [url=http://subversion.tigris.org/Subversion[/url]]. Subversion will overtake Perforce one year soon I guess. When do you branch then?Ideally for release only. trunk/ releases/ rel-1.0/ rel-1.1/ rel-1.2.x/Youmay branch some days before release, then "production harden" thebranch on a staging box. You're not going to give permissions toall developers to that branch, just a couple who are ensuring its readyand handling later merges (one's or two's only if at all). Youbranch the release from trunk of course - given that CI proved thattrunk was at all times pretty solid.

As well as Stacy Curl, I'm hoping [url=http://www.martinfowler.com/Martin[/url]] writes an article on this important practice. He is better with words than me.


偶然看到 Paul Hammant 在2007年4月26日写的一篇文章:http://paulhammant.com/blog/branch_by_abstraction.html。觉得还不错,就翻译了出来。虽然文章的内容并不复杂,翻译过程中仍深深觉得水平有限,好几处翻译得很不理想,请朋友们指正。

Branch By Abstraction

尽管不为人知,但我推行一种叫做 Branch by Abstraction 的源码控制方法的最佳实践好几个年头了。当对代码进行大规模的改动时,构建很可能失败,甚至得花费数周时间才能重新构建成功。而我说的这种做法能让你把大批开发者拴在同一个主干下工作,而不是产生许多 “短期的特性分支”,因为这些分支会一而再、再而三地打断构建过程......



  • 应用程序被分解为多个组件
  • 每个组件在主干中占有一个目录(可能是多级的)
  • 每个目录里的源码是自包含的,可单独构建(可能也是多级的)(译注:这里的多级我理解为组件可以依赖于它的子组件)
  • 有一组很好的单元测试,这对于演示组件的用法非常重要
  • 应用了持续集成,特别是有数百个组件的时候,得把它们放入类似 Maven 的库中。CruiseControl 有个很好的指示字,与指示字一起使用的话能完成超酷的 CI 效果:既能管理好分支又不需要专门的 CI 管理员(译注:我对 CruiseControl 没有深入了解,这一条全凭感觉翻译的)
  • 你能做好版本发布的计划与管理
  • 开发者从不愿轻易打断构建过程 :-)


Java 代码 复制代码

  1. trunk/
  2. foo-components/
  3. foo-api/
  4. foo-beans/
  5. foo-impl/
  6. build.xml
  7. src/
  8. java/
    1. test/
    2. cruisecontrol-config-snippet.xml
    3. remote-foo/
    4. bar-services/
    5. bar/
    6. build.xml
    7. src/
    8. java/
    9. test/
    10. cruisecontrol-config-snippet.xml
    11. bar-web-service/

trunk/ foo-components/ foo-api/ foo-beans/ foo-impl/ build.xml src/ java/ test/ cruisecontrol-config-snippet.xml remote-foo/ bar-services/ bar/ build.xml src/ java/ test/ cruisecontrol-config-snippet.xml bar-web-service/


假定,你的团队想把代码从 Hibernate 移植到 iBatis 上,而可能有数千个类依赖于 Hibernate,该怎么办?架构师可能说这样的改动将让构建中断数周,所以最好新开一个分支。但是,让我们试试 Branch by Abstraction(BBA)而不是传统的 “Branch by Source Control”(这可是 Stacy Curl 说的 - 嘿嘿,我得叫他写篇更好的博文)。

实施 Branch By Abstraction 的步骤


  1. 在要改动的重点代码上增加一个抽象层
  2. 找到原来直接调用将被改动的代码的地方,把这些地方改为通过新的抽象层间接调用(将被改动的代码)
  3. 为抽象层按新的要求重新实现,并编写单元测试来测试新实现的核心功能
  4. 找到第 2 步骤中提到的那些代码,改为调用新的实现(也是通过新的抽象层间接调用)
  5. 废弃原有实现(如果你觉得代码足够稳定,也可以直接跳到下一步)
  6. 删除原有的实现代码(因为你没不需要回头了)
  7. 如果你觉得增加的那个抽象层不够优雅,就把它去掉


* 只有一小撮人受到改动的影响 * 改动到哪个阶段,代码都很健康 - 因为调用这些组件的应用程序总是能照常运行 * 进度是可管理的 * 避免了炼狱般的分支合并操作 * 引入抽象也有助于理解和规范代码 - 这本身就很有意义

当然,BBA 不是包治百病的仙丹。它只是一种开发者和架构师都可以常用的实践,让架构师在考虑是否要引入长期的特性分支时少伤脑筋。架构师应该多试试 BBA 而不是新的特性分支 -如果架构师在一开始就说新开一个分支是 “唯一的途径”,就别想达到目标。(译注:这一段感觉翻译得很有问题,请大家指正)

一个朋友上周告诉我,他的一个客户有 21 个重要的代码分支,这些分支的合并顺序简直莫名其妙!我吸了一口冷气。当我猜测他们是用 ClearCase 做 SCM 时,朋友只是苦笑。无论是 ClearCase 的动态、静态还是 UCM 模型,在敏捷开发的实践中都没有立足之地。它象是一个自相矛盾的预言术,需要数十个管理员加数个黑带级合并大师才能玩弄;它只能产生更多分支并导致开发周期拖长、瀑布开发思维及高人才流动率。还有一个更糟的就是 PVCS(谁手上还有它?)。如果想找个适合敏捷开发的好工具,应该看看 Perforce(我一直最欣赏它的是 IntelliJ 能很好地与它配合)或 Subversion。我想 Subversion 最快一年内就能超越 Perforce 了。


仅仅在发布新版本的时候。 Java 代码 复制代码

  1. trunk/
  2. releases/
  3. rel-1.0/
  4. rel-1.1/
  5. rel-1.2.x/

trunk/ releases/ rel-1.0/ rel-1.1/ rel-1.2.x/

你可以在发布前新开分支,在这个分支上进行最后的锤炼使产品定型。这时你不能再授权给所有的开发者了,而只能给少数几个开发者,他们保证分支稳定并负责后续的合并(仅限于一、两个必要的合并)。当然,你得从主干分支出来 - 这样才能用 CI 验证主干总是稳定的。

与 Stacy Curl 一样,我希望 Martin 能写篇关于这项重要实践的文章。他的文笔可比我要好。


需要 登录 后方可回复。