一篇文章显得略长,本文对应第3-4章。前言、第1-2章请参考Part 1;第5-6章、附录、认证考试、参考资源等内容,请参考Part 3。
流动的技术实践
持续交付:降低在生产环境中部署和发布变更的风险。包括:打好自动化部署流水线的基础、确保团队能够使用自动化测试持续验证代码是否处于可部署状态、保证开发人员每天都将代码提交到主干、构建有利于实现低风险发布的环境和代码。
下面这些DevOps实践能有效缩短创建类生产环境的前置时间。持续测试可以为每个团队成员快速提供反馈,让小型团队能够安全、独立地开发、测试和向生产环境部署代码,从而使向生产环境的部署和发布成为日常工作的一部分。
为部署流水线奠定基础
为了使工作快速可靠地从开发流向运维,应当保证价值流的每个阶段都使用类生产环境。
部署流水线的目标就是能够基于VCS中的信息重复搭建整套生产环境。
在过程中保证质量,而不是事后检查质量。
这些问题可以归咎于不一致的环境和没有将变更纳入VCS。
按需搭建开发环境、测试环境和生产环境
应用统一的代码仓库
必须把下列资源也纳入版本控制系统:
- 应用的所有代码和依赖项(库、静态内容等);
- 任何用于创建数据库模式的脚本、应用的参考数据等;
- 所有用于搭建环境的工具和工件(VMware或AMI虚拟机模板、Puppet或Chef配置模块等);
- 任何构建容器所使用的文件(Docker、Rocket、Compose文件等);
- 所有支持自动化测试和手动测试的脚本;
- 任何支持代码打包、部署、数据库迁移和环境置备的脚本;
- 所有项目工件(需求文档、部署过程、发布说明等);
- 所有云平台配置文件(AWS Cloud Formation模板、Microsoft Azure Stack DSC文件,OpenStack HEAT模板文件);
- 创建支持多种基础设施服务(企业服务总线、数据库管理系统、DNS区域文件、防火墙配置规则和其他网络设备)所需的任何其他脚本或配置信息。
使基础设施的重建更容易
运行在类生产环境里才算完成
一般来说,部署的间隔时间越长,软件质量越差。
完成指不仅实现功能正确的代码,且在每个迭代周期结束时,已经在类生产环境中集成和测试可工作和可交付的代码。
实现快速可靠的自动化测试
对代码和环境做持续构建、测试和集成
部署流水线工具:Jenkins、ThoughtWorks GoCD、Concourse、Bamboo、Microsoft Team Foundation Server、TeamCity和GitLab CI,以及基于云的解决方案,例如Travis CI和Snap。
构建快速可靠的自动化测试套件
自动化测试从快到慢分为:
- 单元测试:通常独立测试每个方法、类或函数。目的是确保代码按照开发人员的设计运行。由于诸多原因(如需要进行快速和无状态的测试),通常会使用打桩(stub out)的方式,隔离数据库和其他外部依赖(如把函数修改为返回静态的预定义值,而不是调用数据库)。
- 验收测试:通常整体测试应用,确保各个功能模块按照设计正常工作(例如符合用户故事的业务验收标准,API能正确调用),而且没有引入回归错误(即没有破坏以前正常的功能)。JezHumble和David Farley认为单元测试和验收测试的区别在于:单元测试的目的是证明应用的某一部分符合程序员的预期……验收测试的目的则是证明应用能满足客户的愿望,而不仅仅是符合程序员的预期。”在构建的版本通过单元测试后,部署流水线就对其执行验收测试。任何通过验收测试的构建版本通常都可用于手动测试(例如探索性测试、用户界面测试等)和集成测试。
- 集成测试:保证应用能与生产环境中的其他应用和服务正确地交互,而不再调用打桩的接口。Jez Humble和David Farley写道:“大部分系统集成测试工作都是在部署应用的新版本,并使它们能正常协作。在这种情况下,冒烟测试通常是指针对整个应用进行的一组成熟的验收测试。”只有通过单元测试、验收测试的版本才能执行集成测试。集成测试通常是脆弱的,应该尽量减少其次数,并且要在单元测试和验收测试期间,尽可能多地找出缺陷。一个至关重要的架构需求是,在执行验收测试时能够调用虚拟或模拟的远程服务。
尽早发现错误:最快速的测试应该尽可能多地发现错误。如果大多数错误都是在验收测试和集成测试阶段发现的,那么开发人员收到反馈的速度要比单元测试发现错误时慢上好几个数量级——集成测试需要用到稀缺且复杂的集成测试环境(每次只能供一个团队使用),因此反馈更慢。
在部署流水线失败时拉下安灯绳
并行测试:
TDD:Test Driven Development,测试驱动开发。极限编程。的
3个步骤:
- 确保测试失败,为想要增加的功能编写测试用例,检入测试用例;
- 确保测试通过,编写实现功能的代码,直到测试通过,检入代码;
- 重构新旧代码,优化结构,确保测试都能通过,再次检入代码。
ATDD:基于TDD,验收测试驱动开发,Acceptance Test Driven Development,
瀑布式Scrum反模式(water-Scrum-fall anti-pattern):表面上采用敏捷开发实践,但实际上所有测试和缺陷修复仍然在项目快结束时才进行。
应用和实践持续集成
VCS中分支的作用:
- 让开发人员可并行地工作在系统的各个组成部分
- 避免开发人员提交的代码对主干(trunk,master或mainline)的稳定性造成影响或引入错误
当开发人员的数量和VCS中的分支个数增加时,自动化测试会变得更加重要。开发人员在自己的分支上独自工作的时间越长,就越难将变更并入主干。当分支个数和每个分支上的变更数都在增加时,合并难度会骤增。
Gary Gruver:如果没有自动化测试,持续集成只能产生一大堆没有经过编译而且不能正确运行的垃圾。
分支策略,可分为以下两类:
- 提高个人生产力:所有人都在自己的分支上工作。每个人都独立地工作,不能干扰其他人;然而,代码合并将是一场噩梦。协作将变得相当困难,每个人都不得不谨小慎微地合并代码,即便是完成系统里最小的部分。
- 提高团队生产力:所有人都在同一个区域里工作。并没有分支,只有一条很长、不可被中断的主干;也没有规则,因此代码的提交过程很简单。但任何一次提交都有可能破坏整个项目,同时导致项目中断。
大批量合并的副作用:合并难度越大,开发人员就越不可能(也越不愿意)改进和重构代码,重构很可能导致其他所有人返工。人们就更不愿意去修改那些在整个代码库中都有依赖项的代码。
解决大批量合并问题的对策是,应用持续集成和基于主干的开发实践,让每个开发人员每天都至少向主干提交一次代码。
门控提交,对部署流水线进行配置:拒绝接受任何使系统偏离可部署状态的提交(如代码变更或环境变更)。即部署流水线要确认所提交的变更能成功合并和正常构建,并且在合并到主干之前就已经通过所有的自动化测试。如果测试失败,则开发人员将收到通知,这样就可以在不影响价值流中的其他人的情况下自己解决问题。
自动化和低风险发布
持续部署,要求代码的部署操作是自动化、可重复和可预测的。
自动化部署流程:尽可能地简化和自动化手动步骤。不但要缩短前置时间,而且还要尽可能减少交接次数,从而降低出现错误和流失知识的可能性。
部署流水线的需求:
- 用相同的方式处理所有环境的部署:通过对所有环境采用相同的部署机制,可提高生产环境部署成功率;
- 对部署执行冒烟测试:在部署过程中,应该测试依赖的所有系统是否能正常访问,并通过单次测试看看系统是否能正常工作。如果以上任何一个测试失败,部署就是失败的;
- 维持环境的一致性:创建一步搭建环境的流程,必须持续保证这些环境的搭建方式是一致的。
理想的流程:
- 构建:部署流水线必须基于VCS构建可部署到任何环境的软件包;
- 测试:任何人都应该能够在工作站或测试系统中运行任何一个自动化测试套件;
- 部署:任何人都应该能够将这些软件包部署到具有访问权限的任何环境,通过执行(已提交到VCS中的)脚本来完成部署。
自动化部署必须具备如下能力:
- 保证在持续集成阶段构建的软件包可以部署到生产环境中;
- 使生产环境的就绪情况一目了然;
- 为能在生产环境中部署的任何代码,建立一键式和自助式的发布机制;
- 自动记录审计和合规管理所需的相关内容,包括在哪台机器上运行命令,运行什么命令,是谁授权的,以及结果如何;
- 通过冒烟测试验证系统正常工作,数据库连接字符串等配置正确;
- 为开发人员快速提供反馈,能够尽快了解部署结果。
只有进行更频繁的部署,才能实现流畅和快速的工作流。为了实现这一点,需要将生产环境部署和特性发布解耦。
部署和发布是不同的动作,且有着截然不同的目标:
- 部署:在特定的环境中安装指定版本的软件。部署可能与某个特性的发布相关,也可能无关;
- 发布:把一个或一组特性提供给所有客户或部分客户。代码和环境架构要能够满足这种要求:特性发布不需要变更应用的代码。
如果部署周期过长,会限制向市场频繁地发布新特性的能力。假如能够做到按需部署,那何时向客户发布新特性,就变成业务和市场的决策,而不再是技术决策。通常使用的发布模式有以下两种:
- 基于环境的发布模式:在两个或更多的环境中部署系统,但实际上只有一个环境处理客户流量。将新的代码部署到非生产环境中,再把生产流量切换到这个环境。一般只需要对应用做很少的改变,或几乎不用改变;包括蓝绿部署、金丝雀发布和集群免疫系统。
- 基于应用的发布模式:对应用进行修改,从而通过细微的配置变更,选择性地发布或开放应用特性。例如,可以通过特性开关逐渐地开放新特性——先开放给开发团队,再开放给所有内部员工,然后开放给1%的客户;或者在确认特性完全符合设计后,直接发布给全体客户。所谓的黑启动技术——在生产环境里将所有特性都部署完毕,并在发布前用生产环境的流量做测试。例如,在发布前的几周里,用生产环境的流量来测试新特性,以便在正式发布之前发现和解决所有问题。
蓝绿部署:最简单,支持回滚。
金丝雀发布:监控软件在每个环境中的运行情况。一旦出现问题,就回滚;否则就在下一个环境中进行部署。
集群免疫系统:扩展金丝雀发布,将生产环境的监控系统和发布流程联系起来,并在面向用户的生产系统的性能超出预定范围时(如新用户的转化率低于15%~20%),自动回滚代码。
基于应用的发布模式更安全,通过代码来更灵活、更安全地向客户逐一发布新特性。
基于应用的发布模式主要是通过特性开关来实现的。特性开关机制使我们能在不进行生产环境代码部署的情况下,选择性地启用和禁用特性。通过特性开关,可以将应用的特性向某些特定用户(例如内部员工和某些客户群)开放。
特性开关的优势:
- 轻松地回滚:只需更改特性开关的设置,就可以在生产环境中,快速安全地禁用出问题或造成服务中断的特性。在非频繁部署的情况下,它的价值更大——关掉某一个特性通常要比回滚整个版本容易得多。
- 缓解性能压力:当服务遭遇极高的负载时,通常需要扩容系统;更糟糕的是,可能导致生产环境中的服务中断。不过,可以使用特性开关来缓解系统的性能压力。换句话说,可以通过减少可用的特性,来支持更多的用户(例如,减少使用某特性的客户数量,禁用推荐等CPU密集型特性,等等)。
- 采用面向服务架构提高恢复能力:即便某个特性依赖于还没有上线的服务,仍然可以将这个特性部署到生产环境中,然后用特性开关把它先隐藏起来。当所依赖的服务上线后,就可以启用这个特性。当所依赖的服务中断时,也可以关闭该特性,这样做不但可以和下游的故障服务隔离,同时还可以保持应用的其余部分正常运行。
黑启动:
《持续交付:发布可靠软件的系统方法》值得一读。
持续交付:所有开发人员都在主干上进行小批量工作,或者在短时间存在的特性分支上工作,并且定期向主干合并,同时始终让主干保持可发布状态,并能做到在正常的工作时段里按需进行一键式发布。开发人员在引入任何回归错误时,都能快速得到反馈。一旦发现这类问题,就立即解决,从而保持主干始终处于可部署状态。
持续部署:在持续交付的基础上,由开发或运维人员自助式地定期向生产环境部署优质的构建版本,这意味着每天每人至少做一次生产环境部署,甚至每当开发人员提交代码变更时,就触发一次自动化部署。
持续交付是持续部署的前提条件,就像持续集成是持续交付的前提条件一样。持续部署更适用于交付线上的Web服务,而持续交付适用于几乎任何对质量、交付速度和结果的可预测性有要求的低风险部署和发布场景,包括嵌入式系统、商用现货产品和移动应用。
降低发布风险的架构
能提高生产力、可测试性和安全性的架构
架构原型:单体架构与微服务
单体架构的本质并不坏。事实上,在产品生命周期的早期阶段,单体架构通常是最佳的选择。
关于架构转型,亚马逊的几个经验教训:
- 严格遵从面向服务理念的架构设计能完美地实现隔离,从而达到前所未有的掌控水平。
- 禁止客户端直接访问数据库,使在不涉及客户端的情况下提高服务状态的可扩展性和可靠性成为可能。
- 在切换到面向服务的架构后,开发和运维流程将受益匪浅。服务模式进一步强化了以客户为中心的团队理念。每个服务都有一个与之对应的团队,该团队对服务全面负责(从功能规划到架构设计、构建和运维)。
安全地演进企业架构
TODO
反馈的技术实践
建立能发现并解决问题的遥测系统
建设集中式监控架构
建立生产环境的应用程序日志遥测
日志级别:
- 调试级别:此级别的信息是相关应用程序中发生的所有事件,最常用于调试的时候。通常,调试日志在生产中是禁用的,但在故障诊断期间要暂时启用。
- 信息级别:此级别的信息包括用户触发的或系统特定的操作(例如“开始信用卡交易”)。
- 警告级别:此级别的信息告诉我们可能的出错情况(例如,调用数据库花费的时间超过某个特定时长)。可能会因此而触发报警和故障诊断过程,而其他日志消息会有助于更好地理解事件的原因。
- 错误级别:此级别的信息侧重于错误状况(例如,API调用失败,内部出错)。
- 致命级别:此级别的信息告诉我们何时发生了中断情况(例如,网络守护进程无法绑定网络套接字)。
使用遥测指导问题的解决
平均清白证明时间:即花多长时间说服其他人,不是我们造成中断。一种指标
将建立生产遥测融入日常工作
建立自助访问的遥测和信息辐射器
Information Radiator:信息辐射器。定义:团队放置在一个非常显眼位置上的手写、绘制、印刷或电子信息展示,让所有团队成员以及路过的人都可以快速浏览最新信息:自动化测试次数、速率、事故报告、持续集成状态等。这个想法起源于丰田生产系统。
发现和填补遥测的盲区
以下层级的度量指标:
- 业务级别:示例包括交易订单的数量、产生的营业额、用户注册数、流失率、A/B测试的结果等。
- 应用程序级别:示例包括事务处理时间、用户响应时间、应用程序故障等。
- 基础架构级别(如数据库、操作系统、网络、存储):示例包括Web服务器吞吐量、CPU负载、磁盘使用率等。
- 客户端软件级别(如客户端浏览器上的JavaScript、移动应用程序):示例包括应用程序的出错和崩溃、用户端的事务处理时间等。
- 部署流水线级别:示例包括构建流水线状态(例如:各种自动化测试套件的红色或绿色状态)、变更部署前置时间、部署频率、测试环境上线状态和环境状态。
分析遥测数据以更好地预测故障和实现目标
异常检测:首先在计算集群节点总数一定的情况下计算出当前正常值,然后识别出与之不符的节点,并将它们从生产环境中移除。
用均值和标准差识别潜在问题
通过提高信噪比、关注差异值或异常值,建立更好的告警。
钟形曲线中间的垂直线是均值,由其他垂直线表示的第一、第二和第三标准差分别包含68%、95%和99.7%的数据。
标准差的常见用途是,定期检查数据集的某个度量,如果与均值有显著差异就告警。如,当每天未经授权的登录次数比均值大三个标准差时就告警。只要这个数据集呈高斯分布,就预计只有0.3%的数据点会触发告警。
异常状态的处理和告警
生产环境事故的潜在征兆指标:
- 应用级别:网页加载时间正在增加等;
- 操作系统级别:服务器闲置内存不足、磁盘空间不足等;
- 数据库级别:数据库事务处理时间超出正常值等;
- 网络级别:负载均衡器背后运行的服务器数量下降等。
非高斯分布遥测数据的问题
TODO
应用异常检测技术
TODO
应用反馈实现安全部署
代码部署恐惧。
通过提供更快和更频繁的反馈,减少部署工作的批量大小,可以让工程师获得代码部署的安全感,进而重拾信心。
仅仅实现部署流程的自动化是不够的,必须要将生产遥测的监控融入到部署工作中,同时还要建立文化规范,那就是每个人都对整个价值流的健康承担着相同的责任。
通过遥测使部署更安全
部署过程中积极地监控软件功能相关的度量指标。
部署出错的解决方法:
- 使用特性开关关闭出错的功能;
- 前向修复:为了修复缺陷,再次修改、提交、部署代码到生产环境;
- 回退:回滚到上一个版本
开发和运维共同承担值班工作
让价值流中的所有人共同承担处理运维事故的下游责任。让开发人员、开发经理和架构师轮流和运维团队共同值班。
产品功能完成的定义:所有功能都在生产环境中按照设计正常地运行,没有引起重大的故障,也没有引发计划外的运维或开发工作。
不管团队的组织结构怎样,基本原则是不变的:当开发人员获得应用程序在生产环境中运行的反馈时,包括故障的修复状况,他们与客户之间的距离拉近,这会使价值流中的所有人都受益。
让开发人员跟踪工作对下游的影响
交互和用户体验设计中最强大的技术之一是情境访谈。
让开发去使用他们开发出的产品。
通过进行用户体验观察,能够在源头保证质量,并对价值流中的其他团队成员产生同理心。理想情况下,用户体验观察有助于我们创建应用的非功能需求,并将其放入共享的待办工作中去,最终我们可以主动地将它们落实到构建的所有服务中。
让开发人员自行管理生产服务
谷歌的实践:让开发团队在生产环境中管理他们开发的服务,然后才交由集中的运维团队管理。通过让开发人员自己负责部署工作并在生产环境中提供支持,他们所开发的产品更有可能顺利地过渡给运维团队去管理。
服务发布指南:
- 缺陷计数和严重性:应用程序是按设计运行的吗?
- 告警的类型/频率:在生产环境中应用程序所产生的告警数量是否太多,无法得到支持?
- 监控覆盖率:监控覆盖的范围是否够大,能够为恢复故障服务提供足够的信息?
- 系统架构:服务松耦合的程度是否足以支持生产环境中高频率的变更和部署?
- 部署过程:在生产环境中代码部署的过程是不是可预测的、确定性的和足够自动化的?
- 生产环境的整洁:是否有迹象表明生产习惯已经足够好,可以让其他任何人提供生产支持?
这项服务是否要遵从任何监管目标:
- 服务是否产生大量的收益?
- 服务的用户流量或停机/损害成本是否很高?
- 服务是否存储付款卡持有者信息(如信用卡号)或个人身份信息(如社会安全号码或病人护理记录)?是否存在可能产生监管、合同义务、隐私或声誉风险的其他安全问题?
- 服务是否有任何其他监管或合同要求,如美国出口监管、PCI-DSS、HIPAA等?
服务回传机制:当生产环境中的一个服务变得非常脆弱时,运维部门能把支持这个服务的责任交回给开发部门。
谷歌SRE,Site Reliability Engineer。
LRR:Launch Readiness Review,上线就绪审核。
HRR:Hand-off Readiness Review,交接就绪审核。
谷歌在将任何新服务公开给客户并且接收生产流量之前,必须进行LRR,而且要签字验收,而当将服务转换到运维管理状态后(通常是在LRR几个月之后)执行HRR。LRR和HRR审核清单其实是相似的,但是HRR更加严格,并且验收标准更高,而LRR是由产品团队自行执行并上报的。
假设驱动的开发和A/B测试
在软件项目中,开发人员往往花几个月或几年的时间开发功能,期间经历多次发布,却从未确认过业务需求是否得到满足,某个功能是否达到所期望的效果,甚至是否被用过。
开展最廉价、最快速的实验,通过用户研究来验证设想的功能能否产生预想的业务成果。我们可以使用假设驱动的开发、客户获取渠道和A/B测试等技术。
越快地实验、迭代并将反馈集成到产品或服务中,我们就可以越快地学习和超越竞争对手。集成反馈的速度取决于部署和发布软件的能力。
A/B测试简史
A/B测试技术是在直效营销中率先使用的,它是两大类营销策略之一。另一类称为大众营销或品牌营销,通常通过向公众投放尽可能多的广告来影响人们的购买决策。
有良好文档记录的A/B测试案例包括竞选筹款、互联网营销和精益创业方法论。
在功能测试中集成A/B测试
A/B测试,也称为在线控制实验和拆分测试。在实验的过程中还支持多个变量,从而观察变量之间的相互作用,即多变量测试。
很多时候,开发团队只知道实现产品经理或项目经理分发的功能。但是这些功能对公司的价值很可能为零,甚至为负,因为它们增加代码的复杂度;随着时间的推移,应用维护的成本将增加,软件也变得更加难以修改。构建这些功能往往是以牺牲真正有价值的功能(机会成本)为代价的。
在发布中集成A/B测试
通过在生产环境中快速轻松地按需部署,利用特性开关将软件的多个版本同时交付给多个用户群,可以进行快速、迭代的A/B测试。
具备A/B测试功能的一些框架:
- Feature:Etsy开源,支持A/B测试,在线调整,能对实验组进行限流;
- Optimizely:
- Google Analytics:
在功能规划中集成A/B测试
一旦拥有支持A/B功能发布和测试的基础设施,还必须确保产品经理将每个功能都视为一个假设,并基于在生产环境中实际的用户实验结果来证明或反驳这些假设。
建立评审和协作流程以提升当前工作的质量
PR:Pull Request。
GitHub Flow的5个步骤:
- 工程师为实现一项新功能需求,基于主干检出一个命名良好的分支;
- 工程师提交代码到本地分支,并定期将工作成果推送到远端服务器的同名分支上;
- 当需要反馈或帮助,或准备将分支代码合并到主干时,得发起一个PR;
- 在他们获得期望的评审并通过必要的审核后,即可将代码合并到主干;
- 一旦将代码变更合并进主干,就可将其部署到生产环境。
变更审批流程的危险
Knight Capital,15分钟的部署事故造成4.4亿美元的交易损失,生产服务无法停止。推荐阅读Project Failure Case Study Knight Capital。
在低信任度的指挥与控制型文化环境中,这些变更控制和测试实践反而会增加问题复发的几率,甚至造成更严重的后果。
过度控制变更的潜在危险
传统的变更控制可能会导致意想不到的后果,例如延长交付时间,降低部署过程中反馈的强度和即时性。
TPS:最了解问题的人通常是离问题最近的人。让距离工作较远的运维(领导层)来做相关审批的步骤,这实际上会降低工作成功的概率。
变更的协调和排程
当多个团队在共享依赖关系的系统上工作时,就可能需要协调变更,以确保不会相互干扰。组织架构越松耦合,组件团队之间需要沟通和协调的事情就越少。
在松耦合的架构里,当多个团队每天进行数百次独立部署时,变更彼此干扰的风险可能依然存在。缓解风险的方式:
- 聊天室
- 碰头会
- 技术性的保障措施,如冗余备份系统、故障切换、综合测试和变更模拟(理想情况下)。
变更的同行评审
代码评审和变更评审,在本书是一个意思,都是同行之间进行的评审,Peer Review。
保持小批量尺寸的原则也适用于代码评审。
代码评审的指导原则:
- 将代码提交到主干以前,必须要有同行来评审变更;
- 每个人都应该持续关注其他成员的提交活动,以便识别和审查出潜在的冲突;
- 定义哪些变更属于高风险变更,从而决定是否需要请领域专家来进行审查;
- 如果同行看不懂PR,说明提交的变更尺寸太大,那变更就需要分解成多个较小的变更来多次提交。
代码评审的几种形式:
- 结对编程:程序员结对地在一起工作。
- 肩并肩:在一名程序员编写一段代码后,评审程序员接着就逐行阅读他的代码。
- 电子邮件送审:在代码被签入到代码管理系统中后,系统就立刻自动向评审者们邮寄一份代码。
- 工具辅助评审:如Gerrit、GitHub PR等,或源码仓库(如Mercurial、Subversion、Atlassian Stash和Atlassian Crucible等)提供的类似功能。
人工测试和变更冻结的潜在危害
引入自动化测试。
利用结对编程改进代码变更
结对编程:两名软件开发工程师同时在同一台工作站上工作的开发方法。由极限编程和敏捷开发广泛推广的实践。
结对模式:
- 扮演驾驶者角色的工程师,负责编写代码;另一名作为导航员、观察者或督导者,负责检查驾驶者正在进行的工作。
- 测试驱动开发,一名工程师编写自动化测试,另外一名工程师编写代码。
结对编程还能有益于知识在组织内的传播,以及信息在团队内部的流动。
一个好的表明评审过程有效的PR的基本要素:必须足够详细地说明变更的原因、如何做的变更,以及任何已识别的风险和应对措施。
消除官僚流程
许多公司仍然存在着由来已久的、动辄需要数月的审批流程。此时,必须重新设计流程,才便更快、更安全地实现目标。