背景
项目开发有两大难题:
1.确定开发需求、确定目标
2.确定工作量、把控交付质量
第二个难题贯穿了项目研发的始末。 根据二八定律,最艰难的东西可能只占整个项目的20%,却可能决定了项目是否能成功交付。如果项目缺少可见性、质量预估,哪怕已经完成80%的工作量,也无法安心
团队成员可能会因以下问题而感到焦虑:
1.大家所提交的所有组成部分是否能协同工作?
2.我的代码复杂程度如何?
3.大家是否都按照了制定的编码标准?
4.自动测试覆盖了多少代码?
5.最后一次提交,测试都通过了吗?
6.应用程序能满足开发需求吗?
7.是否存在未被发现的大风险?
在开发的过程中也可能会被以下事情困扰:
1.需要重复进行某些细小而繁琐的配置操作
2.开发人员间信息不透明,产生不必要冲突
3.数据库同步过于依赖某人,阻碍研发进程
4.没有可部署的软件,对当前的产出没信心
5.某些原因导致代码质量低、但重新调整很难
6.很晚才发现缺陷,修复需要大量时间、人力
…
综上,我们可以知道:研发过程中,除了思考功能如何实现、是否能满足要求等需要脑力的工作,我们还有许多发生在研发日常的、,重复的、繁琐的、需要流程规范的、减少开发风险事情要做。
持续集成正是为了解决后面这种情况而诞生的,用煽情一点的话来说就是“focus on coding,把时间还给开发”。
持续集成向我们传播的一个理念是:如果一件事很难,我们可以经常做,每次完成一点。 持续集成,是“分而治之”,也是“滴水穿石”、“跬步千里”。
持续集成概论
持续集成(Continuous Integration):开发实践中,团队成员经常集成他们的工作,通常每人每天至少集成一次——这样项目每天会集成多次。每次通过自动化构建进行,尽快地检查集成错误,减少大量的集成问题,更快地开发一致的高质量的产品。
传统构建流程
开发者修改源代码-数据库管理员(DBA)修改表定义-构建和部署人员修改配置文件-接口人员修改DTD/XSD规范
CI的场景
1.开发对被分配给自己的任务进行修改,执行一次私有构建
2.开发将变更内容提交到版本控制库。同时,集成构建计算机轮询检查版本控制库中的变更或用户提交变更触发集成任务
3.CI服务器检测到版本控制库发生的变更,从库中取得最新的代码副本执行构建,进行集成
4.集成完成后,结果信息通过之前配置的不同渠道通知到特定人员
CI的基本特征
1.与版本控制系统连接,确保单一集成控制
2.可以进行源代码编译,保证持续构建
3.进行集成源代码变更,生成可部署软件
4.拥有信息反馈机制,即时传递集成信息
CI的价值体现
1.减少风险,包括:快速检测和修复缺陷、测量软件健康程度
2.减少假定、减少重复过程,包括:在一个干净的环境不断使用相同的过程和脚本重复构建、测试软件,减少不实假定,减少重复配置、自动化执行任务等,达到确保每次执行方式相同、集成过程有序、提交变更即可执行的效果
3.软件健康程度可测量:自动集成过程中包括测试和审查,帮助有效地决策,注意到趁势,如构建成功失败、整体品质及其他相关信息,增加项目可见性
4.随时生成可部署的软件:项目管理、软件被交付方都可以直观看到研发的进度
5.增强团队信心:在有把握、可见性强的环境下工作,让研发进度、编码标准和设计标准是否被遵守、产品质量等都被直观看到,大家对项目的执行也更有信心
需要用到持续集成的包括但不限于以下人员
1.开发:通过持续集成,将精力放到开发过程,不再在集成问题上浪费时间、精力
2.构建\配置\发布管理:通过持续集成,不必等到开发周期末尾就能得到一致的、可测试、能工作的产品
3.测试:通过持续集成进行小范围高频次的测试,测试在研发过程中一直进行
4.项目经理:通过持续集成,更有效地管理时间、费用和品质,及时得到真实的测量指标数据及反馈信息
CI平台组成内容
1.版本控制库
通过受控的访问库管理源代码和其他软件资产(如文档)的变更,提供“单一源代码位置”,让开发人员可从一个可靠渠道取得所有代码,也可以沿时间回溯取得源代码和其他文件的不同版本。(数据库集成)
其中,集中放置软件资产包括:组件(源文件、库文件等);第三方组件(取决于语言和使用的平台);配置文件;初始化应用程序和数据文件;构建脚本和构建环境设置;组件的安装脚本等。
2.CI服务器
变更提交到版本控制库后执行集成构建。可配置定时轮询检查也可按任务手动一键提交新内容,变更版本控制库。然后CI服务器取出所有源文件运行构建脚本,进行集成构建。
通常CI服务器会提供一个显示板,构建完成后展示最新构建的结果和构建报告等;同时CI服务器也可以减少定制脚本的数量。
CI平台也要提供不同触发类型的触发机制,构建类型常规分为:私有构建、集成构建、发布构建等,根据不同的使用情况,会有不同的触发方式需求,如用户驱动触发、定期执行、轮询变更、事件驱动等。
3.构建脚本
由于CI是一个自动的过程,只使用IDE的构建方式不能适应CI的需求,所以需要用构建脚本实现过程自动化,包括编译、测试、审查、部署等。
自动化脚本制作使用步骤:确定自动化流程-创建构建脚本-利用版本控制系统将脚本分享到团队使用-利用CI使自动化发挥作用
4.反馈机制、文档及反馈
及时提供集成构建的反馈信息,尽快地修复发现的问题。
不同业务的持续集成流程不同,在使用CI平台时会遇到各种使用问题,平台需提供使用步骤指南、常见问题答疑等文档。
5.集成构建计算机
独立的专门用于集成构建的计算机,确保集成位置不受过去制品的约束。
6.对接工具平台插件脚本
研发流程通常是:开发-构建编译-部署-测试-审查-发布,流程很长,不同业务使用的工具平台不同,CI平台可提供对应接口、插件脚本,使各个模块可连通、数据信息传递,从而达到自动化、一体化持续集成的效果。
降低风险之道
风险一:没有可部署的产品
快要交付了才进行最后的构建,构建期间将是“集成地狱”。如构建耗时长、接口不能用、配置文件缺失、测试不通过等问题会成为整个团队的噩梦。
>>典型场景
1.在我的机器上构建是正常的,在测试服务器上构建最新版本缺失败
2.难以维护开发和测试环境,不能快速重建数据库,不可复现可测试的构建
3.手工部署费时费力,对某些人员的操作依赖性强,系统配置点错了难修复
4.害怕修改或重构数据库和源代码,很难用不同测试数据填充数据库
5.交付之前需要很长时间集成,这段时间没做其他工作
>>反省问题
哪些过程是手工的?哪些其实可以用自动化实现?
版本控制库中是否有重建数据库和数据的全部脚本?
可在构建过程中重建数据库和测试数据吗?
>>解决方案
解除IDE与构建过程的耦合,利用CI系统随时构建可部署的软件。
创建可重复构建过程,利用构建脚本自动化实现部署过程,消除过度依赖某人部署的瓶颈,而且避免出错。
使用版本控制库来管理所有软件资产,在构建脚本中重建数据库和数据,并对数据库进行测试审查。
风险二:很晚才发现缺陷
无法确定最新变更是否导致其他问题,无法判断修复一个错误是否会导致其他错误浮现,无法确定。除了测试自己提交的变更,整个系统的测试时间较长,可能导致错误很晚才被发现
>>典型场景
1.没有时间执行所有测试,没有发现之前就存在的缺陷
2.无法确定已经通过测试的代码占比是多少
>>反省问题
大部分缺陷是什么时候发现的?
如何通知构建版本或部署版本可接受测试了?
对软件变更时能够执行回归测试吗?包括功能、集成、负载和性能测试等
>>解决方案
每次变更时都执行开发者测试并运行代码覆盖率工具,评估多少代码实际被测试执行过。
用构建脚本执行测试,每次向版本控制库签入时都执行测试,在开发生命周期中尽早发现缺陷。
风险三:缺少项目可见性
保证信息及时同步,并且确保相关的人都接收到了同步的信息,对于团队协作极为重要;向团队成员简单明了地解释整个项目总体设计、各项原则,减少设计缺陷被引入和被修复之间的时间间隔也极为重要。增加项目可见性对快速上手项目、高效协同工作都有重要意义。
>>典型场景
1.新入职员工、新加入项目员工被忽略,不能及时知道项目相关信息
2.无法简单明了地向团队成员介绍整个项目的总体设计情况、当前进度等
>>解决方案
利用CI平台:自动化拉取项目成员名单,主动推送集成信息;经常运行构建,随时了解项目健康状况;生成可视化任务流程图,对项目内各流程有直接的感观认识。
风险四:低品质的软件
在研发过程中会遇到很多意外问题,事情往往不会按照最初设定的样子正常执行。如果对某些问题想当然,会浪费很多时间、增加很多风险。软件设计不好,不遵守项目标准,维护起来很麻烦。低品质的软件成长到一定程度,重构或修改很难。
>>典型场景
1.制定了编码标准,但是部分项目成员没有遵守
2.编码标准过多,无法全部记得并遵守
3.没有遵守预期设计的源代码,没有维持软件设计的框架
4.重复代码过多,复制粘贴而来的代码存在很多风险
>>反省问题
有达成项目品质测量标准约定吗?
是否使用了测试覆盖率工具?是否能确定哪些源代码没有对应的测试?
重复代码有多少?能否设法减少重复代码率?
是否能检查源代码是否遵守了软件框架?
如何向新来项目的开发这介绍软件框架?软件当前示图可见吗?
>>解决方案
利用自动化审查工具、代码静态分析工具,来强制执行编码标准,每次变更时执行测试和审查,发现违反编码标准的代码不允许构建通过。通过复杂程度、重复情况、设计、代码覆盖率和其他因素发现代码中的缺陷。
CI实践自检
>>>对于项目
持续集成系统搭建:使用版本控制库、项目构建过程自动化并可重复、自动化测试是构建过程的一部分、确定编码变准和设计标准、自动化反馈机制、使用独立集成计算机进行构建等
构建脚本从IDE中分离:集中放置软件资产,在不需要IDE的情况下执行自动化构建,减少错误的依赖关系,减少在不同机器上构建失败的几率
代码库目录结构一致:集成时构建软件更容易、更规范
执行单命令构建:保证输入一个命令就能取出最新的代码,并根据构建脚本执行构建
自动化构建:CI系统执行自动化构建,在每次版本控制库中发生变更时构建软件
针对所有环境构建:在集成机器及所有必要平台环境下,执行同样的自动化构建
让构建快速失败:将最容易失败的活动放在前面,让反馈信息最迅速,最快修复问题(推荐步骤:集成组件从版本控制库取得最新变更并进行编译-运行真正的单元测试,不涉及数据或其他依赖关系的快速测试-执行其他自动化过程,如重建数据库、审查和部署等)
使用专门的集成构建机器:专门用于集成构建的计算机可减少在构建上花费的时间,而且所有东西都在版本控制库中更有利于管理,在执行前删除集成环境中所有代码依赖关系,清理环境,也可以确保集成位置不受过去制品的约束(docker镜像构建相互隔离是优点是趋势)
使用CI服务器:可设置定时自动轮询,在独立的计算机上执行版本控制库中的变更、实现自动化、自动通知消息、展示构建结果等(见上面CI平台组成内容)
自动化的手工构建:自动化构建脚本一次手工执行集成构建,按任务形式进行构建
提升构建速度:可以增加计算机资源、分布式编译、分离较慢的测试、减少审查、分段构建等手段,少量多次集成;也可以通过收集构建测量数据、分析评估得出改良方案
分阶段构建:轻量级编译、单元测试、部署在前,次级组件测试、系统测试等较长时间测试审查在后(后面详细说)
>>>对于开发者
执行私有构建:先拉分支取出最新的变更,本地执行完整的集成构建,防止集成失败
避免签出无法构建的代码:等待新的变更或帮助修复无法集成的构建后在取出最新的代码(或利用版本控制库回滚上一次提交的变更,但这个方法不是很好),不然会浪费时间
经常提交代码:每天至少向版本控制库提交一次代码,包括进行小变更、每个任务完成后提交等
不提交无法构建的代码:先进行私有构建,所有测试必须100%通过,无法编译或不能通过测试的代码坚决不更新到版本控制库内
无法集成的构建立即修复:最近提交代码的开发者必须参与修复失败的构建
编写自动化测试:在自动化构建中执行这些测试,利用CI经常执行它们