如果那很痛苦,就多做几次

Created
Apr 8, 2024 02:14 PM
Tags
If it hurts, do it more often.
这句话出自《持续交付 - 发布可靠软件的系统方法》,一本真正讲软件工程的入门书籍。

痛苦和时间的关系

教父级软件工程师 Martin Flower 应该是很多人的偶像,他早在 2011 年的博客里就写到:Frequency Reduces Difficulty,频繁去尝试你认为很难的事情,才有可能让事情变得更简单。在那个时候开发软件功能相对来说需要更长的时间,大家都知道将自己的工作和别人的工作集成在一起往往时令人沮丧和痛苦的过程,所以大家都会选择推迟集成的时间。
如果我们把集成代码的痛苦和时间的关系表示出来,我们会看到这样的图表。
notion image
时间越往后,功能集成就越困难,做这件事的痛苦程度就越高。然而,Martin 指出,只要你频繁去做软件集成,这样的痛苦就大大减少了,如果能做到持续集成 - 功能完成后马上合并到主干分支进行部署测试,集成的痛苦几乎就消失了。

少做是不是更明智

我曾经和很多团队讨论过提高软件发布频率的话题。大家觉得以下哪种方式更科学更可靠?
  1. 团队 A 说,我们每次尽最大努力提高软件发布的质量和稳定性,每个环节都全面测试仔细验证,每次发布我们都将严阵以待尽心尽力,确保万无一失,我们要做少但精。
  1. 团队 B 说,我们尽最大努力让发布流程自动化,尽量不需要人工干预就可以完成发布,我们争取做到每天发布 N 次,遇到问题可以快速补救或者回滚,我们要做快但小。
团队 A 的人说,我们是金融公司,跟钱打交道,要谨慎,首先追求的是稳,绝对不能出错。我跟团队 A 的人说,那其实你们可以一年发布一次,只要年底的发布是成功的,那么成功率就是 100%,大家摆摆手说使不得使不得。我说,当年微软发布 Windows 8 就光测试就花了快 3 年时间,慢工出细活。大家说,我们不一样,我们现在都在讲敏捷,瀑布开发已经过时了。我说,那两三个月发布一次算敏捷吗?大家说,我们的客户没需求说要快速交付啊,他们已经习惯现在我们两个月上一个版了。
团队 B 的人说,我们组人变少了,以前还有人专门负责环境和发布,现在这样的岗位都被拿掉了,我们也是迫不得已才要搞自动化的。我跟团队 B 的人说,撇开公司的优化策略,你们是否感受到了这些变化带来的好处。大家说,当然,以前周末要花半天时间负责生产环境部署,周一来了还是要再等用户上线了确认才能把心放到肚子里。现在用户的思维方式也被我们改了,有些小功能快的话第二天就能看到效果,目前最大的问题是用户对小功能的尺度把握不好,催的越来越急,我们也越来越卷。
软件开发领域领从来就没有银弹,但是有些规律和原则是不变的。
  1. 如果你或者你的产品被用户需要,那你对用户来说就是有价值的。反之,如果用户可以在很长一段时间内不需要你或者想不起你,你或者你的产品就是可有可无的。
  1. 如果社会允许竞争,那一定是有竞争力的一方会获得最后的生存权。公司和公司之间存在合作关系,但在有限的资源和份额面前,竞争的关系会大于合作的关系。
