【DevCloud · 敏捷智库】暴走在发布前夜的开发,你怕不怕?

摘要:每月都有2天开发团队要通宵熬夜,你们苦不堪言。有个别的开发同窗,骂完公司骂同事,骂完同事骂客户的,甚至连本身都不放过……

来自一个CEO的叙述

在一次企业交流会上,一个公司的CEO提道,“咱们公司作敏捷开发的转型有一段时间了,采用的是4周一迭代,相比以前的瀑布式开发,咱们能够在每个月就让客户看到咱们的成果物,这确实为公司和客户搭建起了良好的沟通桥梁。可是,也出现了一个很差的状况,就是开发和客户以前的矛盾激化了,因为采用了迭代,因此每月都有2天开发团队要通宵熬夜,你们苦不堪言。有个别的开发同窗,骂完公司骂同事,骂完同事骂客户的,甚至连本身都不放过……”web

那些暴走在发布前夜的开发,你是否也碰见过呢?面试

感同身受的无奈和愤怒

来自开发的一波怒气数据库

“我晕,这谁提的代码啊,上来就白页面了,还玩个球啊!”编程

“我倒,我本地都是好用的啊,怎么部署到环境上不行了呢!”segmentfault

“我去,这哪一个大兄弟提了这么些代码,太能写了。我和他代码冲突多到想哭!”api

“个人代码让哪一个孙子给覆盖了,我一下午白写了,别让我查出来谁干的哈!”安全

“催催催,催个大脑壳啊,你行你来,不行就别说话,合代码这事是人干的活吗!”服务器

“几位大哥,我知道问题出在哪了,我这还有段代码没提交上去呢,嘿嘿,很差意思哈。”“我*!”网络

来自领导的心酸无奈框架

领导:“每次发布前,我都不太想去大家开发那,太压抑了!,你说咋办?”

骨干:“咋办,还能咋办,换人呗。一个个都不懂咋开发还能咋办。”

领导:“不是都通过笔试面试进来的吗?咋还能不懂开发呢?”

骨干:“开发不是开发完了就行,得好用啊。这帮小年轻就知道埋头coding,而后扣出来的都是一堆很差用的代码,很差用倒也没啥,直接就往代码库里提交啊!”

领导:“这帮小年轻这么虎吗?”

骨干:“这还不算是虎的呢,还那种代码冲突了的,无论三七二十一直接就忽略冲突提交,我有好几次,一拉取最新代码,一面红色啊。”

领导:“那你多带带他们,告诉他们怎么作啊!“

骨干:“我都告诉过不少遍了,每次都说‘我测了啊!’,‘诶?奇怪了!’,‘很差意思哥,我忘提交了’,就这帮小年轻,我是真心带不动哈。我仍是以为之前瀑布挺好的,要不就变回去得了。“

领导:“那不行啊,客户如今挺承认咱们的。用敏捷一个月就能看到新作的东西。效果好,客户满意度高。你仍是想一想办法吧。“

骨干:“我看仍是换人吧。我是没法阻止别人不**的“

领导:“……“

问题出在哪里

不知道读者读到这里是否感同身受了一下下,若是没有的话,那么恭喜你,你很幸运的加入到了一个优秀的团队或者公司。

不过,可能你的IT生涯是不完整的……

近些年来,整个IT圈子都在宣扬DevOps,也所以不少人都知道Dev的工做是给应用系统增长新的功能/修复Bug,而Ops的工做是要保持系统的稳定和高性能,而DevOps后就是要调和了Dev和Ops的矛盾、打破两者的壁垒,以更好的面对变化。你们满怀着但愿开始了敏捷和DevOps,但是每每在新潮和流行的“上层建筑”每每发现了“形而下”的落地困难。好比Dev侧自身内部的问题。

在上面举例中的开发的那波怒火和领导的无奈中,诚然有开发人员自身能力素质的问题,但这并不能算是问题,由于全部人都是从菜鸟过来了,没有人是天生的王者。“怒气”到底由于什么?为何会有怒气呢?

这个怒气几乎都来源于在团队协做中的“别人”,其实就是在沟通上产生了问题,这能够归结为工做方式方法的问题,说得更直白就是没有遵循一个良好的软件开发实践。

在传统的瀑布开发的时候,开发每每会在最后“奋力一搏”完成了项目的部署工做,而后就进入了“休息”的状态,若是有bug就修改bug,若是有其余的(如文档补充,希望你没有这样的经历)作其余的,处于被动触发这种相对轻松的姿态,因此他们从某种程度上说,是能够接受“别人”的问题的,毕竟忍耐一下就过去了。

