当前位置: 首页 > 编程日记 > 正文

持续集成之戏说Check-in Dance

《infoq

众所周知,敏捷软件开发方法中有多种最佳实践,既有管理方面的,也有技术方面的。在尝试敏捷之初,并不是每个团队都能使用全部最佳实践,也不是每个实践都能在短时间内见效。但其中有一种最佳实践却是团队的必选,那就是持续集成,但这并不表示持续集成非常容易。


尽管Thoughtworks的首席科学家Martion folwer 为“持续集成 ”下了定义,但由于自身背景与经历的不同,每个人对其都有不同的理解。从狭义上讲,持续集成可以认为是一种基于某种或者某些变化对软件系统进行的经常性的构建活动(注:这里的构建活动不仅指编译打包工作,还包含各类自动化测试、部署及发布活动)。然而,它忽视了一点,即:任何实践中都应该包含“与人的交互”这一因素。因此,从广意上讲,持续集成应该是软件开发团队在上述活动的约束下所采用的整个开发流程及活动。它强调开发团队与持续集成系统之间的互动性。我们既见过持续集成做得非常成功的团队,也见过效果不佳的持续集成,甚至失败的案例。

那么,到底如何从持续集成中得到最大的收益呢?这要从持续集成所涉及的诸多方面进行分析,并根据团队具体情况(比如团队规模、人员组成以及是否为分布式团队 等)及所开发软件自身的特点(是企业应用软件,还是中间件?是嵌入式软件,还是互联网产品等)制定实践策略与实现步骤。本专栏将与大家共同探讨与持续集成、持续部署及持续交付相关的方法、工具与经验。

在软件开发中,持续集成实践能够解决的问题是尽早的集成和尽早的反馈。因此,尽管目前流行的所有版本控制工具都提供了分支/合并功能,但在少于20 人的团队中实现持续集成的话,推荐使用Single Branch开发策略。这样会减少多分支开如在合并时的开销。另外,由于理想情况下,每个分支都需要有专属的持续集成环境(包括持续集成服务器、构建环境和测试环境等),所以Single Branch也减少了对持续集成环境的需求量(当编译时间较长或测试用例较多时,这个因素的影响尤其重要)。

当团队完成最初搭建持续集成服务器,编写好一键式编译和测试脚本工作后,就需要考虑如何利用持续集成环境高效地进行团队协作开发了。一定有人会问:

“多人同时在一个分支上开发的话,每个人提交时都要合并代码,不是更浪费时间吗?”

这个问题也正是持续集成期望解决的问题。每当开发人员提交代码时,就是其与其他开发人员工作成果的一次集成。如果每个人都能够频繁提交代码,那么代码集成的频率就会提高,在持续集成的有力支持下,代码中潜在的问题就会更早地暴露出来(比如代码编译链接问题,自动化测试失败反映出来的代码功能问题,或需求理解不一致等问题),以便团队尽早解决之。

当然,持续集成所鼓励的频繁提交并不是指那种仅将版本控制库当成备份工具,无约束的“随意”提交,还需要团队开发流程约束的。下面我们来一同探讨“持续集成环境中的团队开发流程是什么样的”。

让我们先设想一个软件开发场景。

一、使用版本管理工具做备份

故事的主人公叫Joe,他打算写一个游戏,所以用Subversion建立了一个版本控制库用于保存代码,然后就动手写代码了。Joe的开发流程是这样的。

  1. 从代码库中检出一份代码;
  2. 为增加某个功能修改一些代码;
  3. 在本地运行了一下自动化测试;
  4. 测试通过之后,提交代码到版本控制库;
  5. 重复前面的步骤。

如图1所示。

二、搭建持续集成服务器做自动构建

“每次在本地手工运行自动化测试太麻烦了,”Joe想到,“这种重复的工作为什么不让机器来做呢”。

于是,Joe上网查了一下,发现持续集成工具是做这个事情的,就找来一台旧机器,用CruiseControl搭建了一个持续集成服务器。他的开发流程也变为:

  1. 从代码库中检出一份代码;
  2. 开发新功能或修改bug;
  3. 提交到版本控制库,思考下一个功能的实现;
  4. 持续集成服务器运行自动化构建和测试;
  5. 如果测试通过,转到步骤(1);
  6. 如果测试没有通过,转到步骤(2)。如图2所示。