一个组织内部合作关系理论上应该大于竞争关系,因为每个组织都有共同的目标和利益驱动。但作为组织的管理者,是否完全不鼓励或者避免竞争呢?相信大家都有自己的答案。
商鞅变法前,土地是不允许买卖的。张三有两亩地,李四也有两亩地,张三每亩地每年能产 100 斤粮食,李四每亩地能产 200 斤粮食,收成怎样各不相干。
商鞅变法后,土地允许买卖租赁,张三就把地租给李四,租金 50 斤每年,张三不再干活还能多收50 斤粮食,李四每年多了两亩地的收成
 
 
这种更频繁地做痛苦事情的想法在敏捷思维中经常出现。测试、重构、数据库迁移、与客户对话、规划、发布 —— 各种活动都更加频繁地进行。
是什么造成了这种效应呢?我认为主要有以下三个原因。首先,随着要做的事情的数量增加,大多数这些任务变得更加困难,但是当分解成更小的块时,它们就很容易组合起来。数据库迁移就是一个很好的例子。指定涉及多个表的大型数据库迁移非常困难且容易出错。但如果你每次只做一点点改变,那么每一项都正确就容易多了。此外,您可以轻松地将小型迁移串起来形成一个序列。因此,当您将大型迁移分解为一系列小型迁移时,一切都会变得更容易处理。这就是数据库重构的本质。
反馈是第二个原因。敏捷思维的大部分内容都是关于建立反馈循环,以便我们可以更快地学习。反馈是极限编程的明确价值,也是Ken Schwaber 关于定义过程控制和经验过程控制之间差异的讨论的核心。在软件开发等复杂过程中,您必须经常检查自己所处的位置并进行修正。为此,您必须寻找一切机会添加反馈循环并增加获得反馈的频率,以便您可以更快地进行调整。
第三个原因是练习。对于任何活动,只要我们经常做,我们就会进步。人们常说,获得良好手术效果的关键是找到经常进行手术的外科医生。练习可以帮助你解决流程中的问题,并让你更熟悉出现问题的迹象。如果你反思自己正在做的事情,你也会想出改进你的练习的方法。软件还有自动化的潜力。一旦你完成某件事几次,你就会更容易了解如何将其自动化,并且你更有动力将其自动化。自动化特别有用,因为它可以提高速度并减少出错的机会。
因此,每当您面临痛苦的活动时,问问自己这些力量是否适用。如果是这样,增加频率可以让你更有效率并消除压力源。
 