而在敏捷的迭代开发中,每次迭代都要产出潜在的可交付成果物,部署和发布是“永不止境”的,因此就没有仿佛能看到黎明吹响胜利号角的“奋力一搏”,合代码的人率先遭遇一波伤害,紧接着其余的开发一个个承受着伤害(若是出现Bug),而后你们最后再在一块儿承受某个或某些谁都不知道的问题带来的打击……因此每每每次的发布都是一次心志的磨练和煎熬,尤为以大工做量周期以月为单位迭代为最——这个背后的元凶其实就是“集成”!

有什么好办法

虽然相对传统制造业软件显得“年轻”,可是也经历了无数的大风大浪,这种问题并不专属于某些公司,这种烦恼和无奈也并不是只有他们才经历过。早在软件开发的“上古”时代,软件界的大神——Martin Fowler就有过这样的经历:

“我还能够生动记起第一次看到大型软件工程的情景。我当时在一家大型英国电子公司的QA部门实习。个人经理带我熟悉公司环境,咱们进到一间巨大的,充满了压抑感和格子间的的仓库。我被告知这个项目已经 开发了好几年,如今正在集成阶段,并已经集成了好几个月。个人向导还告诉我没人知道集成要多久才能结束”。

Martin Fowler不只在他实习的期间认识到集成是一件很耗时并难以预测的过程,而且不少项目和团队并不把集成当回事。因此为了解决集成所带来的问题以及不少人思想上的不觉得意,Martin Fowler 提出了——持续集成。

持续集成 是一种软件开发实践。在持续集成中,团队成员频繁集成他们的工做成果,通常每人天天至少集成一次,也能够屡次。每次集成会通过自动构建(包括自动测试)的 检验,以尽快发现集成错误。

从其定义上来看,持续集成能够很好的解决开发们的“怒气”的问题,开发的怒气根本上来讲就是因为在协做中缺乏“沟通”所形成的,进而将问题推到了“别人”身上,试想若是整个开发的过程当中,每一个团队的成员彼此作的功能,或者说所提交的代码是“透明”的,那么就能够很大程度上减小这种“别人”的问题了。而且这种“透明”化的周期无需太长时间,最长为一天,最短于几个小时内,从而能够很好的解决了开发团队集成的问题,下降了交付的风险。

那么,具体的落地应该有哪些呢?

应该如何落地

欲善其功必先利其器,在谈落地实践以前,首先看看要实现持续集成须要有哪些工具。

基础工具一:版本控制系统。持续集成最基本的前提条件是对其代码库的版本控制,即:对于代码库的每一项变动,都必须被安全地存放到专有的版本控制系统中,目前最主流的版本控制系统当属Git。

基础工具二:构建工具。构建工具可以经过处理应用的源代码,自动生成所需的软件(包)。软件工具的构建步骤取决于所选用的技术栈。如,Java的应用,可以使用Maven做为构建工具。

讲完了持续集成的定义和基础工具后,那么持续集成的过程是怎么样的呢?咱们一块儿看看Martin Fowler是怎么带着咱们玩转持续集成的吧。(如下内容来自Marin Fowler的持续集成)

举个简单的例子:如今假设要完成一个软件的一部分功能,具体任务是什么并不重要,咱们先假设这个 feature 很小,只用几个小时就能够完成。

一开始,将已集成的源代码复制一份到 本地计算机。这能够经过从源码管理系统的 mainline 上 check out 一份源代码作到。

如今拿到了工做拷贝,接下来须要作一些事情来完成任务。这包括修改产品代码和添加修改自动化测试。在持续集成中,软件应该包含完善的可自动运行的测试——自测试代码。这通常须要用到某一个流行的 XUnit 测试框架。

一旦完成了修改,就会在本身的计算机上启动一个自动化 build。这会将工做拷贝中的源代码编译并连接成为一个可执行文件,并在之上运行自动化测试。只有当全部的 build 和测试都完成并无任何错误时,这个 build 过程才能够认为是成功的。

当本地build 成功后,就能够考虑将改动提交到源码仓库。但麻烦的状况在于别人可能已经在我以前修改过 mainline。这时我须要首先把别人的修改更新到本身的工做拷贝中,再从新作 build。若是别人的代码和本身的有冲突,就会在编译或测试的过程当中引发错误。本身有责任改正这些问题,并重复这一过程,直到本身的工做拷贝能经过 build 并和 mainline 的代码同步。

