团队在实践“持续部署”和“持续交付”之前,要先做好“持续集成”。
本文标题之所以没有使用“最佳实践”,而是使用了“良好实践”,是因为下面每个实践在各个背景不同的团队落地时,都有可改进的空间。
“安全发布半成品”的持续集成策略
持续集成的重要意义,在于把部署流水线当作一个高效的沟通和验证平台,尽早发现各个开发人员代码上的冲突和缺陷,让他们之间尽早沟通解决,避免后期返工,拖后进度。
为了扩大持续集成的上述成效,要改变过去只有需求完全开发完才提交代码到主干的习惯,而开始考虑使用“安全发布半成品”的持续集成策略——即在使用自动化回归测试保证已有功能不被破坏的情况下,尽早小批量地将半成品代码集成并上线,在用户感知不到的情况下,尽早解决代码冲突和缺陷。半成品一旦完工,且通过测试后,再开放给用户。
“安全发布半成品”的持续集成策略,需要开发人员掌握“新旧并存”的代码提交策略——保留旧的可以工作的代码,同时编写新代码,当新代码编写完成并通过测试,再替换旧的代码。就如同我的同事健总(王健)所总结的“旧的不变,新的创建,一步切换,旧的再见”。比如:
-
替换旧代码时使用基于抽象的代码替换。在旧代码外增加一层接口,让对旧代码的调用改为调用接口,再编写实现该接口的新的实现代码。此时可以进行“安全发布半成品”的持续集成。等新代码完成并通过测试,再替换旧代码。
-
对于新功能的开发使用特性开关。用一个开关控制用户是否能够看到新功能。当新功能尚未完成时,关闭开关。此时可以进行“安全发布半成品”的持续集成。当新功能编写完成并通过测试,再打开开关,让用户可见。
-
使用增加新列的方式替换旧的数据库列。比如要把数据库的“姓名”列,替换为“姓”和“名”两列,可以先保留旧的“姓名”列,并增加“姓”和“名”两列。再编写程序,使得当程序访问旧的“姓名”列时,会将“姓”和“名”识别出来,并保存到新增的“姓”和“名”列。此时可以进行“安全发布半成品”的持续集成。等所有的姓名都保存到“姓”和“名”两列,再删除旧的“姓名”列。
持续集成规则
持续集成认证测试[1]
-
每位正在编写代码的程序员,每天至少一次将所写代码提交到团队代码主干。
-
每次团队代码主干上的代码提交,都能自动触发部署流水线的构建和自动化测试。
-
如果上述自动触发的构建和测试运行失败,则团队能在此之后,既不提交代码到主干(除非是修复代码),也不从主干获取代码,且能10分钟内修复(提交新的修复代码或回滚)部署流水线。
如果你的团队能同时做到上述3点,那么就可以给自己团队颁发一个“持续集成”证书,挂在墙上最显眼的位置。
从“持续集成认证测试”,能引出下述开发人员持续集成的良好习惯。
持续集成良好习惯
-
掌握“安全发布半成品”的持续集成策略和方法(见上文)。
-
每天上班后全量获取最新代码:开发人员每天上班后,第一件事就是从团队主干分支获取自己所开发的模块的全部最新代码到本地,并解决冲突。
-
单意图安全提交代码且“红不过夜”:开发人员一旦完成一个意图的代码编写,并用自动化测试验证了这次代码改动已满足上述“安全发布半成品”的要求,就再次从团队主干分支获取最新代码到本地,并解决冲突,然后在本地运行自动化测试,通过后,再提交代码到团队主干分支(详见下文“7步提交法”),并在提交时,用能揭示意图的文字描述这次提交;与主干相连的部署流水线会自动触发构建和测试,开发人员要看到这次自动构建依然健康,才能下班。否则就要在10分钟内修复或回滚,不能让部署流水线整晚都处于构建失败的状态,这就是“红不过夜”;单意图代码提交,能便于编写提交描述信息,让团队每日代码回顾容易进行,便于开发人员阅读、提交和撤回代码。
7步提交法
7步提交法- 前提:团队代码主干对应一条部署流水线,且每次主干上的代码提交,都能自动触发部署流水线的构建和自动化测试,同时团队能随时看到部署流水线的健康状况。
-
编写新代码前获取最新代码:开发人员在从主干获取最新代码之前,先在本地运行自动化测试并通过;开发人员检查部署流水线健康状况。如果发现流水线是红的(有问题),则立即参与修复或回滚流水线,直到流水线变绿;开发人员从主干上获取最新代码到本地,并解决相应的冲突;开发人员再次在本地运行自动化测试,并确保测试通过。
-
编写新代码:开发人员在本地为新用户故事或缺陷修复编写新代码。
-
本地构建:开发人员频繁在本地运行自动化测试,并确保测试通过。
-
解决冲突前再次获取最新代码(因为在做第2步编写新代码时,其他人有可能已经往主干上提交了代码):开发人员检查部署流水线健康状况。如果发现流水线是红的(有问题),则立即参与修复或回滚流水线,直到流水线变绿;开发人员从主干上获取最新代码到本地,并解决相应的冲突;开发人员再次在本地运行自动化测试,并确保测试通过。
-
解决冲突后再次获取最新代码(因为在做第4步解决冲突时,其他人有可能已经往主干上提交了代码):开发人员在确保部署流水线健康的情况下,从主干获取代码,解决冲突,在本地运行自动化测试,直到主干上没有最新代码,且本地自动化测试运行通过。
-
立即提交代码到主干:为减少此时主干出现新代码的风险,开发人员此刻应该立即提交代码到主干。部署流水线的构建和测试将自动触发。
-
提交后看到流水线运行成功后才离开:开发人员观察部署流水线的健康状态,如果发现流水线是红的(有问题),则立即修复或回滚流水线(确保10分钟内修复),直到流水线变绿,才能下班。
构建与部署
包传递
在部署流水线上,代码只构建一次,然后将这次构建后的同一个二进制包,分别部署到SIT、UAT、准生产和生产环境,依次进行不同种类的测试。
代码与配置分离
将每个测试和生产环境的配置参数,与代码分离,并存储在版本控制系统中。通过测试和生产环境的环境变量来保存相应环境的配置参数。
部署方式一致
使用同样的方式,将构建出的二进制包,依次部署到SIT、UAT、准生产和生产环境,以便测试部署方式本身。
冒烟测试
二进制包部署到SIT、UAT、准生产和生产环境后,都要进行冒烟测试。
各环境尽量一致
SIT、UAT、准生产和生产环境的系统及其配置要尽量一致。
构建包容易获得
团队任何成员都能容易地获取最新构建的二进制包进行测试。
自动部署
部署流水线能自动把最新构建的二进制包部署到SIT等测试环境。
部署流水线可视化
团队任何成员都能容易地看到部署流水线的健康状态,比如使用显示屏或警报灯。
代码静态扫描
持续集成流水线每次构建,能使用诸如SonarQube工具来扫描代码内在质量,并反馈给团队,偿还技术债。
版本控制一切代码
团队的所有代码,包括测试代码、构建脚本、部署脚本都统一管理在版本控制库中,并通过持续集成流水线持续得到更新和验证。
网友评论