自从 12 年,开始选型研发 team 的 CI 工具链的选项和搭建,在经过了近一年的摸索后,13 年初开始全权负责公司内部的持续集成系统的流程设计和工具链的搭建,压力山大。
当时阅读了包括持续交付在内的一些技术书籍,借鉴了一些开源社区的 CI 体系以及工具链,Openstack 社区的持续集成流程和规范给我了非常大的帮助,参与了一些国内的技术讲座,Qcon 上百度的乔梁所做的持续集成分享给我了诸多启发。
《持续交付》是我手头唯一的纸质参考书,也是市面上屈指可数讲述持续交付的书籍。
这类书讲得是道,方法论,也就是做事的方法,但不会深入技术细节。
因为每家公司的业务不同,技术栈不同,研发团队的组成也不尽相同,虽然此书以 Java 开发作为范例,主要是来说明某些点上做进一步的阐述。
每本书给人的启发不尽相同,它给我的最大感触是建立一套成体系的规范的流程非常重要。
那么说到持续集成,那么就来叨叨下怎么成为一名顶级的 DevOps 工程师。
软件世界的战场
如果你对 devops 的概念不是很了解的话,没有关系,可以先跳到维基百科阅读一下 DevOps 条目。有了模模糊糊的概念之后, 我们先抛开所有市面上对于 devops 的各种夸大和炒作,首先来思考一下为什么近年来会出现这么一个职位。
在软件开发中,一个人可以孤军奋战身兼数职:产品设计,开发,测试,运维等等。无需考虑多人协作带来的沟通成本,很好地控制项目进度。
可惜,这种美好景象仅在小项目或者项目初期会出现,一个优秀的产品往往是由众多子项目组成,是一个庞大的系统工程,需要多人的协作才能使之如期交付。
在一个公司的研发部门中,每一个项目常常会涉及到开发团队,测试团队,运维团队。项目 leader 在设计好架构和确定技术路线之后,会将开发任务按功能和模块分给开发团队,开发人员完成开发后,交给测试人员进行测试,反复迭代直到通过集成测试完成预期目标,交给运维团队去完成产品的交付或上线。期间会有项目经理持续跟踪进度。是曾相识么,这就是软件公司以及互联网公司中最常见的软件开发的场景了。
这个过程看上去不是挺不错的么,有什么问题?
问题很大,就像是在谈现实和理想。
首先,技术主管给出的架构并不是那么合理,并且也没有做到把业务完全解耦和模块化,在开发过程中,才发现那些看似相互独立的开发工作,还有强依赖关系。
接着,在给出的技术路线中使用了一些很 cool 的语言,开发框架,设计模式,但是暗中布满了密密麻麻还没跌过的坑,留下了运维隐患。在随后的线上运维中,相关的开发 / 运维人员发现了一些很诡异的现象却只能抓耳挠腮。
然后,开发人员的水平参差不齐,在随手写出惊为天书的代码的同时,还免费附赠了一堆已知和未知的 bug,导致后人在接替工作或维护的时候,几乎看不懂前人留下的神奇符号,然后就是重构,重构,重构。
同时,代码的版本管理毫无章法,最终在部署的时候出现了大量问题。
随后,测试人员拿到刚出炉的代码后直呼开发人员坑爹却没能力挽狂澜擒下所有臭虫,留下了一些未知的 bug,这些彩蛋将会伴随着运维人员手机上的午夜凶铃逐一浮现。
终于到了集成的日子,每个小组拿着子系统 / 模块 / 组件 ABCDE 进行整合,跑集成测试的时候发现了各种不可预料的问题,原定本周交付的项目突然变得无法预期。
最后,代码终于到了运维人员的手里,接力棒到了最后一公里,这里将会是最混乱的战场:运维人员参考开发人员给出的部署文档,进行部署,可惜有些开发人员的文档写得很烂,更多的是不写文档,跑过来递给运维人员一支芙蓉王,你只需要执行我精心准备的 start.sh 就可以运行了。接着,运维人员对软件进行编译,打包,有时被后面虎视眈眈的项目经理逼得丢弃了节操,怎么快捷就怎么来,KPI is more important,直接上源码。在经过几次测试后,胆战心惊地把软件交付给了客户,或是将服务上线。
那么,接力棒传送就此结束了吗? 在随后的日子里,运维人员每晚都会被该死的报警短信吵醒,为了业务赶紧恢复正常,开发人员测试也没写赶紧把 bug hotfix 了,有的甚至直接在线上环境就进行了修改。
接着大家就睡觉了,一觉起来的时候已经忘记了昨晚发生的一切,直到某日,开发人员把新的升级包部署上去,结果旧 bug 又复活了,同时新版本又引入了新的 bug,服务无法正常启动。运维人员需要进行回滚操作,但是预先就没有考虑回滚策略,只好手动进行回滚操作,却发现数据库表格式居然也变了…
另外一边的世界是客户的浏览器:503 Service UnAvailable。 卧槽,这是什么破网站。
然后 Boss 在听完业务部经理的汇报后,怒气冲冲地召集了研发部的所有老大们。研发,测试,运维的老大们开始了激烈的相互吐槽...
全剧终。
我们该怎么办
大量的事实表明,在大型企业中会滋生更多的 “我们 VS 他们” 的部落文化而阻碍了生产力。而且这些部落文化并不仅限于 “开发 VS 运维”,同时也存在于 “产品 VS 销售”,“市场 VS 开发” 以及 “开发 VS 质量保证” 等。
在实际的场景中,开发组老大为了争取在 XX 技术会议上吹嘘一番,总是乐于往新版本里引入新技术新框架,加入尽可能多的新特性;而运维组老大出于对运维稳定性的考虑,总是倾向于变化越少越好。项目经理则总是希望开发进度越快越好,为了进度不停逼迫开发人员砍掉一些测试,等等等。
如果,我是说如果:
如果,负责架构的哥们,可以把解耦做得再好点。
如果,负责技术路线的哥们,可以从运维的角度出发,多使用一些成熟的技术。
如果,开发人员再努力一些,提高本身的代码质量。
如果,测试人员的覆盖率再高一些,多捉住几只臭虫。
如果,运维人员再经验丰富一些,熟悉市面上所有主流和新兴的技术,会使用先进的自动化工具来进行部署和监控。
可惜,没有如果。
对于架构的设计需要长时间高强度的积累,不是用心就能做到完美的。
新技术的使用将会提高生产力,同时带来潜在的隐患,仅通过数天时间的技术调研而不深入使用是无法断言手上正握着的双刃剑到底是哪一面对着自己。
开发人员的水平是受诸多因素影响的,你不可能对着最牛逼的那个开发者按 ctrl+c,ctrl+v。
测试只是减少故障发生的概率,而不能避免没有 bug。
同样的,运维人员也不可能对于每种技术细节了如指掌。
你应该干什么
上述是我们很难去改变的。
但是
这时候你出现了,大吼一声我是 DevOps。
别人以看外星人的眼神瞪着你:DevOps 这个职位存在的意思是什么?
我们的存在是为了团队的和谐和幸福。
我们现在都很苦逼,你能帮助我们摆脱这种困境?
我们将会采用统一的规约和完善的工具链来改善当前的僵局。
统一的代码管理
首先在代码的版本控制上必须有一个统一标准,细致到仓库的命名和分类,代码分支的规约以及软件的发布周期管理都必须有一个统一规范来约束。
为什么这需要由 DevOps 来做?首先,研发、测试和运维部门都是会涉及到代码的管理,因此需要有人来统一所有部门的代码管理,其次在版本控制和分支开发规范上,使得所有人员只需要阅读同一份文档,就可以完成相应的协同工作,例如某开发小组喜欢用 master 作为 develop 分支,而其他小组则用 master 分支作为 production 分支,这将导致运维人员在部署时就需要分散精力去区别对待。
严格的代码审查机制
其次在代码的质量上,引入代码审查机制,让有经验的开发人员来审查其他人的代码,从而来减少 bug,提高代码的质量。
当然人工审查并不能保证代码的万无一失,在每次代码提交中,就应该附带相应的测试代码,通过自动化的测试工具,确保每次提交的代码逻辑上符合期望。
同时,将只有通过了测试和人工审查的代码入库并打包。
频繁的集成构建
从项目可以进行集成的当天起,所有项目将被进行频繁地集成构建,运行单元测试,功能测试,人肉测试等等,并将构建失败的错误日志发送给相关人员,然后找出导致这次集成失败的原因,并且必须在当天解决。
频繁的集成构建把留到最终的集成风险平摊到了每一天,使得项目的开发进度变得可控。
生产环境的所有操作拒绝人工干预
我们将使用生命周期管理和系统配置管理工具编写部署代码,在编写这些脚本前,你需要和开发 / 运维人员反复地沟通,在规范问题上不要做任何的妥协,直到完成目标。最后将这些部署代码交付给运维人员,所有的软件部署通过工具自动完成而无需人工干预。
加强各小组间的沟通
在软件开发的整个流程中,开发不懂运维,运维不懂开发是很常见的事情,因为我们要加强各小组间的沟通,我们会去了解 DBA 们为什么会讨厌那几个做后端的开发人员,运维人员为什么会在埋怨某个项目的部署。
这里我隐藏了许多细节,从大体上给出了 DevOps 的主要职责所在。
看到这里,你应该会眼前一亮,devops 的职责之一是规范,规范是保证团队协作有序进行的先决条件。
其次使用持续集成工具链如 Gitlab,Jenkins,Gerrit,Foreman,Puppet 等来替代人工操作,使用自动化的方法来减少重复劳动和避免人为造成的失误。
另外一个重要工作是沟通,促进各种团队间的协作。
我们需要专职的 DevOps 人员吗
如果你发现你已经在做上述事情中的某一些时,其实你已经在做 devops 相关的工作了。那么是否可以让众人各领相应的活儿,而不需要设这么一个职位?
我的回答是不可以。
一个职位对应着一份职责。
如果你是一个开发人员,运维小组的代码管理混乱你会去关心吗,你会为此负责吗?
如果你是一个运维人员,开发小组的代码没有人审查也没有跑测试就推到仓库中,你会去关心,你会为此负责吗?
但是如果你是 devops 人员,你必须纠正混乱的代码管理,你必须在源头上掐死没有人工审查和没有跑过测试的代码提交。
所以,我们需要一个负责 devops 的人员。
不过我并不赞同在一个小团队中设置一个专职的 devops 人员,在我看来,一个 devops 工程师,首先他得是一个合格的开发 / 测试 / 运维人员,devops 表明他还担负着另一个重要的职责。
因为,假如 devops 脱离了实际的岗位,就犹如纸上谈兵一般,无法触碰团队中的痛点,就无法解决实际问题。
因此,一个 “兼职” 的 devops 才是我心目中理想的 devops 工程师。
关于 Top
很庆幸你能耐着性子能阅读到这里,如果能胜任以上工作,恭喜你,你就是一个合格的 DevOps 工程师了。
等等,文章的题目不是写着如何成为一名 Top DevOps Engineer 么?!
额,我不认为想要成为顶级的 Devops 工程师仅仅通过阅读一篇陈词滥调的文章就能够速成的。实际上 devops 的活儿并不好做,作为 devops 必须强势,必须有话语权,否则你怎么去摆平研发,测试,运维组;作为 devops 必须熟悉甚至精通每个领域,否则你怎么去制定一套规范合理的规约;作为 devops 必须熟悉各种持续集成的工具,否则你怎么挑选符合团队实际需求的工具链;作为 devops 必须善于交流,否则你怎么去掌握每个人的真实想法。在成为一名 devops 之前,你应该有计划地把精力投入到 Dev,Test 和 Ops 各个领域,站在他们的角度来思考问题,然后再回到 DevOps 的位子上来,再去 rethink 应该怎么做。
DevOps 需要你去不断地尝试和调整,不要害怕失败和挫折,它们是积累宝贵经验的源泉,但是绝对不要在同样的坑里摔倒第二遍。 我喜欢这句话:所谓专家,就是在一个很小的领域里把所有错误都犯过了的人。
 

