3.4 持续集成
3.4.1 持续集成是什么
Martin Fowler是这么描述持续集成的:“(它是)一种软件开发实践,即团队的成员经常集成他们的工作,通常每个成员每天至少集成一次——这导致每天发生多次集成。每次集成都通过自动化构建(包括测试)来验证,从而尽快检测出集成错误。”[5]
更详细的介绍,请参考2007年出版的《持续集成:软件质量改进和风险降低之道》一书。
为了理解持续集成,我们先来看看什么是集成。集成包括两个方面:一方面是把各个改动汇聚在一起;另一方面是发现并修复其质量上的问题。
而持续集成就是指让这两类事情都比较频繁地发生。
一方面,将改动频繁地汇聚在一起。持续集成推荐开发者频繁地提交改动,每天都进行一次甚至多次提交。提交到哪里呢?提交到一个公共的集成分支,或者说是主干、主线上。那么在提交过程中,自然就会遇到代码改动冲突,并需要解决冲突。提交完成后,本次代码改动就自然而然地和以前别人提交的代码改动汇聚到一起了。
另一方面,频繁地构建和测试。在持续集成中提到的测试,主要是指可以自动执行且不需要测试环境的测试活动[6],通常包括代码扫描和单元测试。构建和测试首先发生在本地,通过后才提交代码改动。而每次提交后,都将自动触发持续集成服务器上的构建和测试,随后要尽快修复遇到的问题。
3.4.2 为什么要持续集成
为什么要让这两类事情比较频繁地发生呢?
首先,在不同改动的合并汇聚中,每个改动的改动量越大,改动之间潜在的冲突就越多。这既包括代码改动合并时暴露出来的冲突,也包括编译时、运行时暴露出来的冲突。这种冲突随代码量增加的增长速度不是固定的,而是越来越快:把两个分别有20人日的代码改动的分支合并到一起,理论上冲突的数量是10人日时的4倍而非2倍。而冲突越多,解决冲突需要花费的时间和精力就越多。因此,早点合并,早点暴露并处理这样的冲突,不仅使每次要处理的冲突量变少了,而且在一段时间内要处理的冲突的总量也变少了。
其次,越早发现问题,越容易修复问题。问题发现得早,便于缩小查找问题原因的范围,容易定位到在哪个开发人员的哪几行代码改动中;问题发现得早,开发人员的思维还停留在当时的开发上下文中,趁着记忆还新鲜,可以很快修正;问题发现得早,还没有和其他问题混在一起,因果关系清晰。
再次,集成后可以工作的代码,有利于跟踪进度和提供对进度的感知。因为跟开发人员本地的代码相比,或者跟设计文档中的描述相比,集成后可以工作的代码,其状态更接近我们的目标:发布给用户使用。
最后,从一个需求提出到发布上线的整个过程来看,越是频繁地集成,越是有利于产品早点发布上线。虽然不一定集成频繁了,发布上线就明显变快,但是反过来,如果集成要等上很久,那么整个过程一定快不了。
让这两类事情比较频繁地发生,于是集成不再是一个漫长且难以预测的过程,而是可以随时进行、随时完成,而且开发人员的负担很轻。
3.4.3 如何做到持续集成
以上讲的是持续集成要做成什么样,以及为什么要做成这样。下面讲怎么做。
• 版本控制:使用版本控制工具,将源代码及构建脚本、自动化测试脚本等纳入版本控制中。而将构建的结果放到制品库中供团队随时取用。
• 质量内建:在将系统交给测试人员之前先由开发人员自测,代码级检测优先于系统级检测。
• 自动化:不仅构建、代码扫描、单元测试这些活动本身是自动化的,而且整个流程也应该是自动化的——提交自动触发这一系列活动;在此过程中如果遇到问题,也应自动化地通知到提交人。
• 过程可视化:确保每个人都可以方便地看到系统当前的状态和发生的变更。
• 加速:考虑各种方法提高构建和测试的执行速度,比如增量构建和并行测试;考虑各种办法提高问题的修复速度,比如遇到问题先回退。
持续集成从理念到实践已经成为业界主流,并且还有进一步的发展,也就是持续交付和持续部署。下面分别进行介绍。