Continuous Integration - Build

三种分支模式

  1. 稳定主线

    项目中只有一条稳定主线,所有开发人员的代码都直接提交到该主线上,包括新features,bug fix 等。项目Release时不开新分支,只给主线上打上tag进行标记。

        该模式的最大好处就是管理方便,分支零成本管理,不涉及多分支间的合并问题。也是Martin Fowler同学推荐的模式。

      该模式带来的问题是如果团队规模较大(20人+),构建时间较长时,开发人员提交代码的频率会降低,也会降低开发人员提交代码的积极性。

 

  1. 稳定分支

    项目中有一条稳定主线,该主线只进行新features开发。项目Release时拉新分支作为发布分支。发布分支相对stable,不做新特性开发,只进行hot fixes.

        该模式比较适合传统软件的开发,例如freebsd 只有一条主线current,所有的新features都在该主线上发布,等到主线的特性积累到一定的milestone时,再从主干分出一个stable分支。

      如果新功能已经集成在主干上,但是达不到发布的要求,那么稳定分支就不能创建,这会影响到下一个发布计划。并且所有在stable上做的hot fixes最终都要合并到主干上来。

 

  1. 活跃分支-稳定主线-稳定分支

    项目中除了一条稳定主线与若干条稳定分支外,还存在有一条或多条活跃分支,该类型分支的建立通常有两方面原因:
  • 项目中开发人员人员较多时,会出现稳定主线模式所带来的问题。此时按照feature等拉出新的活跃分支时,可以使相关开发人员的集成关注点更加明确,也能提高他们提交代码的积极性。比如CWP项目中的Proxy feature最初就是在新分支上进行构建,每天早上由指定人员来与主干进行合并。
  • 有时项目中可能会有一些改动的影响面较大,并且需要较长时间。但是这些改动同时具有原子性,即或者全部改动生效,或者全部改动都需要进行回滚。例如CWP项目中的new branding 特性就属于这类情况。该特性需要对所有页面进行布局重构,影响面很大,最初的做法是将改动直接提交到主干上,但是发现经常会break 集成测试。因此对该特性也拉出一条活跃分支,使其独立工作在活跃分支上。最后在改动全部完成后,将其所有代码合并回主干。

这种模式所带来的最大问题就是代码合并,因为随着分支数量的增加,意味着每条分支所作的修改最终可能都需要合并到主干上。

构建

 Martin Fowler指出一次完整的构建应该包括如下七个步骤:

  • 将已集成的源代码复制一份到本地计算机。
  • 修改产品代码和添加修改自动化测试。
  • 在自己的计算机上启动一个自动化构建。
  • 构建成功后,把别人的修改更新到我的工作拷贝中。
  • 再重新做构建。
  • 把修改提交到源码仓库。
  • 在集成计算机上并基于主线的代码再做一次构建。

其中第5步操作会要求锁住主线代码,不允许其他人在这个时间段再次提交。

在讨论有哪些步骤可以省略的过程时,我首先想到的是省略本地构建过程,这里包含了两个假设:

  1. 主线必须是长绿的,表示随时可以发布,项目发展健康。并且只有在主线绿的时候才能更新代码。
  2. 第4步更新下来的代码无论如何都是需要本地构建的。而此时构建出的错误也必须是构建者来修理。

因此,无论有没有第3步构建,4,5两步都是要做的,而且错误发生在本地,还必须由构建者来处理。因此这样看来第3步似乎有些多余。那么第3步的价值究竟体现在哪里呢?个人觉得是在于出错后的反馈时间较快,并且能较为容易的定位到问题。

换一种思路,如果省掉的不是步骤3,而是步骤5会怎么样?这也可以从几个方面来分析:

  1. 本地自己写的代码质量是由第3步构建保证的,而第5步之所以可能出错,原因也一定是由合并代码导致的。但是这种错误出现的几率较小,可以考虑忽略。
  2. 如果省略了第5步,就不会导致主线在该阶段被锁,这样有助于提升构建效率。
  3. 主线是要保证健康的,但是健康状态一定是由长绿来保证么?我觉得未必,健康不代表不会出错,而是应该关注出错后的修复时间,如果主线构建出错,但是只需要很少的时间便能修复。那么把第5步的构建过程推迟到第7步去做,即使构建出错,也问题不大。

构建问题:

构建时间长:

每次构建需要较长时间,已经超出团队的容忍限度。解决方式通常包括几个方面:

  1. 分析原因。构建脚本做了太多没用的事情?构建流程是否应该改进等等。
  2. 并行构建。一般通过增加硬件机器来进行。这也是一种见效最快的方案。
  3. 低成本测试。将项目中花费时间较长的测试改为时间较短的测试,通常可以尽可能多的将功能(集成)测试的验证通过做单元测试来覆盖。数据库相关的测试改为内存相关等等。但是这同时也会带来一些负面影响,比如降低了测试的可信度。
  4. 分阶段或者减少无用测试。通常可以将测试划分为快和慢两种情况,针对速度较快的测试,可以在每次构建的时候都运行,而对于速度较慢但相对稳定的测试,可以选择分时段运行。

环境不一致:

构建的环境与产品实际运行环境不一致。通常包括几个方面:

  • 操作系统不一致。比如开发用windows,构建用linux。而实际产品可能跨平台。解决方法是采用多种平台进行构建。
  • 测试工具不一致。通常为开发环境下用的测试工具和集成环境下用的测试工具上的差异。
  • 设置不一致。包括权限设置不一致、环境变量设置不一致、文件系统不一致等等。
  • 数据不一致。比如测试用的数据都是些固定简单的fixtures,而产品环境下的数据较为复杂。虽然每次构建都是通过的,但是没能暴露出问题。这也可以归朔回构建不可信的原因。

强行提交:

构建尚未通过,其他人就已经开始提交。这类问题的解决方法是提交前进行检查,如果上次提交未通过,那么先revert上次提交的代码,直到待提交分支通过后再提交本地改动代码。

构建报告的通知方式:

包括email,SMS,音乐,熔岩灯,显示器等。

报告的分析:

结合工具从横向(不同人,不同团队之间)与纵向(团队自身的过去与现在)将数据以趋势和对比的形式展示出来.

 

参考文献:http://www.infoq.com/cn/articles/ci-theory-practice 肖鹏

Posted by Leo 2011年12月09日 01:22


Continuous Integration - Why need it?

    Continuous Integration is a software development practice where members of a team integrate their work frequently, usually each person integrates at least daily - leading to multiple integrations per day. Each integration is verified by an automated build (including test) to detect integration errors as quickly as possible. Many teams find that this approach leads to significantly reduced integration problems and allows a team to develop cohesive software more rapidly. This article is a quick overview of Continuous Integration summarizing the technique and its current usage. -- Martin Fowler

开场用老马的话来引入持续集成的概念。作为一个系列Camp,首先介绍下为什么需要持续集成。

为什么需要持续集成:

在传统软件(瀑布模型)公司做过开发的朋友应该都清楚,软件开发的流程大致分为:

需求定义——系统分析——概要设计——详细设计——编码——测试——部署

等几个步骤。一般情况下只有再软件测试完毕后客户才能拿到自己“想要”的产品。而这里面却隐含了两个问题:

首先,什么时候软件才能测试完毕?这个通常随着项目的周期长短而不同,或者若干个月,或者一年半载甚至更长。也就是说,只有在用户提出需求后的很长时间后,他们才能看到软件。

其次,数月后产生的东西真的是用户“想要”的产品吗?未必,或者更极端说一定不可能。这可以从两个方面进行解释。

  • 不同人多相同事物的理解是不一致的。即便充分沟通后,也有可能对一些概念产生曲解。比如在结对编程中有一种Drive-Watch的模式,这通常在一个经验相对丰富的人和一个经验相对较少的人pair时采用。通常人们都会将该模式理解为经验丰富的人来Drive(写代码),经验较少的人来Watch(观察学习)。其实不然。事实上Drive-Watch对象指的都是经验丰富的那个人,而他主要负责指点新人编程,而不是代码都由他来写。类似于这种被称为common sense的概念如果开始时就被曲解,而没有提前发现,就很有可能在今后逐步积累成更大的错误。同理,软件开发过程也是一样的。如果我们开始对需求的理解有就错误(事实上不可能没有错误),尤其是一些概念的理解偏差,而这种错误没有及时暴露出来,后续很多功能又都是基于该概念的。那么最后出来的软件质量可想而知。

     

  • 人对事物的理解是渐进的。在面对一个庞大而复杂的系统时,人脑很难对它有一个完整且清晰的认识。客户提需求也是一样,软件交付之所以困难,其中很大一部分原因就是因为需求的不断变化。而这种变化是贯穿在整个软件开发过程中,或者说,需求变化本身就是软件开发过程的组成部分。当采用瀑布模型开发时,这种变化也只能在数月甚至数年后测试结束时才能反映出来。

 

相信做过传统软件开发的朋友,在这两点上都或多或少的被瀑布模型刺痛过。那么有没有一种开发模式能解决上述问题呢?答案当然是肯定的——持续集成。

开始持续集成:

定义

从狭义上来说,持续集成是指持续集成工具,市场上包括Hudson,Cruise,Go等,该类型工具可以监听代码库的改动(ChangeSet),并且根据预定义的脚本来执行测试、构造等活动。以达到快速反馈的目的。

从广义上来说,持续集成就是敏捷开发,它不仅有上面提到的狭义定义,还贯穿整个软件的开发流程,包括团队组织模式,Story划分,Pair Programming,TDD,重构,代码集成策略,以及部署等等。

版本控制系统(VCS)的比较与选择

现在市面主流的版本控制系统包括SVN, Mercurial Hg,Git,ClearCase,VSS等等。

Hg与Git 属于分布式版本控制系统(DVCS),适合分布式团队开发。同时他们会在本地存一份完整的Repository,因此提交速度也相对较快。支持多人同时修改同一个文件(需要手工或自动Merge)。

SVN的Repository在远程,因此提交代码或者查看文件修改历史时会相对较慢。也支持多人同时修改同一文件。

ClearCase与VSS的Repository在远程,修改的提交是基于文件而非ChangeSet,因此提交速度最慢。并且不支持多人同时修改同一文件。

在代码所有制为集体的前提下,推荐使用SVN或者HG/GIT。这两类工具可以更好的提升团队的开发效率。

Posted by Leo 2011年12月07日 00:10