常见的发布反模式

手工部署软件

  1. 有一份非常详尽的文档,该文档描述了执行步骤及每个步骤中易出错的地方。
  1. 以手工测试来确认该应用程序是否运行正确。
  1. 在发布当天开发团队频繁地接到电话,客户要求解释部署为何会出错。
  1. 在发布时,常常会修正一些在发布过程中发现的问题。
  1. 如果是集群环境部署,常常发现在集群中各环境的配置都不相同,比如应用服务器的连接池设置不同或文件系统有不同的目录结构等。6. 发布过程需要较长的时间(超过几分钟)。
  1. 发布结果不可预测,常常不得不回滚或遇到不可预见的问题。
  1. 发布之后凌晨两点还睡眼惺忪地坐在显示器前,绞尽脑汁想着怎么让刚刚部署的应用程序能够正常工作。

开发完成之后才向类生产环境部署

由于部署工作中的很多步骤根本没有在试运行环境上测试过,所以常常遇到问题。比如,文档中漏掉了一些重要的步骤,文档和脚本对目标环境的版本或配置作出错误的假设,从而使部署失败。部署团队必须猜测开发团队的意图。

生产环境的手工配置管理

很多组织通过专门的运维团队来管理生产环境的配置。如果需要修改一些东西,比如修改数据库的连接配置或者增加应用服务器线程池中的线程数,就由这个团队登录到生产服务器上进行手工修改。
  1. 多次部署到试运行环境都非常成功,但当部署到生产环境时就失败。
  1. 集群中各节点的行为有所不同。例如,与其他节点相比,某个节点所承担的负载少一些,或者处理请求的时间花得多一些。
  1. 运维团队需要较长时间为每次发布准备环境。
  1. 系统无法回滚到之前部署的某个配置,这些配置包括操作系统、应用服务器、关系型数据库管理系统、Web 服务器或其他基础设施设置。
  1. 不知道从什么时候起,集群中的某些服务器所用的操作系统、第三方基础设施、依赖库的版本或补丁级别就不同了。