三、多人并行开发

两周后,游戏初见原型,Joe向他的几个朋友介绍了他的游戏创建,他们都非常喜欢,因此也加入了游戏开发。麻烦很快就出现了。持续集成服务器中构建结果经常失败,所以每次检出代码后都要做问题清理工作。于是,Job与朋友们坐下来讨论如何解决这个问题。

Alice说:“我们每个人都拉一个独立分支,当每个人的功能开发完成以后,再合并到一起不就行了吗?”

Joe不同意这样的做法。“游戏的需求还不明晰,要经常合在一起看一下效果。所以还是在同一个分支上开发吧。下面,我们讨论一下如何让这种失败少一些吧。”

于是,他们花了点儿时间,发现有两个主要原因导致失败。

  1. 本地代码有问题,原本就编译不了或会导致测试失败,但还是提交了;
  2. 开始做新功能时,没有特别注意分支上的持续集成状态,直接将主分支上的代码直接就与本地代码合并了;

Joe提出,开发流程应该变成如图3所示:

  1. 每个人在开发新代码之前,只能从持续集成已成功的那个最新版本检出代码;
  2. 开发新功能或修改bug;
  3. 提交前将主分支上的代码再次取到本地合并;
  4. 运行本地测试,确保测试可以通过;
  5. 提交代码到主分支,由持续集成服务器再次运行测试。
  6. 如果测试通过,转到步骤(1);
  7. 如果测试没有通过,转到步骤(2),直到修复持续集成上的构建。

可是,Alice提出反对意见。她认为:“既然本地已经运行了测试,为什么还要在持续集成服务器上再次运行呢?”

Joe解释到:“主要是因为我们每个人的本地环境都不完全相同,很可能出现‘它在我的机器没有问题呀’的这个现象,所以还是要在独立的持续集成服务器上再运行一次。”

因此,大家就这么决定了。

四、两次本地构建的目的

四周后的一天,Joe花了很长时间完成了某个新功能后,打算提交了。于是他把分支当前的代码与其本地代码进行了一次合并。然后运行了本地测试,但测试失败了。他用了很长时间来定位该问题是在他自己修改的功能里,还是在被合入的代码中。这让他对提交流程进行了反思。

“要是在合入他人代码之前,能够先运行一次本地测试,验证一下我的代码没问题就好了,反正本地测试所花的时间也不长。”

于是,他把这个想法告诉了其他人,最后大部分人都同意这么做。于是,其提交流程就变成了这样:?

  1. 每个人在开发新代码之前,只能从持续集成完全成功的那个最新版本检出代码;
  2. 开发新功能或修改bug;
  3. 运行本地测试,如果有失败就立即修复,直至测试成本;
  4. 提交前将主分支上的代码再次取到本地合并;
  5. 运行本地测试,确保测试可以通过;
  6. 提交代码到主分支,由持续集成服务器再次运行测试。
  7. 如果测试通过,转到步骤(1);
  8. 如果测试没有通过,转到步骤(2)。

这个过程就被称为“Check-in Dance”。

Alice还说道:“我们在从主分支上检出代码时,一定是那个通过持续集成验证的最新版本。这样可以避免检出的代码就是有问题的,而影响自己本地的代码。”整个过程如图4所示。

五、持续集成令牌

过了几天,有人把大家叫到了一起,这次是Alice。她说:

“我今天遇到一个问题。我提交代码之后,正等着持续集成服务器返回结果呢,Bob就提交代码了。幸好我提交的代码通过了测试,否则的话,我就要在 Bob的代码之上修复啦。所以,我建议我们需要设立一个提交令牌,只有拿到这个提交令牌的人才能提交。也就是说,当一个人做完本地测试之后,去拿这个令牌。拿到之后,再进行代码合并、本地测试和提交。提交以后当持续集成服务器返回成功通过的结果时,才能交还令牌。这样就不会出现我和Bob这种情况了。”