一旦本地的代码能经过 build,并和 mainline 同步,就能够把个人修改提交到源码仓库。

然而,提交完代码不表示就完事大吉了。还要作一遍集成 build,此次在集成计算机上并要基于 mainline 的代码。只有此次 build 成功了,修改才算告一段落。由于总有可能会忘了什么东西在本身的机器上而没有更新到源码仓库。只有提交的改动被成功的集成了,此次工做才能算结束。

若是两个开发者的修改存在冲突,这一般会被第二我的提 交代码前本地作 build 时发现。即便这时侥幸过关,接下来的集成 build 也会失败掉。无论怎样,错误都会被很快检测出来。此时首要的任务就是改正错误并让 build 恢复正常。在持续集成环境里,必须尽量快地修复每个集成 build。好的团队应该天天都有多个成功的 build。错误的 build 能够出现,但必须尽快获得修复。

这样作的结果是你总能获得一个稳定的软件,它可能有一些 bug,但能够正常工做。每一个人都基于相同的稳定代码进行开发,并且不会离得太远,不然就会不得不花很长时间集成回去。Bug被发现得越快,花在改正上的 时间就越短。

上述基本上就是持续集成的过程和步骤了。那么基于此持续集成又又哪些关键的实践呢?主要有以下几个:

只维护一个源代码

在软件项目里须要不少文件协调一致才能 build 出产品。跟踪全部这些文件是一项困难的工做,尤为是当有不少人一块儿工做时。因此,一点也不奇怪,软件开发者们这些年一直在研发这方面的工具。这些工具称为 源代码管理工具,或配置管理,或版本管理系统,或源码仓库,或各类其它名字。大部分开发项目中它们是不可分割的一部分。但惋惜的是,并不是全部项目都是如 此。虽然很罕见,但我确实参加过一些项目,它们直接把代码存到本地驱动器和共享目录中,乱得一塌糊涂。

因此, 做为一个最基本的要求,你必须有一个起码的源代码管理系统。成本不会是问题,由于有不少优秀的开源工具可用。当前较好的开源工具是 Subversion。(更 老的一样开源的 CVS 仍被普遍使用,即便是 CVS 也比什么都不用强得多,但 Subversion 更先进也更强大。)有趣的是,我从与开发者们的交谈中了解到,不少商业源代码管理工具其实不比 Subversion 更好。只有一个商业软件是你们一致赞成值得花钱的,这就是 Perforce。

一旦你有了源代码管理系统,你要确保全部人都知道到哪里去取代码。不该出现这样的问题:“我应该到哪里去找xxx文件?” 全部东西都应该存在源码仓库里。

即使对于用了源码仓库的团队,我仍是观察到一个很广泛的错误,就是他们没有把 全部东西都放在源码仓库里。通常人们都会把代码放进去,但还有许多其它文件,包括测试脚本,配置文件,数据库Schema,安装脚本,还有第三方的库,所 有这些build时须要的文件都应该放在源码仓库里。我知道一些项目甚至把编译器也放到源码仓库里(用来对付早年间那些莫名其妙的C++编译器颇有效)。 一个基本原则是:你必须可以在一台干净的计算机上重作全部过程,包括checkout和彻底build。只有极少许的软件须要被预装在这台干净机器上,通 常是那些又大又稳定,安装起来很复杂的软件,好比操做系统,Java开发环境,或数据库系统。

你必须把 build须要的全部文件都放进源代码管理系统,此外还要把人们工做须要的其余东西也放进去。IDE配置文件就很适合放进去,由于你们共享一样的IDE配 置可让工做更简单。

版本控制系统的主要功能之一就是建立 branch 以管理开发流。这是个颇有用的功能,甚至能够说是一个基础特性,但它却常常被滥用。你最好仍是尽可能少用 branch。通常有一个mainline就够 了,这是一条能反映项目当前开发情况的 branch。大部分状况下,你们都应该从mainline出发开始本身的工做。(合理的建立 branch 的 理由主要包括给已发布的产品作维护和临时性的实验。)

通常来讲,你要把build依赖的全部文件放进代码管理 系统中,但不要放build的结果。有些人习惯把最终产品也都放进代码管理系统中,我认为这是一种坏味道——这意味着可能有一些深层次的问题,极可能是无 法可靠地从新build一个产品。