6. 直接修改生产环境上的配置来改变系统配置。
要有统一的配置管理,其责任之一就是让你能够重复地创建那些你开发的应用程序所依赖的每个基础设施。这意味着操作系统、补丁级别、操作系统配置、应用程序所依赖的其他软件及其配置、基础设施的配置等都应该处于受控状态。你应该具有重建生产环境的能力,最好是能通过自动化的方式重建生产环境。

如何实现目标

  1. 自动化。如果构建、部署、测试和发布流程不是自动化的,那它就是不可重复的。由于软件本身、系统配置、环境以及发布过程的不同,每次做完这些活动以后,其结果可能都会有所不同。
  1. 频繁做。如果能够做到频繁发布,每个发布版本之间的差异会很小。这会大大减少与发布相关的风险,且更容易回滚。

反馈流程

  1. 创建可执行代码的流程必须是能奏效的。这用于验证源代码是否符合语法。q 2. 软件的单元测试必须是成功的。这可以检查应用程序的行为是否与期望相同。q 3. 软件应该满足一定的质量标准,比如测试覆盖率以及其他与技术相关的度量项。q 4. 软件的功能验收测试必须是成功的。这可以检查应用是否满足业务验收条件,交付了所期望的业务价值。q 5. 软件的非功能测试必须是成功的。这可以检查应用程序是否满足用户对性能、有效性、安全性等方面的要求。q 6. 软件必须通过了探索性测试,并给客户以及部分用户做过演示。这些通常在一个手工测试环境上完成。此时,产品负责人可能认为软件功能还有缺失,我们自己也可能发现需要修复的缺陷,还要为其写自动化测试来避免回归测试

快速反应

接受到反馈的信息之后需要快速做出反应。
 