可Bob并不同意这样的做法,“这次没有出什么问题,为什么还要这么做呢?”

此时,Joe把话接了过来,说道:“Alice的这个建议很好,我已经遇上过一次这样的事情了,那次测试失败以后,我花了很长时间才发现问题并不在我的提交中,而是在Mary的提交中。我把它修复后,又做了一次提交。”由于大多数人都同意这么做,因此团队决定试一试。因为目前测试运行时间很短,所以提交和集成工作没有遇到什么瓶颈。提交流程如图5所示。

似乎事情到这里就结束了。然而,这个游戏被某投资公司看中,决定做更大的投入,招更多的开发人员,让它成为一个开放游戏平台。那么,接下来Joe与他的朋友们还会遇到哪些问题呢?

转载于:https://www.cnblogs.com/pangblog/p/3357850.html

相关文章:

C语言的基础题目,几个c语言的基础题目

该楼层疑似违规已被系统折叠 隐藏此楼查看此楼{day_number day_1 day_2 day_3 day_4 day_5 day;printf("%d年%d月%d日为这一年的第%d天!\n", year, month, day, day_number);}else{printf("输入的日不合法!\n");}break;case 7…

Exchange企业实战技巧(3)配置Exchange证书

Exchange2010需要证书支持,exchange2010安装之后会默认开启ssl,在IE中只能使用https://而不是http://来访问owa。如果没有证书,也能安装exchange2010,也能使用owa,但是会有告警出现。 要想消除警告信息&…

【转载】locust性能测试3

#codingutf-8 from locust import HttpLocust,TaskSet,task import queue import randomclass test_taskset(TaskSet):taskdef register(self):try:emailself.locust.emailqueue.get() #获取队列里的数据print(email)except queue.Empty: #队列取空后,直接退出p…

基于 WPF + Modern UI 的 公司OA小助手 开发总结

前言: 距离上一篇博客,整整一个月的时间了。人不能懒下来,必须有个阶段性的总结,算是对我这个阶段的一个反思。人只有在总结的过程中才会发现自己的不足。 公司每天都要在OA系统上上班点击签到,下班点击签退&#xff0…

pprof搭配ceph tell命令分析ceph内存

文章目录安装使用使用ceph tell产生堆栈信息文使用pprof工具分析内存及ceph tell释放内存火焰图FlameGraph可视化进程堆栈信息pprof是一个google开发的支持可视化、且可分析profile文件而达到对内存的分析。并且能够输出文本和图像来支持分析过程,pprof源码 安装 可以直接通过…

android jar 电子书下载,【Android】Gradle project sync jar包长时间下载不下来的解决办法...

当我们新建一个Android项目,或者在项目中依赖使用一个新的第三方库时,Android Studio经常会从jcenter或者maven仓库下载jar包,但是我们的网络环境不一定一直那么的顺畅,当网络环境不好,导致有时候jar包好长时间下载不下…

TextField输入结束后让键盘消失的两个技巧

一、点击Return键消失需要调用Did End On Exit事件。- (IBAction) doneEditing:(id) sender { [sender resignFirstResponder];} 当你输入结束后点击Return键,启动Did End On Exit事件。resignFirstResponder会撤消UITextField的第一响应状态。意味着你…

机器学习 决策树 ID3

构造决策树时需要解决的第一个问题是:当前数据集中哪个特征在划分数据分类时起决定性作用。 划分数据集的原则:将无序的数据变得更加有序 信息增益:在划分数据集前后信息发生的变化 获得信息增益最大的特征就是最好的特征 熵:信息…

centos6.5原生系统修改ceph-mon 的ELF来让其加载低版本glibc库函数

文章目录Step 1:glibc-2.17 被libc.so.6库依赖,升级glibc库Step2:升级编译器-->4.8.2可以正常编译glibc2.17Step3:修改ELF,降低ceph-mon依赖的库函数版本解决ceph-mon调用高版本libc库(修改动态库链接表ELF)Step 1:glibc-2.17 …

如何创建一个基础jQuery插件