自动化Build

一般来讲,由源代码转变成一个可运行的系统是一个复杂的过程,牵扯到编译,移动文件,将 schema 装载到数据库,诸如此类。可是,同软件开发中的其它相似任务同样,这也能够被自动化,也必须被自动化。要人工来键入各类奇怪的命令和点击各类对话框纯粹是浪费时间,也容易滋生错误。

在大部分开发平台上都能找到自动化 build 环境的影子。好比 make,这在 Unix 社区已经用了几十年了,Java 社区也开发出了 Ant,.NET 社区之前用 Nant,如今用 MSBuild。无论你在什么平台上,都要确保只用一条命令就能够运行这些脚本,从而 build 并运行系统。

一 个常见的错误是没有把全部事都放进自动化 build。好比:Build 也应该包括从源码仓库中取出数据库 schema 并在执行环境中设置的过程。我要重申一下前面说过的原则:任何人都应该能从一个干净的计算机上 check out 源代码,而后敲入一条命令,就能够获得能在这台机器上运行的系统。

Build 脚本有不少不一样的选择,依它们所属的平台和社区而定,但也没有什么定势。尽管大部分的 Java 项目都用 Ant,仍是有一些项目用 Ruby(Ruby Rake 是一个不错的 build 脚本工具)。咱们也曾经用 Ant 自动化早期的 Microsoft COM 项目,事实证实颇有价值。

一个大型 build 一般会很耗时,若是只作了很小的修改,你不会想花时间去重复全部的步骤。因此一个好的 build 工具应该会分析哪些步骤能够跳过。一个通用的办法是比较源文件和目标文件的修改时间,并只编译那些较新的源文件。处理依赖关系要麻烦一些:若是一个目标文 件修改了,全部依赖它的部分都要从新生成。编译器可能会帮你处理这些事情,也可能不会。

根据你的须要,你可能 会想 build 出各类不一样的东西。你能够同时 build 系统代码和测试代码,也能够只 build 系统代码。一些组件能够被单独 build。Build 脚本应该容许你在不一样的状况中 build 不一样的 target。

咱们许多人都用 IDE,许多 IDE 都内置包含某种 build 管理功能。然而,相应的配置文件每每是这些 IDE 的专有格式,并且每每不够健壮,它们离了 IDE 就没法工做。若是只是 IDE 用户本身一我的开发的话,这还可以接受。但在团队里,一个工做于服务器上的主 build 环境和从其它脚本里运行的能力更重要。咱们认为,在 Java 项目里,开发者能够用本身的 IDE 作 build,但主 build 必须用 Ant 来作,以保证它能够在开发服务器上运行。

让你的Build自行测试

传统意义上的 build 指编译,连接,和一些其它能让程序运行起来的步骤。程序能够运行并不意味着它也工做正常。现代静态语言能够在编译时检测出许多 bug,但仍是有更多的漏网之鱼。

一种又快又省的查 bug 的方法是在 build 过程当中包含自动测试。固然,测试并不是完美解决方案,但它确实能抓住不少 bug——多到可让软件真正可用。极限编程(XP)和测试驱动开发(TDD)的出现很好地普及了自测试代码的概念,如今已经有不少人意识到了这种技巧的 价值。

常常读个人著做的读者都知道我是 TDD 和 XP 的坚决追随者。可是我想要强调你不须要这二者中任何一个就能享受自测试代码的好处。二者都要求你先写测试,再写代码以经过测试,在这种工做模式里测试更多 着重于探索设计而不是发现 bug。这绝对是一个好方法,但对于持续集成而言它并没必要要,由于这里对自测试代码的要求没有那么高。(尽管我确定会选择用 TDD 的方式。)

自测试代码须要包含一套自动化测试用例,这些测试用例能够检查大部分代码并找出 bug。测试要可以从一条简单的命令启动。测试结果必须能指出哪些测试失败了。对于包含测试的 build,测试失败必须致使 build 也失败。

在过去的几年里,TDD 的崛起普及了开源的 XUnit 系列工具,这些工具用做以上用途很是理想。对于咱们在 ThoughWorks 工做的人来讲,XUnit 工具已经证实了它们的价值。我老是建议人们使用它们。这些最先由 Kent Beck 发明的工具使得设置一个彻底自测试环境的工做变得很是简单。

