我之前总结了一下自己在做咨询时辅导团队时遇到的问题,并且给出了相应解答。
Q1:什么是持续集成?
集成,就是一些孤立的事物或元素通过某种方式集中在一起,产生联系,从而构成一个有机整体的过程。知识经济的社会,集成已经成了很重要的一个名词。各行各业基本都会用到集成。比如汽车行业,那么复杂的一台跑车愣是通过一大堆零件组装起来。对于这些传统行业,它们在研发成功以后,可以通过流水线的方法批量生产进行集成。而在软件行业中,集成并不是一个简单的“搬箱子”的过程。因为软件工业是一个知识生产活动,其内在逻辑非常复杂,需求又很难一次性确定,完成的产品与最初的设计往往相差很远。敏捷宣言中就有一条是说响应变化重于遵循计划。而且由于软件行业的迅猛发展,软件变的越来越复杂,单靠个人是根本无法完成。大型软件为了重用及解耦,往往还需要分成好几个模块,这样集成就成了软件开发中不可或缺的一部分。
image持续集成这个词语最早是由大名鼎鼎的Martin Fowler。他在早期进行软件行业实习的时候就发现一个问题,即集成是项目中的一个大难题。当他在英国一家软件公司实习时,项目经理亲口告诉他一个项目已经开发了好几年了,现在正在做集成,集成已经进行了好几个月了,每个人都很疲惫,并不知道集成什么时候才能结束。其中一个很重要的原因就是项目集成发生的频率太低,导致大家对项目很没有信心。
在《持续集成》一书中,对持续集成的定义如下:持续集成是一种软件开发实践。在持续集成中,团队成员频繁集成他们的工作成果,一般每人每天至少集成一次,也可以多次。每次集成会经过自动构建(包括自动测试)的检验,以尽快发现集成错误。自从在团队中引入这样的实践之后,Martin Fowler发现这种方法可以显著减少集成引起的问题,并可以加快团队合作软件开发的速度。
Q2:持续集成能给团队带来什么好处?
如果想要谈持续集成的好处,那么我们应该先谈谈没有采纳持续集成,项目会出现什么问题。总体来说,没有采用持续集成的项目一般会面临下面四个问题:
- 没有一致的可部署的软件。只有在完成集成测试、系统测试后,才能得到可用的软件,整个过程中只有最后时刻才能拿到可运行软件。集成活动不一定在一个标准的构建机器上生成,而是在某个开发人员的机器上构建的,那么可能存在在其他机器上无法运行的问题。
- 很晚才发现缺陷,并且难以修复。实践证明,缺陷发现的越晚,需要修复的时间和精力也就越大。从上一个可工作的软件到发现缺陷之间可能存在很多次提交,而要从这些提交中找出问题并修复的成本会很大,因为开发人员需要回忆每个提交的上下文来评估影响点。
- 低品质的软件。 由于集成时每次包含的代码很多,所以大家的关注点主要都是如何保证编译通过、自动化测试通过,而往往很容易忽略代码是否遵守了编码规范、是否包含有重复代码、是否有重构的空间等问题。而这些问题又反过来会影响今后的开发和集成,久而久之集成变得越来越困难,软件的质量可想而知。
- 项目缺少可见性。
而通过持续集成的活动,我们可以实现以下价值:
- 减少风险。缺陷的检测和修复变得更快。软件的健康程度可以测量。
- 减少重复过程。让人们有时间做更多的需要动脑筋的、更高价值的工作。通过对重要过程自动化,克服项目中某些成员对实现改进的抵制。
- 在任何时间、任何地点生成可部署的软件。对客户来说,可以部署的软件是最实际的资产。
- 增强项目的可见性。集成就像我们项目的一面镜子,通过这面镜子能够快速的了解项目目前的状况、存在的问题。
- 对开发团队的软件产品建立起更强大的信心。它能够帮我们有效的决策,注意到项目进展的趋势。
Q3:持续集成都包括哪些要素?
一个最小化的持续集成系统需要包含以下几个要素:
- 版本管理系统:项目的源代码需要托管到适合的版本管理系统中,一般我们使用git作为版本控制库,版本管理软件可以使用github、gitlab、stash等。
- 构建脚本:每个项目都需要有构建脚本来实现对整个项目的自动化构建。比如Java的项目就可以使用gradle作为构建工具。通过构建工具实现对编译、静态扫描、运行测试、样式检查、打包、发布等活动串起来,可以通过命令行自动执行。
- CI服务器:CI服务器可以检测项目中的代码变动,并及时的通过构建机器运行构建脚本,并将集成结果通过某种方式反馈给团队成员。
Q4:持续集成的全景图是什么样子的?
以下是持续集成的一个全景图。从中可以看到我们需要版本管理系统、构建脚本、CI服务器、CI构建机器、反馈机制。
imageQ5:持续集成一般都包含哪些任务?
持续集成并不是说只要代码能编译通过就是集成成功,我们已经把每次集成都看做一次完整的测试。任何迁入到代码库中的代码都应该是可以部署到产品环境的。拿一个Java项目为例,持续集成一般执行的任务有:
- 代码静态扫描:通过静态扫描确定代码的一些潜在bug,比如未被使用的变量等。
- 代码样式检查:团队一致定义出需要遵循的编码规范,并通过一些插件对迁入的代码进行样式合规性检查,防止不守规范的代码进入版本库。比如方法名首字母小写、类的大字母大写、if关键字后面需要加空格等问题都可以纳入到样式检查中。
- 单元测试、集成测试、系统测试:通过运行自动化的单元测试、集成测试、系统测试可以有效的保证迁入代码的质量。一旦有测试失败,开发人员就需要快速反应进行修复。
- 测试覆盖率检查:一般项目会设置一个测试覆盖率指标(比如80%),如果代码达不到这样的测试覆盖率,就不会允许代码迁入。这样可以保证开发人员在新增功能时也要为新加入的功能编写自动化测试。
- 编译打包:确保没有任何语法错误,生成构建产出物。
- 发布: 将通过完整构建的产出物放置到产出物仓库,以便进行后续部署。
这些任务都必须是能通过命令行自动完成的,不同类型的项目任务略有不同。
Q6:持续集成这些任务应该遵循什么顺序?
其中有一个重要的原则就是fail fast,即快速失败。一般会把运行时间短的、价值大的任务放在前面,而运行时间长的任务放置到后面。因为构建成功的标准是所有的验证都能够通过,那么执行时间短的任务放在前面能更快的得到反馈。
Q7:为什么我们组搭建了持续集成服务器,并且还派专人看守CI,但是感觉项目并没有明显的改善?
并不是说搭建了持续集成服务器就说明团队能成功运行持续集成了。持续集成是一个实践,所以大家要遵循一些原则。
大家可以先思考一下问题:
- 在CI服务器上多久会看到一次集成?
- CI服务器的集成结果是绿色居多(指构建成功)还是红色居多(指构建失败)?
- 当构建失败后,团队成员有没有第一时间修复构建,有没有在构建失败的情况下依然在提交代码,在提交代码之前有没有进行本地的私有构建?
从这些问题可以引申出持续集成中需要遵循的一些原则:
- 经常提交代码
- 不要提交无法构建的代码
- 立即修复无法集成的构建
- 编写自动化的开发者测试
- 必须通过所有测试和审查
- 执行私有构建
- 避免迁出无法构建的代码
Q8: 本地提交代码应该经过哪些步骤?
本地提交可以采用经典的七步提交法。
网友评论