如何创建一个基础插件 How to Create a Basic Plugin 有时你想使一块功能性的代码在你代码的任何地方有效.比如,也许你想调用jQuery对象的一个方法,对该对象进行一系列的操作.可能你写了一个真正有用的实用函数,想它能够轻易的移植到其他项目.在这种情况下,你可能想写一个插件.…

rk3399在linux机上烧写img,烧写固件 — TB-96AI documentation

Window主机烧写固件1、安装Windows PC端USB驱动(首次烧写执行)。2、双击DriverAssitant_v4.5DriverInstall.exe打开安装程序,点击“驱动安装”按提示安装驱动即可,安装界面如下所示:3、Type-C线连接主机端的USB接口和RK3399Pro TB-96AI开发板的Type-C接口…

Eclipse,Mycclipse自动补全快捷键设置

为什么80%的码农都做不了架构师?>>> eclipse3.3及以后的版本中中把内容助手(content assist)的快捷键由 alt /改成了ctrl space,这又刚好跟我们操作系统的切换输入法的快捷键冲突,所以造成内容助手不能使用了,给写代…

php 无限极分类

无限极分类1&#xff1a; 1 public function judeg($id)2 {3 $rs Db::name(finance_class) -> field(parent_code) -> where(id,$id) -> select();4 $i 1;5 foreach($rs as $k > $v){6 if($v[parent_code] <> 0){7 $i $this -…

ceph-bluestore-tool基本使用

主要是在bluestore的实例上执行低级管理操作的使用程序,是ceph bluestore的管理工具 命令 help显示帮助信息fsck [--deep]对bluestore元数据进行一致性检查。如果指定了–deep,还要读取所有对象数据并验证校验和repair运行一致性检查 并修复我们可以发生的任何错误bluefs-expo…

Android基础是什么,Android基础概念