毋庸置疑,对于自动测试的工做而言,XUnit 工具只是一个起点。你还必须本身寻找其余更适合端对端测试的工具。如今有不少此类工具,包括FIT,Selenium,Sahi,Watir,FITnesse, 和许多其它我没法列在这里的工具。

固然你不能期望测试发现全部问题。就像人们常常说的:测试经过不能证实没有 bug。然而,完美并不是是你要经过自测试 build 达到的惟一目标。常常运行不完美的测试要远远好过梦想着完美的测试,但实际什么也不作。

每人天天要向mainline提交代码

集成的主要工做实际上是沟 通。集成可让开发者告诉其余人他们都改了什么东西。频繁的沟通可让人们更快地了解变化。

让开发者提交到 mainline 的一个先决条件是他们必须可以正确地 build 他们的代码。这固然也包括经过 build 包含的测试。在每一个提交迭代里,开发者首先更新他们的工做拷贝以与 mainline 一致,解决任何可能的冲突,而后在本身的机器上作 build。在 build 经过后,他们就能够随便向 mainline 提交了。

经过频繁重复上述过程,开发者能够发现 两我的之间的代码冲突。解决问题的关键是尽早发现问题。若是开发者每过几个小时就会提交一次,那冲突也会在出现的几个小时以内被发现,从这一点来讲,由于 尚未作太多事,解决起来也容易。若是让冲突待上几个星期,它就会变得很是难解决。

由于你在更新工做拷贝时也 会作 build,这意味着你除了解决源代码冲突外也会检查编译冲突。由于 build 是自测试的,你也能够查出代码运行时的冲突。后者若是在一段较长的时间还没被查出的话会变得尤为麻烦。由于两次提交之间只有几个小时的修改,产生这些问题 只可能在颇有限的几个地方。此外,由于没改太多东西,你还能够用 diff-debugging 的技巧来找 bug。

总的来讲,我 的原则是每一个开发者天天都必须提交代码。实践中,若是开发者提交的更为频繁效果也会更好。你提交的越多,你须要查找冲突错误的地方就越少,改起来也越快。

频繁提交客观上会鼓励开发者将工做分解成以小时计的小块。这能够帮助跟踪进度和让你们感觉到进展。常常会有人一开始根 本没法找到能够在几小时内完成的像样的工做,但咱们发现辅导和练习能够帮助他们学习其中的技巧。

每次提交都 应在集成计算机上从新构建 mainline

使用每日提交的策略后,团队就能获得不少通过测试的 build。这应该意味着 mainline 应该老是处于一种健康的状态。但在实践中,事情并不是老是如此。一个缘由跟纪律有关,人们没有严格遵照在提交以前在本地更新并作 build 的要求。另外一个缘由是开发者的计算机之间环境配置的不一样。

结论是你必须保证平常的 build 发生在专用的集成计算机上,只有集成 build 成功了,提交的过程才算结束。本着“谁提交,谁负责”的原则,开发者必须监视 mainline 上的 build 以便失败时及时修复。一个推论是若是你在下班前提交了代码,那你在 mainline build 成功以前就不能回家。

我知道主要有两种方法能够使用:手动 build,或持续集成服务器软件。

手动 build 描述起来比较简单。基本上它跟提交代码以前在本地所作的那次 build 差很少。开发者登陆到集成计算机,check out 出 mainline 上最新的源码(已包含最新的提交),并启动一个集成 build。他要留意 build 的进程,只有 build 成功了他的提交才算成功。(请查看 Jim Shore 的描述。)

持续集成服务器软件就像一个监视着源码仓库的监视器。每 次源码仓库中有新的提交,服务器就会自动 check out 出源代码并启动一次 build,而且把 build 的结果通知提交者。这种状况下,提交者的工做直到收到通知(一般是 email)才算结束。

在 ThoughtWorks,咱们都是持续集成服务器软件的坚决支持者,实际上咱们引领了 CruiseControl 和 http://CruiseControl.NET 最 早期的开发,二者都是被普遍使用的开源软件。此后,咱们还作了商业版的 Cruise 持续集成服务器。咱们几乎在每个项目里都会用持续集成服务器,而且对结果很是满意。

不是每一个人都会用持续集成服务器。Jim Shore 就清楚地表达了为何他更偏好手动的办法。我赞成他的见解中的持续集成并不只仅是安装几个软件而已,全部的实践 都必须为了能让持续集成更有效率。但一样的,许多持续集成执行得很好的团队也会发现持续集成服务器是个颇有用的工具。