本书主要出发点就是敏捷思想的那个原则:If it hurts,do if more often 。
在软件项目中,发布是风险最高的一个环节,所以,根据敏捷的思想,怎么把发布的东西提前、频繁的做就成了关键,也就是所谓的持续交付。
而要达到频繁、重复做一件事,核心就是自动。只有自动化,才能重复的、可靠的去做。所以持续交付的核心就是全面版本控制和自动化。版本的管理不单是程序代码和对应配置信息,还包括运行环境及其配置信息、部署脚本的版本控制;自动化包括自动化构建、自动化单元测试、自动化验收测试、自动化部署、自动化发布等。通过持续的构建、部署,能提供一种快速的反馈,能让修复的成本最低,并且让软件一直保持在一种可用的状态。
现在很多项目都是开发者开发后将困难交给测试者,而测试者又在发布时将困难转嫁到运维团队。当出现问题时,人们花费大量的时间来修复错误,并用同等的时间来互相指责。其实,这些错误就是这种各自为政的工作方式所不可避免的结果。为了解决这个问题,为了加强合作,将敏捷思想注入了系统管理和发布中,就是我们说的 DevOps 运动。
要达到持续发布的目标,需要开发、测试的通力合作,编写能自动运行的测试脚本;需要运维、开发的通力合作,编写相关的自动构建和部署脚本、自动化的环境准备(虚拟化技术)。只有这样,才能让开发人员简单的、可重复的把代码部署到各种环境。为了完成这些任务,离不开开发人员、测试人员、运维人员的脚本编写能力。再说虽然有很多自动化工具的支撑,但是还是需要有一定的脚本编写能力才能更好的发挥相关工具的作用。
在实际发布过程中,环境的管理以及对应的配置管理最容易给忽略。为了达到持续发布的目的,所有的环境变更在上线之前必须经过测试,因而要将其编成脚本,放在版本控制系统中。这样,一旦修改被认可,就可以通过自动化的方式将其放在生产环境中。这样,对环境的修改和对软件的修改就没什么分别了。
像作者所说,持续集成就是不断对程序进行测试;持续部署就是对部署过程进行测试;只有这些测试在发布前频繁的、重复的做,那么到了发布那天,一切也水到渠成了。