android {compileSdkVersion 23buildToolsVersion “23.0.1”defaultConfig {applicationId “com.example.checkyourtargetsdk"minSdkVersion 15targetSdkVersion 23versionCode 1versionName “1.0”}以上是Android工程里名称为app的module的build.gradle文件其中的内容…

HDOJ 1060 Leftmost Digit

Author Ignatius.L题目大意&#xff1a;1.第一行输入一个整数T代表接下来有T组测试数据。2.接下来的T行&#xff0c;每行输入一个整数&#xff08;1<N<1,000,000,000&#xff09;。3.输出结果为N^N&#xff08;N的N次方&#xff09;最左边的那一位数&#xff08;即最高位…

WPF-002 下拉列表的简单实现

最近在一个WPF项目中用到一个下拉列表&#xff0c;随着用户输入字符而进行显示&#xff0c;使用了绑定等知识&#xff0c;虽然实现比较简单&#xff0c;可是在性能上也是想了很多办法终于才勉强可以用&#xff0c;与大家分享下。 用于页面绑定的模型类&#xff1a; public clas…

洛谷:P3950 部落冲突

原题地址:https://www.luogu.org/problemnew/show/P3950 题目简述 给定一棵树&#xff0c;每次给定一个操作&#xff0c;有如下两种&#xff1a; 将某条边染黑 2.询问给定的u,v两点间是否有边被染黑思路 询问两点间是否有边被染黑只需要在求LCA时判一下就行。所以直接上树链剖分…

深入理解ceph-disk prepare 源码逻辑

文章目录CEPH-DISK代码逻辑DEF MAIN:DEF PARSE_ARGS:DEF Prepare.set_subparser(subparsers)def _prepare(self):PrepareBluestore的_prepare函数def prepare(self, *to_prepare_list):PrepareData类中的prepare函数def prepare_device(self, *to_prepare_list): #prepare_devi…

Deep Learning 学习随记(三)续 Softmax regression练习

上一篇讲的Softmax regression&#xff0c;当时时间不够&#xff0c;没把练习做完。这几天学车有点累&#xff0c;又特别想动动手自己写写matlab代码 所以等到了现在&#xff0c;这篇文章就当做上一篇的续吧。 回顾&#xff1a; 上一篇最后给出了softmax regression的代价函数和…

html画三个重叠的矩形,html5 实现两个矩形的叠加

Canvas Primer - Example: Drawing shadowswindow.addEventListener(load, function () {//得到canvas&#xff0c;并检测是否支持canvasvar elem document.getElementById(myCanvas);if (!elem || !elem.getContext) {return;}// 得到可以画图的上下文contextvar context el…

sqlplusw下登录sys账户

今天使用sqlplusw时&#xff0c;发现每次使用sys用户登录时总是报错&#xff0c;提示要以sysdba或者sysoper的身份登录&#xff0c;错误提示如下图所示&#xff1a;可是界面上没地方可以输入角色的地方呀&#xff0c;后经尝试发现&#xff0c;在口令输入框里首先输入密码&#…

mybatis =或这个=提示错误Tag name expecte问题解决

解决方案&#xff1a; 1、将<号或者>号进行转义 DATE_SUB(CURDATE(), INTERVAL 31 DAY) < DATE(created) 2、使用<![CDATA[ ]]>符号进行说明 <![CDATA[DATE_SUB(CURDATE(), INTERVAL 31 DAY) < DATE(created)]]> 附&#xff1a; 附录&#xff1a;常见…

s-sgdisk源码分析 “--set-alignment=value分区对齐参数”

文章目录边界对齐子命令使用源码分析sgdisk.cc main函数入口gptcl.cc DoOptions解析并执行具体命令函数gpt.cc CreatePartition创建分区函数&#xff0c;设置起始扇区对齐gpt.cc Align分区对齐函数&#xff0c;设置起始扇区对齐sgdisk命令是由 gdisk-0.8.6-4.el7.x86_64程序包安…

NuGet学习笔记(3) 搭建属于自己的NuGet服务器

文章导读 创建NuGetServer Web站点 发布站点到IIS 添加本地站点到包包数据源 在上一篇NuGet学习笔记(2) 使用图形化界面打包自己的类库 中讲解了如何打包自己的类库&#xff0c;接下来进行最重要的一步&#xff0c;从零开始搭建属于自己的NuGet服务器&#xff0c;诚然园子里及其…

计算机网络共享打不开,网络和共享中心打不开,共享无法访问没有权限

在Win7系统下如果别的计算机设置了共享&#xff0c;那么在本机设置网络发现后就可以打开网络搜索到共享计算机和共享文件了&#xff0c;不过一些朋友反馈win7系统网络发现无法启用的问题&#xff0c;下面小编整理了解决方法&#xff0c;大家可以参考一下哦。解决方法如下&#…

千万不要把 bool 当成函数参数

我们有很多 Coding Style 或 代码规范。 但这一条可能会经常被我们所遗忘&#xff0c;就是我们 经常会在函数的参数里使用bool参数&#xff0c;这会大大地降低代码的可读性。 不信&#xff1f;我们先来看看下面的代码。 当你读到下面的代码&#xff0c;你会觉得这个代码是什么意…

修改ceph-disk源码,增加指定ceph.conf部署osd的功能

文章目录 ceph环境源码修改 主文件:`ceph-disk/main.py`main函数入口parse_args(argv)增加子命令解析get_conf函数使`conf`生效修改所有调用get_conf函数的上级函数参数配置由于最近工作中需要优化osd部署流程,单节点并发加盘过程需要指定特定conf文件,来完成单盘db,wal分区…

相关计算机专业的英语文献,英文文献及翻译计算机专业.doc

英文文献及翻译计算机专业外文资料翻译—英文原文NET-BASED TASK MANAGEMENT SYSTEMHector Garcia-Molina, Jeffrey D. Ullman, Jennifer WisdomABSTRACTIn net-based collaborative design environment, design resources become more and more varied and complex. Besides c…

作业 3 应用分支与循环结构解决问题 统计字符个数

/*统计字符&#xff0c;包括空格或回车&#xff0c;数字字符和其他字符*/#include<stdio.h> int main(void) {int digit,space,letter,other; /*定义4个变量分别存放统计结果*/ char ch;int i;digitspaceletterother0; /*置…