许多组织根据安排好的日程表作例行 build,如天天晚上。这其实跟持续集成是两码事,并且作得远远不够。持续集成的最终目标就是要尽量快地发现问题。Nightly build 意味着 bug 被发现以前可能会待上整整一天。一旦 bug 能在系统里呆这么久,找到并修复它们也会花较长的时间。

作好持续集成的一个关键因素是一旦 mainline 上的 build 失败了,它必须被立刻修复。而在持续集成环境中工做最大的好处是,你总能在一个稳定的基础上作开发。mainline 上 build 失败并不老是坏事,但若是它常常出错,就意味着人们没有认真地在提交代码前先在本地更新代码和作 build。当 mainline 上 build 真的失败时,第一时间修复就成了头等大事。为了防止在 mainline 上的问题,你也能够考虑用 pending head 的方法。

当团队引入持续集成时,这一般是最难搞定的事情之一。在初期,团队会很是难以接 受频繁在 mainline 上作 build 的习惯,特别当他们工做在一个已存在的代码基础上时更是如此。但最后耐心和坚决不移的实践经常会起做用,因此不要气馁。

保持快速 build

持续集成的重点就是快速反馈。没有什么比缓慢的 build 更能危害持续集成活动。这里我必须认可一个奇思怪想的老家伙关于 build 快慢标准的的玩笑(译者注:原文如此,不知做者所指)。个人大部分同事认为超过1小时的 build 是不能忍受的。团队们都梦想着把 build 搞得飞快,但有时咱们也确实会发现很难让它达到理想的速度。

对大多数项目来讲,XP 的10分钟 build 的指导方针很是合理。咱们如今作的大多数项目都能达到这个要求。这值得花些力气去作,由于你在这里省下的每一分钟都能体如今每一个开发者每次提交的时候。持 续集成要求频繁提交,因此这积累下来能节省不少时间。若是你一开始就要花1小时的时间作 build,想加快这个过程会至关有挑战。即便在一个从头开始的新项目里,想让 build 始终保持快速也是颇有挑战的。至少在企业应用里,咱们发现常见的瓶颈出如今测试时,尤为当测试涉及到外部服务如数据库。

也许最关键的一步是开始使用分阶段build(staged build)。分阶段 build(也被称做 build 生产线)的基本想法是多个 build 按必定顺序执行。向 mainline 提交代码会引起第一个 build,我称之为提交 build(commit build)。提交 build 是当有人向 mainline 提交时引起的 build。提交 build 要足够快,所以它会跳过一些步骤,检测 bug 的能力也较弱。提交 build 是为了平衡质量检测和速度,所以一个好的提交 build 至少也要足够稳定以供他人基于此工做。

一旦提交 build 成功,其余人就能够放心地基于这些代码工做了。但别忘了你还有更多更慢的测试要作,能够另找一台计算机来运行运行这些测试。

一个简单的例子是两阶段 build。第一阶段会编译和运行一些本地测试,与数据库相关的单元测试会被彻底隔离掉(stub out)。这些测试能够运行得很是快,符合咱们的10分钟指导方针。可是全部跟大规模交互,尤为是真正的数据库交互的 bug 都没法被发现。第二阶段的 build 运行一组不一样的测试,这些测试会调用真正的数据库并涉及更多的端到端的行为。这些测试会跑上好几小时。

这种状况下,人们用第一阶段做为提交 build,并把这做为主要的持续集成工做。第二阶段 build 是次级build,只有 在须要的时候才运行,从最后一次成功的提交 build 中取出可执行文件做进一步测试。若是次级 build 失败了,你们不会马上停下手中全部工做去修复,但团队也要在保证提交 build 正常运行的同时尽快修正 bug。实际上次级 build 并不是必定要正常运行,只要 bug 都可以被检查出来而且能尽快获得解决就好。在两阶段 build 的例子里,次级 build 常常只是纯粹的测试,由于一般只是测试拖慢了速度。

若是次级 build 检查到了 bug,这是一个信号,意味着提交 build 须要添加一个新测试了。你应该尽量把次级 build 失败过的测试用例都添加到提交 build 中,使得提交 build 有能力验证这些 bug。每当有 bug 绕过提交测试,提交测试总能经过这种方法被增强。有时候确实没法找到测试速度和 bug 验证兼顾的方法,你不得不决定把这个测试放回到次级 build 里。但大部分状况下都应该能够找到合适加入提交 build 的测试。

