《持续交付--发布可靠软件的系统方法》读书心得
看了这本书,总结的一些脑图:
这本书之前看过,不过没有做笔记。在看板管理这本书里面有推荐,就顺便再看了一遍,温故而知新。
本书主要出发点就是敏捷思想的那个原则: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。