持续交付:发布可靠软件的系统方法
[英] Jez Humble
版本控制不仅仅针对源代码。每个与所开发的软件相关的产物都应被置于版本控制之下。开发人员不但要用它来管理和控制源代码,还要把测试代码、数据库脚本、构建和部署脚本、文档、库文件和应用软件所用的配置文件都纳入到版本控制之中,甚至把编译器以及工具集等也放在里面,以便让新加入项目的成员可以很容易地从零开始工作。
保证大型团队能高效工作的关键就在于一致性和良好的组织性。
无论提交注释写得多么短小精悍,你也得不到奖励。然而,多写几行字来描述你做了什么,会为将来节省很多时间。
在交付过程中,缺陷被发现得越早,修复它的成本就越低,因此也就大大节省了成本和时间。
一旦对同一个测试重复做过多次手工操作,并且你确信不会花太多时间来维护这个测试时,就要把它自动化。
像Cucumber、JBehave、Concordion和Twist这类工具让你能在一个文本编辑器中用自然语言写验收条件,然后再写代码让这些验收条件变成可执行的测试,并且如果对这些测试代码进行重构,它们也会更新相应的测试规范。
在很多项目中,测试被认为是一个由一些专职人员负责的独立阶段。可是,只有当测试成为与软件交付相关的每个人的责任,并从项目一开始就被引入并持续进行时,才能产生高质量的软件。
单元测试仅仅是从开发人员的角度测试某个问题的解决方案。对于验证应用程序是否以用户期望的方式运行,单元测试的能力有限。
提交测试应该聚焦于一点,即尽快地捕获那些因修改向系统中引入的最常见错误,并通知开发人员,以便他们能快速修复它们。提交阶段提供反馈的价值在于,对它的投入可以让系统高效且更快地工作。
单元测试的目标就是要证明:应用程序的某个单一部分的确是按开发人员的思路运行的,但这并不能断言它也就是用户想要的功能。
任何项目中,测试人员都是至关重要的。他们的角色就是确保交付团队的每个人(包括客户)都了解并理解正在开发的软件的当前质量和生产准备情况。
软件工程协会(Software Engineering Institute)的ATAM(Architectural Tradeoff Analysis Method,架构权衡分析方法)就是通过对系统非功能需求(称为“质量属性”)进行完整分析,帮助团队选择一种合适的架构。
最明显的切入点就是通过UI对系统的交互操作进行记录和回放。这也是大多数商业负载测试产品的方式。
流水线应该是对测试和发布流程的建模
部署流水线就是为了创建一个可重复的、可靠的自动化系统,把修改的代码尽快放到生产环境中。这就是用最高质量的流程创建最高质量的软件。
发布计划最关键的部分是将来自组织各部门参与交付的代表组织起来:构建、基础设施、运维团队、开发团队、测试团队、DBA和技术支持团队。在整个项目周期中,这些人应该不断地交流,持续合作,从而使交付过程更加高效。
通用术语基础设施(infrastructure)代表了你所在组织中的所有环境,以及支持其运行的所有服务,如DNS服务器、防火墙、路由器、版本控制库、存储、监控应用、邮件服务器,等等。事实上,应用程序环境和所在组织的其他基础设施之间的分界限可能非常明确(比如,对于嵌入式软件),也可能极其模糊(比如,在面向服务架构的情况下,很多基础设施是在各应用程序之间共享和依赖的)。
自动化数据中心管理系统
几乎所有大中型公司都会将开发活动和基础设施管理活动(也就是常说的运维活动)分交给两个独立的部门完成2。常常能看到这两拨人的关系并不是很好。这是因为往往鼓励开发团队尽可能快地交付软件,而运维团队的目标则是稳定。
确保冒烟测试在部署时检查所有的连接,找出潜在的路由或连接问题。
最后,当出现问题时,使用一些辅助工具。Wireshark和Tcpdump都是相当有用的工具,用它很容易查看和过滤包,从而完全隔离你想要找的包。UNIX的工具Lsof以及在Windows上类似的工具Handle和TCPView(是Sysinternals套件的一部分)也很容易用来查看机器上被打开的文件或套接字。
由于生命周期不同,数据管理也面临一些待解决的问题。尽管这些问题与部署流水线上下文中的问题有所不同,但管理数据所用的基本原则是一样的。关键是要把创建和迁移数据库全部变成自动化过程。这个过程是部署流程的一个组成部分,确保它的可重复性和可靠性。无论是将应用程序部署到开发环境或包含最小数据集的验收测试环境,还是作为部署的一部分将生产数据集迁移到生产环境中都要使用相同的过程。
即使应用程序是由多个组件构成的,也并不是说一定要为每个组件实现各自的构建。最简单而且是很令人吃惊的方法就是整个应用程序只有一个构建流水线。每次提交修改时,就应该构建并测试整个应用。在大多数情况下,我们建议将整个软件系统作为一个整体来构建,除非是反馈过程太长。
对于大中型团队来说,正确的解决方案是将应用程序分解成多个组件,并确保组件之间是松耦合的。这些原则是设计良好的系统应该具备的属性。通过增量合并使主干上的代码一直保持可工作状态的方法仅会对项目施加一些徐缓而微小的压力,这会让软件的设计更为良好。
如果每次都晋级到主干,那么如何管理一个有很多开发人员,且有多个版本发布的大型团队呢?这个问题的答案是:软件需要良好的组件化、增量式开发和特性隐藏(feature hiding)。这要求在架构和开发中更加细心,而它的收益是:不需要设定一个无法预期的较长的集成阶段将多个流合并到一起创建一个可发布的分支,因为这些工作的精力远比花在架构和开发上要多得多。