上面这个例子是关于两阶段 build,但基本原则能够被推广到任意数量的后阶段 build。提交 build 以后的其它 build 均可以同时进行,因此若是你的次级测试要两小时才能完成,你能够经过用两台机器各运行一半测试来快一点拿到结果。经过这个并行次级 build 技巧,你能够向平常 build 流程中引入包括性能测试在内的各类自动化测试。(当我过去几年内参加 Thoughtworks 的各类项目时,我碰到了不少有趣的技巧,我但愿可以说服一些开发者把这些经验写出来。)

在模拟生产环境中进行测试

测试的关键在于在受控条件下找出系统内可能在实际生产中出现的任何问题。这里一个明显的因素是生产系 统的运行环境。若是你不在生产环境作测试,全部环境差别都是风险,可能最终形成测试环境中运行正常的软件在生产环境中没法正常运行。

天然你会想到创建一个与生产环境尽量彻底相同的测试环境。用相同的数据库软件,还要同一个版本;用相同版本的操做系统;把全部生产环 境用到的库文件都放进测试环境中,即便你的系统没有真正用到它们;使用相同的IP地址和端口;以及相同的硬件;

好吧,现实中仍是有不少限制的。若是你在写一个桌面应用软件,想要模拟全部型号的装有不一样第三方软件的台式机来测试显然是不现实的。相似的,有些生产环境可 能由于过于昂贵而没法复制(尽管我常碰到出于经济考虑拒绝复制不算太贵的环境,结果得不偿失的例子)。即便有这些限制,你的目标仍然是尽量地复制生产环 境,而且要理解并接受因测试环境和生产环境不一样带来的风险。

若是你的安装步骤足够简单,无需太多交互,你也许能在一个模拟生产环境里运行提交 build。但事实上系统常常反应缓慢或不够稳定,这能够用 test double 来解决。结果经常是提交测试为了速度缘由在一个假环境内运行,而次级测试运行在模拟真实的生产环境中。

我注意到愈来愈多人用虚拟化来搭建测试环境。虚拟机的状态能够被保存,所以安装并测试最新版本的build相对简单。此外,这可让你在一台机器上运行多个测试,或在一台机器上模拟网络里的多台主机。随着虚拟化性能的提高,这种选择看起来愈来愈可行。

让每一个人都能轻易得到最新的可执行文件

软件开发中最困难的部分是肯定你的软件行为符合预期。咱们发现事先清楚并正确描述需求很是困难。对人们而言,在一个有缺陷的东西上指出须要修改的地方要容易得多。敏捷开发过程承认这种行为,并从中受益。

为了以这种方式工做,项目中的每一个人都应该能拿到最新的可执行文件并运行。目的能够为了 demo,也能够为了探索性测试,或者只是为了看看这周有什么进展。

这作起来其实至关简单:只要找到一个你们都知道的地方来放置可执行文件便可。能够同时保存多份可执行文件以备使用。每次放进去的可执行文件应该要经过提交测试,提交测试越健壮,可执行文件就会越稳定。

若是你采用的过程是一个足够好的迭代过程,把每次迭代中最后一个 build 放进去一般是明智的决定。Demo 是一个特例,被 demo 的软件特性都应该是演示者熟悉的特性。为了 demo 的效果值得牺牲掉最新的 build,转而找一个早一点但演示者更熟悉的版本。

每一个人都能看到进度

持续集成中最重要的是沟通。你须要保证每一个人都能轻易看到系统的状态和最新的修改。

沟通的最重要的途径之一是 mainline build。若是你用 Cruise,一个内建的网站会告诉你是否正有 build 在进行,和最近一次 mainline build 的状态。许多团队喜欢把一个持续工做的状态显示设备链接到 build 系统来让这个过程更加引人注目,最受欢迎的显示设备是灯光,绿灯闪亮表示 build 成功,红灯表示失败。一种常见的选择是红色和绿色的熔岩灯,这不只仅指示 build 的状态,还能指示它停留在这个状态的时间长短,红灯里出现气泡表示 build 出问题已经太长时间了。每个团队都会选择他们本身的 build 传感器。若是你的选择带点幽默性和娱乐性效果会更好(最近我看到有人在实验跳舞兔)。