文章摘要

  • 一个可工作的软件包括:可执行的代码、配置信息、运行环境和数据。软件部署包括:1、提供并管理呢的软件所需要的运行环境,包括硬件配置、所依赖的软件、基础设施以及所需要的外部服务;2、将你的应用程序的正确版本安装在其之上;3、配置你的应用程序,包括它所需要的任何数据及状态。
  • 自动化:可靠、可重复、可审计。
  • 敏捷宣言的第一原则:我们的首要任务是尽早持续交付有价值的软件并让客户满意。
  • 精益软件开发运动告诉我们:整体优化是非常重要的。
  • 持续集成,就像盖房子的时候,每道工序(类似软件开发中的功能点)完成就做验收,而不是等房子都建好再去验收。
  • 精益和迭代软件开发理论:快速并迭代地交付有价值且可工作的软件,并持续不断地从交付流程中消除浪费。
  • 性能:是指对处理单一事务所花时间的一种度量,既可以单独衡量,也可以在一定的负载下衡量;
  • 吞吐量:是指系统在一定时间内处理事务的数量,通常它受限于系统中某个瓶颈。
  • 容量:是指在一定的工作负载下,当每个单独请求的响应时间维持在可接受范围内时,改系统所能承担的最大吞吐量。
  • 找出有多少中负载,以及每种负载有多大,并考虑覆盖不同路径的场景,既是一门艺术,也是一门科学。完全复制真实生产环境的流量是不可能的,所以需要做流量分析,并结合经验和直觉来达到尽可能接近与真实环境的模拟。另外,也不要依据硬件的某些特定参数对应用程序的扩展性作出线性推论,这是在蒙蔽你自己。... 复杂系统的行为很少是这种线性相关的。
  • 我们不建议通过 UI 进行容量测试。
  • 自动化部署(脚本),一方面把部署专家从这些重复的、枯燥的工作中解放出来;另一方面能把部署专家的知识沉淀下来。
  • 伏尔泰说过,追求完美是把事情做好的大敌。
  • 精益制造的目标是确保快速交付高质量的产品,它聚焦于消除浪费,减少成本。
  • 配置管理是指一个过程,通过该过程,所有与项目相关的产物,以及它们之间的关系都被唯一定义、修改、存储和检索。
  • 可以将整个环境(包括配置基线上的操作系统)做成一个虚拟镜像,放在版本控制库中,这可以作为更高级别的保证措施,并且可以提高部署的简单性。
  • 持续集成,就要避免参建分支(除了发布分支之外),因为分支会带来合并的问题。
  • 提交的时候,要使用意义明显的提交注释,并且这个注释还需要包括一个链接,可以链接到项目管理工具中的一个功能或者缺陷,从而知道为什么要修改这段代码。
  • 可配置的软件并不总是像它看起来那么便宜。更好的方法几乎总是先专注于提供具有高价值且可配置程度较低的功能,然后在真正需要时再添加可配置选项。
  • 不要把密码签入到版本控制系统中,也不要把它硬编码到应用程序中。用户在部署时每次都手工输入密码。
  • 配置管理中不同环境配置管理的重要性。 个人注:有一次,测试机的配置文件用错了生产环境的配置,导致流程测试的短信通知都发送到了实际的员工那里。
  • 要为每个应用程序维护一份所有配置选项的索引表,记录这些配置保存在什么地方,它们的生命周期有多长,以及如何修改它们。
  • 我们要把应用程序的配置信息当做代码一样看待,恰当的管理它,并对他们进行测试。
  • 配置管理包括环境的配置 (硬件、依赖软件、基础设施、外部系统等) 以及应用程序的配置,两者都同样重要。
  • 对于跨地区的团队管理,让各团队之间的人员做定期的轮换也是非常有必要的,这样每个地方的成员都能与其它地方的团队成员建立起一些私人交情。
  • 我们一般将代码覆盖率高于 80% 的测试视为 “全面的” 测试。
  • 大多数界面测试工具与界面本身紧紧耦合在一起,其后果就是,一旦界面改变了(哪怕是一点儿),测试也会被破坏,这会导致很多假阳性,因为你会经常遇到这种情况,即测试被破坏的原因并不是应用功能不正确,而只是由于某个复选框的名字被修改了。
  • 需要些的最重要的自动化测试是哪些对 Happy Path 的测试。每个需求或者用户故事都应该有对 Happy Path 的自动化验收测试,而且至少有一个。这些测试应该被美味开发人员当做冒烟测试来使用。
  • 遗留系统的代码通常没有标准组件化,结构比较差。所以修改系统某部分的代码却影响了另一部分代码的事情经常发生。
  • 可以将应用程序分成两部分,一部分是实现系统功能的具体代码,另一部分则是在这些代码之下,为实现系统功能提供支撑的框架代码。
  • 编译出来的二进制包应该具有与环境无关性。
  • 会变动的与不变的东西分离。
  • 在部署应用程序是,应该用一个自动化脚本做一下冒烟测试,用来确保应用程序已经正常启动并运行了。这个测试应该非常简单,比如只要启动应用程序,检查一下,能看到主页面,并在主页面上能看到正确的内容就行了。这个冒烟测试还应该检查一下应用程序所依赖的服务是否都已经启动,并且正常运行了,比如数据库,消息总线或外部服务。
  • 尽管验收测试非常有价值,但他们的创建和维护成本也是非常高的。所以要时刻牢记,自动化验收测试也是回归测试。不要幼稚地对照着验收测试条件,盲目地把所有东西都自动化了。
  • 生产环境应该是完全受控的,即对生产环境的任何修改都应该通过自动化过程来完成。这不仅包括应用程序的部署,还包括对配置、软件栈、网络拓扑以及状态的所有修改。通过自动化的环境准备和管理、最佳的配置管理实践以及虚拟化技术,环境准备和维护的成本会显著降低。
  • 所有的构建工具都有一个共同的核心功能,即可以对依赖关系建模。每个任务都包括两点内容,一是它做什么,二是它依赖于什么。
  • 幂等:多次运算结果是一样的,例如绝对值运算。abs (x)=abs (abs (x))
  • Ant 很快成了 Java 项目构建工作的事实标准。现在很多 IDE 和其它工具都支持 Ant。
  • Maven 这种流行的 “惯例胜于配置”(convention over configuration) 的原则意味着,只要项目按 Maven 指定的方式进行组织,它就几乎能用一条命令执行所有的构建、部署、测试和发布任务,却不用写很多行的 XML。
  • 如果你刚开始一个 Java 项目,或者想找 Ant 或 Maven 的替代品,我们强烈推荐 Builder.
  • “使用同样的脚本部署每个环境” 和 “环境配置信息的不同(比如服务器 URI 或 IP 地址)这两件事应该分开管理,即将配置信息从脚本中分离出来,并将其保存再版本控制库中。
  • “脚本” 这个属于被广泛应用,通常是指辅助我们进行构建、测试、部署和发布应用程序所有自动化脚本。
  • 尤其注意的一点是,运行的单元测试不应该与文件系统、数据库、库文件、框架或外部系统等打交道。所有对这些方面的调用都应该使用测试替身代替,比如模拟对象(Mock)和桩等。
  • 通常我们会让提交测试在 10 分钟内完成。
  • 当使用 XUnit Test 这类测试框架时,可以将验收条件写在测试的名字中,然后通过 XUnit Test 测试框架直接运行验收测试。
  • 首先,抵制使用生产数据的备份作为验收测试的测试数据库的诱惑(尽管有时它对吞吐量测试是有用的)。相反,我们要维护一个受控的数据最小集。
  • 原子测试会创建它所需要的一切,并在运行后清理干净。 ... 一个常用的技术就是在测试开始时创建一个事务,在其结束时将其回滚。这样,数据库就回到了测试之前的状态。
  • 自动化验收测试不应该运行在包含所有外部系统集成点的环境中。相反,应该为自动化验收测试提供一个受控的环境,并且被测系统应该能在这个环境上运行。
  • 不断运行这些复杂的验收测试,的确会花费开发团队很多时间。然而,根据我们的经验,这种成本投入是一种投资,会节省很多倍的维护成本。
  • 在项目开始就识别出哪些是重要的非功能性需求,这一点至关重要。
  • 从审计人员的角度来捕获非功能性需求。
  • 部署与发布之间的主要区别在于回滚的能力。
  • 服务器应用程序不应该有 GUI。 个人注:PM 的工具就是这样,导致出错的时候,会在 GUI 弹出对话框。导致程序无法运行。
  • MTBF (Mean Time Between Failure,平均无故障时间)MTTR (Mean Time To Repair,平均修复时间)RPO (Recovery Point Objective, 恢复点目标)RTO (Recovery Time Objective, 恢复时间目标)
  • 基础设施访问控制在没有批准的情况下,不允许他人修改基础设施;制定一个对基础设施进行变更的自动化过程;对基础设施进行监控,一旦发生问题,能尽早发现。
  • PXE 是通过以太网启动机器的一个标准。当在机器的 BIOS 中选择通过网络启动的话,那实际上就是 PXE。
  • 很多企业有一个双重身份的试运行环境,既承担生产环境部署的测试 Udine,也可以作为故障备份。
  • 备份网络与生产环境网络也是物理隔绝的,以便当备份时大量数据的移动不会影响性能或管理网络。
  • SNMP 是监控领域最常见的标准。在 SNMP 中,所有的都是变量,通过查看这些变量来监控系统。
  • “向前兼容性” 是指应用程序的早期版本仍旧可以工作在后续版本的数据库上的一种能力。
  • 有些人把组件叫做 “模块”(Module)。在 windows 平台上,一个组件通常是以 DLL 形式打包的。在 Unix 上,它可能就被打包成 SO 文件了。而在 Java 的世界里,它可能就是一个 JAR 包。
  • 基于组件的设计通常被认为是一种良好的架构,具有松耦合性,是一种鼓励重用的设计。对组件的一个要求就是它应该可以独立部署。组件为其他系统提供一个接口(比如提供某个 API 的框架或服务)。
  • 依据功能领域而不是组件来组件团队确保了每个人都有权利修改代码库的任何部分,同时在团队之间定期交换人员,确保团队人员之间的良好沟通。
  • 悲观锁、乐观锁是版本控制系统的概念。乐观锁,就是允许大家同时修改一个文件。乐观锁通常假设某个文件中的某一行是一个可变的最小单位。
  • 主干开发模式:在主干上开发,而只有发布的时候创建分支,并且在分支上修复 BUG,然后合并到主干上。
  • 版本好的格式:w.x.y.z 其中 w 是主版本,x 是一个发布,y 是某个客户的表示,而 z 是一个构建。
  • 像精益制造业一样,没有频繁交付的软件就是仓库中的库存。它已经花钱制造完了,却还没有为你赚钱,实际上保管它也是花钱的。
  • 本书主要关于与被称做服务转换(service transition)的 ITIL 阶段。
  • 持续集成的目标是让正在开发的软件一直处于可工作状态。
  • 自动化测试,就类似 Dos 里面的批处理文件,可以重复的、自动的执行;而人工测试,就类似 Windows 的界面操作,只能靠人工处理。 可以想象,要把一个目录 copy 到另外一个盘符的对应目录,两者的操作方式是有很大的区别。
  • 治理:Governance。