即便你在使用手动持续集成,可见程度依然很重要。Build 计算机的显示器能够用来显示 mainline build 的状态。你极可能须要一个 build 令牌放在正在作 build 那人的桌子上(橡皮鸡这种看上去傻傻的东西最好,缘由同上)。有时人们会想在 build 成功时弄出一点噪音来,好比摇铃的声音。

持续集成服务器软件的网页能够承载更多信息。Cruise 不只显示谁在作 build,还能指出他们都改了什么。Cruise 还提供了一个历史修改记录,以便团队成员可以对最近项目里的状况有所了解。我知道 team leader喜欢用这个功能了解你们手头的工做和追踪系统的更改。

使用网站的另外一大优势是便于那些远程工做的人了解项目的状态。通常来讲,我倾向于让项目中发挥做用的成员都坐在一块儿工做,但一般也会有一些外围人员想要了解项目的动态。若是组织想要把多个项目的 build状况聚合起来以提供自动更新的简单状态时,这也会颇有用。

好的信息展现方式不只仅依赖于电脑显示器。我最喜欢的方式出现于一个中途转入持续集成的项目。很长时间它都没法拿出一个稳定的 build。咱们在墙上贴了一全年的日历,每一天都是一个小方块。每一天若是 QA 团队收到了一个能经过提交测试的稳定 build,他们都会贴一张绿色的贴纸,不然就是红色的贴纸。日积月累,从日历上能看出 build 过程在稳定地进步。直到绿色的小方块已经占据了大部分的空间时,日历被撤掉了,由于它的使命已经完成了。

自动化部署

自动化集成须要多个环境,一个运行提交测试,一个或多个运行次级测试。天天在这些环境之间频繁拷贝 可执行文件可不轻松,自动化是一个更好的方案。为实现自动化,你必须有几个帮你将应用轻松部署到各个环境中的脚本。有了脚本以后,天然而然的结果是你也要 用相似的方式部署到生产环境中。你可能不须要天天都部署到生产环境(尽管我见过这么作的项目),但自动化可以加快速度并减小错误。它的代价也很低,由于它 基本上和你部署到测试环境是一回事。

若是你部署到生产环境,你须要多考虑一件事情:自动化回滚。坏事情随时可 能发生,若是状况不妙,最好的办法是尽快回到上一个已知的正常状态。可以自动回滚也会减轻部署的压力,从而鼓励人们更频繁地部署,使得新功能更快发布给用 户。(Ruby on Rails 社区开发了一个名为 Capistrano 的工具,是这类工具很好的表明。)

我还在服 务器集群环境中见过滚动部署的方法,新软件每次被部署到一个节点上,在几小时时间内逐步替换掉原有的软件。

在 web 应用开发中,我碰到的一个有趣的想法是把一个试验性的 build 部署到用户的一个子集。团队能够观察这个试验 build 被使用的状况,以决定是否将它部署到全体用户。你能够在作出最终决定以前试验新的功能和新的 UI。自动化部署加上良好的持续集成的纪律是这项工做的基础。

(以上内容来自Marin Fowler的持续集成)

写在最后

“个人脑海中仍是会浮现出第一段描述的早期软件项目。他们已经到了一个漫长项 目的末期(至少他们指望如此),但仍是不知道距离真正的结束有多远。”这是来自Martin Fowler曾经历过的感觉。

而文中的第二段的那些开发们的“怒气”是笔者从十年前作开发的时候,所经历过的几个团队所发生过的。

在集成的过程当中,总会有种种没法预测的事情发生,不管是人仍是事,你根本没法预测其进展从而很容易进入到迷茫地带,每个处在迷茫地带的人都很难去作到轻松应对,长此以往开发人员会产生疲于奔命之感,致使团队没法凝聚成“拳头”打出强有力的一拳。基于这种状况,笔者认为这正是咱们引入持续集成的缘由所在。

笔者认为Martin Fowler关于持续集成的落地实践部分已经比较详尽彻底能够用来你们公共参考学习,因此没有在关公面前耍大刀,故引用于此文章。可是在咱们持续集成实际的过程当中必定会遇到不少问题,好比提高build效率的分段build策略或者其余实际的需求等,这都须要咱们在平常工做中,经过迭代不断的来研究和完善其实践的方法,并在回顾的过程当中加以讨论、分析总结,最终提高团队的研发效率。也能够使用一些大厂如华为云DevCloud做为持续集成的工具,其提供专业的一站式解决方案,方便了中小企业的DevOps落地。

点击关注,第一时间了解华为云新鲜技术~

相关文章
相关标签/搜索