This commit is contained in:
louzefeng
2024-07-11 05:50:32 +00:00
parent bf99793fd0
commit d3828a7aee
6071 changed files with 0 additions and 0 deletions

View File

@@ -0,0 +1,140 @@
<audio id="audio" title="05 | 价值流分析关于DevOps转型我们应该从何处入手" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/9b/ae/9b64eb475fd7994730604fd3c1c264ae.mp3"></audio>
你好,我是石雪峰。
关于“DevOps如何落地”的问题向来是关注度很高的所以从今天开始我会用16讲的篇幅跟你聊聊这个话题的方方面面。作为“落地实践篇”的第1讲我先跟你聊聊DevOps转型的那些事儿。
相信你一定听说过持续交付吧现在几乎每家实施DevOps的企业都宣称他们已经有了一套持续交付平台或者是正在建设持续交付平台。但是如果你认为只需要做好持续交付平台就够了那就有点OUT了。因为现在国外很多搞持续交付产品的公司都在一门心思地做另外一件事情这就是VSM价值流交付平台。
比如Jenkins的主要维护者CloudBees公司最新推出的DevOptics产品主打VSM功能而经典的持续交付产品GoCD的VSM视图也一直为人所称道。那么这个VSM究竟是个啥玩意儿呢
要说清楚VSM首先就要说清楚什么是价值。简单来说**价值就是那些带给企业生存发展的核心资源**,比如生产力、盈利能力、市场份额、用户满意度等。
VSM是Value Stream Mapping的缩写也就是我们常说的价值流图。它起源于传统制造业的精益思想用于分析和管理一个产品交付给用户所经历的业务流、信息流以及各个阶段的移交过程。
说白了VSM就是要说清楚在需求提出后怎么一步步地加工原材料进行层层的质量检查最终将产品交付给用户的过程。通过观察完整流程中各个环节的流动效率和交付质量识别不合理的、低效率的环节进行优化从而实现整体效率的提升。
这就好比我们在餐厅点了一道菜,这个需求提出后,要经历点单、原材料初加工(洗菜)、原材料细加工(切菜)、制作(炒菜),最终被服务员端到餐桌上的完整过程。但有时候,厨师已经把菜做好摆在窗口的小桌上了,结果负责上菜的服务员正在忙,等他(她)忙完了,才把菜端到我们的餐桌上,结果热腾腾的锅气就这么流失了。
对软件开发来说,也是如此。由于部门职责的划分,每个人关注的都是自己眼前的事情,这使得软件交付过程变得碎片化,以至于没有一个人能说清楚整个软件交付过程的方方面面。
所以通过使用价值流图对软件交付过程进行建模使整个过程可视化从而识别出交付的瓶颈和各个环节之间的依赖关系这恰恰是“DevOps三步工作法”的第一步“流动”所要解决的问题。
我简单介绍下“DevOps三步工作法”。它来源于《DevOps实践指南》可以是说整本书的核心主线。高度抽象的“三步工作法”概括了DevOps的通用实施路径。
- **第一步:流动**。通过工作可视化,限制在制品数量,并注入一系列的工程实践,从而加速从开发到运营的流动过程,实现低风险的发布。
- **第二步:反馈**。通过注入流动各个过程的反馈能力,使缺陷在第一时间被发现,用户和运营数据第一时间展示,从而提升组织的响应能力。
- **第三步:持续学习和试验**。没有任何文化和流程是天生完美的,通过团队激励学习分享,将持续改进注入日常工作,使组织不断进步。
## 关键要素
你并不需要花大力气去研究生产制造业中的价值流分析到底是怎么玩的你只要了解有关VSM的几个关键要素和核心思想就行了。那么VSM中有哪些关键要素和概念呢有3点是你必须要了解的。
1. **前置时间**Lead Time简称LT。前置时间在DevOps中是一项非常重要的指标。具体来说它是指一个需求从提出典型的就是创建一个需求任务的时间点开始一直到最终上线交付给用户为止的时间周期。这部分时间直接体现了软件开发团队的**交付速率**,并且可以用来计算**交付吞吐量**。**DevOps的核心使命之一就是优化这段时长**。
1. **增值活动时间和不增值活动时间**Value Added Time/Non-Value Added Time简称VAT/NVAT。在精益思想中最重要的就是**消除浪费**,也就是说最大化流程中那些增值活动的时长,降低不增值活动的时长。在软件开发行业中,典型的不增值活动有很多,比如无意义的会议、需求的反复变更、开发的缺陷流向下游带来的返工等。
1. **完成度和准确度**% Complete/Accurate简称%C/A。这个指标用来表明工作的质量也就是有多少工作因为质量不符合要求而被下游打回。这里面蕴含了大量的沟通和返工成本从精益的视角来看也是一种浪费。
在实践中,企业往往将需求作为抓手,来串联打通各个环节,而前置时间是需求管理的自然产物,采集的难度不在于系统本身,而在于各环节的操作是否及时有效。有的团队也在使用需求管理工具,但是前置时长大多只有几秒钟。问题就在于,他们都是习惯了上线以后,一下子把任务状态直接从开始拖到最后,这样就失去了统计的意义。
需要注意的是,关于前置时间,有很多种解释,一般建议采用**需求前置时间**和**开发前置时间**两个指标进行衡量,关于这两个指标的定义,你可以简单了解一下。
>
需求前置时间:从需求提出(创建任务),到完成开发、测试、上线,最终验收通过的时间周期,考查的是团队整体的交付能力,也是用户核心感知的周期。
>
开发前置时间:从需求开始开发(进入开发中状态),到完成开发、测试、上线,最终验收通过的时间周期,考查的是团队的开发能力和工程能力。
对于增值活动时长,我的建议是初期不用过分精细,可以优先把等待时长统计出来,比如一个需求从准备就绪,到进入开发阶段,这段时间就是等待期。同前置时间一样,很多时候,研发的操作习惯也会影响数据的准确性,比如有的研发喜欢一次性把所有的需求都放到开发阶段,然后再一个个处理掉,这就导致很多实际的等待时间难以识别。所以,如果完全依靠人的操作来确保流程的准确性,就会存在很大的变数。**通过流程和平台的结合来驱动流程的自动化流转这才是DevOps的正确姿势。**
举个例子,研发开发完成发起提测后,本次关联的需求状态可以自动从“开发中”变成“待测试”状态,而不是让人手动去修改状态,这样就可以避免人为因素的影响。通过代码,流水线和需求平台绑定,从而实现状态的自动流转。
关于完成度和准确度在使用VSM的初期可以暂不处理。实际上我见过一些公司在跑通主流程之后着手建设质量门禁相关的指标比如研发自测通过率这些指标就客观地反映了VSM的完成度和准确度。关于质量门禁在专栏后面我会花一讲的时间来介绍你一定不要错过。
## 方式
关于VSM的关键要素知道这些就足够了。那么作为企业DevOps转型工作的第一步我们要如何开展一次成功的VSM活动呢一般来说有2种方式。
1.**召开一次企业内部价值流程梳理的工作坊或者会议。**
这是我比较推荐的一种方式。对于大型企业而言,可以选取改进项目对象中某个核心的业务模块,参加会议的人员需要覆盖软件交付的所有环节,包括工具平台提供方。而且,参会人员要尽量是相对资深的,因为他们对自身所负责的业务和上下游都有比较深刻的理解,比较容易识别出问题背后的根本原因。
不过,这种方式的实施成本比较高。毕竟,这么多关键角色能够在同一时间坐在一起本身就比较困难。另外,面对面沟通的时候,为了给对方保留面子,大家多少都会有所保留,这样就会隐藏很多真实的问题。
所以,一般情况下,像团队内部的**敏捷回顾会**,或者是**版本发布总结会**,都是很合适的机会,只需要邀请部分平常不参会的成员就行了。
2.**内部人员走访。**
如果第1种方式难以开展你可以退而求其次地采用第2种方式。通常来说企业内部的DevOps转型工作都会有牵头人甚至会成立转型小组那么可以由这个小组中的成员对软件交付的各个环节的团队进行走访。这种方式在时间上是比较灵活的但对走访人的要求比较高最好是DevOps领域的专家同时是企业内部的老员工这样可以跟受访人有比较深入坦诚的交流。
无论哪种方式,你都需要识别出几个关键问题,缩小谈话范围,避免漫无目的地东拉西扯,尽量做到有效沟通。比如,可以建立一个问题列表:
- 在价值交付过程中,你所在团队的主要职责是什么?
- 你所在团队的上下游团队有哪些?
- 价值在当前环节的处理方式,时长是怎样的?
- 有哪些关键系统支持了价值交付工作?
- 是否存在等待或其他类型的浪费?
- 工作向下游流转后被打回的比例是多少?
为了方便你更好地理解这些问题,我给你提供一份测试团队的访谈示例。
<img src="https://static001.geekbang.org/resource/image/e1/58/e147f1cbae3847793d7c10eaccba0058.jpg" alt="">
通过访谈交流我们就可以对整个软件交付过程有一个全面的认识并根据交付中的环节、上下游关系、处理时长、识别出来的等待浪费时长等按照VSM模型图画出当前部门的价值流交付图以及各个阶段的典型工具如下图所示
<img src="https://static001.geekbang.org/resource/image/b4/6c/b469758cb927c11b04edf254dd1a666c.png" alt="">
当然实际交付流程相当复杂涉及到多种角色之间的频繁互动是对DevOps转型团队的一种考验。因为这不仅需要团队对软件开发流程有深刻的认识还要充分了解DevOps的理念和精髓在沟通方面还得是一把好手能够快速地跟陌生人建立起信任关系。
## 价值
话说回来为什么VSM会是企业DevOps转型的第一步呢实际上它的价值绝不仅限于输出了一幅价值流交付图而已。VSM具有非常丰富的价值包括以下几个方面
**1.看见全貌。**
如果只关注单点问题我们会很容易陷入局部优化的怪圈。DevOps追求的是**价值流动效率最大化**,也就是说,就算单点能力再强,单点之间的割裂和浪费对于价值交付效率的影响也是超乎想象的。所以,对于流程改进来说,第一步,也是最重要的一步,就是能够看见全貌,这样才能从全局视角找到可优化的瓶颈点,从而提升整体的交付效率。
另外,**对于全局交付的建模,最终也会体现到软件持续交付流水线的建设上**,因为流水线反映的就是企业客观的交付流程。这也就很好理解,为啥很多做持续交付流水线的公司,现在都延伸到了价值流交付平台上。因为这两者之间本身就存在一些共性,只不过抽象的级别和展现方式不同罢了。
**2.识别问题。**
在谈到企业交付效率的时候,我们很容易泛泛而谈,各种感觉满天飞,但感觉既不可度量,也不靠谱,毕竟,它更多地是依赖于个人认知。换句话说,即便交付效率提升了,也不知道是为啥提升的。
而VSM中的几个关键指标也就是前置时长、增值和不增值时长以及完成度和准确度都是可以客观量化改进的指标。当面对这样一幅价值流图的时候我们很容易就能识别出当前最重要的问题和改进事项。
**3.促进沟通。**
DevOps倡导通过团队成员间的沟通和协作来提升交付效率但客观现实是在很多企业中团队成员基本都是“网友关系”。即便都在一个楼里办公也会因为部门不同坐在不同的地方基本上只靠即时通讯软件和邮件交流。偶尔开会的时候能见上一面但也很少有深入的交流。如果团队之间处于你不认识我、我也不认识你的状况下又怎么有效协作呢
另外很多时候在我们开展VSM梳理的时候团队才第一次真正了解上下游团队的职责、工作方式以及让他们痛苦低效的事情。这时我们通常会设身处地地想“只要我们多做一点点就能大大改善兄弟团队的生存状况了。”实际上这种**同理心对打破协作的壁垒很有帮助**可以为改善团队内部文化带来非常正面的影响。实际上这也是我推荐你用会议或者工作坊的方式推进VSM的根本原因。
**4.驱动度量。**
我们都认可数据的力量让数据驱动改进。但是面对这么庞杂的数据体系到底哪些才是真正有价值的呢VSM就可以回答这个问题。
在VSM访谈的时候我们要问一个团队的交付周期、准确率等指标问题如果你发现这个团队支支吾吾只能给出模糊的回答这时你就要注意啦这里本身就大有问题。因为这就表示当前环节的度量指标不够清晰或者指标过于复杂团队不清楚关键的结果指标。
另外,如果数据的提取需要大量时间,比如需要采用人为统计算数的方式,那么这就体现了这个环节的平台建设能力不足,无法自动化地收集和统计数据,甚至有些关键数据还没有沉淀到数据系统中,只能通过人工本地化的方式进行管理。
这些都是DevOps转型的过程中需要解决的问题可以优先处理。可以说**VSM是一场团队协作的试炼**。收集VSM数据的过程本身就需要平台间的打通和数据共享以及自动化的推进这有助于度量活动的开展。
**5. 价值展现。**
对于企业而言任何投入都需要有产出。要实现DevOps的转型企业需要投入大量的精力。那么如何让高层领导明白企业交付效率改善所带来的价值呢价值流梳理就是一种很好的方式。因为VSM从价值分析而来到价值优化而去本身就是在回答DevOps对于企业的价值问题。
## 总结
在这一讲中我给你介绍了DevOps转型的第一步——VSM价值流图包括它的来源、3个关键要素以及在企业中开展VSM的2种方式。最后我介绍了VSM的5大价值分别是看见全貌、识别问题、促进沟通、驱动度量和价值展现。
就像我们常说的DevOps转型是一场没有终点的旅程VSM的梳理也不会是一帆风顺的。因为对于企业价值交付流程的梳理需要随着认知的深入不断地进行迭代和优化。不过好的开始是成功的一半当我们开始梳理VSM的时候我们的着眼点就会慢慢调整到DevOps模式并真正地开启我们的DevOps转型之旅。
<img src="https://static001.geekbang.org/resource/image/7c/dc/7c5851cdbeb135853f4d8d46b023dfdc.jpeg" alt="">
## 思考题
最后给你留一道思考题你认为在公司内部梳理价值流的最大障碍是什么在提取价值流图中的3个关键要素的数据时你遇到过什么挑战吗
欢迎在留言区写下你的思考和答案,我们一起讨论,共同学习进步。如果你觉得这篇文章对你有所帮助,欢迎你把文章分享给你的朋友。

View File

@@ -0,0 +1,105 @@
<audio id="audio" title="06 | 转型之路企业实施DevOps的常见路径和问题" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/dc/5e/dc2955e14fcafca78f65e7db4336435e.mp3"></audio>
你好我是石雪峰。今天我来跟你聊聊企业实施DevOps的常见路径和问题。
由于种种原因我曾直接或者间接地参与过一些企业的DevOps转型过程也跟很多企业的DevOps负责人聊过他们的转型故事。这些企业的转型过程并不是一帆风顺的在最开始引入DevOps的时候他们也面临很多普遍的问题比如企业业务都忙不过来了根本没有时间和精力投入转型工作之中或者是企业内部的系统在经历几代建设之后变得非常庞大以至于谁都不敢轻易改变。
但是,即便存在着种种问题,我也始终认为,**DevOps转型之路应该是有迹可循的**。很多企业所面临的问题并不是独一无二的,甚至可以说,很多公司都是这样一步步走过来的。所以,在转型之初,如果能够参考借鉴一条常见的路径,并且对可能遇到的问题事先做好准备,企业的转型过程会顺利很多。
## 两种轨迹
其实对于企业的转型来说DevOps也并没有什么特别之处跟更早之前的敏捷转型一样如果想在企业内部推行一种新的模式无外乎有两种可行的轨迹**一种是自底向上,一种是自顶向下。**
### **自底向上**
在这种模式下企业内部的DevOps引入和实践源自于一个小部门或者小团队他们可能是DevOps的早期倡导者和实践者为了解决自身团队内部以及上下游团队交互过程中的问题开始尝试使用DevOps模式。由于团队比较小而且内部的相关资源调动起来相对简单所以这种模式比较容易在局部获得效果。
当然DevOps的核心在于团队间的协作仅仅一个小团队内部的改进还算不上是DevOps转型。但是就像刚刚提到的那样如果企业太大以至于很难一次性改变的话的确需要一些有识之士来推动这个过程。如果你也身处在这样一个团队之中那么我给你的建议是采用“羽化原则”也就是首先在自己团队内部以及和自己团队所负责的业务范围有强依赖关系的上下游团队之间建立联系**一方面不断扩展自己团队的能力范围另一方面逐步模糊上下游团队的边界由点及面地打造DevOps共同体**。
当然如果想让DevOps转型的效果最大化你一定要想方设法地让高层知晓局部改进的效果让他们认可这样的尝试最终实现横向扩展在企业内部逐步铺开。
###
**自顶向下**
你还记得我在专栏[第2讲](https://time.geekbang.org/column/article/146839)中提到的那家把DevOps定义为愿景OKR指标的金融企业吗这就是典型的自顶向下模式也就是企业高层基于自己对于行业趋势发展的把握和团队现状的了解以行政命令的方式下达任务目标。在这种模式下公司领导有足够的意愿来推动DevOps转型并投入资源各个团队也有足够清晰的目标。
那么这样是不是就万事大吉了呢其实不然。在企业内部有这样一种说法只要有目标就一定能达成。因为公司领导对于细节的把握很难做到面面俱到团队为了达成上层目标总是能想到一些视角或数据来证明目标已经达成这样的DevOps转型说不定对公司业务和团队而言反而是一种伤害。
举个例子有一次我跟一家公司的DevOps转型负责人聊天。我问道“你们的前置时间是多久”他回答说“一周。”我心想这还挺好的呀。于是就进一步追问“这个前置时间是怎么计算的呢”他回答说“我们计算的是从开发开始到功能测试完成的时间。”我心想这好像有点问题。于是我就又问道“那从业务方提出需求到上线发布的时间呢”他回答“这个啊大概要两个月时间。”你看难怪业务方抱怨不断呢提个需求两个月才能上线。但是如果仅仅看一周的开发时长感觉是不是还不错呢
所以,一套客观有效的度量指标就变得非常重要,关于这个部分,我会用两讲的时间来和你详细聊聊。
说到这儿不知道你发现了没有无论企业的DevOps转型采用哪条轨迹**寻求管理层的认可和支持都是一个必选项**。如果没有管理层的支持DevOps转型之路将困难重重。因为无论在什么时代变革一直都是一场勇敢者的游戏。对于一家成熟的企业而言无论是组织架构、团队文化还是工程能力、协作精神都是长期沉淀的结果而不是在一朝一夕间建立的。
除此之外转型工作还需要持续的资源投入这些必须借助企业内部相对比较high level的管理层的推动才能最终达成共识并快速落地。如果你所在的公司恰好有这样一位具备前瞻性视角的高层领导那么恭喜你你已经获得了DevOps转型道路上至关重要的资源。
我之前的公司就有这样一位领导他一直非常关心内部研发效率的提升。听说他要投入大量资源加紧进行DevOps能力建设时我兴奋地描绘了一幅美好的图景但当时他说了一句意味深长的话“这个事你一旦做起来就会发现并不容易。”后来在实施DevOps的过程中这句话无数次得到了印证。
## 通用路径
因此你看管理层的支持只是推动DevOps转型的要素之一在实际操作过程中还需要很多技巧。为了帮助你少走弯路我总结提取了一条通用路径现在分享给你。
**第1步寻找合适的试点项目**
试点项目是企业内部最初引入DevOps实践并实施改进工作的业务对象。可以说一个合适的项目对于企业积累DevOps实践经验是至关重要的。我认为一个合适的项目应该具备以下几个特征
- **贴近核心业务**。DevOps要以业务价值为导向。对于核心业务管理层的关注度足够高各项业务指标也相对比较完善如果改进效果可以通过核心业务指标来呈现会更有说服力。同时核心业务的资源投入会有长期保障。毕竟你肯定不希望DevOps转型落地项目因为业务调整而半途而废吧。
- **倾向敏捷业务**。敏捷性质的业务需求量和变更都比较频繁更加容易验证DevOps改造所带来的效果。如果一个业务以稳定为主要诉求整体处于维护阶段变更的诉求和意愿都比较低那么这对于DevOps而言就不是一个好的选择。我之前在跟一家军工企业沟通的时候了解到他们每年就固定上线两次那么在这种情况下你说还有没有必要搞DevOps呢
- **改进意愿优先**。如果公司内部的团队心比天高完全瞧不上DevOps觉得自己当前的流程是最完美的那么你再跟他们费力强调DevOps的价值结果很可能事倍功半。相反那些目前绩效一般般的团队都有非常强烈的改进诉求也更加愿意配合转型工作。这时团队的精力就可以聚焦于做事本身而不会浪费在反复拉锯的沟通上。
**第2步寻找团队痛点**
找到合适的团队,大家一拍即合,接下来就需要识别团队的痛点了。所谓痛点,就是当前最影响团队效率的事情,同时也是改进之后可以产生最大效益的事情。
不知道你有没有读过管理学大师高德拉特的经典图书《目标》,他在这本书中,提出的最重要的理论就是约束理论。关于这个理论,我会在后面的内容中展开介绍,现在你只需要记得“木桶原理”就行了,即最短的木板决定了团队的容量。
至于如何找寻痛点,我已经在上一讲详细介绍过了。你不妨在内部试点团队中开展一次价值流分析活动,相信你会有很多意外的发现。如果你不记得具体怎么做了,可以回到[第5讲](https://time.geekbang.org/column/article/152806)复习一下。
**第3步快速建立初期成功**
找到了合适的团队也识别出了一大堆改进事项你是不是感觉前景一片大好准备撸起袖子加油干了呢打住这个时候切记不要把面铺得太广把战线拉得太长这其实是DevOps转型初期最典型的一个陷阱。
首先,转型初期资源投入有限,难以支撑大量任务并行。其次,由于团队成员之间还没有完全建立起信任关系,那些所谓的最佳实践很容易水土不服。如果生搬硬套的话,很可能会导致大量摩擦,从而影响改进效果。最后,管理层的耐心也没有想象中那么多,如果迟迟看不到效果,很容易影响后续资源的投入。
所以,**最关键的就是识别一个改进点,定义一个目标**。比如环境申请和准备时间过程那么就可以定义这样一个指标优化50%的环境准备时长。这样一来,团队的目标会更加明确,方便任务的拆解和细化,可以在几周内见到明显的成果。
**第4步快速展示和持续改进**
取得阶段性的成果之后,要及时向管理层汇报,并且在团队内部进行总结。这样,一方面可以增强管理层和团队的信心,逐步加大资源投入;另一方面,也能够及时发现改进过程中的问题,在团队内部形成持续学习的氛围,激发团队成员的积极性,可以从侧面改善团队的文化。
当然,类似这样的案例在企业内部都极具价值。如果可以快速扩展,那么效果就不仅仅局限于小团队内部,而是会上升到公司层面,影响力就会更加明显了。
以上这四个步骤基本涵盖了企业DevOps转型的通用路径。不过即便完全按照这样的路径进行转型也很难一帆风顺。在这条路径之下也隐藏着一些可以预见的问题最典型的就是**DevOps转型的J型曲线**这也是在2018年DevOps状态报告中的一个重点发现。
<img src="https://static001.geekbang.org/resource/image/eb/85/ebefde97d464b2b99cfd55ec1f5a3b85.png" alt="">
在转型之初,团队需要快速识别出主要问题,并给出解决方案。在这个阶段,整个团队的效能水平比较低,可以通过一些实践引入和工具的落地,快速提升自动化的能力和水平,从而帮助团队获得初期的成功。
但是,随着交付能力的提升,质量能力和技术债务的问题开始显现。比如,由于大量的手工回归测试,团队难以压缩测试周期,从而导致交付周期陷入瓶颈;项目架构的问题带来的技术债务导致集成问题增多,耦合性太强导致改动牵一发而动全身……
这个时候,团队开始面临选择:是继续推进呢?还是停滞不前呢?继续推进意味着团队需要分出额外的精力来加强自动化核心能力的预研和建设,比如优化构建时长、提升自动化测试覆盖率等,这些都需要长期的投入,甚至有可能会导致一段时间内团队交付能力的下降。
与此同时与组织的固有流程和边界问题相关的人为因素也会制约企业效率的进一步提升。如何让团队能够有信心减少评审和审批流程同样依赖于质量保障体系的建设。如果团队迫于业务压力暂缓DevOps改进工作那就意味着DevOps难以真正落地发挥价值很多DevOps项目就是这样“死”掉的。
那么说到这儿你可能会问这些到底应该由哪个团队来负责呢换句话说企业进行DevOps转型是否需要组建一个专职负责的团队呢如果需要的话团队的构成又是怎样的呢
关于这些问题,我的建议是,**在转型初期,建立一个专职的转型工作小组还是很有必要的**。这个团队主要由DevOps转型关联团队的主要负责人、DevOps专家和外部咨询顾问等牵头组成一般是各自领域的专家或者资深成员相当于DevOps实施的“大脑”主要负责制定DevOps转型项目计划、改进目标识别、技术方案设计和流程改造等。
除了核心团队管理团队和工具团队也很重要。我挂一个转型小组的团队组成示意图供你参考。当然DevOps所倡导的是一专多能跨领域的人才对于企业DevOps的实施同样不可或缺在挑选小组成员的时候这一点你也需要注意下。
<img src="https://static001.geekbang.org/resource/image/c7/ae/c7c8b813a3a9e8232f83acb783e94cae.jpg" alt="">
## 总结
今天我给你介绍了企业DevOps转型的常见轨迹分别是自底向上和自顶向下。无论采用哪种轨迹寻求管理层的支持都至关重要。接下来我和你一起梳理了DevOps转型的通用路径你要注意的是任何变革都不会是一帆风顺的企业的DevOps转型也是如此。在经历初期的成功之后我们很容易陷入“J型曲线”之中如果不能突破困局就很容易导致转型半途而废回到起点。最后我们一起探讨了是否需要专职的DevOps转型团队。在企业刚刚开始尝试DevOps的时候这样的团队对于快速上手和建立团队的信心还是很有必要的。
无论如何,就像陆游在《冬夜读书示子聿》一诗中写的那样:“纸上得来终觉浅,绝知此事要躬行。”**听过了太多实施DevOps的方法和路径却还是无法真正享受到它的巨大效益差的可能就是先干再说的信心和动力吧。**
## 思考题
你在企业中实施DevOps时遇到过什么问题吗你是怎么解决这个问题的呢你是否走过一些弯路呢
欢迎在留言区写下你的思考和答案,我们一起讨论,共同学习进步。如果你觉得这篇文章对你有所帮助,欢迎你把文章分享给你的朋友。

View File

@@ -0,0 +1,130 @@
<audio id="audio" title="07 | 业务敏捷帮助DevOps快速落地的源动力" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/92/a2/929eb0314a531ae0d8e3c920ec1c9ca2.mp3"></audio>
你好,我是石雪峰,今天我要跟你分享的主题是业务敏捷,那么,我们先来聊一聊,什么是业务敏捷,为什么需要业务敏捷呢?
先试想这样一个场景你们公司内部成立了专项小组计划用三个月时间验证DevOps落地项目的可行性。当要跟大老板汇报这个事情的时候作为团队的负责人你开始发愁怎么才能将DevOps的价值和业务价值关联起来以表明DevOps对业务价值的拉动和贡献呢
如果朝着这个方向思考,就很容易钻进死胡同。因为,从来没有一种客观的证据表明,软件交付效率的提升,和公司的股价提升有什么对应关系。换句话说,软件交付效率的提升,并不能直接影响业务的价值。
实际上,软件交付团队一直在努力通过各种途径改善交付效率,但如果你的前提是需求都是靠谱的、有效的,那你恐怕就要失望了。因为,实际情况是,业务都是在不断的试错中摸着石头过河,抱着“宁可错杀一千,也不放过一个”的理念,各种天马行空的需求一起上阵,搞得软件交付团队疲于奔命,宝贵的研发资源都消耗在了业务的汪洋大海中。但是,这些业务究竟带来了多少价值,却很少有人能说得清楚。
在企业中推行DevOps的时间越长就越会发现开发、测试和运维团队之间的沟通障碍固然存在但实际上业务部门和IT部门之间的鸿沟有时候会更加严重。试问有多少公司的业务方能够满意IT部门的交付效率又有多少IT团队不会把矛头指向业务方呢说白了就一句话**如果业务不够敏捷IT再怎么努力也没用啊**所以,我觉得很有必要跟你聊一聊有关需求的话题。
回到最开始的那个问题如果DevOps不能直接提升公司的业务价值那么为什么又要推行DevOps呢实际上如果你把DevOps的价值拆开业务价值和交付能力两个部分就很好理解了。
在现在这个多变的时代,没人能够准确地预测需求的价值。所以,交付能力的提升,可以帮助业务以最小的成本进行试错,将新功能快速交付给用户。同时,用户和市场的情况又能够快速地反馈给业务方,从而帮助业务校准方向。而业务的敏捷能力高低,恰恰体现在对功能的设计和需求的把握上,如果不能灵活地调整需求,专注于最有价值的事情,同样会拖累交付能力,导致整体效率的下降。
也就是说,在这样一种快速迭代交付的模式下,业务敏捷和交付能力二者缺一不可。
所以,开发更少的功能,聚焦用户价值,持续快速验证,就成了产品需求管理的核心思想。
## 开发更少的功能
很多时候,团队面临的最大问题,就是需求太多。但实际上,很多需求一开始就没想好,甚至在设计和开发阶段还在不断变更,这就给交付团队带来了极大的困扰。所以,在把握需求质量的前提下,如何尽可能地减小需求交付批次,采用最小的实现方案,保证高优先级的需求可以快速交付,从而提升上线实验和反馈的频率,就成了最关键的问题。
关于需求分析,比较常见的方法就是影响地图。
影响地图是通过简单的“Why-Who-How-What”分析方法实现业务目标和产品功能之间的映射关系。
- Why代表目标它可以是一个核心的业务目标也可以是一个实际的用户需求。
- Who代表影响对象也就是通过影响谁来实现这个目标。
- How代表影响也就是怎样影响用户以实现我们的目标。
- What代表需要交付什么样的功能可以带来期望的影响。
如果你是第一次接触影响地图,可能会听起来有点晕。没关系,我给你举个例子,来帮你理解这套分析方法。
比如一个专栏希望可以在上线3个月内吸引1万名用户那么这个Why也就是最核心的业务目标。为了达成这个目标需要影响的角色包含哪些呢其实就包含了作者、平台提供方、渠道方和最终用户。需要对他们施加哪些影响呢对作者来说需要快速地回答用户的问题提升内容的质量对平台来说需要对专栏进行重点曝光增加营销活动对渠道方来说需要提高推广力度和渠道引流对于用户来说增加分享有礼、免费试读和个人积分等活动。
那么基于以上这些影响方式,转化为最终的实际需求,就形成了一张完整的影响地图,如下图所示:
<img src="https://static001.geekbang.org/resource/image/2c/d9/2c8f3c2e85f517501f2ebe14120c82d9.png" alt="">
你可能会问,需求这么多,优先级要怎么安排呢?别急,现在我就给你介绍一下“卡诺模型”。
>
[卡诺模型](https://www.kanomodel.com/)Kano Model是日本大师授野纪昭博士提出的一套需求分析方法它对理解用户需求对其进行分类和排序方面有着很深刻的洞察。
<img src="https://static001.geekbang.org/resource/image/c7/e4/c70d3184824a47b13b0917fce4e54ee4.png" alt="">
卡诺模型将产品需求划分为五种类型:
1. 兴奋型指超乎用户想象的需求是可遇不可求的功能。比如用户想要一个更好的功能手机乔布斯带来了iPhone这会给用户带来极大的满足感。
1. 期望型:用户的满意度会随着这类需求数量的增多而线性增长,做得越多,效果越好,但难以有质的突破。比如,一个电商平台最开始是卖书,后面逐步扩展到卖电脑、家居用品等多个类别。用户更多的线性需求被满足,满意度自然也会提升。
1. 必备型:这些是产品必须要有的功能,如果没有的话,会带来非常大的影响。不过有这些功能的话,也没人会夸你做得有多好,比如安全机制和风控机制等。
1. 无差别型:做了跟没做一样,这就是典型的无用功。比如你花了好大力气做了一个需求,但是几乎没有用户使用,这个需求就属于无差别型。
1. 反向型:无中生有类需求,实际上根本不具备使用条件,或者用户压根不这么想。这类需求做出来以后,通常会给用户带来很大的困扰,成为被吐槽的对象。
对于五类需求来说核心要做到3点
- **优先规划期望型和必备型需求**,将其纳入日常的交付迭代中,保持一定的交付节奏;
- **识别无差别型和反向型需求**,这些对于用户来说并没有产生价值。如果团队对需求的分类有争议,可以进一步开展用户调研和分析。
- **追求兴奋型需求**因为它会带来产品的竞争壁垒和差异化。不过对于大公司而言经常会遇到创新者的窘境也就是坚持固有的商业模式而很难真正投入资源创新和自我颠覆。这就要采用精益创业的思想采用MVP最小可行产品的思路进行快速验证并且降低试错成本以抓住新的机遇。
在面对一大堆业务需求的时候,首先要进行识别和分类。当然,最开始时,人人都相信自己的需求是期望型,甚至是兴奋型的,这也可以理解。毕竟,这就好比公司里面所有的缺陷问题等级都是最高级一样,因为只要不提最高级,就会被其他最高级的问题淹没,而长期得不到解决。而**解决的方法,就是让数据说话,为需求的价值建立反馈机制,而这里提到的价值,就是用户价值**。
## 聚焦用户价值
“以终为始”这四个字在精益、DevOps等很多改进的话题中经常会出现。说白了就是要“指哪打哪而不是打哪指哪”。产品开发方经常会问“这个功能这么好为什么用户就不用呢”**这就是典型的用产品功能视角看问题,嘴上喊着“用户是上帝”的口号,但实际上,自己却用上帝视角来看待具体问题**。
如果你所在的公司也在搞敏捷转型,那你应该也听说过用户故事这个概念。需求不是需求,而是故事,这也让很多人不能理解。那么,用户故事是不是换了个马甲的需求呢?
关于这个问题,我曾经特意请教过一位国内的敏捷前辈,他的话让我记忆犹新。他说,从表面上看,用户故事是一种采用故事来描述需求的形式,但实际上是业务敏捷性的重要手段。它改变的不仅仅是需求的书写方式,还是需求达成共识的方式。也就是说,如果所谓的敏捷转型,没有对需求进行拆解,对需求达成共识的方式进行改变,对需求的价值进行明晰,那么可能只是在做迭代开发,而跟敏捷没啥关系。
在以往进行需求讨论的时候,往往有两个极端:一种是一句话需求,典型的“给你一个眼神,你自己体会”的方式,反正我就要做这件事,至于为什么做、怎么做一概不管,你自己看着办;另一种是上来就深入实现细节,讨论表字段怎么设计、模块怎么划分,恨不得撸起袖子就跟研发一起写代码。
每次需求讨论都是一场唇枪舌剑,达成的共识都是以一方妥协为前提的,这样显然不利于团队的和谐发展。更重要的是,始终在功能层面就事论事,而不关注用户视角,这样交付出来的需求很难达到预期。
而用户故事则是以用户的价值为核心,圈定一种角色,表明通过什么样的活动,最终达到什么样的价值。团队在讨论需求的时候,采用一种讲故事的形式,代入到设定的用户场景之中,跟随用户的操作路径,从而达成用户的目标,解决用户的实际问题。这样做的好处在于,经过团队的共同讨论和沟通,产品、研发和测试对需求目标可以达成共识,尤其是对想要带给用户的价值达成共识。
在这个过程中,团队不断探索更好的实现方案和实现路径,并补充关联的用户故事,从而形成完整的待办事项。更重要的是,团队成员逐渐培养了用户和产品思维,不再拘泥于技术实现本身,增强了彼此之间的信任,积极性方面也会有所改善,从而提升整个团队的敏捷性。
用户故事的粒度同样需要进行拆分拆分的原则是针对一类用户角色交付一个完整的用户价值也就是说用户故事不能再继续拆分的粒度。当然在实际工作中拆分的粒度还是以迭代周期为参考在一个迭代周期内交付完成即可一般建议是35天。检验用户故事拆分粒度是否合适可以遵循INVEST原则。
那么什么是INVEST原则呢
- Independent独立的减少用户故事之间的依赖可以让用户故事更加灵活地验证和交付而避免大批量交付对于业务敏捷性而言至关重要。
- Negotiable可协商的用户故事不应该是滴水不漏、行政命令式的而是要抛出一个场景描述并在需求沟通阶段不断细化完成。
- Valuable有价值的用户故事是以用户价值为核心的所以每个故事都是在对用户交付价值所以要站在用户的视角思考问题避免像最近特别火的那句话一样“我不要你觉得我要我觉得。”
- Estimatable可评估的用户故事应该可以粗略评估工作量无论是故事点数还是时间都可以。如果是一个预研性质的故事则需要进一步深挖可行性避免不知道为什么做而做。
- Small小的用户故事应该是最小的交付颗粒度所以按照敏捷开发方式无论迭代还是看板都需要在一个交付周期内完成。
- Testable可测试的也就是验收条件如果没有办法证明需求已经完成也就没有办法进行验收和交付。
## 持续快速验证
所谓用户价值,说起来多少有些虚无缥缈。的确,就像我们无法预测未来一样,**需求的价值难以预测,但是需求的价值却可以定义**。所以需求价值的定义可以理解为需求价值的度量分为客观指标和主观2个方面。
- 客观指标:也就是客观数据能够表明的指标,比如对电商行业来说,可以从购买流程角度,识别商品到达率、详情到达率、加入购物车率、完成订单率等等;
- 主观指标:也就是用户体验、用户满意度、用户推荐率等等,无法直接度量,只能通过侧面数据关联得出。
但是无论是客观指标,还是主观指标,每一个需求在提出的时候,可以在这些指标中选择需求上线后的预期,并定义相关的指标。一方面加强价值导向,让产品交付更有价值的需求,另外一方面,也强调数据导向,尽量客观地展现实际结果。
当然,产品需求是一个复杂的体系,相互之间也会有影响和依赖,怎么从多种指标中识别出关键指标,并跟需求本身进行关联,这就是一门学问了。不过你别担心,我会在度量相关的内容中跟你详细讨论一下。
在很多企业中精益创业的MVP思想已经深入人心了。面对未知的市场环境和用户需求为了快速验证一个想法可以通过一个最小化的产品实现来获取真实的市场反馈并根据反馈数据修正产品目标和需求优先级从而持续迭代产品需求。
<img src="https://static001.geekbang.org/resource/image/d4/b3/d433037a08130b6e36141c0a63342db3.png" alt="">
这套思想基本上放之四海而皆准,但是在企业中实际应用的时候,也会出现跑偏的情况。比如,在需求提出的时候,产品预定义了一组指标,但是在上线后由于缺乏数据支撑,需求价值的评估变成了纯粹的主观题,比如业务方自主判断需求是达到预期,符合预期还是未达到预期。这样一来,十有八九统计出来的结果都是符合预期及以上。但问题是,这样推导出来的结果对产品方向是否真的有帮助呢?
所以,采用客观有效的反馈机制就成了必选项。从技术层面来说,一个业务需求的背后,一般都会关联一个埋点需求。所谓埋点分析,是网站分析的一种常用的数据采集方法。设计良好的埋点功能,不仅能帮助采集用户操作行为,还能识别完整的上下文操作路径,甚至进行用户画像的聚类和分析,帮助识别不同类型用户的行为习惯。从用户层面来说,众测机制和用户反馈渠道是比较常见的两种方式,核心就是既要听用户怎么说,也要看用户怎么做。
## 总结
DevOps的关注点要从研发环节继续向上游延伸一直把业务团队包括进来。也就是说IT部门不仅仅是被动的按照业务需求交付功能还要更加快速地提供业务数据反馈辅助业务决策。同时交付能力的提升也进一步降低了业务的试错成本而业务的敏捷性也决定了研发交付的需求价值和交付节奏通过影响地图进行需求分析再通过卡诺模型分析需求属性和优先级通过用户故事和整个团队达成共识通过持续快速验证帮助产品在正确的道路上发展前进。
引入业务的DevOps就成了BizDevOps这也是DevOps发展的一种潮流。最后我帮你梳理下BizDevOps的核心理念
- 对齐业务和开发目标、指标;
- 把握安全、合规指标;
- 及时对齐需求,减少无用开发;
- 体现DevOps的价值
- 让开发团队开始接触业务,不单单是执行,调动积极性。
## 思考题
你所在的企业中对于需求的价值是如何衡量的呢?是否有一套指标体系可以客观地展现需求的价值呢?
欢迎在留言区写下你的思考和答案,我们一起讨论,共同学习进步。如果你觉得这篇文章对你有所帮助,欢迎你把文章分享给你的朋友。

View File

@@ -0,0 +1,110 @@
<audio id="audio" title="08 | 精益看板(上):精益驱动的敏捷开发方法" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/d2/46/d2ac48b55e9cbb72d085238c59802d46.mp3"></audio>
你好,我是石雪峰。
提到敏捷开发方法你可能会情不自禁地联想到双周迭代、每日站会、需求拆分等。的确作为一种快速灵活、拥抱变化的研发模式敏捷的价值已经得到了行业的普遍认可。但是即便敏捷宣言已经发表了将近20个年头很多公司依然挣扎在敏捷转型的道路上各种转型失败的案例比比皆是。
我曾经就见过一家公司,一度在大规模推行敏捷。但是,这家公司很多所谓的敏捷教练都是项目经理兼任的,他们的思维和做事习惯还是项目制的方式。即便每天把团队站会开得有模有样,看板摆得到处都是,但从产品的交付结果来看,并没有什么显著的变化。没过多久,由于组织架构的调整,轰轰烈烈的敏捷转型项目就不了了之了。
这家公司虽然表面上采用了业界流行的敏捷实践也引入了敏捷工具但是团队并没有对敏捷的价值达成共识团队领导兼任Scrum Master好好的站会变成了每日工作汇报会。甚至在敏捷项目复盘会上领导还宣称“敏捷就是要干掉变化我们的目标就是保证团队按照计划进行。”这种“貌合神离”的敏捷并不能帮助企业达到灵活响应变化、快速交付价值的预期效果。
作为一种最广泛的敏捷框架Scrum的很多理念和实践都深入人心比如很多时候迭代式开发几乎等同于跟敏捷开发。但是Scrum对于角色的定义并不容易理解在推行Scrum的时候如果涉及到组织变革就会举步维艰。
实际上企业的敏捷转型并没有一条通用的路径所用的方法也没有一定之规。今天我就跟你聊聊另外一种主流的敏捷开发方法——精益看板。与Scrum相比看板方法的渐进式改变过程更加容易被团队接受。我之前所在的团队通过长期实践看板方法不仅使产品交付更加顺畅还提升了团队的整体能力。
那么,这个神奇的精益看板是怎么回事呢?
如果你之前没听说过精益看板,还是很有必要简单了解下它的背景的。其实,“看板”是一个日语词汇,泛指日常生活中随处可见的广告牌。而在生产制造系统中,看板作为一种信号卡,主要用于传递信息。很多人认为看板是丰田公司首创的,其实并非如此,比如在我之前所在的尼康公司的生产制造车间里,看板同样大量存在。
当然,看板之所以能广为人知,还是离不开丰田生产系统。《改变世界的机器》一书首次提到了著名的丰田准时化生产系统,而看板正是其中的核心工具。
简单来说,看板系统是一种拉动式的生产方式。区别于以往的大规模批量生产,看板采用按需生产的方式。也就是说,下游环节会在需要的时候,通过看板通知上游环节需要生产的工件和数量,然后上游再启动生产工作。
说白了,所谓拉动式生产,就是从后端消费者的需求出发,向前推导,需要什么就生产什么,而不是生产出来一大堆没人要的东西,从而达到减低库存、加速半成品流动和灵活响应变化的目的。我你分享一张有关丰田生产方式的图片,它演示了整个丰田生产方式的运作过程,你可以参考一下。
<img src="https://static001.geekbang.org/resource/image/a6/2d/a69ccb0d561d1d866f6bfe87384dbb2d.png" alt="">
>
图片来源:[https://www.toyota-europe.com/world-of-toyota/this-is-toyota/toyota-production-system](https://www.toyota-europe.com/world-of-toyota/this-is-toyota/toyota-production-system)
软件开发中的看板方法,借鉴了丰田生产系统的精益思想,同样以限制在制品数量、加快价值流动为核心理念。也就是说,**如果没有在制品限制的拉动系统,只能说是一个可视化系统,而不是看板系统,这一点非常重要**。
比如很多团队都在使用Jira并在Jira中建立了覆盖各个开发阶段的看板围绕它进行协作这就是一个典型的可视化板而非看板。那么为什么对于看板方法而言约束在制品数量如此重要呢
就像刚才提到的,**加快价值流动是精益看板的核心。在软件开发中,这个价值可能是一个新功能,也可能是缺陷修复,体验优化**。根据利特尔法则,我们知道:**平均吞吐率=在制品数量/平均前置时间**。其中在制品数量就是当前团队并行处理的工作事项的数量。关于前置时间你应该并不陌生作为衡量DevOps产出效果的核心指标它代表了从需求交付开发开始到上线发布这段时间的长度。
比如1个加油站只有1台加油设备每辆车平均加油时长是5分钟如果有10辆车在等待那么前置时长就是50分钟。
但是这只是在假设队列中的工作都是顺序依次执行的情况下在实际的软件开发过程中。如果一个开发人员同时处理10件事情那么在每一件事情上真正投入的时间绝不是1/10。
还拿刚刚的例子来说如果1台加油设备要给10辆车加油这就意味着给每一辆车加油前后的动作都要重复一遍比如取出加油枪、挪车等。这样一来任务切换的成本会造成极大的资源消耗导致最终加满一辆车的时长远远超过5分钟。
所以,**在制品数量会影响前置时间,并行的任务数量越多,前置时间就会越长**,也就是交付周期变长,这显然不是理想的状态。
不仅如此,**前置时间还会影响交付质量,前置时间增长,则质量下降**。这并不难理解。比如,随着工作数量的增多,复杂性也在增加,多任务切换总会导致失误。另外,人的记性没那么可靠。对于一个需求,刚开始跟产品沟通的时候就是最清晰的,但是过了一段时间就有点想不起来是怎么回事了。这个时候,如果按照自己的想法来做,很有可能因为对需求的理解不到位,最终带来大量的返工。
再进一步展开来看的话软件开发工作总是伴随着各种变化和意外。如果交付周期比需求变化周期更长那就意味着紧急任务增多。比如老板发现一个线上缺陷必须高优先级修复类似的紧急任务增多就会导致在制品数量进一步增多。这样一来团队就陷入了一个向下螺旋这对团队的士气和交付预期都会造成非常不好的影响以至于有些团队90%的精力都用来修复问题了,根本没时间交付需求和创新。
更加严重的问题是这个时候业务部门对IT部门的信任度就会直线下降。业务部门往往会想“既然无法预测需求的交付实践那好吧我只能一次性压给你一大堆需求。”这样一来就进一步导致了在制品数量的上升。
可见,一个小小的在制品数量,牵动的是整个研发团队的信心。我把刚刚提到的连环关系整理了一下,如下图所示:
<img src="https://static001.geekbang.org/resource/image/ea/44/eaf59898b2d1428c96c07df6ef897944.png" alt="">
当然针对刚才加油站的问题你可能会说“多加几台加油设备不就完了吗何必依赖同一台机器呢”的确当并行任务过多的时候适当增加人员有助于缓解这个问题但是前置时间的缩短是有上限的。这就好比10个人干一个月的事情给你100个人3天做完这就是软件工程管理的经典图书《人月神话》所讨论的故事了我就不赘述了。这里你只需要知道随着人数的增多人与人之间的沟通成本会呈指数级上升。而且从短期来看由于内部培训、适应环境等因素新人的加入甚至会拖慢原有的交付速度。
了解了精益看板的核心理念,以及约束在制品数量的重要性,也就掌握了看板实践的正确方向。那么,在团队中要如何开始一步步地实施精益看板方法呢?在实施的过程中,又有哪些常见的坑,以及应对措施呢?这正是我要重点跟你分享的问题。我把精益看板的实践方法分为了五个步骤。
- 第一步:可视化流程;
- 第二步:定义清晰的规则;
- 第三步:限制在制品数量;
- 第四步:管理工作流程;
- 第五步:建立反馈和持续改进。
今天,我先给你介绍精益看板实践方法的第一步:可视化流程。在下一讲中,我会继续跟你聊聊剩余的四步实践。
## 第一步:可视化流程
在看板方法中提高价值的流动效率快速交付用户价值是核心原则所以第1步就是要梳理价值交付流程通过对现有流程的建模让流程变得可视化。关于价值流建模的话题在专栏[第5讲](https://time.geekbang.org/column/article/152806)中我已经介绍过了,如果你不记得了,别忘记回去复习一下。
其实,在组织内部,无论采用什么研发模式,组织结构是怎样的,价值交付的流程一直都是存在的。所以,在最开始,我们只需要忠实客观地把这个现有流程呈现出来就可以了,而无需对现有流程进行优化和调整。也正因为如此,看板方法的引入初期给组织带来的冲击相对较小,不会因为剧烈变革引起组织的强烈不适甚至是反弹。所以,**看板方法是一种相对温和的渐进式改进方法**。
接下来,就可以根据价值流定义看板了。看板的设计没有一个标准样式,因为每个组织的价值流都不相同。对于刚刚上手看板方法的团队来说,看板的主要构成元素可以简单概括成“一列一行”。
**1.一列。**
这是指看板的竖向队列,是按照价值流转的各个主要阶段进行划分的,比如常见的需求、开发、测试、发布等。对识别出来的每一列进一步可以划分成“进行中”和“已完成”两种状态,这也是精益看板拉动式生产的一个显著特征。对于列的划分粒度可以很细,比如开发阶段可以进一步细分成设计、编码、自测、评审、提测等环节,或者就作为一个单独的开发环节存在。划分的标准主要有两点:
- **是否构成一个独立的环节**。比如对于前后端分离的开发来说,前端开发和后端开发就是两个独立的环节,一般由不同的角色负责,这种就比较适合独立阶段。
- **是否存在状态的流转和移交**。看板是驱动上下游协同的信号卡,所以,我们需要重点关注存在上下游交付和评审的环节,这也是提示交付吞吐率和前置时长的关键节点。
除此之外,看板的设计需要定义明确的起点和终点。对于精益看板来说,覆盖端到端的完整价值交付环节是比较理想的状态。但实际上,在刚开始推行看板方法的时候,由于组织架构、团队分工等多种因素,只能在力所能及的局部环节建立看板,比如开发测试环节,这并不是什么大问题,可以在局部优化产出效果之后,再尝试向前或向后延伸。
另外,即便看板可以覆盖端到端的完整流程,各个主要阶段的关注点各不相同,所以,也会采用看板分类分级的方式。对于开发看板来说,起点一般是需求准备就绪,也就是说,需求经过分析评审设计并同研发团队沟通一致准备进入开发的状态,终点可以是提测或者发布状态。流程的起点和终点同样要体现在看板设计中,以表示在局部环节的完整工作流程。
<img src="https://static001.geekbang.org/resource/image/4f/be/4f34bc80c89c696864d7640687eec7be.png" alt="">
**2.一行。**
这是指看板横向的泳道。泳道用于需求与需求之间划清界限,尤其在使用物理看板的时候,经常会因为便利贴贴的位置随意等原因导致混乱,而定义泳道就可以很好地解决这个问题。比如,高速公路上都画有不同的行车道,这样车辆就可以在各自的车道内行驶。
当然,泳道的意义不只如此。泳道还可以按照不同维度划分。比如,有的看板设计中会加入紧急通道,用于满足紧急需求的插入。另外,非业务类的技术改进需求,也可以在独立泳道中进行。对于前后端分离的项目来说,一个需求会拆分成前端任务和后端任务,只有当前后端任务都完成之后才能进行验收。这时,就可以把前后端任务放在同一个泳道中,从而体现需求和任务的关联关系,以及任务与任务之间的依赖关系,快速识别当前阻塞交付的瓶颈点。
当然看板的设计没有一定之规。在我们团队的看板中往往还有挂起类需求区域、缺陷区域以及技术攻关类区域等用于管理特定的问题类型。比如对于长期挂起的需求在一定时间之后就可以从看板中移除毕竟如果是几个月都没有进入任务队列的需求可能就不是真正的需求这些可以根据团队的实际情况灵活安排。如果你在使用Jira这样的工具虽然没有区域的概念但是可以通过泳道来实现比如按照史诗任务维度区分泳道然后新建对应区域的史诗任务就可以啦。
<img src="https://static001.geekbang.org/resource/image/4d/23/4d78eac23b10166656d58e5dae684723.png" alt="">
## 总结
今天我给你介绍了敏捷常用的两种框架Scrum和看板。看板来源于丰田生产系统以拉动式生产为最典型的特征。关注价值流动加速价值流动是精益看板的核心限制在制品数量就是核心实践因为在制品数量会直接影响团队的交付周期和产品质量甚至还会影响团队之间的信任导致团队进入向下螺旋。
在团队中实践精益看板,可以分为五个步骤,分别是:可视化流程、定义清晰的规则、限制在制品数量、管理工作流程和建立反馈并持续改进。今天我给你介绍了第一个步骤,也就是可视化流程,通过价值流分析将团队的交付路径可视化,建立起看板的主要结构,那么接下来就是开始应用看板了。下一讲,我会跟你聊聊其余的四个步骤,敬请期待。
## 思考题
最后,给你留一个思考题:你所在的公司是否也在实践敏捷呢?在敏捷转型的过程中,你遇到的最大问题、踩过的最大的坑是什么呢?
欢迎在留言区写下你的思考和答案,我们一起讨论,共同学习进步。如果你觉得这篇文章对你有所帮助,欢迎你把文章分享给你的朋友。

View File

@@ -0,0 +1,126 @@
<audio id="audio" title="09 | 精益看板(下):精益驱动的敏捷开发方法" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/9b/5c/9b5da1533c5d4de6a754f10f764c205c.mp3"></audio>
你好我是石雪峰。在上一讲中我给你介绍了两种常见的敏捷框架Scrum和精益看板。我重点提到关注价值流动是精益的核心理念限制在制品数量则是核心实践。此外我还给你介绍了实施精益看板第一步可视化流程。那么今天我会继续介绍剩余的四个步骤。
先提一句,如果你比较关心工具使用方面的问题,我给你分享一份有关常见的工具配置和使用方面的资料,你可以点击[网盘](https://pan.baidu.com/s/1SAmWYv7WeYgM6yZSRs5nag)下载提取码是mrtd。
好了,现在正式开始今天的内容。
## 第二步:定义清晰的规则
在完成可视化流程之后,看板的雏形就出来啦。接下来你要做的,就是定义清晰的规则。
可视化的意义不仅在于让人看得见,还在于让人看得懂。工作时间久了,我们很容易产生一种感觉,那就是**沟通的成本甚至要大于工作的成本**。沟通的最主要目的就是同步和传递信息,如果有一种途径可以提升信息传递的效率,那岂不是很好吗?
而看板恰恰有一个重要的意义,就是状态可视化。团队的所有成员可以通过看板了解当前在进行的任务状态、流程中的瓶颈点、任务与任务之间的依赖关系等信息,从而自发地采取相应的活动,来保证价值交付的顺畅,使整个项目能够有条不紊地交付。
当然,如果想要做到这点,光靠可视化流程还远远不够,你还需要在看板的设计中融入一定的规则。这些规则可以大大地降低团队成员之间的沟通成本,统一团队的沟通语言,形成团队成员之间的默契。看板的规则包含两个方面,一个是可视化规则,另一个是显式化规则,我分别来介绍一下。
**1.可视化规则。**
在上一讲中我们提到看板中的主要构成元素是“一列一行”。实际上看板中卡片的设计也有讲究主要有3点。
- 卡片的颜色:用于区分不同的任务类型,比如需求(绿色)、缺陷(红色)和改进事项(蓝色);
- 卡片的内容用于显示任务的主要信息比如电子看板ID号需求的名称、描述、负责人、预估工作量和停留时长等
- 卡片的依赖和阻塞状态:用于提起关注,比如在卡片上通过张贴不同的标志,表示当前卡片的健康程度,对于存在依赖和阻塞状态的卡片,需要团队高优先级协调和处理。这样一来,看板就显得主次分明啦。
**2.显式化规则。**
**看板除了要让人看得懂,还要让人会操作,这一点非常重要**。尤其是在引入看板的初期,大家对这个新鲜事物还比较陌生,所以,定义清晰的操作规则就显得格外重要了。而且,在团队习惯操作之前,需要反复地强调以加深团队的印象,慢慢培养团队的习惯。当团队习惯了使用看板之后,效率就会大大提升。这些规则包括:
- 谁来负责整理和移动卡片?
- 什么时间点进行卡片操作?
- 卡片的操作步骤是怎样的?(比如,卡片每停留一天需要做一次标记。)
- 什么时候需要线下沟通?(比如缺陷和阻塞)
- 哪些标识代表当前最高优先级的任务?
- 看板卡片的填充规则是怎样的?
- 谁来保障线下和线上看板的状态一致性?
还是那句话,这些规则在团队内部可能一直都存在,属于心照不宣的那种类型,但是,通过看板将规则显示化,无论是对于规则的明确,新人的快速上手,还是团队内部的持续改进,都有着非常大的好处。
## 第三步:限制在制品数量
**限制在制品数量是看板的核心,也是最难把握的一个环节,主要问题就在于把数量限制为多少比较合适的呢?**
要回答这个问题,首先要明确一点:**应用看板方法只能暴露团队的现有问题,而不能解决团队的现有问题。**
怎么理解这句话呢?这就是说,当在制品数量没有限制的时候,团队的交付时间和交付质量都会受到影响,这背后的原因可能是需求把控不到位,发布频率不够高,自动化程度不足以支撑快速交付,组织间的依赖和系统架构耦合太强……这些都是团队的固有问题,并非是使用看板方法就能统统解决掉的。
**但看板方法的好处在于,通过降低在制品数量,可以将这些潜在的问题逐步暴露出来。**比如在极端情况下假设我们将在制品数量设置为1也就是说团队当前只工作在一个需求上按道理来说交付的前置时间会大大缩短。但实际上团队发现由于测试环境不就绪导致无法验收交付或者交付窗口过长错过一个窗口就要再等2周的时间到头来还是不能达到快速交付价值的目标。那么这里的原因就在于测试环境初始化问题和交付频率的问题。这些都是团队固有的问题只不过在没有那么高的交付节奏要求时并没有显现出来而已。
所以,如果你能够摆正心态,正视团队的固有问题,你就会明白,限制在制品数量绝不仅仅是纠结一个数字这么简单的。在我看来,限制在制品数量有两个关键节点:一个是需求流入节点,一个是需求交付节点。
**1.需求流入节点。**
这里的关键是限制需求的流入。你可能就会说这太不靠谱了面对如狼似虎的业务方研发团队只能做个小绵羊毕竟只要你敢say“no”业务方就直接立刻写邮件抄送老板了。
其实需求的PK是个永恒的话题敢问哪个研发经理没经历过几十、上百次需求PK的腥风血雨呢我之前就因为同项目团队需求PK得过于激烈一度做好了被扫地出门的准备。但是后来我们发现到头来大家还是一根绳子上的蚂蚱在资源有限的前提下一次提100个需求和提10个需求从交付时长来看其实并没有什么区别。所以限制在制品数量只是换了一个方式PK需求从之前业务方提供一大堆需求让研发团队给排期的方式变成了根据需求的优先级限制并行任务数量的方式。
当然,研发团队需要承诺业务方以最快的速度交付最高优先级的需求。如果业务方看到需求的确按照预期的时间上线甚至是提前上线,他们就会慢慢习惯这种做法,团队之间的信任也就一点点建立起来了。
**2.需求流出节点。**
这里的关键在于加速需求的流出。在一般的看板中,最容易出现堆积的就是待发布的状态列,因为发布活动经常要根据项目的节奏安排,由专门团队在专门的时间窗口进行。如果发现待发布需求大量堆积,这时候就有理由推动下游加快发布节奏,或者以一种更加灵活的方式进行发布。
毕竟DevOps所倡导的是“You build ityou run it”的理念这也是亚马逊公司最为经典的团队理念意思是开发团队自己负责业务的发布每个发布单元都是独立的彼此没有强依赖关系从而实现团队自制。通过建立安全发布的能力将发布变成一件平常的事情这才真正有助于需求价值的快速交付。说白了要想做到业务敏捷就得想发就发做完一个上一个。
至于要将在制品数量限制为多少,我的建议是采用渐进式优化的方式。你可以从团队人数和需求的现状出发,在每个开发人员不过载的前提下,比如并行不超过三件事,根据当前处理中的任务数量进行约定,然后观察各个环节的积压情况,再通过第四步实践进行调整,最终达到一个稳定高效的状态。
## 第四步:管理工作流程
在专栏[第5讲](https://time.geekbang.org/column/article/152806)中,我提到过精益理论中的增值环节和不增值环节,而会议一般都会被归为不增值环节。于是,有人就会产生这样一种误解:“那是不是所有不增值的环节都要被消除掉,以达到最高的流动效率呢?”
如果这么想的话,那是不是类似项目经理这样的角色也就不需要了呢?毕竟,他们看起来并没有直接参与到软件开发的活动中。显然,这是很片面的想法。实际上,在精益的不增值活动中,还可以进一步划分出必要不增值活动和不必要不增值活动,有些会议虽然不直接增值,但却是非常必要的。所以,我们不能简单地认为精益就等于不开会、不审批。
看板方法同样根植于组织的日常活动之中,所以,同样**需要配套的管理流程,来保障看板机制的顺畅运转**。在看板方法中,常见的有三种会议,分别是每日站会、队列填充会议和发布规划会议。
**1.每日站会。**
接触过敏捷的团队应该都非常熟悉每日站会。但是与Scrum方法的“夺命三连问”昨天做了什么今天计划做什么有什么困难或者阻塞相比看板方法的站会则略有不同。因为我们在第二步制定了清晰的规则团队的现状已经清晰可见只需要同步下重点任务就可以了。看板方法更加关注两点
- 待交付的任务。看板追求价值的快速流动,所以,对于在交付环节阻塞的任务,你要重点关注是什么原因导致的。
- 紧急、缺陷、阻塞和长期没有更新的任务。这些任务在规则中也有相应的定义如果出现了这些问题团队需要最高优先级进行处理。这里有一个小技巧就是当卡片放置在看板之中时每停留一天卡片的负责人就会手动增加一个小圆点标记通过这个标记的数量就可以看出哪些任务已经停留了太长时间。而对于使用电子看板的团队来说这就更加简单了。比如Jira本身就支持停留时长的显示。当然你也可以自建过滤器按照停留时长排序重点关注Top问题的情况。
每日站会要尽量保持高效,对于一些存在争议的问题,或者是技术细节的讨论,可以放在会后单独进行。同时,会议的组织者也要尽量观察每日站会的执行效果,如果出现停顿或者不顺畅的情况,那就意味着规则方面有优化空间。比如,如果每日站会依赖一名组织者来驱动整个过程,只要这个人不发问,团队就不说话,这就说明规则不够清晰。另外,对于站会中迸发出来的一些灵感或者好点子,可以都记录下来,作为优化事项跟进解决。
**2.队列填充会议。**
队列填充会议的目标有两点:一个是对任务的优先级进行排序,一个是展示需求开发的状态。一般情况下,队列填充会议需要业务方、技术方和产品项目负责人参与进来,对需求的优先级达成一致,并填充到看板的就绪状态中。
在初期,我建议在每周固定时间举行会议,这样有助于整个团队共享需求交付节奏,了解需求交付状态,帮助业务方和技术方建立良好的合作和信任关系,在会议上也可以针对在制品数量进行讨论和调整。
**3.发布规划会议。**
发布规划会议以最终交付为目标。一般情况下,项目的交付节奏会影响队列填充的节奏,二者最好保持同步。另外,随着部署和发布的分离,研发团队越来越趋近于持续开发持续部署,而发布由业务方统一规划把控,发布规划会议有助于研发团队和业务方的信息同步,从而实现按节奏部署和按需发布的理想状态。
## 第五步:建立反馈和持续改进
实际上无论是DevOps还是精益看板任何一套方法框架的终点都是持续改进。因为作为一种新的研发思想和研发方法只有结合业务实际并根据自身的情况持续优化规则、节奏、工具和流程才能更好地为业务服务。关于这部分的内容我会在度量和持续改进中进行详细介绍。你要始终记得没有天然完美的解决方案只有持续优化的解决方案。看板方法的实践是一个循序渐进的过程。为此看板创始人David J Anderson总结了看板方法的成熟度模型用于指导中大型团队实践看板方法如下图所示
<img src="https://static001.geekbang.org/resource/image/ae/3c/ae98048d5805b01f3040ef2d4216393c.png" alt="">
>
图片来源:[http://leankanban.com/kmm/](http://leankanban.com/kmm/)
这个模型将看板的成熟度划分为7个等级。除此之外它还针对每一级的每一个实践维度给出了具体的能力参考对看板方法的实施有非常强的指导作用可以用于对标现有的能力图谱。
如果你想获取更加详细的信息,可以点击在这一讲的开头我分享给你的链接,作为补充参考。
## 总结
好啦,回顾一下,在这两讲中,我先给你介绍了看板的背景和起源。看板来源于生产制造行业,是一种常用的生产信号传递方式,同时,看板也是以丰田生产系统为代表的精益生产的核心工具,也就是以拉动为核心的按需生产方式。
接着我跟你探讨了为什么要限制在制品数量以及背后的理念也就是缩短交付前置时长以快速、高质量、可预期的交付方式在业务方和IT部门之间建立起合作信任关系。
除此之外我还给你介绍了精益看板的5个核心实践包括可视化流程定义清晰的规则约束在制品数量管理工作流程和建立反馈持续改进。掌握了这些你就获取了开启精益看板之旅的钥匙。在真正进行实践之后相信你会有更多的收获和感悟。
需要提醒你的是,僵化的实践方法,脱离对人的关注,可以说是影响精益看板在组织内落地的最大障碍。就像《丰田之道》中提到的那样,持续改进和对人的尊重,才是一切改进方法的终极坐标,这一点是我们必须要注意的。
## 思考题
最后,给你留一个思考题:如果让你现在开始在团队中推行精益看板方法,你觉得有哪些挑战吗?
欢迎在留言区写下你的思考和答案,我们一起讨论,共同学习进步。如果你觉得这篇文章对你有所帮助,欢迎你把文章分享给你的朋友。

View File

@@ -0,0 +1,142 @@
<audio id="audio" title="10 | 配置管理最容易被忽视的DevOps工程实践基础" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/8a/f0/8ac56b053a9670ed8ee823dfe5d21ef0.mp3"></audio>
你好我是石雪峰。从今天开始专栏正式进入了工程实践的部分。在DevOps的体系中工程实践所占的比重非常大而且和我们的日常工作息息相关。正因为如此DevOps包含了大量的工程实践很多我们都耳熟能详比如持续集成、自动化测试、自动化部署等等这些基本上是实践DevOps的必选项。
可是还有一些实践常常被人们所忽视但这并不代表它们已经被淘汰或者是不那么重要了。恰恰相反它们同样是DevOps能够发挥价值的根基配置管理Configuration Management就是其中之一。它的理念在软件开发过程中无处不在可以说是整个DevOps工程实践的基础。所以今天我们就来聊一聊配置管理。
说了这么多,那软件配置管理到底是个啥呢?
熟悉运维的同学可能会说不就是类似Ansible、Saltstack的环境配置管理工具吗还有人会说CMDB配置管理数据库也是配置管理吧这些说法都没错。配置管理这个概念在软件开发领域应用得非常普遍几乎可以说无处不在但是刚刚提到的这些概念都是细分领域内的局部定义。
我今天要讲到的配置管理,是一个宏观的概念,是站在软件交付全生命周期的视角,对整个开发过程进行规范管理,控制变更过程,让协作更加顺畅,确保整个交付过程的完整、一致和可追溯。
看到这里,我估计你可能已经晕掉了。的确,配置管理的理论体系非常庞大。但是没关系,你只需要把四个核心理念记在心中就足够了。这四个理念分别是:**版本变更标准化,将一切纳入版本控制,全流程可追溯和单一可信数据源**。
## 1. 版本变更标准化
**版本控制是配置管理中的一个非常核心的概念,而对于软件来说,最核心的资产就是源代码**。现在很多公司都在使用类似Git、SVN之类的工具管理源代码这些工具其实都是版本控制系统。版本描述了软件交付产物的状态可以说从第一行软件代码写下开始版本就已经存在了。
现代软件开发越来越复杂,往往需要多人协作,所以,如何管理每个开发者的版本,并把它们有效地集成到一起,就成了一个难题。实际上,版本控制系统就是为了解决这个问题的。试想一下,如果没有这么一套系统的话,所有代码都在本地,不要说其他人了,就连自己都会搞不清楚哪个是最新代码。那么,当所有人的代码集成到一起的时候,那该是多么混乱啊!
不仅如此,如果线上发生了严重问题,也找不到对应的历史版本,只能直接把最新的代码发布上去,简直就是灾难。
**配置管理中的另一个核心概念是变更**。我们对软件做的任何改变都可以称之为一次变更,比如一个需求,一行代码,甚至是一个环境配置。**版本来源于变更**。对于变更而言,核心就是要记录:**谁,在什么时间,做了什么改动,具体改了哪些内容,又是谁批准的**。
这样看来,好像也没什么复杂的,因为现代版本控制系统基本都具备记录变更的功能。那么,是不是只要使用了版本控制系统,就做到变更管理了呢?
的确,版本控制系统的出现,大大简化了管理变更的成本,至少是不用人工记录了。但是,从另一方面来看,用好版本控制系统也需要有一套规则和行为规范。
比如版本控制系统需要打通公司的统一认证系统也就是任何人想要访问版本控制系统都需要经过公司统一登录的认证。同时在使用Git的时候你需要正确配置本地信息尤其是用户名和邮箱信息这样才能在提交时生成完整的用户信息。另外系统本身也需要增加相关的校验机制避免由于员工配置错误导致无效信息被提交入库。
改动说明一般就是版本控制系统的提交记录,一个完整的提交记录应该至少包括以下几个方面的内容:
- **提交概要信息**:简明扼要地用一句话说明这个改动实现了哪些功能,修复了哪些问题;
- **提交详细信息**:详细说明改动的细节和改动方式,是否有潜在的风险和遗留问题等;
- **提交关联需求**:是哪次变更导致的这次提交修改,还需要添加上游系统编号以关联提交和原始变更。
这些改动应该遵循一种标准化的格式,并且有相关的格式说明和书写方式,比如有哪些关键字,每一行的长度,变更编号的区隔是使用逗号、空格还是分号等等。如果按照这个标准来书写每次的变更记录,其实成本还是很高的,更不要说使用英文来书写的话,英文的表达方式和内容展现形式又是一个难题。
我跟你分享一个极品的提交注释,你可以参考一下。
>
switch to Flask-XML-RPC dependency
CR: PBX-2222
The Flask-XML-RPC-Re fork has Python 3 support, but it has a couple
other problems.
<ol>
<li>
test suite does not pass
</li>
<li>
latest code is not tagged
</li>
<li>
uncompiled source code is not distributed via PyPI
</li>
</ol>
The Flask-XML-RPC module is essentially dead upstream, but it is
<p>packaged in EPEL 7 and Fedora. This module will get us far enough to<br>
the</p>
point that we can complete phase one for this project.
When we care about Python 3, we can drop XML-RPC entirely and get the
service consumers to switch to a REST API instead.
<p>(Note, with this change, the Travis CI tests will fail for Python 3.<br>
The</p>
solution is to drop XML-RPC support.)
这时,肯定有人会问,花这么大力气做这个事情,会不会有点得不偿失呢?从局部来看,的确如此。但是,换个角度想,当其他人看到你的改动,或者是评审你的代码的时候,如果通过提交记录就能清晰地了解你的意图,而不是一脸蒙地把你叫过来,让你再讲一遍,这样节约的时间比当时你书写提交记录的时间要多得多。
**所以你看,一套标准化的规则和行为习惯,可以降低协作过程中的沟通成本,一次性把事情做对,这也是标准和规范的重要意义**
当然,如果标准化流程要完全依靠人的自觉性来保障,那就太不靠谱了。毕竟,人总是容易犯错的,会影响到标准的执行效果。所以,当团队内部经过不断磨合,逐步形成一套规范之后,最好还是用自动化的手段保障流程的标准化。
这样做的好处有两点:一方面,可以降低人为因素的影响,如果你不按标准来,就会寸步难行,也减少了人为钻空子的可能性。比如,有时候因为懒,每次提交都写同样一个需求变更号,这样的确满足了标准化的要求,但是却产生了大量无效数据。这时候,你就可以适当增加一些校验机制,比如只允许添加你名下的变更,或者是只允许开放状态的变更号等等。另一方面,在标准化之后,很多重复性的工作就可以自动化完成,标准化的信息也方便计算机分析提取,这样就可以提升流程的流转效率。
**可以说标准化是自动化的前提自动化又是DevOps最核心的实践**。这样看来说配置管理是DevOps工程实践的基础就一点不为过了吧。
## 2. 将一切纳入版本控制
如果说,今天这一讲的内容,你只需要记住一句话,那就是将一切纳入版本控制,这是配置管理的金科玉律。你可能会问,需要将什么样的内容纳入版本控制呢?我会毫不犹豫地回答你:“一切都需要!”比如软件源代码、配置文件、测试编译脚本、流水线配置、环境配置、数据库变更等等,你能想到的一切,皆有版本,皆要被纳入管控。
这是因为,软件本身就是一个复杂的集合体,任何变更都可能带来问题,所以,全程版本控制赋予了我们全流程追溯的能力,并且可以快速回退到某个时间点的版本状态,这对于定位和修复问题是非常重要的。
之前我就遇到过一个问题。一个iOS应用发灰度版本的时候一切正常但是正式版本就遇到了无法下载的情况。当时因为临近上线为了查这个问题可以说是全员上阵团队甚至开始互相抱怨研发说代码没有变化所以是运维的问题运维说环境没动过所以是研发的问题。结果到最后才发现这是由于一个工具版本升级某个参数的默认值从“关闭”变成了“打开”导致的。
所以你看,如果对所有内容都纳入版本控制,快速对比两个版本,列出差异点,那么,解决这种问题也就是分分钟的事情,大不了就把所有改动都还原回去。
纳入版本控制的价值不止如此。实际上很多DevOps实践都是基于版本控制来实现的比如环境管理方面推荐采用基础设施即代码的方式管理环境也就是说把用代码化的方式描述复杂的环境配置同时把它纳入版本控制系统中。这样一来任何环境变更都可以像提交代码一样来完成不仅变更的内容一目了然还可以很轻松地实现自动化。**把原本复杂的事情简单化,每一个人都可以完成环境变更**。
这样一来开发和运维之间的鸿沟就被逐渐抹平了DevOps的真谛也是如此。所以现在行业内流行的“什么什么即代码”其背后的核心都是版本控制。
不过这里我需要澄清一下纳入版本控制并不等同于把所有内容都放到Git中管理。有些时候我们很容易把能力和工具混为一谈。Git只是一种流行的版本控制系统而已而这里强调的其实是一种能力工具只是能力的载体。比如Git本身不擅长管理大文件那么可以把这些大文件放到Artifactory或者其他自建平台上进行管理。
对自建系统来说实现版本控制的方式有很多种比如可以针对每次变更插入一组新的数据或者直接复用Git这种比较成熟的工具作为后台。唯一不变的要求就是无论使用什么样的系统和工具都需要把版本控制的能力考虑进去。
另外,在实践将一切纳入版本控制的时候,你可以参考一条小原则。如果你不确定是否需要纳入版本控制,有一个简单的判断方法就是:**如果这个产物可以通过其他产物来重现,那么就可以作为制品管理,而无需纳入版本控制**。
举个例子,软件包可以通过源代码和工具重新打包生成,那么,代码、工具和打包环境就需要纳入管控,而生成的软件包可以作为制品;软件的测试报告如果可以通过测试管理平台重新自动化生成,那么同样可以将其视为制品,但前提是,测试管理平台可以针对每一个版本重新生成测试报告。
## 3. 全流程可追溯
对传统行业来说,全流程可追溯的能力从来不是可选项,而是必选项。像航空航天、企业制造、金融行业等,对变更的管控都是非常严谨的,一旦出现问题,就要追溯当时的全部数据,像软件源代码、测试报告、运行环境等等。如果由于缺乏管理,难以提供证据证明基于当时的客观情况已经做了充分的验证,就会面临巨额的罚款和赔偿,这可不是闹着玩的事情。像最近流行的区块链技术,除了发币以外,最典型的场景也是全流程可追溯。所以说,**技术可以日新月异,但很多理念都是长久不变的**。
**对于配置管理来说,除了追溯能力以外,还有一个重要的价值,就是记录关联和依赖关系**。怎么理解这句话呢?我先提个问题,在你的公司里面,针对任意一个需求,你们是否能够快速识别出它所关联的代码、版本、测试案例、上线记录、缺陷信息、用户反馈信息和上线监控数据呢?对于任意一个应用,是否可以识别出它所依赖的环境,中间件,上下游存在调用关系的系统、服务和数据呢?
如果你的回答是“yes”那么恭喜你你们公司做得非常好。不过绝大多数公司都是无法做到这一点的。因为这不仅需要系统与系统之间的关联打通、数据联动也涉及到一整套完整的管理机制。
DevOps非常强调价值导向强调团队内部共享目标这个目标其实就是业务目标。但实际情况是业务所关注的维度和开发、测试、运维所关注的维度都各不相同。业务关心的是提出的需求有没有上线而开发关心的是这个需求的代码有没有集成运维关心的是包含这个代码的版本是否上线。所以如果不能把这些信息串联打通就没有真正做到全流程可追溯。
关于这个问题,我给你的建议是**把握源头,建立主线**。所谓源头,对于软件开发而言,最原始的就是需求,**所有的变更都来源于需求**。所以,首先要统一管理需求,无论是开发需求、测试需求还是运维需求。
接下来要以需求作为抓手去关联下游环节打通数据这需要系统能力的支持也需要规则的支持。比如每次变更都要强制关联需求编号针对不同的需求等级定义差异化流程这样既可以减少无意义的审批环节给予团队一定的灵活性也达到了全流程管控的目标。这是一个比较漫长的过程但不积跬步无以至千里DevOps也需要一步一个脚印地建设才行。
## 4. 单一可信数据源
最后,我想单独谈谈单一可信数据源。很多人不理解这是什么东西,我举个例子你就明白了。
有一个网络热词叫作“官宣”,也就是官方宣布的意思。一般情况下,官宣的信息都是板上钉钉的,可信度非常高。可问题是,如果有多个官宣的渠道,信息还都不一样,你怎么知道要相信哪一个呢?这就是单一可信数据源的意义。
试想一下,我们花了很大力气来建设版本控制的能力,但如果数据源本身不可靠,缺乏统一管控,那岂不是白忙一场吗?所以,对于软件开发来说,必须要有统一的管控:
- 对于代码来说,要有统一的版本控制系统,不能代码满天飞;
- 对于版本来说,要有统一的渠道,不能让人随便本地打个包就传到线上去了;
- 对于开发依赖的组件来说,要有统一的源头,不能让来路不明的组件直接集成到系统中。这不仅对于安全管控来说至关重要,对于企业内部的信息一致性也是不可或缺的。
**同时,单一可信数据源也要能覆盖企业内部元数据的管控**。比如企业内部经常出现这种情况同样是应用在A部门的系统中叫作123在B部门的系统中叫作ABC在打通两边平台的时候这就相当于“鸡同鸭讲”完全对不上。再比如信息安全团队维护了一套应用列表但实际上在业务系统中很多应用都已经下线且不再维护了这样一来不仅会造成资源浪费还伴随着非常大的安全风险。
很多时候,类似的这些问题都是因为缺乏统一的顶层规划和设计导致的,这一点,在建立配置管理能力的时候请你格外关注一下。
## 总结
今天我给你介绍了DevOps工程实践的基础配置管理以及配置管理的四大理念分别是版本变更标准化、将一切纳入版本控制、全流程可追溯和单一可信数据源希望能帮你掌握配置管理的全局概念。
虽然配置管理看起来并不起眼,但是就像那句经典的话一样:“岁月静好,是因为有人替你负重前行。” 对于任何一家企业来说,信息过载都是常态,而**配置管理的最大价值正是将信息序列化**,对信息进行有效的整理、归类、记录和关联。而软件开发标准和有序,也是协同效率提升的源头,所以,配置管理的重要性再怎么强调都不为过。
## 思考题
你在企业中遇到过哪些配置管理方面的难题呢?你们的配置管理体系又是如何建立的呢?你遇到过因为缺乏单一可信数据源而导致“鸡同鸭讲”的有趣故事吗?
欢迎在留言区写下你的思考和答案,我们一起讨论,共同学习进步。如果你觉得这篇文章对你有所帮助,欢迎你把文章分享给你的朋友。

View File

@@ -0,0 +1,175 @@
<audio id="audio" title="11 | 分支策略:让研发高效协作的关键要素" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/fe/23/fe70df33608b2f49ebcad1498d9f8623.mp3"></audio>
你好,我是石雪峰。今天我们来聊聊分支策略。
在上一讲中,我反复强调过一个理念,那就是将一切纳入版本控制。其实,现代版本控制系统不仅可以记录版本和变更记录,还有一个非常重要的功能,那就是**分支管理**。
现代软件开发讲究效率和质量,大多依赖于多团队间的协作来实现。对于一些大型软件来说,即便是百人团队规模的协作也没什么奇怪的。如果软件架构没有良好的拆分,很有可能出现几百人在一个代码仓库里面工作的情况。这时,分支管理就成了不可或缺的功能。
一方面,分支可以隔离不同开发人员的改动,给他们提供一个相对独立的空间,让他们能够完成自己的开发任务。另一方面,整个团队也需要根据软件的发布节奏来完成代码提交、审核、集成、测试等工作。
所以,如果说多人软件协作项目中有一个灵魂的话,我认为,这个灵魂就是分支策略。可以说,**分支策略就是软件协作模式和发布模式的风向标**。选择一种符合DevOps开发模式的分支策略对于DevOps的实践落地也会大有帮助。
今天,我会给你拆解一些常见的分支策略,帮你了解这些策略的核心流程、优缺点,以及适用的场景和案例。
## 主干开发,分支发布
<img src="https://static001.geekbang.org/resource/image/71/85/717a85f005b8da0b593d6376db679685.png" alt="">
>
<p>图片来源:<br>
[https://paulhammant.com/2013/12/04/what_is_your_branching_model/](https://paulhammant.com/2013/12/04/what_is_your_branching_model/)</p>
在这种分支策略下,开发团队共享一条主干分支,所有的代码都直接提交到主干分支上,主干分支就相当于是一个代码的全量合集。**在软件版本发布之前,会基于主干拉出一条以发布为目的的短分支**。
你需要注意一下这句话里的两个关键词:
1. **以发布为目的**。这条分支存在的意义不是开发新功能而是对现有功能进行验收并在达到一定的质量标准后对外发布。一般来说新功能不会基于这条分支提交只有一些Bugfix会集成进来。所以对于这种发布分支会有比较严格的权限管控。毕竟谁都不想让那些乱七八糟、未经验证的功能跑到发布分支上来。
1. **短分支**。这条发布分支一般不会存在太长时间,只要经过回归验证,满足发布标准后,就可以直接对外发布,这时,这条分支的历史使命也就结束了。除非上线之后发现一些紧急问题需要修复,才会继续在这条分支上修改验证,并将改动同步回主干分支。所以,只要在主干分支和发布分支并行存在的时间段内,所有发布分支上的改动都需要同步回主分支,这也是我们不希望这条分支存在时间过长的原因,因为这会导致重复工作量的线性累计。
对于以版本节奏驱动的软件项目来说,这种分支策略非常常见,比如客户端产品,或者是那种需要在客户终端升级的智能硬件产品,像智能手机、智能电视等。
早在很多年前,乐视刚刚推出超级电视的时候,喊过一个口号叫“周周更新”。要知道,当时智能电视产品的更新频率普遍是几个月一次。
其实,如果你了解分支策略的话,你就会发现,“周周更新”的背后也没什么特别的。当时,我所在的团队恰好负责智能电视产品线的分支策略,采用的就是主干开发、分支发布的模式。其中基于主干的发布分支提前两周拉出,然后在发布分支上进行回归验证,并在第一周发出体验版本给喜欢尝鲜的用户试用。然后,根据用户反馈和后台收集的问题进行进一步修正,并最终发布一个稳定版本。我把当时的分支策略图分享给你,你可以参考一下。
<img src="https://static001.geekbang.org/resource/image/e0/46/e05c3b28341b3c99cceb3b916f5e7046.jpg" alt="">
这种模式的优势有三个:
1. 对于研发团队来说,只有一条主线分支,不需要在多条分支间切换。
1. 在发布分支拉出之后,主干分支依然处于可集成状态,研发节奏可以保持在一个相对平稳的状态。
1. 发布分支一般以版本号命名,清晰易懂,线上哪个版本出了问题,就在哪个分支上修复。
不过,这种模式也存在着缺点和挑战:
1. **它对主线分支的质量要求很高**。如果主线分支出了问题就会block所有开发团队的工作。对于一个百人团队、每日千次的提交规模来说如果不对提交加以约束这种情况的发生频率就会非常高。
1. **它对团队协作的节奏要求很高**。如果主线分支上的功能没有及时合入,但是业务方又坚持要在指定版本上线这个功能,这就会导致发布分支“难产”。甚至有些时候,会被迫允许部分未开发完成的功能在发布分支上继续开发,这会给发布分支的质量和稳定性造成很大的挑战。
1. **在主线和发布分支并存期间,有可能会导致两边提交不同步的情况**。比如,发布分支修复了一个线上问题,但是由于没有同步回主线,导致同样的问题在下一个版本中复现。测试出来的问题越多,这种情况出现的概率就越大,更不要说多版本并存的情况了。
这些问题的解决方法包括以下几点:
1. 建立提交的准入门禁,不允许不符合质量标准的代码合入主线。
1. 采用版本火车的方式,加快版本的迭代速度,功能“持票上车”,如果跟不上这个版本就随下个版本上线。另外,可以采用功能开关、热修复等手段,打破版本发布的固定节奏,以一种更加灵活的方式对外发布。
1. 通过自动化手段扫描主线和发布分支的差异建立一种规则。比如Hotfix必须主线和发布分支同时提交或者发布分支上线后由专人反向同步等。
## 分支开发,主干发布
<img src="https://static001.geekbang.org/resource/image/b9/69/b956a9dc626cad58976b55c5cb773169.png" alt="">
>
图片来源:[https://paulhammant.com/2013/12/04/what_is_your_branching_model/](https://paulhammant.com/2013/12/04/what_is_your_branching_model/)
当开发接到一个任务后会基于主干拉出一条特性开发分支在特性分支上完成功能开发验证之后通过Merge request或者Pull request的方式发起合并请求在评审通过后合入主干并在主干完成功能的回归测试。开源社区流行的GitHub模式其实就是属于这种。
根据特性和团队的实际情况,还可以进一步细分为两种情况:
- 每条特性分支以特性编号或需求编号命名,在这条分支上,只完成一个功能的开发;
- 以开发模块为单位,拉出一条长线的特性分支,并在这条分支上进行开发协作。
**两者的区别就在于特性分支存活的周期,拉出时间越长,跟主干分支的差异就越大,分支合并回去的冲突也就越大**。所以,对于长线模式来说,要么是模块拆分得比较清晰,不会有其他人动这块功能,要么就是保持同主干的频繁同步。**随着需求拆分粒度的变小,短分支的方式其实更合适**。
这种模式下的优势也有两点:
1. **分支开发相对比较独立,不会因为并行导致互相干扰**。同时,特性只有在开发完成并验收通过后才会合入主干,对主干分支的质量起到了保护作用;
1. 随着特性分支的流行,在这种模式下,分支成了特性天然的载体。一个特性所关联的所有代码可以保存在一条特性分支上,这为以特性为粒度进行发布的模式来说提供了一种新的可能性。也就是说,如果你想要发布哪个特性,就可以直接将特性分支合并到发布分支上,这就让某一个特性变得“可上可下”,而不是混在一大堆代码当中,想拆也拆不出来。
关于这种特性分支发布的方法,我给你提供一份[参考资料](https://mp.weixin.qq.com/s/JsBX3UPgZL_HUOTCIopr_A),你可以了解一下。不过,我想提醒你的是,特性发布虽然看起来很好,但是有三个前置条件:第一个是**特性拆分得足够小**,第二是**有强大的测试环境作支撑**,可以满足灵活的特性组合验证需求,第三是**要有一套自动化的特性管理工具**。
当然,分支开发、主干发布的模式也有缺点和挑战:
1. 非常考验团队特性拆分的能力。如果一个特性过大,会导致大量并行开发的分支存在,分支的集成周期拉长,潜在的冲突也会增多。另外,分支长期存在也会造成跟主线差异过大的问题。所以,**特性的粒度和分支存活的周期是关键要素。根据经验来看,分支存活的周期一般不要超过一周**。
1. 对特性分支的命名规范要求很高。由于大量特性分支的拉出,整个代码仓库会显得非常乱。面对一大堆分支,谁也说不清到底哪个还活着,哪个已经没用了。所以,如果能够跟变更管理系统打通,自动化创建分支就最好了。
1. 特性分支的原子性和完整性,保证一个特性的关联改动需要提交到一条分支上,而不是到处都是。同时,特性分支上的提交也需要尽量清晰,典型的就是原子性提交。
我之前所在的一个团队就是采用的这种分支策略。有一次,我为了分支策略的执行细节跟研发负责人争得面红耳赤,争论的核心点就是:当特性分支合并回主干的时候,到底要不要对特性分支上的代码进行整理?
只要做过开发,你就会知道,很少有人能只用一次提交就把代码写对的,因为总是会有这样那样的问题,导致特性分支上的提交乱七八糟。
在合入主干的时候为了保证代码的原子性其实是有机会对代码提交进行重新编排的Git在这方面可以说非常强大。如果你熟练掌握git rebase命令就可以快速合并分拆提交将每一个提交整理为有意义的原子性的提交再合入主干或者干脆把特性分支上的改动压合成一个提交。当然这样做的代价就是不断重写特性分支的历史给研发团队带来额外的工作量。我跟你分享一些常见的命令。
>
比如当前特性分支feature1主分支master那么你可以执行以下命令整理提交历史
>
git checkout feature1 &amp;&amp; git fetch origin &amp;&amp; git rebase -i origin/master
>
<img src="https://static001.geekbang.org/resource/image/b7/1b/b709ba3701064f950534eb93d822731b.png" alt="">
>
<p>最常见的操作包括:<br>
p选择提交<br>
r更新提交的注释信息<br>
e编辑提交可以将一个提交拆分成多个<br>
s压合提交将多个提交合并成一个<br>
f类似压合提交但是放弃这个提交的注释信息直接使用合并提交的注释信息<br>
当然在git rebase的交互界面中你也可以调整提交的顺序比如将特性功能和关联的Bugfix整合在一起。</p>
**需要提醒你的是,分支策略代表了研发团队的行为准则,每个团队都需要磨合出一套适合自己的模式来**
## 主干开发,主干发布
<img src="https://static001.geekbang.org/resource/image/8f/b0/8f1b96d9847430effaba8d5ee45d8bb0.png" alt="">
>
图片来源:[https://paulhammant.com/2013/12/04/what_is_your_branching_model/](https://paulhammant.com/2013/12/04/what_is_your_branching_model/)
今天给你介绍的第三种分支策略是主干开发、主干发布。武学高手修炼到一定境界之后,往往会发现大道至简,分支策略也是如此。所以,第三种分支策略可以简单理解为没有策略。**团队只有一条分支,开发人员的代码改动都直接集成到这条主干分支上,同时,软件的发布也基于这条主干分支进行**。
对于持续交付而言,最理想的情况就是,每一次提交都能经历一系列的自动化环境并部署到生产环境上面,而这种模式距离这个目标就更近了一点。
可想而知,如果想要做到主干分支在任何时间都处于可发布状态,那么,这就对每一次提交的代码质量要求非常高。
在一些追求工程卓越的公司里你要提交一行代码就必须经历“九九八十一难”因为有一系列的自动化验收手段还有极为严格的代码评审机制来保证你的提交不会把主干分支搞挂掉。当然即便如此问题也是难以避免的那我们该怎么做呢这里我就要给你介绍下Facebook的分支策略演进案例了。
Facebook最早采用的也是主干开发、分支发布的策略每天固定发布两次。但是随着业务发展的压力增大团队对于发布频率有了更高的要求这种分支策略已经无法满足每天多次发布的需求了。于是他们开始着手改变分支策略从主干开发、分支发布的模式演变成了主干开发、主干发布的模式。
为了保证主干分支的质量自动化验收手段是必不可少的因此每一次代码提交都会触发完整的编译构建、单元测试、代码扫描、自动化测试等过程。在代码合入主干后会进行按需发布先是发布到内部环境也就是只有Facebook的员工才能看到这个版本如果发现问题就立刻修复如果没有问题再进一步开放发布给2%的线上生产用户,同时自动化检测线上的反馈数据。直到确认一切正常,才会对所有用户开放。
最后通过分支策略和发布策略的整合注入自动化质量验收和线上数据反馈能力最终将发布频率从固定的每天2次提升到每天多次甚至实现了按需发布的模式。Facebook最新的分支策略如图所示
<img src="https://static001.geekbang.org/resource/image/b2/64/b2a7a2d841e5b95d1fbf83d286d42364.jpg" alt="">
>
图片来源:[https://engineering.fb.com/web/rapid-release-at-massive-scale/](https://engineering.fb.com/web/rapid-release-at-massive-scale/)
看到这里,你可能会问:“在这三种典型策略中,哪种策略是最好的?我应该如何选择呢?”其实,这个问题也困扰着很多公司。
的确,不同类型、规模、行业的软件项目采用的分支策略可能都不尽相同,同时,发布频率、软件架构、基础设施能力、人员能力水平等因素也在制约着分支策略的应用效果。
所以很难说有一种通用的分支策略可以满足所有场景的需求。但是有些分支策略的原则更加适合于快速迭代发布的场景也就更加适合DevOps的发展趋势。所以我个人比较推荐的是**主干开发结合特性分支的模式**,也就是团队共享一条开发主干,特性开发基于主干拉出特性分支,快速开发验收并回归主干,同时,在特性分支和主干分别建立不同的质量门禁和自动化验收能力。
这样做的好处在于,**可以加快代码集成频率,特性相对独立清晰**,并且主干分支又可以保持一定的质量水平。不过,在执行的过程中,你需要遵守以下原则:
1. 团队共享一条主干分支;
1. 特性分支的存活周期要尽量短最好不要超过3天
1. 每天向主干合并一次代码如果特性分支存在超过1天那么每天都要同步主干代码
1. 谨慎使用功能开关等技术手段,保持代码干净和历史清晰;
1. 并行分支越少越好,如果可能的话,尽量采用主干发布。
关于最后一条,你需要注意的是,**是否需要发布分支,主要取决于项目的发布模式**。对于按照版本方式发布的项目来说比如App、智能硬件系统以及依赖大量外部系统联调的核心系统可以按照发布固定的节奏拉出发布分支对于发布节奏较快、系统架构拆分后相对独立的应用来说可以直接采用主干发布的模式并结合安全发布策略把控整体的发布质量。
这种分支发布的策略图如下所示:
<img src="https://static001.geekbang.org/resource/image/16/5e/165381a31f212516ee92fd295040465e.jpg" alt="">
## 总结
今天,我给你介绍了三种分支策略,建议你对照我给你分享的分支策略图,好好理解一下。另外, 我还介绍了适合DevOps模式的分支策略以及一些使用原则。还记得我最开始说的吗分支策略就是研发协作和发布模式的风向标分支策略的变化对整个研发团队的习惯和节奏都是一个非常大的调整找到适合当前团队的分支策略才是最重要的。
## 思考题
你目前所在的团队采用的是哪种分支策略?你觉得当前的分支策略有哪些问题或改进空间吗?你是否经历过分支策略的调整呢?如果有的话,你在这个过程中踩过什么“坑”吗?有没有什么心得呢?
欢迎在留言区写下你的思考和答案,我们一起讨论,共同学习进步。如果你觉得这篇文章对你有所帮助,欢迎你把文章分享给你的朋友。

View File

@@ -0,0 +1,145 @@
<audio id="audio" title="12 | 持续集成你说的CI和我说的CI是一回事吗" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/99/15/99b9c51a177216d667d2cb27e5f8e015.mp3"></audio>
你好我是石雪峰。今天我来跟你聊聊CI。
之前我曾应邀参加某公司的DevOps交流活动他们质量团队的负责人分享了DevOps平台建设方面的经验其中有一大半时间都在讲CI。刚开始还挺好的可是后来我越听越觉得奇怪以至于在交流环节我只想提一个问题“你觉得CI是个啥意思”后来为了不被主办方鄙视话到嘴边我又努力憋回去了。
回来的路上我就一直在思考这个问题。很多时候人们嘴上总是挂着CI但是他们说的CI和我理解的CI好像并不是一回事。比如有时候CI被用来指代负责内部工具平台建设的团队有时候CI类似一种技术实践间接等同于软件的编译和打包有时候CI又成了一种职能和角色指代负责版本的集成和发布的人。可见CI的定义跟DevOps一样每个人的理解都千差万别。
可问题是如果不能理解CI原本的含义怎么发挥CI真正的价值呢以CI的名义打造的平台又怎么能不跑偏并且解决真正的问题呢
所以,今天,就让我们一起重新认识下这个“最熟悉的陌生人”。
CI是Continuous Integration的缩写也就是我们熟悉的持续集成顾名思义这里面有两个关键的问题集成什么东西为什么要持续要回答这两个问题就得从CI诞生的历史说起了。
在20世纪90年代软件开发还是瀑布模式的天下人们发现在很长一段时间里软件是根本无法运行的。因为按照项目计划软件的功能被拆分成各个模块由不同的团队分别开发只有到了开发完成之后的集成阶段软件才会被真正地组装到一起。可是往往几个月开发下来到了集成的时候大量分支合并带来的冲突和功能问题集中爆发团队疲于奔命各种救火甚至有时候发现压根集成不起来。
我最初工作的时候做的就是类似这样的项目。我们负责客户端程序的开发到了集成的时候才发现客户的数据库使用的是Oracle而我们为了省事使用的是微软Office套件中的Access估计现在很多刚工作的年轻工程师都没听说过这个数据库这就导致客户下发的数据没法导入到本地数据库中。结果整整一个元旦假期我们都在加班加点好不容易赶工了一个数据中间层这才把两端集成起来。
所以,软件集成是一件高风险的、不确定的事情,国外甚至有个专门的说法,叫作“集成地狱”。也正因为如此,人们就更倾向于不做集成,这就导致开发末端的集成环节变得更加困难,从而形成了一个恶性循环。
为了解决这个问题CI的思想应运而生。CI本身源于肯特·贝克Kent Beck在1996年提出的极限编程方法ExtremeProgramming简称XP。顾名思义极限编程是一种软件开发方法作为敏捷开发的方法之一目的在于通过缩短开发周期提高发布频率来提升软件质量改善用户需求响应速度。
不知道为什么,每次听到极限编程,我心中都热血沸腾。不管在任何时代,总有那么一群程序员走在时代前沿,代表和传承着极客精神,就像咱们平台的名字极客时间,就代表了不甘于平庸、追求极致的精神,特别好。
扯远了让我们回归正题。极限编程方法中提出的实践现在看来依然相当前沿比如结对编程、软件重构、测试驱动开发、编程规范等这些词我们都耳熟能详但是真正能做到的却是凤毛麟角。其中还有一个特别有意思的实践规范叫作每周40小时工作制也就是一周工作5天每天工作8小时。联想到前些日子在网络上引发激烈争论的“996”就可以看出极限编程方法在国内的发展还是任重而道远啊。
当然,在这么多实践中,持续集成可以说是第一个被广泛接受和认可的。
关于CI的定义我在这里引用一下马丁·福勒Martin Fowler的一篇博客中的内容这也是当前最为业界公认的定义之一
>
CI是一种软件开发实践团队成员频繁地将他们的工作成果集成到一起通常每人每天至少提交一次这样每天就会有多次集成并且在每次提交后自动触发运行一次包含自动化验证集的构建任务以便尽早地发现集成问题。
CI采用了一种反常规的思路来解决软件集成的困境其核心理念就是越是痛苦的事情就要越频繁地做。很多人不理解为什么举个例子你就明白了。我小时候身体非常不好经常要喝中药第一次喝的时候每喝一口都想吐可是连续喝了一个星期之后我发现中药跟水的味道也没什么区别。这其实是因为人的适应力很强慢慢就习惯了中药的味道。对于软件开发来说也是这个道理。
如果开发周期末端的一次性集成有这么大的风险和不确定性,那不如把集成的频率提高,让每次集成的内容减少,这样即便失败,影响的也仅仅是一次小的集成内容,问题定位和修复都可以更加快速地完成。这样一来,不仅提高了软件的质量,也大大降低了最后阶段的返工所带来的浪费,还提升了软件交付效率。
你可能会说,这个道理我也懂啊,我们的持续集成就是这样的。别急,我们一起来测试一下。
假如你认为自己所在的项目和团队在践行CI那么你可以思考3个问题看看你们是否做到了。
>
<ol>
- 每一次代码提交,是否都会触发一次完整的流水线?
</ol>
>
<ol start="2">
- 每次流水线是否会触发自动化的测试环节?
</ol>
>
<ol start="3">
- 如果流水线出现了问题是否能够在10分钟之内修复
</ol>
我曾在现场做过很多次这个测试如果参与者认为做到了就会举手表示如果没有做到就会把手放下。每次面对一群自信满满的CI“信徒们”三连问的结果总会让人“暗爽”因为最开始几乎所有人都会举手他们坚信自己在实践持续集成。但接下来我每问一个问题就会有一半的人把手放下坚持到最后的人寥寥无几这几个人面对周边人的目光内心也开始怀疑起来如果我再适时地追问两下基本就都放下了。
这么看来CI听起来简单易懂但实施起来并没有那么容易。可以说CI涵盖了三个阶段每个阶段都蕴含了一组思想和实践只有把这些都做到了那才是真正地在实施CI。接下来让我们逐一看下这三个阶段。
## 第一阶段:每次提交触发完整的流水线
第一个阶段的关键词是:**快速集成**。这是对CI核心理念的最好诠释也就是集成速度做到极致每次变更都会触发CI。
当然,这里的变更有可能是代码变更,也有可能是配置、环境、数据变更。我之前强调过,**要将一切都纳入版本控制**这样所有的元数据变更都会被版本管理系统捕获并通过事件或者Webhook的方式通知持续集成平台。
对于现代的持续集成平台比如大家常用的Jenkins默认支持多种触发方式比如定时触发、轮询触发或者Webhook触发。那么**如果想做到每次提交都触发持续集成的话,首先就需要打通版本控制系统和持续集成系统**比如GitLab和Jenkins的集成网上已经有很多现成的材料大家照着操作一般都不会有太多问题。但是只要打通两个系统就足够了吗显然没有这么简单。实施提交触发流水线还需要一些前置条件。
1.**统一的分支策略**。
既然CI的目的是集成那么首先就需要有一条以集成为目的的分支。这条分支可以是研发主线也可以是专门的集成分支一旦这条分支上发生任何变更就会触发相应的CI过程。那么可能有人会问很多时候开发都是在特性分支或者版本分支上进行的难道这些分支上的提交就不要经过CI环节了吗这就引出了第2个前置条件。
2.**清晰的集成规则**。
对于一个大中型团队来说,每天的提交量是非常惊人的,这就要求持续集成具备足够的吞吐率,能够及时处理这些请求。而对于不同分支来说,持续集成的步骤和要求也不尽相同。不同分支的集成目的不同,相应的环节自然也不相同。
比如,对于研发特性分支而言,目的主要是快速验证和反馈,那么速度就是不可忽视的因素,所以这个层面的持续集成,主要以验证打包和代码质量为主;而对于系统集成分支而言,它的目的不仅是验证打包和代码质量,还要关注接口和业务层面的正确性,所以集成的步骤会更加复杂,成本也会随之上升。所以,**根据分支策略选择合适的集成规则对于CI的有效运转来说非常重要**。
3.**标准化的资源池**。
资源池作为CI的基础设施重要性不言而喻。
首先,**资源池需要实现环境标准化**也就是任何任务在任何节点都具备可运行的能力这个能力就包括了工具、配置等一系列要素。如果CI任务在一个节点可以运行跑到另外一个节点就运行失败那么CI的公信力就会受到影响。
另外,**资源池的并发吞吐量应该可以满足集中提交的场景,可以动态按需初始化的资源池就成了最佳选择**。当然,同时还要兼顾**成本因素**,因为大量资源的投入如果没有被有效利用,那么造成的浪费是巨大的。
4.**足够快的反馈周期**。
越是初级CI对速度的敏感性就越强。一般来讲如果CI环节超过1015分钟还没有反馈结果那么研发人员就会失去耐心所以CI的运行速度是一个需要纳入监控的重要指标。对于不同的系统而言要约定能够容忍的CI最大时长如果超过这个时长同样会导致CI失败。所以这就需要环境、平台、开发团队共同维护。
你看一套基本可用的CI所依赖的条件远不止这些核心还是为了能够在最短的时间内完成集成动作并给出反馈。如果你们公司已经实现了代码提交的CI并且不会有大量失败和排队的情况发生那么恭喜你第一阶段就算通过了。
## 第二阶段:每次流水线触发自动化测试
第二个阶段的关键词是:**质量内建**。关于质量内建我会在专栏后面的内容中详细介绍。实际上CI的目的是尽早发现问题这些问题既包括构建失败也包括质量不达标比如测试不通过或者代码规约静态扫描等不符合标准。
我见过的很多CI都是“瘸腿”CI因为缺失了自动化测试的能力注入或者自动化测试的能力很差基本无法发现有效问题。这里面有几个重要的关注点我们来看一下。
1.**匹配合适的测试活动**。
对于不同层级的CI而言同样需要根据集成规则来确定需要注入的质量活动。比如最初级的提交集成就不适合那些运行过于复杂、时间太长的测试活动快速的代码检查和冒烟测试就足以证明这个版本已经达到了最基本的要求。而对于系统层的集成来说质量要求会更高这样一来一些接口测试、UI测试等就可以纳入到CI里面来。
2.**树立测试结果的公信度**。
自动化测试的目标是帮助研发提前发现问题但是如果因为自动化测试能力自身的缺陷或者环境不稳定等因素造成了CI的大量失败那么这个CI对于研发来说就可有可无了。所以**我们要对CI失败进行分类分级重点关注那些异常和误报的情况并进行相应的持续优化和改善**。
3.**提升测试活动的有效性**。
考虑到CI对于速度的敏感性那么如何在最短的时间内运行最有效的测试任务就成了一个关键问题。显然大而全的测试套件是不合时宜的只有在基础功能验证的基础上结合与本次CI的变更点相关的测试任务发现问题的概率才会大大提升。所以根据CI变更自动识别匹配对应的测试任务也是一个挑战。
当你的CI已经集成了自动化验证集并且该验证集可以有效地发现问题那么恭喜你第二阶段也成功了。但这并不是“一锤子买卖”毕竟由于业务需求的不断变化自动化测试要持续更新才能保证始终有效。
## 第三阶段:出了问题可以在第一时间修复
到现在为止我们已经做到了快速集成和质量内建说实话利用现有的开源工具和框架快速搭建一套CI平台并不困难**真正让CI发挥价值的关键还是在于团队面对持续集成的态度以及团队内是否建立了持续集成的文化**。
硅谷的很多公司都有一种不成文的规定,那就是员工每天下班前要先确认持续集成是正常的,然后再离开公司,同时,公司也不建议在深夜或者周末上线代码,因为一旦出了问题,很难在第一时间修复,造成的影响难以估计。
其实很多企业并不知道他们花费大量人力、物力建设CI的平均修复时长是多少也缺乏这方面的数据统计。就现状而言有些时候他们可以做到在10分钟内修复而有些时候就需要几个小时原因可能是负责人出去开会了或者是赶上了午休的时间。
当然也有一些企业质疑10分钟这个时间长度因为软件项目的特殊性很有可能每次集成周期就远大于10分钟。如果你也是这样想的那你可能就误解CI的理念和初衷了毕竟我也不相信马丁·福勒能够保证在10分钟内修复问题。在这么短的时间里人为因素其实并不可控所以**人不是关键,建立机制才是关键**。
什么是机制呢?**机制就是一种约定,人们愿意遵守这样的行为,并且做了会得到好处**。对于CI而言保证集成主线的可用性其实就是团队成员间的一种约定。这不在于谁出的问题谁去修复而在于我们是否能够保证CI的稳定性足够清楚问题的降级路径并且主动关注、分析和推动问题解决。
另外团队要建立清晰的规则比如10分钟内没有修复则自动回滚代码比如当CI“亮红灯”的时候团队不再提交新的代码因为在错误的基础上没有办法验证新的提交这时需要集体放下手中的工作共同恢复CI的状态。
只有团队成员深信CI带给团队的长期好处远大于短期投入并且愿意身体力行地践行CI这个“10分钟”规则才有可能得到保障并落在实处。
## 总结
在这一讲中我们回顾了CI诞生的历史和CI试图解决的根本问题。同时我们也介绍了CI落地建设的三个阶段和其中的核心理念即快速集成、质量内建和文化建立。
最后我特别想再提一点很多人经常会把工具和实践混为一谈一旦结果没有达到预期就会质疑实践是否靠谱工具是否好用很容易陷入工具决定论的怪圈。实际上CI的核心理念从未有过什么改变但工具却一直在升级换代。工具是实践的载体实践是工具的根基单纯的工具建设仅仅是千里之行的一小步这一点我们必须要明白。
## 思考题
可以说一个良好的CI体现了整个研发团队方方面面的能力那么你对企业内部实践CI都有哪些问题和心得呢
欢迎在留言区写下你的思考和答案,我们一起讨论,共同学习进步。如果你觉得这篇文章对你有所帮助,欢迎你把文章分享给你的朋友。

View File

@@ -0,0 +1,159 @@
<audio id="audio" title="13 | 自动化测试DevOps的阿克琉斯之踵" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/81/e0/812614c1d697ee2f88374a1425915ce0.mp3"></audio>
你好,我是石雪峰。
在古希腊神话中战神阿克琉斯英勇无比浑身刀枪不入唯独脚后跟是他的致命弱点。在特洛伊战争中他的脚后跟被一箭射中倒地身亡从此阿克琉斯之踵就被用来形容致命的缺陷。我今天要跟你聊的自动化测试就是DevOps的阿克琉斯之踵。
我之前走访过很多公司,我发现,在工程实践领域,比如配置管理、持续集成等,他们实践得还不错,但是却有两大通病,一个是研发度量,另一个就是自动化测试。
没有人会否认自动化测试的价值而且很多公司也都或多或少地在实践自动化测试。但从整体来看自动化测试的实施普遍不成体系大多都在关注单点工具。另外团队对自动化测试的真实效果也存在疑惑。如果不能解决这些问题就很难突破实践DevOps的天花板。
那么,自动化测试究竟要解决什么问题,又适合哪些业务形态和测试场景呢?我们该如何循序渐进地推进建设,并且正确地度量效果以免踩坑呢?这些问题,就是我要在这一讲中跟你分享的重点内容。
## 自动化测试要解决什么问题?
产品交付速度的提升,给测试工作带来了很大的挑战。一方面,测试时间被不断压缩,以前三天的测试工作要在一天内完成。另一方面,需求的变化也给测试工作的开展带来了很大的不确定性。这背后核心的问题是,**业务功能的累加导致测试范围不断扩大,但这跟测试时长的压缩是矛盾的**。说白了,就是要测试的内容越来越多,但是测试的时间却越来越短。
全面测试会带来相对更好的质量水平,但是投入的时间和人力成本也是巨大的,而快速迭代交付就意味着要承担一定的风险。那么,究竟是要速度,还是要质量,这是一个很难回答的问题。
所以,要想提升测试效率,自然就会联想到自动化手段。实际上,自动化测试适用于以下几种典型场景:
1. 有大量机械的重复操作,并且会反复执行的场景,比如批量的回归测试;
1. 有明确的设计规范且相对稳定的场景,比如接口测试;
1. 大批量、跨平台的兼容性测试,比如覆盖多种版本和多种机型的测试,几十个机型还可以接受,如果覆盖成百上千个机型,就只能依靠自动化了;
1. 长时间不间断执行的测试,比如压力测试、可用性测试等。
这些典型场景往往都具备几个特征:设计明确、功能稳定、可多次重复、长期大批量执行等,核心就是通过自动化手段来解决测试成本的问题,也就是人的问题。但这并不意味着手工测试就没有价值了。相反,当人从重复性劳动中解放出来后,就可以投入到更有价值的测试活动中,比如探索性测试、易用性测试、用户验收测试等,这些都属于手工测试的范畴。
这听上去还挺合理的,可是,为什么很多公司还是倾向于采用手工测试的方式呢?实际上,并非所有的测试活动都适合自动化,而且,自动化测试建设也面临着一些问题。
1. **投入产出比**:很多需求基本上只会上线一次(比如促销活动类需求),那么,实现自动化测试的成本要比手动测试高得多,而且以后也不会再用了,这显然有点得不偿失。
1. **上手门槛**:自动化测试依赖代码方式实现,要开发一套配置化的测试框架和平台,对架构设计和编码能力都有很大的要求。但是,测试人员的编码能力一般相对较弱。
1. **维护成本高**:无论是测试环境、测试用例还是测试数据,都需要随着需求的变化不断进行调整,否则就很容易因为自动化测试过时,导致执行失败。
1. **测试设备投入高**比如移动App的测试需要有大量的手机资源想要覆盖所有的手机型号、操作系统版本本身就不太现实。更何况有限的机器还经常被测试人员拿去做本地调试这就进一步加剧了线上测试没有可用资源的情况。
## 自动化测试的设计
这么看来,自动化测试并不是一把万能钥匙,我们也不能指望一切测试都实现自动化。只有在合适的领域,自动化测试才能发挥出最大价值。那么,你可能就要问了,面对这么多种测试类型,到底要从哪里启动自动化测试的建设呢?
首先我来给你介绍一下经典的测试三角形。这个模型描述了从单元测试、集成测试到UI测试的渐进式测试过程。越是靠近底层用例的执行速度就越快维护成本也越低。而在最上层的UI层执行速度要比单元测试和接口测试要慢比手工测试要快相应的维护成本要远高于单元测试和接口测试。
<img src="https://static001.geekbang.org/resource/image/28/6f/28d6b53907036a38d5649a673664006f.png" alt="">
>
图片来源“DevOps Handbook"
这样看来从靠近底层的单元测试入手是一个投入产出相对比较高的选择。但实际上单元测试的执行情况因公司而异有的公司能做到80%的覆盖率,但有的公司却寸步难行。毕竟,单元测试更多是由开发主导的,开发领导的态度就决定了运行的效果。但不可否认的是,单元测试还是非常必要的,尤其是针对核心服务,比如核心交易模块的覆盖率。当然,好的单元测试需要研发投入大量的精力。
对于UI层来说执行速度和维护成本走向了另外一个极端这也并不意味着就没有必要投入UI自动化建设。**UI层是唯一能够模拟用户真实操作场景的端到端测试**页面上的一个按钮可能触发内部几十个函数调用和单元测试每次只检查一个函数的逻辑不同UI测试更加关注模块集成后的联动逻辑**是集成测试最有效的手段**。
另外很多测试人员都是从UI开始接触自动化的再加上相对成熟的测试工具和框架实施不依赖于源码也是一种比较容易上手的自动化手段。在实际应用中UI自动化可以帮助我们节省人工测试成本提高功能测试的测试效率。不过它的缺点也是比较明显的**随着敏捷迭代的速度越来越快UI控件的频繁变更会导致控件定位不稳定提高了用例脚本的维护成本**。
综合考虑投入产出比和上手难度的话,位于中间层的接口测试就成了一种很好的选择。一方面,现代软件架构无论是分层还是服务调用模式,对接口的依赖程度都大大增加。比如典型的前后端分离的开发模式,前后端基本都是在围绕着接口进行开发联调。另一方面,与单元测试相比,接口测试调用的业务逻辑更加完整,并且具备清晰的接口定义,适合采用自动化的方式执行。
正因为如此对于基于Web的应用来说我更推荐椭圆形模型也就是以中间层的API接口测试为主以单元测试和UI测试为辅。你可以参考一下分层自动化测试模型图。
<img src="https://static001.geekbang.org/resource/image/14/9b/140a33713f7332277c8d2114d050d39b.png" alt="">
## 自动化测试的开发
**有效的自动化测试离不开工具和平台的支持**。以接口测试为例最早都是通过cURL、Postman、JMeter等工具单机执行的。但是一次成功的接口测试除了能够发起服务请求之外还需要前置的测试数据准备和后置的测试结果校验。对于企业的实际业务来说不仅需要单接口的执行还需要相对复杂的多接口而且带有逻辑的执行这就依赖于调用接口的编排能力甚至是内建的Mock服务。
不仅如此,测试数据、用例、脚本的管理,测试过程中数据的收集、度量、分析和展示,以及测试报告的发送等,都是一个成熟的自动化测试框架应该具备的功能。
比如对于UI自动化测试来说最让人头疼的就是UI控件变化后的用例维护成本问题。**解决方法就是操作层获取控件和控件本身的定位方法,进行解耦,这依赖于框架的设计与实现**。在实际操作控件时,你可以通过自定义名称的方式来调用控件,自定义名称在控件相关配置文件中进行定义。在具体操作时,可以通过操作层之下的代理层来处理。示例代码如下:
```
public void searchItem(String id) {
getTextBox(&quot;SearchBar&quot;).clearText();
getTextBox(&quot;SearchBar&quot;).setText(id);
getButton(&quot;Search&quot;).click();
}
```
在代码中搜索条控件被定义为SearchBar通过调用代理层的getTextBox方法得到一个文本输入框类型对象并调用该对象的清除方法。然后在对应的控件配置文件中添加对应的自定义名称和控件的定位方法。
这样一来,即便控件发生改变,对于实际操作层的代码来说,由于采用的是自定义名称,所以你不需要修改逻辑,只要在对应的控件配置文件中,替换控件的定位方法就行了。关于具体的控件配置文件,示例代码如下:
```
&lt;TextBox comment=&quot;首页搜索框&quot; id=&quot;SearchBar&quot;&gt;
&lt;iOS&gt;
&lt;appium&gt;
&lt;dependMethod methodName=&quot;findElementByXPath&quot;&gt;
&lt;xpath&gt;
//XCUIElementTypeNavigatorBar[@name=&quot;MainPageView&quot;]/XCUIElementTypeOther/...
&lt;/xpath&gt;
&lt;/dependMethod&gt;
&lt;/appium&gt;
&lt;/iOS&gt;
&lt;/TextBox&gt;
```
当然为了简化测试人员的编写用例成本你可以在操作层使用Page-Object模式针对页面或模块封装操作方式通过一种符合认知的方式来实现具体的功能操作。这样一来在实际编写用例的时候你就可以非常简单地调用操作层的接口定义。示例代码如下
```
@TestDriver(driverClass = AppiumDriver.class)
public void TC001() {
String id='10000'
page.main.switchView(3);
page.cart.clearShoppingCart();
page.main.switchView(0);
page.search.searchProduct(id);
page.infolist.selectlist(0);
page.infodetail.clickAddCart();
Assert.assertTrue(page.cart.isProductCartExist(), &quot;商品添加成功&quot;)
}
```
从这些示例中我们可以看出一个良好的自动化测试框架可以显著降低测试人员编写测试用例的门槛以及测试用例的维护成本。对于一个成熟的平台来说平台易用性是非常重要的能力通过DSL方式来声明测试过程可以让测试人员聚焦在测试业务逻辑的设计和构建上大大提升自动化测试的实现效率。
关于自动化测试框架的能力模型,我给你分享你一份资料,你可以点击[网盘](https://pan.baidu.com/s/1E3xAHgcehW9NyWKVgTXxFQ)获取提取码是gk9w。这个能力模型从测试脚本封装、测试数据解耦、测试流程编排、报告生成等多个方面展示了框架建设的各个阶段应该具备的能力。
## 自动化测试结果分析
那么,我们该如何衡量自动化测试的结果呢?当前比较常用的方式是**覆盖率**,不过问题是,测试覆盖率提升就能发现更多的缺陷吗?
一家大型金融公司的单元测试覆盖率达到了80%接口覆盖率更是达到了100%从这个角度来看他们的自动化测试做得相当不错。但是当我问到自动化测试发现的问题数量占到整体问题的比例时他们的回答有点出人意料。在这么高的覆盖率基础上自动化测试发现的问题占比仅仅在5%左右。那么花了这么大力气建设的自动化测试最后仅仅发现了5%的有效问题,这是不是说明自动化测试的投入产出比不高呢?
实际上,说自动化测试是为了发现更多的缺陷,这是一个典型的认知误区。在实际项目中,手工测试发现的缺陷数量要比自动化测试发现的缺陷数量多得多。自动化测试更多是在帮助守住软件质量的底线,尤其是应用在回归测试中,自动化测试可以确保工作正常的已有功能不会因为新功能的引入而带来质量回退。可以这么说,**如果自动化测试覆盖率足够高,那么软件质量一定不会差到哪儿去**。
在自动化测试领域,除了追求覆盖率一个指标以外,自动化测试的结果分析也值得重点关注一下。如果自动化测试的结果并不准确,甚至带来大量误报的话,这对团队来说反而是一种干扰。关于测试误报,是指由于非开发代码变更导致的自动化测试用例执行失败的情况。业界对于误报率的普遍定义是:
>
自动化测试误报率=非开发变更引入的问题用例数量/测试失败的用例数量
>
比如单次自动化测试执行了100个用例其中有20个用例失败这20个失败用例有5个是由于本次功能或代码变更引入的也就是真实的缺陷那么误报率就等于20 - 5/20 = 75%
**测试误报率是体现自动化测试稳定性的一个核心指标**。对于不同测试类型和产品形态,误报的的原因有很多。比如测试环境的网络不稳定导致的连接超时、测试脚本和测试工具本身的固有缺陷导致的执行失败、测试数据不齐备、测试资源不可用等等。
由于测试误报的客观存在,即便执行了自动化测试并给出了测试结果,但还是需要人工审查判断之后,才能将真正的问题上报缺陷系统。这样一来,在自动化执行末端加入了人工处理,就导致自动化测试难以大规模推行,这也是自动化测试略显“鸡肋”的原因之一。
那么,要如何解决这个问题呢?这就要依赖于自动化测试结果的分析啦。
1. 对自动化测试的问题进行分类。你要弄清楚一次失败是环境问题、网络问题、功能变更,还是系统缺陷?你需要将失败的用例归纳到这些分类之中。当一个类别的问题非常多的时候,你可以考虑进行拆分,比如网络问题,你可以拆分为网络不可达、延迟超时、域名解析错误等等。
1. 增加已有分类的自动识别能力。比如,对于捕获到的常见异常,可以根据异常信息自动上报到对应的错误分类,从而简化人工识别和归类错误的工作量。
1. 提升自动化测试工具和环境的健壮性,对已知问题增加一定的重试机制。
1. 持续积累和丰富错误分类,有针对性地开展改进工作,从而不断提升自动化测试的稳定性。
我跟你分享一幅某公司的自动化测试结果分析示意图。通过统计错误的分类,可以看出错误的占比情况,并且针对常见的误报类型进行有针对性的优化,并建立度量指标来跟踪长期结果,从而保证自动化测试结果的整体可信度。这些工作都需要长期的投入才能看出成效,这也是让自动化测试价值最大化和团队能力提升的必经之路。
<img src="https://static001.geekbang.org/resource/image/70/07/70445e2161b3c447c7d21384da947e07.png" alt="">
## 总结
总结一下,这一讲我给你介绍了有关自动化测试的四个方面,包括自动化测试要解决的问题和适用场景、实施的路径、框架工具开发的典型思路以及结果分析的要点。希望能够帮你建立起对自动化测试这个“老大难”问题的全面认知,让你在推进自动化测试能力建设的时候有迹可循。
## 思考题
你所在的企业在进行自动化建设时,有哪些困境和问题,你们是如何解决的呢?
欢迎在留言区写下你的思考和答案,我们一起讨论,共同学习进步。如果你觉得这篇文章对你有所帮助,欢迎你把文章分享给你的朋友。

View File

@@ -0,0 +1,134 @@
<audio id="audio" title="14 | 内建质量:丰田和亚马逊给我们的启示" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/00/b9/0038b70c49ff029ad8203f1f490f36b9.mp3"></audio>
你好,我是石雪峰,今天我来跟你聊一个非常重要的话题:内建质量。
我之前给你讲过一个故事,说的是在美国汽车工厂装配流水线的末端,总是有个人在拿着橡胶锤子敲打车门,以检查车门是否安装良好。我还说,如果一个公司要靠“拿锤子的人”来保证质量,这就说明,这个公司的流程本身可能就有问题。
这个观点并不是我凭空捏造出来的而是来自于质量管理大师爱德华·戴明博士经典的质量管理14条原则。其中第3条指出**不应该将质量依赖于检验工作,因为检验工作既昂贵,又不可靠。最重要的是,检验工作并不直接提升产品质量,只是为了证明质量有缺陷**。而正确的做法是将质量内建于整个流程之中,并通过有效的控制手段来证明流程自身的有效性。
## 为什么内建质量如此重要?
在传统的软件开发过程中,检验质量的“锤子”往往都握在测试团队的手中。他们在软件交付的末端,通过一系列的“锤子”来“敲打”软件产品的方方面面,试图找到一些潜在的问题。
这样做的问题是,测试通过尽可能全面的回归测试来验证产品质量符合预期,成本是巨大的,但是效果却不见得有多好。
因为测试只能基于已知的产品设计进行验证,但那些潜在的风险有可能连开发自己都不知道。比如,开发引入了一些第三方的类库,但这些库本身存在缺陷,那么,如果测试没有回归到这个场景,就很有可能出现漏测和生产事故。
另外由于测试存在的意义在于发现更多的缺陷有些团队的考核指标甚至直接关联缺陷提交数量以及缺陷修复数量。那么这里的前提就是假设产品是存在缺陷的。于是测试团队为了发现问题而发现问题在研发后面围追堵截这也造成了开发和测试之间的隔阂和对立这显然不是DevOps所倡导的状态。
那么,解决这个问题的正确“姿势”,就是内建质量啦!
关于内建质量,有个经典的案例就是丰田公司的安灯系统,也叫作安灯拉绳。丰田的汽车生产线上方有一条绳子,如果生产线上的员工发现了质量问题,就可以拉动安灯系统通知管理人员,并停止生产线,以避免带有缺陷的产品不断流向下游。
要知道在生产制造业中生产线恨不得24小时运转因为这样可以最大化地利用时间生产更多的产品。可是现在随随便便一个员工就可以让整条生产线停转丰田公司是怎么想的呢
其实这背后的理念就是“Fail fast”即快速失败。如果工人发现了有缺陷的产品却要经过层层审批才能停止生产线就会有大量带有缺陷的产品流向下游所以停止生产线并不是目的及时发现问题和解决问题才是目的。
当启动安灯系统之后,管理人员、产线质量控制人员等相关人员会立刻聚集到一起解决这个问题,并尽快使生产线重新恢复运转。更重要的是,这些经验会被积累下来,并融入组织的能力之中。
内建质量扭转了看待产品质量的根本视角,也就是说,**团队所做的一切不是为了验证产品存在问题,而是为了确保产品没有问题**。
几年前我在华为参加转正答辩的时候被问到一个问题“华为的质量观是怎样的”答案是三个字“零缺陷。”我当时并不理解人非圣贤孰能无过产品零缺陷简直就是反常理。但是后来我慢慢明白所谓零缺陷并不是说产品的Bug数量等于零这其实是一种质量观念倡导全员质量管理构建质量文化。每一个人在工作的时候都要力争第一时间发现和解决缺陷。
所以,总结一下,内建质量有两个核心原则:
- 问题发现得越早,修复成本就越低;
- 质量是每个人的责任,而不是质量团队的责任。
说了这么多,你应该已经对内建质量有了初步的认识。那么接下来,我来给你介绍下内建质量的实践思路、操作步骤、常见问题以及应对方法。
## 内建质量的实施思路
既然是内建质量,那么,我们就应该在软件交付的各个环节中注入质量控制的能力。
在需求环节,可以定义清晰的需求准入规则,比如需求的价值衡量指标是否客观、需求的技术可行性是否经过了验证、需求的依赖是否充分评估、需求描述是否清晰、需求拆分是否合理、需求验收条件是否明确等等。
通过前置需求质量控制,可以减少不靠谱的需求流入。在很多公司,“一句话需求”和“老板需求”是非常典型的例子。由于没有进行充分沟通,研发就跟着感觉走,结果交付出来的东西完全不是想要的,这就带来了返工浪费。
**在开发阶段,代码评审和持续集成就是一个非常好的内建质量的实践**。在代码评审中,要尽量确认编码是否和需求相匹配,业务逻辑是否清晰。另外,通过一系列的自动化检查机制,来验证编码风格、风险、安全漏洞等。
在测试阶段,可以通过各类自动化测试,以及手工探索测试,覆盖安全、性能、可靠性等,来保障产品质量;在部署和发布阶段,可以增加数据库监控、危险操作扫描、线上业务监控等多种手段。
从实践的角度来说,每个环节都可以控制质量,那么,我们要优先加强哪个环节呢?
根据内建质量的第一原则,我们知道,如果可以在代码刚刚提交的时候就发现和修复缺陷,成本和影响都是最低的。如果等到产品上线后,发现了线上质量问题,再回过头来定位和修复问题,并重新发布软件,成本将会呈指数级增长。
所以,**研发环节作为整个软件产品的源头,是内建质量的最佳选择**。那么,具体要怎么实施呢?
## 内建质量的实施步骤
**第一步:选择适合的检查类型**
以持续集成阶段的代码检查为例,除了有单元测试、代码风格检查、代码缺陷和漏洞检查、安全检查等等,还有各种各样的检查工具。但实际上,这些并不是都需要的。至少在刚开始实践的时候,如果一股脑全上,那么研发基本上就不用干活了。
所以,**选择投入产出比相对比较高的检查类型,是一种合理的策略**。比如代码风格与缺陷漏洞相比检查缺陷漏洞显然更加重要因为一旦发生代码缺陷和漏洞就会引发线上事故。所以这么看来如果是客户端业务Infer扫描就可以优先实施起来。虽然我们不能忽视编码风格问题但这并不是需要第一时间强制执行的。
**第二步:定义指标并达成一致**
确定检查类型之后,就要定义具体的质量指标了。质量指标分两个层面,一个是指标项,一个是参考值,我分别来介绍一下。
**指标项是针对检查类型所采纳的具体指标**,比如单元测试覆盖率这个检查项,可采纳的指标就包括行、指令、类、函数等。那么,我们要以哪个为准呢?这个一般需要同研发负责人达成一致,并兼顾行业的一些典型做法,比如单测行覆盖率就是一个比较好的选择。
另外,很多时候,在既有项目启用检查的时候,都会有大量的技术债。关于技术债,我会在下一讲展开介绍。简单来说,就是欠了一堆债,一时半会儿又还不了,怎么办呢?这个时候,比较合适的做法就是选择动态指标,比如增量代码覆盖率,也就是只关注增量代码的情况,对存量代码暂不做要求。
指标项定义明确之后,就要定义参考值了。这个参考值会直接影响质量门禁是否生效,以及生效后的行为。
我简单介绍下质量门禁。质量门禁就类似一道安全门,通过门禁时进行检查,如果不满足指标,则门禁报警,禁止通过。这就跟交警查酒驾一样,酒精含量如果超过一定的指标,就会触发报警。
**参考值的定义是一门艺术**。对于不同的项目,甚至是同一个项目的不同模块来说,我们很难用“一刀切”的方式定义数值。我比较推荐的做法是**将静态指标和动态指标结合起来使用**。
**静态指标就是固定值**,对于漏洞、安全等问题来说,采取零容忍的态度,只要存在就绝不放过。而**动态指标是以考查增量和趋势为主**比如基线值是100你就可以将参考值定义成小于等于100也就是不允许增加。你还可以根据不同的问题等级定义不同的参考值比如严格检查致命和阻塞问题其余的不做限制。
最后,对于这个指标,你一定要跟研发团队达成共识,也就是说,团队要能够认可并且执行下去。所以,定义指标的时候要充分采纳对方的建议。
**第三步:建立自动化执行和检查能力**
无论公司使用的是开源工具还是自研工具,都需要支持自动化执行和检查的能力。根据检查时机的不同,你也可以在提测平台、发布平台上集成质量门禁的功能,并给出检查结果的反馈。
**按照快速失败的原则,质量门禁的生效节点要尽量靠近指标数据的产生环节**。比如如果要检查编码风格最佳的时间点是在研发本地的IDE中进行其次是在版本控制系统中进行并反馈结果而不是到了最后发布的时间点再反馈失败。
现代持续交付流水线平台都具备质量门禁的功能,常见的配置和生效方式有两种:
1. 在持续交付平台上配置规则,也就是不同指标和参考值组合起来,形成一组规则,并将规则关联到具体的执行任务中。这样做的好处是,各个生成指标数据的子系统只需要将数据提供给持续交付平台就行了,至于门禁是否通过,完全依靠持续交付平台进行判断。另外,一般配置规则的都是质量人员,提供这样一个单独的入口,可以简化配置成本。具体的实现逻辑,如图所示:
<img src="https://static001.geekbang.org/resource/image/16/fb/16168a5d172c4839ef98b201fcdd5dfb.png" alt="">
1. 在各个子系统中配置质量门禁。比如在UI自动化测试平台上配置门禁的指标当持续交付平台调用UI自动化测试的时候直接反馈门禁判断的结果。如果检查不通过则流水线直接失败。
**第四步:定义问题处理方式**
完成以上三步之后,就已经开始进行自动化检查了,而检查的结果和处理方式,对质量门禁能否真正起到作用非常重要。一般来说,质量门禁都具有强制属性,也就是说,如果没有达到检查指标,就会立即停止并给予反馈。
在实际执行的过程中,质量门禁的结果可能存在多种选项,比如失败、告警、人工确认等。这些都需要在制定规则的时候定义清楚,通过一定的告警值和人工确认方式,可以对质量进行渐进式管控,以达到持续优化的目标。
另外,你需要对所有软件交付团队成员宣导质量规则和门禁标准,并明确通知方式、失败的处理方式等。否则,检查出问题却没人处理,这个门禁就形同虚设了。
**第五步:持续优化和改进**
无论是检查能力、指标、参考值,还是处理方式,只有在运行起来后才能知道是否有问题。所以,在推行的初期,也应该具备一定程度的灵活性,比如对指标规则的修订、指标级别和参考值的调整等,**核心目标不是为了通过质量门禁,而是为了质量提升,这才是最重要的**。
## 内建质量的常见问题
内建质量说起来并不复杂,但想要执行到位却很困难,那么,到底有哪些常见的问题呢?我总结了一些常见问题和处理建议,做成了表格,你可以参考一下。
<img src="https://static001.geekbang.org/resource/image/5f/fe/5fe50bad00fced809adcbd31775ed3fe.jpg" alt="">
最后我再给你分享一个亚马逊的故事。2012年安灯系统被引入亚马逊公司一线客服如果收到客户反馈或者观察到商品有潜在的质量和安全风险就可以发出告警邮件并将商品设置为“不可购买”的状态说白了就是强制下架。客服居然可以不经过任何审批直接把商品下架不怕遭到供应商的投诉吗
实际上,这正是亚马逊践行以客户为中心的理念和原则的真实写照,**每个人都为最终质量负责,没有例外**。当员工得知自己被赋予了这样大的权限时,每个人都会尽自己的力量为质量工作加分。即便偶尔会有错误操作,这也是团队内部难能可贵的学习经验。
在公司中,无论是建立质量门禁的规则,还是开发一套平台系统,其实都不是最困难的事情,难的是,在实际过程中,有多少正常流程走了特殊审批?有多少发布是走的紧急通道?又有多少人会说开启了质量门禁,就会阻碍业务交付?
说到底,还是要问问自己,你愿意付出多少代价,来践行自己的理念和原则,先上再说?我想,能在这一点上达成共识,才是内建质量落地的终极要素吧。
## 总结
总结一下在这一讲中我通过两个故事给你介绍了内建质量的背景和原则那就是尽早发现问题尽早修复以及每个人都是质量的负责人。另外我还给你介绍了实施内建质量的五个常见步骤。希望你始终记得质量是生产出来的而不是测试出来的。掌握了内建质量你就揭开了DevOps高效率和高质量并存的秘密。
## 思考题
你所在的企业中是否启用了强制的质量门禁呢?可以分享一些你觉得效果良好的规则吗?
欢迎在留言区写下你的思考和答案,我们一起讨论,共同学习进步。如果你觉得这篇文章对你有所帮助,欢迎你把文章分享给你的朋友。

View File

@@ -0,0 +1,144 @@
<audio id="audio" title="15 | 技术债务:那些不可忽视的潜在问题" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/55/74/5544bb6bf642d02942974dc5ad3a1a74.mp3"></audio>
你好,我是石雪峰,今天我来跟你聊聊技术债务。
如果要问软件开发人员在项目中最不愿意遇到的事情,答案很可能是接手了一个别人开发了一半的系统。而且,系统开发的时间越长,开发人员的抵触情绪也就越大。那么,既然是同一种代码语言,同一种语法规则,至少还是一个能运行的东西,开发人员为什么要发自内心地抵触呢?我猜,很可能是不想看别人写的代码。之所以会这样,看不懂和怕改错是一个非常重要的原因,而这些,其实都是技术债务的结果。
## 什么是技术债务?
那么,究竟什么是技术债务呢?它是从哪里来的呢?好好地写个代码,咋还欠债了呢?
试想这样一种场景老板拍下来一个紧急需求要求你在3天内开发完成上线。在评估需求和设计的时候你发现要实现这个功能有两种方案
- 方案1采用分层架构引入消息队列。这样做的好处是结构清晰功能解耦但是需要1周的时间
- 方案2直接在原有代码的基础上修修补补硬塞进去一块逻辑和页面这样做需要2天时间还有1天时间来测试。
那么,你会选择哪个方案呢?
我想在大多数情况下你可能都会选择方案2因为业务的需求优先级始终是最高的。尤其是当下市场竞争恨不得以秒来计算先发优势非常明显。
而技术债务,就是指团队在开发过程中,为了实现短期目标选择了一种权宜之计,而非更好的解决方案,所要付出的代价。这个代价就是团队后续维护这套代码的额外工作成本,并且只要是债务就会有利息,债务偿还得越晚,代价也就越高。
实际上,带来技术债务的原因有很多,除了压力之下的快速开发之外,还包括不明真相的临时解决方案、新员工技术水平不足,和历史债务累积下来的无奈之举等。总之,代码维护的时间越长,引入的技术债务就会越多,从而使团队背上沉重的负担。
## 技术债务长什么样?
简单来说,你可以把技术债务理解为不好的代码。但是这里的“不好”,究竟是哪里不好呢?我相信,写过代码的人,或多或少都有过这样的经历:
- 一份代码里面定义了一堆全局变量,各个角落都在引用;
- 一个脚本仓库里面,一大堆名字看起来差不多的脚本,内容也都差不多;
- 一个函数里面修修补补写了上千行;
- 数据表查询各种神奇的关联;
- 参数传递纯靠肉眼计算顺序;
- 因为修改一段代码引发了一系列莫名其妙的问题;
- ……
那么究竟要如何对代码的技术债务进行分类呢我们可以借用“Sonar Code Quality Testing Essentials”一书中的代码“七宗罪”也就是复杂性、重复代码、代码规范、注释有效性、测试覆盖度、潜在缺陷和系统架构七种典型问题。你可以参考一下这七种类型对应的解释和描述
<img src="https://static001.geekbang.org/resource/image/a8/ac/a8053cf56a473c22100dca9032bae9ac.jpg" alt="">
除了低质量的代码问题之外,还有很多其他类型的技术债务,比如不合理的架构、过时的技术、冷门的技术语言等等。
比如我们公司之前基于Ruby语言开发了一套系统但是与Java、Python等流行语言相比Ruby比较小众所以很难找到合适的工程师也影响了系统的进一步发展。再比如到2020年元旦官方即将停止为Python 2.x分支提供任何支持如果现在你们的新系统还在采用Python 2进行开发那么很快就将面对升级大版本的问题。虽然官方提供了一些减少迁移成本的方案但是从系统稳定性等方面来讲依然有着非常大的潜在工作量。
## 为什么要重视技术债务?
那么问题来了,为什么要重视技术债务呢?或者说,烂代码会有什么问题呢?
从用户的角度来说技术债务的多少好像并不影响用户的直观体验说白了就是不耽误使用应该有的功能都很正常。那么回到最开始的那个例子既然2天开发的系统和1周开发的系统从使用的角度来说并没有什么区别那是不是就意味着理应选择时间成本更低的方案呢
显然没有这么简单。举个例子,一个人出门时衣着得体,但是家里却乱成一团,找点东西总是要花很长时间,这当然不是什么值得骄傲的事情。对于软件来说,也是如此。**技术债务最直接的影响就是内部代码质量的高低**。如果软件内部质量很差会带来3个方面的影响
**1.额外的研发成本**
对一个架构清晰、代码规范、逻辑有序、注释全面的系统来说新增一个特性可能只需要12天时间。但是同样的需求在一个混乱的代码里面可能要花上1周甚至是更长的时间。因为单是理解原有代码的逻辑、理清调用关系、把所有潜在的坑趟出来就不是件容易的事情。更何况还有大量重复的代码每个地方都要修改一遍一不小心就会出问题。
**2.不稳定的产品质量**
代码质量越差,修改问题所带来的影响可能就越大,因为你不知道改了一处内容,会在哪个边缘角落引发异常问题。而且,这类代码往往也没有可靠的测试案例,能够保证修改前和修改后的逻辑是正确的。如果新增一个功能,导致了严重的线上问题,这时就要面临是继续修改还是回滚的选择问题。因为如果继续修改,可能会越错越多,就像一个无底洞一样,怎么都填不满。
**3.难以维护的产品**
正是由于以上这些问题,研发人员在维护这种代码的时候往往是小心加谨慎,生怕出问题。这样一来,研发人员宁愿修修补补,也不愿意改变原有的逻辑,这就会导致代码质量陷入一种不断变坏的向下螺旋,越来越难以维护,问题越积累越多,直到再也没办法维护的那一天,就以重构的名义,推倒重来。其实这压根就不是重构,而是重写。
另外,如果研发团队整天跟这样的项目打交道,团队的学习能力和工作积极性都有可能受到影响。可见,技术债务的积累就像真的债务一样,属于“出来混,迟早要还”的那种,只不过是谁来还的问题而已。
## 如何量化技术债务?
软件开发不像是银行贷款,技术债务看不见摸不着,所以,我们需要一套计算方法把这种债务量化出来。**目前业界比较常用的开源软件就是SonarQube**。在SonarQube中技术债是基于SQALE方法计算出来的。关于[SQALE](http://www.sqale.org/)全称是Software Quality Assessment based on Lifecycle Expectations这是一种开源算法。当然今天的重点不是讲这个算法你可以在[官网](http://www.sqale.org/)查看更多的内容。同时我再跟你分享一篇关于SQALE算法的[文章](https://blog.sonarsource.com/sqale-the-ultimate-quality-model-to-assess-technical-debt/),它可以帮你更深入地研究代码质量。
Sonar通过将不同类型的规则按照一套标准的算法进行识别和统计最终汇总成一个时间也就是说要解决扫描出来的这些问题需要花费的时间成本大概是多少从而对代码质量有一种直观的认识。
Sonar提供了一种通用的换算公式。举个例子如下图所示在Sonar的默认规则中数据越界问题被定义为严重级别的问题换算出来的技术债务等于15分钟。这里的15分钟就是根据前面提到的SQALE分析模型计算得出的。当然你也可以在规则配置里面对每一条规则的预计修复时间进行自定义。
<img src="https://static001.geekbang.org/resource/image/d1/09/d1b393d5d6744f478fb16a73631f6109.png" alt="">
**计算出来的技术债务会因为开启的规则数量和种类的不同而不同**。就像我在上一讲中提到的那样,团队内部对规则达成共识,是非常重要的。因为只有达成了共识,才能在这个基础上进行优化。否则,如果规则库变来变去,技术债务指标也会跟着变化,这样就很难看出团队代码质量的长期走势了。
另外在Sonar中还有一个更加直观的指标来表示代码质量这就是**SQALE级别**。SQALE的级别为A、B、C、D、E其中A是最高等级意味着代码质量水平最高。级别的算法完全是基于技术债务比例得来的。简单来说就是**根据当前代码的行数,计算修复技术债务的时间成本和完全重写这个代码的时间成本的比例**。在极端情况下一份代码的技术债务修复时长甚至比完全推倒重写还要长这就说明代码已经到了无法维护的境地。所以在具体实践的时候也会格外重视代码的SQALE级别的健康程度。
>
技术债务比例 = 修复已有技术债务的时间 / 完全重写全部代码的时间
将代码行数引入进来可以更加客观地计算整体质量水平。毕竟一个10万行的代码项目和一个1千行的代码项目比较技术债务本身就没有意义。其实这里体现了一种更加可视化的度量方式。比如现在很多公司在做团队的效能度量时往往会引入一大堆的指标来计算根本看不懂。更加高级的做法是将各种指标汇总成一组算法并根据算法给出相应的评级。
当然,如果你想知道评级的计算方法,也可以层层展开,查看详细的数据。比如,持续集成能力,它是由持续集成频率、持续集成时长、持续集成成功率、问题修复时长等多个指标共同组成的。如果在度量过程中,你发现持续集成的整体评分不高,就可以点击进去查看每个指标的数据和状态,以及详细的执行历史。这种数据关联和下钻的能力对构建数据度量体系而言非常重要。
通过将技术债务可视化,团队会对代码质量有更直观的认识,那么接下来,就要解决这些问题了。
## 解决方法和原则
我走访过很多公司他们都懂得技术债务的危害不仅把Sonar搭建起来了还定时执行了但问题是没时间。的确很多时候我们没时间做单测没时间做代码评审没时间解决技术债务但是这样一路妥协啥时候是个头儿呢
前几天,我去拜访一家国内最大的券商公司,眼前一亮。这样一家所谓的传统企业,在研项目的技术债务居然是个位数。在跟他们深入交流之后,我发现,公司在这方面下了大力气,高层领导强力管控,质量门禁严格执行,所以才获得了这样的效果。
所以,从来没有一切外部条件都具备的时候,要做的就是先干再说。那么,要想解决技术债务,有哪些步骤呢?
1. 共识:团队内部要对技术债务的危害、解决项目的目标、规则的选择和制定达成一致意见。
1. 可见通过搭建开源的Sonar平台将代码扫描整合进持续交付流水线中定期或者按需执行让技术债务变得可视化和可量化。不仅如此Sonar平台还能针对识别出来的问题给出建议的解决方法这对于团队快速提升编码水平大有帮助。
1. 止损针对核心业务模块对核心指标类型比如vulnerability缺陷的严重和阻塞问题设定基线也就是控制整体数量不再增长。
1. 改善:创建技术优化需求,并在迭代中留出一定的时间修复已有问题,或者采用集中突击的方式搞定大头儿,再持续改进。
在解决技术债务的过程中要遵循4条原则。
1. **让技术债务呈良性下降趋势**。一种好的趋势意味着一个好的起点,也是团队共同维护技术债务的一种约定。
1. **优先解决高频修改的问题**。技术债务的利息就是引入新功能的额外成本,那么对于高频修改的模块来说,这种成本会快速累积,这也就意味着修复的产出是最大的。至于哪些代码是高频修改的,只要通过**分析版本控制系统**就可以看出来。
1. **在新项目中启动试点**。如果现有的代码过于庞大不可能在短时间内完成修复那么你可以选择控制增长同时在新项目中试点执行一方面磨合规则的有效性另一方面也能试点质量门禁、IDE插件集成等自动化流程。
1. **技术债务无法被消灭,也不要等到太晚**。只要还在开发软件项目,技术债务就基本上无法避免,所以不需要一下子把目标定得太高,循序渐进就行了。但同时,技术债务的累积也不是无穷无尽的,等到再也无法维护的时候就太迟了。
在刚开始解决技术债务的时候最大的问题不是参考指标太少而是太多了。所以团队需要花大量时间来Review规则。关于这个问题我给你两条建议第一参考代码质量平台的默认问题级别。一般来说阻塞和严重的问题的优先级比一般问题更高这也是基于代码质量平台长时间的专业积累得出的结论。第二你可以参考业界优秀公司的实践经验比如很多公司都在参考阿里巴巴的Java开发手册京东也有自己的编码规约。最后我总结了一些影响比较大的问题类型建议你优先进行处理。
- 大量重复代码;
- 类之间的耦合严重;
- 方法过于复杂;
- 条件判断嵌套太多;
- 缺少必要的异常处理;
- 多表关联和缺少索引;
- 代码风险和缺陷;
- 安全漏洞。
## 总结
在这一讲中,我给你介绍了什么是技术债。而技术债的成本,就是团队后续开发新功能的额外成本。技术债务有很多形态,典型的就是代码“七宗罪”。除此之外,我还跟你聊了下技术债的影响,以及量化技术债务的方法。最后,我给出了一些解决方法和原则,希望能帮你攻克技术债这个难题。
<img src="https://static001.geekbang.org/resource/image/21/97/21932cb077d7b910588ef291ee028597.jpeg" alt="">
最近这两年,智能研发的声音不绝于耳,其中关于使用人工智能和大数据技术提升代码质量的方法,是目前的一个热门研究领域。通过技术手段,辅助研发解决技术问题,在未来是一种趋势。如果你在公司中从事的是研发辅助和效率提升类的工作,建议你深入研究下相关的学术文章,这对你的工作会大有裨益。
>
参考资料:
<ol>
- [通过持续监控实现代码克隆的定制化管理](https://mp.weixin.qq.com/s/e4B0PsyUPCD2FAJBL0HNbQ)
- [基于代码大数据的软件开发质量追溯体系](https://mp.weixin.qq.com/s/oPYiFCYj1l4XKfTyNj8zEA)
- [代码克隆那点事:开发人员为何克隆?现状如何改变?](https://mp.weixin.qq.com/s/iGQsMJP-6eusfJX8Q66kaQ)
</ol>
## 思考题
你遇到过印象深刻的烂代码吗?
欢迎在留言区写下你的思考和答案,我们一起讨论,共同学习进步。如果你觉得这篇文章对你有所帮助,欢迎你把文章分享给你的朋友。

View File

@@ -0,0 +1,169 @@
<audio id="audio" title="16 | 环境管理:一切皆代码是一种什么样的体验?" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/32/9a/32ed94a9960fd6d4e8bb6c6ad0d97b9a.mp3"></audio>
你好,我是石雪峰。
网上经常流传着一些有关偏见地图的段子,通俗点说,“偏见地图”就是说网友对世界其他地方的印象,比如很多人认为天津人都会说相声。
如果软件开发中也有偏见地图的话那么对不熟悉运维的人来说提到运维团队可能就觉得是维护环境的那帮人。于是环境就成了软件行业的“头号背锅侠”。比如线上出故障了可以是环境配置错误测试有些功能没测到可以是没有测试环境开发出Bug了也不管三七二十一先甩给环境再说……所以你看好像什么问题都可能跟环境相关。这种没来由的偏见也加剧了开发和运维之间的不信任。
## 环境管理的挑战
那么为啥环境总是让人这么不放心呢其实这是因为现代企业所面对的业务复杂性很大程度上都可以直观地体现在环境管理的方方面面上。总结起来我认为一共有5点
1.**环境种类繁多**
首先软件关联的环境种类越来越多比如开发环境、测试环境、UAT用户验收测试环境、预发布环境、灰度环境、生产环境等。光是分清这些环境的名字和作用就不是件容易的事情。
2.**环境复杂性上升**
现代应用的架构逐渐从单体应用向微服务应用转变。随着服务的拆分,各种缓存、路由、消息、通知等服务缺一不可,任何一个地方配置出错,应用都有可能无法正常运行。这还不包括各种服务之间的依赖和调用关系,这就导致很多企业部署一套完整环境的代价极高,甚至变成了不可能完成的任务。
3.**环境一致性难以保证**
比如,那句经典的甩锅名言“在我的机器上没问题”说的就是环境不一致的问题。如果无法保证各种环境配置的一致性,那么类似的问题就会无休止地发生。实际上,在很多企业中,生产环境由专门的团队管理维护,管理配置还算受控。但是对于开发环境来说,基本都属于一个黑盒子,毕竟是研发本地的电脑,即便想管也管不到。
4.**环境交付速度慢**
由于职责分离环境的申请流程一般都比较冗长从提起申请到交付可用的环境往往需要2周甚至更长的时间。
一方面这跟公司内部的流程审批有关。我见过一家企业申请一套环境需要5级审批想象一下于一家扁平化组织的公司从员工到CEO之间的层级可能也没有5级。另一方面环境配置过程依赖手动完成过程繁琐效率也不高大多数情况下环境配置文档都属于过时状态并不会根据应用升级而动态调整这么一来二去几天就过去了。
5.**环境变更难以追溯**
产品上线以后出现问题,查了半天才发现,原来是某个环境参数的配置导致的。至于这个配置是谁改的,什么时间改的,为什么修改,经过了哪些评审,一概不知,这就给线上环境的稳定性带来了极大的挑战和潜在的风险。要知道,**环境配置变更的重要性,一点也不亚于代码变更,通常都需要严格管控**。
## 基础设施即代码
你可能会问有没有一种方法可以用来解决这些问题呢还真有这就是基础设施即代码。可以这么说如果没有采用基础设施即代码的实践DevOps一定走不远。那么到底什么是基础设施即代码呢
**基础设施即代码就是用一种描述性的语言通过文本管理环境配置并且自动化完成环境配置的方式。典型的就是以CAPS为代表的自动化环境配置管理工具**也就是Chef、Ansible、Puppet和Saltstacks四个开源工具的首字母缩写。
这个概念听起来比较抽象那么所谓基础设施即代码这个描述基础设施的代码长什么样子呢我给你分享一段Ansible的配置示例你可以参考一下。
```
---
- name: Playbook
hosts: webservers
become: yes
become_user: root
tasks:
- name: ensure apache is at the latest version
yum:
name: httpd
state: latest
- name: ensure apache is running
service:
name: httpd
state: started
```
无论你是否了解Ansible单就这段代码而言即便你不是专业运维或者工具专家在注释的帮助下你也大概能理解这个环境配置过程。实际上这段代码就做了两件事安装http的软件包并启动相关服务。
为什么基础设施即代码能够解决以上问题呢?
首先,对于同一个应用来说,各种环境的配置过程大同小异,只是在一些配置参数和依赖服务方面有所差别。**通过将所有环境的配置过程代码化,每个环境都对应一份配置文件,可以实现公共配置的复用**。当环境发生变更时,就不再需要登录机器,而是直接修改环境的配置文件。这样一来,环境配置就成了一份活的文档,再也不会因为更新不及时而失效了。
其次,**环境的配置过程,完全可以使用工具自动化批量完成**。你只需要引用对应环境的配置文件即可,剩下的事情都交给工具。而且,即便各台机器的初始配置不一样,工具也可以保证环境的最终一致性。由于现代工具普遍支持幂等性原则,即便执行完整的配置过程,工具也会自动检测哪些步骤已经配置过了,然后跳过这个步骤继续后面的操作。这样一来,大批量环境的配置效率就大大提升了。
最后既然环境配置变成了代码自然可以直接纳入版本控制系统中进行管理享受版本控制的福利。任何环境的配置变更都可以通过类似Git命令的方式来实现不仅收敛了环境配置的入口还让所有的环境变更都完全可追溯。
基础设施即代码的实践通过人人可以读懂的代码将原本复杂的技术简单化这样一来即便是团队中不懂运维的角色也能看懂和修改这个过程。这不仅让团队成员有了一种共同的语言还大大减少了不同角色之间的依赖降低了沟通协作成本。这也是基础设施即代码的隐形价值所在特别符合DevOps所倡导的协作原则。
看到这儿你可能会说这不就是一种自动化手段吗好像也没什么特别的呀。回头想想DevOps的初衷就是打破开发和运维的隔阂但究竟要如何打通呢
在大多数公司,部署上线的工作都是由专职的运维团队来负责,开发团队只要将测试通过的软件包提供给运维团队就行了。所以,**开发和运维的自然边界就在于软件包交付的环节只有打通开发环节的软件集成验收的CI流水线和运维环节的应用部署CD流水线上线才能真正实现开发运维的一体化**。而当版本控制系统遇上基础设施即代码,就形成了一种绝妙的组合,那就是**GitOps**。
### 开发运维打通的GitOps实践
顾名思义GitOps就是基于版本控制系统Git来实现的一套解决方案核心在于基于Git这样一个统一的数据源通过类似代码提交过程中的拉取请求的方式也就是Pull Request来完成应用从开发到运维的交付过程让开发和运维之间的协作可以基于Git来实现。
虽然GitOps最初是基于容器技术和Kubernetes平台来实现的但它的理念并不局限于使用容器技术实际上**它的核心在于通过代码化的方式来描述应用部署的环境和部署过程**。
在GitOps中每一个环境对应一个环境配置仓库这个仓库中包含了应用部署所需要的一切过程。比如使用Kubernetes的时候就是应用的一组资源描述文件比如部署哪个版本开放哪些端口部署过程是怎样的。
当然你也可以使用Helm工具来统一管理这些资源文件。如果你还不太熟悉Kubernetes可以简单地把它理解为云时代的Linux而Helm就是RPM或者APT这些包管理工具通过应用打包的方式来简化应用的部署过程。
除了基于Kubernetes的应用你也可以使用类似Ansible Playbook的方式。只不过与现成的Helm工具相比使用Ansible时需要自己实现一些部署脚本不过这也不是一件复杂的事情。
你可以看看下面的这段配置文件示例。这些配置文件采用了yml格式它描述了应用部署的主要信息其中镜像名称使用参数形式会有一个独立的文件来统一管理这些变量你可以根据应用的实际版本进行替换以达到部署不同应用的目标。
```
apiVersion: extensions/v1beta1
kind: Deployment
spec:
replicas: 1
template:
metadata:
labels:
app: demo
spec:
containers:
- name: demo
image: &quot;{{ .Values.image.tag }}&quot;
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
```
现在,我们来看看这个方案是如何实现的。
首先开发人员提交新的代码改动到Git仓库这会自动触发持续集成流水线对于常见的版本控制系统来说配置钩子就可以实现。当代码经过一系列的构建、测试和检查环节并最终通过持续集成流水线之后就会生成一个新版本的应用并上传到制品库中典型的就是Docker镜像文件或者war包的形式。
以上面的配置为例假如生成了应用的1.0版本镜像接下来会自动针对测试环境的配置仓库创建一个代码合并请求变更的内容就是修改镜像名称的版本号为1.0。这个时候,开发或者测试人员可以通过接受合并的方式,将这段环境变更配置合入主干,并再一次自动化地触发部署流水线,将新版本的应用部署到测试环境中。每次应用的部署采用相同的过程,一般就是将最新版本的应用制品拷贝到服务器并且重启,或者更新容器镜像并触发滚动升级。
这个时候测试环境就部署完成了当然如果使用Kubernetes可以利用**命名空间的特性**,快速创建出一套独立的环境,这是使用传统部署的应用所不具备的优势。在测试环境验收通过后,可以将代码合并到主分支,再一次触发完整的集成流水线环节,进行更加全面的测试工作。
当流水线执行成功后,可以自动针对预发布环境的配置仓库创建一个合并请求,当评审通过后,系统自动完成预发布环境的部署。如果职责分离要求预发布环境的部署必须由运维人员来操作,把合并代码的权限只开放给运维人员就行了。当运维人员收到通知后,可以登录版本控制系统,查看本次变更的范围,评估影响,并按照部署节奏完成部署。而这个操作,只需要在界面点击按钮就可以实现了。这样一来,开发和运维团队的协作就不再是一个黑盒子了。大家基于代码提交评审的方式完成应用的交付部署,整个过程中的配置过程和参数信息都是透明共享的。
我跟你分享一幅流程图,希望可以帮你充分地理解这个分层部署的过程。
<img src="https://static001.geekbang.org/resource/image/2d/fc/2de091bea58d1c4f376a26fa61c8f0fc.png" alt="">
那么GitOps的好处究竟有哪些呢
首先,就是**环境配置的共享和统一管理**。原本复杂的环境配置过程通过代码化的方式管理起来,每个人都能看懂。这对于开发自运维来说,大大地简化了部署的复杂度。
另外所有最新的环境配置都以Git仓库中为准每一次的变更和部署过程也同样由版本控制系统进行记录。即便仅仅是环境工具的升级也需要经过以上的完整流程从而实现了环境和工具升级的层层验证。所以这和基础设施即代码的理念可以说有异曲同工之妙。
### 开发环境的治理实践
关于开发环境的治理,我再给你举一个实际的案例。对于智能硬件产品开发来说,最大的痛点就是各种环境和工具的配置非常复杂,每个新员工入职,配置环境就要花上几天时间。另外,由于工具升级频繁和多平台并行开发的需要,开发经常需要在多种工具之间进行来回切换,管理成本很高。
关于这个问题,同样**可以采用基础设施即代码的方法生成一个包含全部工具依赖的Docker镜像并分发给开发团队**。在开发时仅需要拉起一个容器,将代码目录挂载进去,就可以生成一个完全标准化的研发环境。当工具版本升级时,可以重新制作一个新的镜像,开发本地拉取后,所有的工具就升级完成了,这大大简化了研发环境的维护成本。
其实,我们也可以发挥创新能力,**把多种工具结合起来使用,以解决实际问题**。比如我们团队之前要同时支持虚拟化设备和容器化两种环境虚拟化可以采用传统的Ansible方式完成环境部署但容器化依赖于镜像的Dockerfile。这就存在一个问题要同时维护两套配置每次升级的时候也要同时修改虚拟化和容器化的配置文件。于是为了简化这个过程就可以把两者的优势结合起来使用单一数据源维护标准环境。
具体来说在Dockerfile中除了基础环境和启动脚本环境配置部分同样采用Ansible的方式完成这样每次在生成一个新的镜像时就可以使用相同的方式完成环境的初始化过程配置示例如下
```
FROM harbor.devops.com:5000/test:ansible
MAINTAINER XX &lt;xx@devops.com&gt;
ADD ./docker /docker
WORKDIR /docker
RUN export TMPDIR=/var/tmp &amp;&amp; ansible-playbook -v -i playbooks/inventories/docker playbooks/docker_container.yml
```
### 开发本地测试的实践
其实我始终认为环境管理是DevOps推行过程中的一个潜在“大坑”。为了提升开发者的效率业界也在探索很多新的实践方向。我在前面也给你介绍过快速失败的理念只有在第一时间反馈失败才能最小化问题修复成本。而对于研发来说由于测试环境的缺失往往要等到代码提交并部署完成之后才能获取反馈这个周期显然是可以优化的。关于如何解决开发本地测试的问题在Jenkins社区也有一些相关的实践。
比如你基于Kubernetes创建了一套最小测试环境按照正常过程来说如果改动一行代码你需要经过代码提交、打包镜像、上传制品、更新服务器镜像等才能开始调试。但如果你使用[KSync](https://github.com/ksync/ksync)工具这些过程统统可以省略。KSync可以帮你建立本地工作空间和远端容器目录的关联并自动同步代码。也就是说只要在本地IDE里面修改了一行代码保存之后KSync就可以帮你把本地代码传到线上的容器中对于类似Python这样的解释型语言来说特别省事。
谷歌也开源了一套基于容器开发自动部署工具[Skaffold](https://github.com/GoogleContainerTools/skaffold)跟KSync类似使用Skaffold命令就可以创建一套Kubernetes环境。当本地修改一行代码之后Skaffold会自动帮你重新生成镜像文件推送远端并部署生效让代码开发变得所见即所得。研发只需要专注于写代码这件事情其余的全部自动化这也是未来DevOps工程实践的一个发展方向。
## 总结
今天,我给你介绍了企业环境管理的五个难题:种类多,复杂性,一致性,交付速度和变更追溯,并解释了为什么基础设施即代码是解决环境管理问题的最佳实践,还跟你分享了三个基础设施即代码的案例,希望能够帮助你理解这个过程。
如果你不太了解Kubernetes和容器可能会有些内容难以消化。我想跟你说的是**无论采用什么技术,代码化管理的方式都是未来的发展趋势**建议你结合文章中的代码和流程图仔细梳理一下并且尝试使用CAPS工具重新定义环境部署过程将环境配置过程实现代码化。如果有问题可以及时在留言区提问。
## 思考题
你认为推行开发自运维的最大难点是什么?关于解决这些难点,你有什么建议吗?
欢迎在留言区写下你的思考和答案,我们一起讨论,共同学习进步。如果你觉得这篇文章对你有所帮助,欢迎你把文章分享给你的朋友。

View File

@@ -0,0 +1,151 @@
<audio id="audio" title="17 | 部署管理:低风险的部署发布策略" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/fd/f9/fd902c2ae2c4a53325cb631ad7bd86f9.mp3"></audio>
你好,我是石雪峰,今天我来跟你聊聊部署管理。
在DevOps年度状态报告中有四个核心的结果指标其中仅“部署”这一项就占了两个关键指标分别是**部署频率**和**部署失败率**。顺便提一下,另外两个指标是**前置时长**和**平均故障修复时长**。
对DevOps来说部署活动就相当于软件交付最后一公里的最后一百米冲刺。只有通过部署发布软件真正交付到最终用户手中的时候前面走过的路才真正创造了价值。
部署和发布这两个概念,经常会被混用,但严格来说,部署和发布代表两种不同的实践。**部署是一组技术实践,表示通过技术手段,将本次开发测试完成的功能实体**(比如代码、二进制包、配置文件、数据库等)**应用到指定环境的过程**,包括开发环境、预发布环境、生产环境等。部署的结果是对服务器进行变更,但是这个变更结果不一定对外可见。
发布也就是Release更偏向一种业务实践也就是**将部署完成的功能正式生效,对用户可见和提供服务的过程**。发布的时机往往同业务需求密切相关。很多时候部署和发布并不是同步进行的比如对于电商业务来说要在0点上线新的活动那么如果部署和发布不分离就意味着要在0点的前1秒完成所有服务器的变更这显然是不现实的。
那么,我想请你思考这样一个问题:所谓的低风险发布,是不是要在发布之前确保本次变更的功能万无一失了,才会真正地执行发布动作呢?
事实上即使没这么说很多公司也都是这样做的。传统软件工程在流程设计的时候也是希望通过层层的质量手段来尽可能全面地验证交付产品的质量。典型的应用就是测试的V模型从单元测试、集成测试、系统测试到用户验收还有各类专项测试其实都是为了在发布之前发现更多的问题以此来保障产品的质量。
那么在DevOps模式下是否也倡导同样的质量思想呢我觉得这是一个有待商榷的问题。
实际上随着发布频率的加速留给测试活动的时间越来越有限了。与此同时现在业务的复杂度也比十年前高了不知道多少个等级。每次发布涉及PC端、移动端还有小程序、H5等多种形态更别提成百上千的终端设备了。要在有限的时间里完成所有的测试活动本来就是件很有挑战的事情。而且各个公司都在衡量测试开发比更是限制了测试人力投入的增长甚至还要不断下降。
你当然可以通过自动化手段来提升测试活动的效率但穷尽测试本来就是个伪命题。那么明明说了DevOps可以又快又好难道是骗人的吗
当然不是。这里的核心就在于DevOps模式下质量思想发生了转变。简单概括就是**要在保障一定的质量水平的前提下,尽量加快发布节奏,并通过低风险发布手段,以及线上测试和监控能力,尽早地发现问题,并以一种最简单的手段来快速恢复。**
这里面有几个关键词:**一定的质量水平****低风险发布手段****线上测试和监控**,以及**快速恢复**。我分别来给你解释一下。
### 一定的质量水平
这个“一定”要怎么理解呢?对于不同形态的软件来说,质量标准的高低自然是不相同的。比如,我有一个制造卫星的同学,他们对于软件质量的要求就是要做到几年磨一剑,甚至是不计成本的。但对于互联网这种快速迭代的业务来说,大家都习惯了默认会出问题,所以在圈定测试范围和测试覆盖的基础上,只要完成严重问题的修复即可发布,低级别的问题可以在后续的众测和灰度的环节继续处理。
所以与定义一个发布质量标准相比更重要的随着DevOps的推广扭转团队的质量观念。**质量不再是测试团队自身的事情,而是整个交付团队的事情**。如果出现了线上问题,团队要一起来定位和修复,并且反思如何避免类似的问题再次发生,从失败中学习。
而测试能力的向前、向后延伸,一方面,提供了工具和平台以帮助开发更容易地进行自测;另一方面,加强针对线上监控埋点等类型的测试,可以保证线上问题可以快速暴露,正常获取辅助分析用户行为的数据,这会全面提升整体的发布质量。
### 低风险的发布手段
既然发布是一件不可回避的高风险事情,那么,为了降低发布活动的风险,就需要有一些手段了。典型的包括以下几种:蓝绿部署,灰度发布和暗部署。
**1.蓝绿部署**
蓝绿部署就是为应用准备两套一模一样的环境,一套是蓝环境,一套是绿环境,每次只有一套环境提供线上服务。这里的蓝和绿,只是用于区分两套环境的标志而已。在新版本上线时,先将新版本的应用部署到没有提供线上服务的环境中,进行上线前验证,验证通过后就达到了准备就绪的状态。在发布时间点,只要将原本指向线上环境的路由切换成另外一套环境,整个发布过程就完成了。
一般来说,**这种方式的实现成本比较高**。因为有两套一模一样的环境,只有一套用于真正地提供线上服务。为了减少资源浪费,在实际操作中,另外一套环境可以当作预发布环境使用,用来在上线之前验证新功能。另外,在这种模式下,数据库普遍还是采用同一套实例,通过向下兼容的方式支持多个版本的应用。
<img src="https://static001.geekbang.org/resource/image/47/27/47931f5ea26ae8fe57dee79022046527.png" alt="">
>
图片来源:[https://www.gocd.org/2017/07/25/blue-green-deployments.html](https://www.gocd.org/2017/07/25/blue-green-deployments.html)
**2.灰度发布**
灰度发布,也叫金丝雀发布。与蓝绿部署相比,灰度发布更加灵活,成本也更低,所以,在企业中是一种更为普遍的低风险发布方式。
**灰度发布有很多种实现机制,最典型的就是采用一种渐进式的滚动升级来完成整个应用的发布过程**。当发布新版本应用时,根据事先设计好的灰度计划,将新应用部署到一定比例的节点上。当用户流量打到这部分节点的时候,就可以使用新的功能了。
值得注意的是要保证同一个用户的行为一致性不能时而看到新功能时而看到老功能。当然解决办法也有很多比如通过用户ID或者cookie的方式来识别用户并划分不同的组来保证。
新版本应用在部分节点验证通过后,再逐步放量,部署更多的节点,依次循环,最终完成所有节点的部署,将所有应用都升级到新版本。分批部署只是实现灰度发布的方法之一,利用配置中心和特性开关,同样可以实现指向性更强的灰度策略。比如,针对不同的用户、地域、设备类型进行灰度。
对于移动端应用来说灰度发布的过程也是必不可少的。我以iOS平台应用为例带你梳理下发布的步骤。首先公司的内部用户可以自行下载安装企业包进行新版本验证和试用。试用OK后再通过官方的Testflight平台对外开启灰度这样只有一部分用户可以收到新版本通知并且在Testflight中安装新版本。灰度指标符合预期后再开启全量用户升级。
现在很多应用都采用了动态下发页面的方法,同样可以使用特性开关,来控制不同用户看到不同的功能。
<img src="https://static001.geekbang.org/resource/image/65/5c/65b39fae9bece629c567d35055ac7f5c.png" alt="">
>
图片来源:[https://www.gocd.org/2017/07/25/blue-green-deployments.html](https://www.gocd.org/2017/07/25/blue-green-deployments.html)
**3.暗部署**
随着A/B测试的兴起暗部署的方式也逐渐流行起来。**所谓暗部署,就是在用户不知道的情况下进行线上验证的一种方法**。比如后端先行的部署方式,把一个包含新功能的接口发布上线,这个时候,由于没有前端导向这个接口,用户并不会真实地调用到这个接口。当用户进行了某些操作后,系统会将用户的流量在后台复制一份并打到新部署的接口上,以验证接口的返回结果和性能是否符合预期。
比如,对于电商业务场景来说,当用户搜索了一个关键字后,后台有两种算法,会给出两种返回结果,然后可以根据用户的实际操作,来验证哪种算法的命中率更高,从而实现了在线的功能验证。
<img src="https://static001.geekbang.org/resource/image/0b/88/0b723413da42fd5327523ba115d0f088.png" alt="">
>
图片来源:[https://www.gocd.org/2017/07/25/blue-green-deployments.html](https://www.gocd.org/2017/07/25/blue-green-deployments.html)
以上这三种低风险发布手段如果应用规模整体不大蓝绿部署是提升系统可用性的最好手段比如各类Hot-standby的解决方案其实就是蓝绿部署的典型应用。而对于大规模系统来说考虑到成本和收益灰度发布显然就成了性价比最高的做法。如果想要跑一些线上的测试收集真实用户反馈那么暗部署是一种不错的选择。
### 线上测试和监控
那么如何验证多种发布模式是正常的呢核心就在于线上测试和监控了。实际上在DevOps中有一种全新的理念那就是**监控就是一种全量的测试**。
你可能会问,为什么要在线上进行测试?这岂不是非常不安全的行为吗?如果按照以往的做法,你应该做的就是花费大量精力来建立一个全仿真的预发布环境,尽可能地模拟线上环境的内容,以达到验证功能可用性的目标。但只要做过测试的团队就知道,测试环境永远不能替代生产环境,即便在测试环境做再多的回归,到了生产环境,依旧还是会有各种各样的问题。
关于测试环境和生产环境,有一个特别有趣的比喻:测试环境就像动物园,你能在里面看到各种野生动物,它们都活得都挺好的;生产环境就像大自然,你永远无法想象动物园里的动物回到大自然之后会有什么样的行为,它们面临的就是一个完全未知的世界。产生这种差异的原因有很多,比如环境设备的差异、用户行为和流量的差异、依赖服务的差异等,每一个变量都会影响组合的结果。
那么,既然无法事先模拟发布后会遇到的所有场景,该如何做线上验证呢?比较常见的,有三种手段。
**1.采用灰度发布、用户众测等方式,逐步观察用户行为并收集用户数据,以验证新版本的可用性是否符合预期。**
这里的主要实践之一就是**埋点功能**。在互联网产品中,埋点是一种最常用的产品分析和数据采集方法,也是数据驱动决策的主要依据之一。它的价值就在于,根据预先设计的收集和监控数据的方法,采集用户的行为、产品质量、运营数据等多维度的数据。
大型公司一般都实现了自己的埋点SDK根据产品设计需求可以自动化地采集数据并配置采集粒度对于小公司来说像**友盟**这种第三方统计工具,就可以满足绝大多数情况的需求了。
**2.用户反馈。**
除了自动化的采集数据之外,用户主动的反馈也是获取产品信息的第一手资料。而用户反馈的渠道有很多,公司里面一般都有**用户运营和舆情监控系统**,用于按照“关键字”等自动爬取各个主流渠道的产品信息。一旦发现负面的反馈,就第一时间进行止损。
**3.使用线上流量测试。**
这一点在讲暗部署时我也提到过,最典型的实践就是**流量镜像**。除了做线上的A/B测试最常用的就是将线上真实的用户流量复制下来以实时或者离线的方式回放到预发布环境中用于功能测试。
除此之外,流量镜像还有很多高级的玩法。像是根据需求选择性地过滤一些信息,比如使用只读的查询内容来验证搜索接口。另外,还可以按照倍数放大和缩小流量,以达到服务压测的目的。还有,可以自动比对线上服务和预发布服务的返回结果,以验证相同的流量过来时,两个版本之间系统的行为是否一致。另外,流量镜像的数据可以离线保存,这对于一些偶发的、难以复现的用户问题,提供了非常难得的数据积累,可以帮助研发团队进一步分析,以避免此类问题的再次发生。
在工具层面,我推荐你使用开源的**GoReplay工具**。它基于Go语言实现作用于HTTP层不需要对系统进行大量改造并且能很好地支持我刚才提到的功能。
### 快速恢复
一旦发现新版本发布后不符合预期,或者有严重的缺陷,最重要的就是尽快控制局面,解决故障。**平均故障修复时长**MTTR是DevOps的四个核心指标之一DevOps的质量信心不仅来源于层层的质量门禁和自动化验证出现问题可以快速定位和修复也是不可忽视的核心能力之一。
平均故障修复时长可以进一步拆解为平均故障检测时长MTTD、平均故障识别诊断时长MTTI以及平均故障修复时长MTTR。在故障发生后根据服务可用性指标SLA对问题进行初步分析定位明确解决方案。在这个领域一款好用的线上诊断工具可以大大地帮助你缓解燃眉之急。比如**阿里的开源工具Arthas**就可以实时监控堆栈信息、JVM信息调用参数查看返回结果跟踪节点耗时等甚至还能查看内存占用、反编译源码等堪称问题诊断利器。
<img src="https://static001.geekbang.org/resource/image/6a/0f/6aca9b3215235e21bdd4a87e8e607e0f.jpg" alt="">
初步对问题进行分析定位后,你可以有两种选择:**向前修复和向后回滚**。
**向前修复就是快速修改代码并发布一个新版本上线,向后回滚就是将系统部署的应用版本回滚到前一个稳定版本**。无论选择哪一种考验的都是自动化的部署流水线和自动化的回滚能力这也是团队发布能力的最佳体现。而在DevOps的结果指标中部署前置时长描述的恰恰就是这段时长。当然最佳实践就是自动化的流水线。往往在这个时候你就会希望流水线更快一些更自动化一些。
<img src="https://static001.geekbang.org/resource/image/46/7c/467adeb8aa1afc297b7009217c8a627c.png" alt="">
最后,再提一点,你可能在很多大会上听过“故障自愈”,也就是出现问题系统可以自动修复。这听起来有点神奇,但实际上,故障自愈的第一步,就要做好**服务降级和兜底策略**。这两个听起来很专业的词是啥意思呢?别着急,我给你举个例子,你就明白了。
我给你截了两张某购物App的图片你可以对比看下有什么不同。
<img src="https://static001.geekbang.org/resource/image/ea/65/eaedb72bd38b7811e2af44c2047c2165.png" alt="">
如果你仔细看的话你会发现单这一个页面就有大大小小8个差异。所以**服务降级就是指,在流量高峰的时候,将非主路径上的功能进行临时下线,保证业务的可用性**。典型的做法就是通过**功能开关的方式**来手动或自动地屏蔽一些功能。
<img src="https://static001.geekbang.org/resource/image/e6/ce/e611e299e35d831ce705bb0c7ef17dce.png" alt="">
而兜底策略是指,当极端情况发生时,比如服务不响应、网络连接中断,或者调用服务出现异常的时候,也不会出现崩溃。常见的做法就是缓存和兜底页面,以及前端比较流行的骨架屏等。
## 总结
在这一讲中我给你介绍了DevOps模式下质量思想的转变那就是要在保障一定的质量水平的前提下尽量加快发布节奏并通过低风险发布手段以及线上测试和监控能力尽早地发现问题并以一种最简单的手段来快速恢复。
质量活动是有成本的,为了保证快速迭代发布,一定程度的问题发生并不是末日,更重要的是通过质量活动向前向后延伸,并在生产环境加强监控和测试。同时,三种典型的低风险发布方式可以满足不同业务场景的需求。当问题发生时,不仅要做到快速识别,快速修复,还要提前通过服务降级、兜底策略等机制保证系统服务的连续性。
## 思考题
你所在的企业采用了哪些手段来保障部署活动是安全可靠的呢?
欢迎在留言区写下你的思考和答案,我们一起讨论,共同学习进步。如果你觉得这篇文章对你有所帮助,欢迎你把文章分享给你的朋友。

View File

@@ -0,0 +1,183 @@
<audio id="audio" title="18 | 混沌工程:软件领域的反脆弱" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/bd/c7/bde3c40d5d2f4d2425639a87c7ab63c7.mp3"></audio>
你好,我是石雪峰。
经济学领域有一本特别有名的书,叫作《反脆弱》。它的核心理念就是,在面对普遍存在又不可预估的不确定性时,通过一种行之有效的方法,不仅可以规避重大风险,还能够利用风险获取超出预期的回报。另外,通过积极地试错,控制损失成本,还能不断提升在不确定性事件发生时的收益。
不仅仅要规避风险,还要在风险中受益,这听起来是不是很神奇?其实,在软件工程领域,也有类似的思想和实践,可以帮助我们在面对极其复杂且规模庞大的分布式系统时,有效地应对不可预见的故障,不仅可以从容不迫地应对,还能从中获益,并且通过频繁、大量地实验,识别并解决潜在的风险点,从而提升对于复杂系统的信心。这就是今天我要给你分享的主题:混沌工程。
## 什么是混沌工程?
混沌工程作为软件领域的一门新兴学科,就和它的名字一样,让很多人感到非常“混沌”。那么,混沌工程究竟是从何而来,又是要解决什么问题呢?
我们先来看看混沌原则网站对混沌工程的定义:
>
Chaos Engineering is the discipline of experimenting on a distributed system in order to build confidence in the systems capability to withstand turbulent conditions in production.
>
混沌工程是一门在分布式系统上进行实验的学科,目的是建立人们对于复杂系统在生产环境中抵御突发事件的信心。
简单来说,混沌工程要解决的,就是复杂环境下的分布式系统的反脆弱问题。那么,我们所要面对的“复杂的分布式”的真实世界是怎样的呢?
我给你举个例子。对于一个大型的平台来说每日在线的活动数以万计服务的用户可以达到千万级别。为了满足这种规模的业务量级仅客户端就有300多个组件后端服务更是不计其数。
可以想象,这样一套复杂的系统,任何一个地方出了一点小问题,都有可能带来线上事故。
另外,随着微服务、容器化等技术的兴起,业务驱动自组织团队独立发布的频率越来越高,再加上架构的不断更新演进,可以说,**几乎没有人能完整地梳理清楚一套系统的服务间调用关系**,这就让复杂系统变成了一个“黑洞”。不管外围如何敲敲打打,都很难窥探到核心问题。
为了让你对复杂的真实系统有更加直观的认识我跟你分享一张Netflix公司在2014年公开的微服务调用关系图你可以参考一下。
<img src="https://static001.geekbang.org/resource/image/fc/db/fc2a435fcba0551bf2b072fa48155edb.jpeg" alt="">
>
图片来源:[https://www.slideshare.net/BruceWong3/the-case-for-chaos?from_action=save](https://www.slideshare.net/BruceWong3/the-case-for-chaos?from_action=save)
面对这样复杂的分布式系统,想要通过穷尽全面的测试来保障质量,不出线上问题几乎是不可能的事情。因为测试的假设前提都是为了验证软件的预期行为,而**真实世界的问题却从来不按套路出牌,被动遵循已有的经验并不能预防和解决未知的问题**。
尤其是,如果系统的可用性是基于某一个服务不会出问题来设计的话,那么,这个服务十有八九会出问题。
比如前不久我们内部的平台就出现了一次宕机原因是依赖的一个基础服务的认证模块出现了异常从而导致存储数据失败。因为平台的所有基础数据都在这个看似万无一失的服务上保存即便监控第一时间发现了这个问题但是除了等待之外我们什么都做不了。结果平台的可用性直接从4个9掉到了3个9。
既然面对复杂的分布式系统我们无法避免异常事件的发生那么有什么更好的办法来应对这种不确定性吗Netflix公司给出了他们的回答而这正是混沌工程诞生的初衷。
区别于以往的方式,混沌工程采取了一种更加积极的方式,换了一个思路主动出击。那就是,**尽可能在这些故障和缺陷发生之前,通过一系列的实验,在真实环境中验证系统在故障发生时的表现**。根据实验的结果来识别风险问题,并且有针对性地进行系统改造和安全加固,从而提升对于整个系统可用性的信心。
## 服务可用性实践
看到这儿,你可能就要问了,这不就是日常的系统可用性保障活动吗?我们公司也有类似的实践呀,比如故障演练、服务降级方案、全链路压测等,这些基本都是大促活动到来前必需的备战活动。
的确,这些实践与混沌工程有相似之处,毕竟,混沌工程就是从这些实践中发展起来的,但是,思路又略有不同。
比较正规的公司基本上都会有一套完整的数据备份机制和服务应急响应预案,就是为了当灾难发生时,可以保证系统的可用性和核心数据的安全。
比如,**故障演练就是针对以往发生过的问题进行有针对性地模拟演练**。通过事先定义好的演练范围,然后人为模拟事故发生,触发应急响应预案,快速地进行故障定位和服务切换,并观察整个过程的耗时和各项数据指标的表现。
故障演练针对的大多是可以预见到的问题比如机器层面的物理机异常关机、断电设备层面的磁盘空间写满、I/O变慢网络层面的网络延迟、DNS解析异常等。这些问题说起来事无巨细但基本上都有一条清晰的路径有明确的触发因素监控事项和解决方法。
另外,在故障演练的过程中,很难覆盖所有的故障类型,只能选择典型的故障进行验证。但是实际问题发生时,往往是多个变量一起出问题,逐个排查下来非常耗时耗力。
很多公司为了模拟线上的真实场景,于是就引入了全链路压测的技术。对于大促密集的电商行业来说,尤为重要。
对于一次完整的压测来说,大致的过程是这样的:
- 首先,准备压测计划,调试压测脚本和环境,对压测容量和范围进行预估;
- 然后,为了保证线上流量不受影响完成机房线路切换,确保在压测过程中没有线上真实流量的引入;
- 接着,根据预定义的压测场景执行压测计划,观察流量峰值并动态调整;
- 最后在压测完成后再次进行流量切换并汇总压测结果识别压测问题。在压测过程中除了关注QPS指标之外还要关注TP99、CPU使用率、CPU负载、内存、TCP连接数等从而客观地体现出大流量下服务的可用性。
**从业务层面来说,面对多变的环境因素,完善的服务降级预案和系统兜底机制也是必不可少的**。在业务压力比较大的时候,可以适当地屏蔽一些对用户感知不大的服务,比如推荐、辅助工具、日志打印、状态提示等,**保证最核心流程的可用性**。另外,**适当地引入排队机制**也能在一定程度上分散瞬时压力。
好啦,说了这么多服务可用性的方法,是不是把这些都做到位就可以确保万无一失了呢?答案是否定的。这是因为,这些活动都是在打有准备之仗。但实际上,很多问题都是无法预知的。
既然现有的实践并不能帮助我们拓展对不可用性的认知,那么就需要一种有效的实验方法,帮助我们基于各种要素排列组合,从而在问题发生之前,发现这些潜在的风险。
比如Netflix公司著名的“混乱猴子Chaos Monkey就是用来随机关闭生产环境的实例的工具。在生产环境放任一个“猴子”乱搞事情这是疯了吗还真不是。Netflix的“猴子军团”的威力一个比一个巨大甚至可以直接干掉一个云服务可用区。
这背后的原因就是,即便是云服务上,也不能确保它们的服务是永远可靠的,所以,**不要把可用性的假设建立在依赖服务不会出问题上**。
当然Netflix并没有权限真正关闭云服务上的可用区他们只是模拟了这个过程并由此来促使工程团队建立多区域的可用性系统促进研发团队直面失败的架构设计不断磨练工程师对弹性系统的认知。
引用Netflix的混沌工程师Nora Jones的话来说
>
混沌工程不是为了制造问题,而是为了揭示问题。
**必须要强调的是,在引入混沌工程的实践之前,首先需要确保现有的服务已经具备了弹性模式,并且能够在应急响应预案和自动化工具的支撑下尽早解决可能出现的问题**
如果现有的服务连基本的可恢复性这个条件都不具备的话,那么这种混沌实验是没有意义的。我跟你分享一幅混沌工程的决策图,你可以参考一下:
<img src="https://static001.geekbang.org/resource/image/77/e3/770700502eb079f09dc0cba03eafc0e3.png" alt="">
>
图片来源:[https://blog.codecentric.de/en/2018/07/chaos-engineering/](https://blog.codecentric.de/en/2018/07/chaos-engineering/)
## 混沌工程的原则
混沌工程不像是以往的工具和实践,作为一门学科,它具有非常丰富的内涵和外沿。你在进入这个领域之前,有必要了解下混沌工程的五大原则:**建立稳定状态的假设、真实世界的事件、在生产中试验、持续的自动化实验、最小影响范围。**
我们分别来看一下这五条原则要如何进行实践。
**1.建立稳定状态的假设**
关于系统的稳定状态,就是说,有哪些指标可以证明当前系统是正常的、健康的。实际上,无论是技术指标,还是业务指标,现有的监控系统都已经足够强大了,稍微有一点抖动,都能在第一时间发现这些问题。
比如对于技术指标来说前面在压测部分提到的指标就很有代表性QPS、TP99、CPU使用率等而对于业务指标来说根据公司具体业务的不同会有所不同。
举个例子对于游戏来说在线用户数和平均在线时长就很重要对于电商来说各种到达率、结算完成率以及更加宏观的GMV、用户拉新数等都能表现出业务的健康程度。
**与技术指标相比,业务指标更加重要**,尤其是对电商这种活动密集型的行业来说,业务指标会受到活动的影响,但基于历史数据分析,总体趋势是比较明显的。
当业务指标发生大量的抖动时(比如瞬时降低提升),就意味着系统出现了异常。比如,几天前微信支付出现问题,从监控来看,支付的成功率就受到了比较明显的影响。
在真实世界中,为了描述一种稳定状态,需要一组指标构成一种模型,而不是单一指标。**无论是否采用混沌工程,识别出这类指标的健康状态都是至关重要的**。而且,还要围绕它们建立一整套完善的数据采集、监控、预警机制。
我给你提供了一些参考指标,汇总在了下表中。
<img src="https://static001.geekbang.org/resource/image/68/3d/68103ce85d10ebaba0a1f9278063f63d.jpg" alt="">
2.**真实世界的事件**
真实世界的很多问题都来源于过往踩过的“坑”,即便是特别不起眼的事件,都会带来严重的后果。
比如我印象比较深的一次故障就是服务器在处理并发任务的时候CPU跑满系统直接卡死。通过调查发现在出现问题的时候系统的I/O Wait很高这就说明磁盘发生了I/O瓶颈。经过仔细地分析最终发现是磁盘Raid卡上的电池没电了从而导致磁盘Raid模式的降级。
像这种事情你很难通过监控所有Raid卡的电池容量来规避问题也不可能在每次模拟故障的时候故意换上没电的电池来进行演练。
所以,既然我们无法模拟所有的异常事情,**投入产出比最高的就是选择重要指标**(比如设备可用性、网络延迟,以及各类服务器问题),**进行有针对性地实验**。另外,可以结合类似全链路压测等手段,从全局视角测试系统整体运作的可用性,通过和稳定状态的假设指标进行对比,来识别潜在的问题。
3.**在生产中实验**
跟测试领域的“质量右移理念”一样,混沌工程同样鼓励在靠近生产环境的地方进行实验,甚至直接在生产环境中进行实验。
这是因为,**真实世界的问题,只有在生产环境中才会出现**。一个小规模的预发布环境更多的是验证系统行为和功能符合产品设计,也就是从功能的角度出发,来验证有没有新增缺陷和质量回退。
但是,系统的行为会根据真实的流量和用户的行为而改变。比如,流量明星的一则消息就可能导致微博的系统崩溃,这是在测试环境很难复现的场景。
但客观来说,在生产环境中进行实验,的确存在风险,这就要求**实验范围可控,并且具备随时停止实验的能力**。还是最开始的那个原则,**如果系统没有为弹性模式做好准备,那么就不要开启生产实验**。
还以压测为例,我们可以随机选择部分业务模块,并圈定部分实验节点,然后开启常态化压测。通过定期将线上流量打到被测业务上,观察突发流量下的指标表现,以及是否会引发系统雪崩,断路器是否生效等,往往在没有准备的时候才能发现真实问题。这种手段作为混沌工程的一种实践,已经普遍应用到大型公司的在线系统之中了。
4.**持续的自动化实验**
**自动化是所有重复性活动的最佳解决方案**。通过自动化的实验和自动化结果分析,我们可以保证混沌工程的诸多实践可以低成本、自动化地执行。正因为如此,以混沌工程为名的工具越来越多。
比如商业化的混沌工程平台Gremlins就可以支持不可用依赖、网络不可达、突发流量等场景。今年阿里也开源了他们的混沌工具[ChaosBlade](https://github.com/chaosblade-io/chaosblade),缩短了构建混沌工程的路径,引入了更多的实践场景。另外,开源的[Resilience4j](https://github.com/resilience4j/resilience4j)和[Hystrix](https://github.com/Netflix/Hystrix)也都是非常好用的工具。无论是自研,还是直接采用,都可以帮助你快速上手。
我相信随着越来越多工具的成熟未来混沌工程也会成为CI/CD流水线的一部分被纳入到日常工作中来。
5.**最小的影响范围**
混沌工程实践的原则就是不要干扰真实用户的使用,所以,在一开始将实验控制在一个较小的范围内,是非常有必要的,这样可以避免由于实验失控带来的更大问题。
比如圈定一小部分用户或者服务范围可以帮助我们客观地评估实验的可行性。假设要实验一个API对错误的处理能力我们可以部署一个新的API实验集群并修改路由导流0.5%的流量用于线上实验。在这个集群中通过故障注入的方式验证API是否能够处理流量带来的错误场景。这有点类似于一个灰度实验环境或者暗部署的方式。
除了可以用于验证新功能做线上的A/B测试同样适用于混沌工程的故障注入。
这五大原则共同勾勒出了混沌工程的全景图,描述系统稳定状态的前提下,将真实世界的事件在生产环境中进行实验,并控制最小影响范围,引入自动化方式持续进行。作为一种全新的工程领域,混沌工程还要走很长的路,才能跨越技术演进的鸿沟。
>
<p>参考资料:<br>
[Netflix混沌工程成熟度模型](https://www.infoq.cn/article/M3EktXxYGRYYm*t5vKga)<br>
[混沌工程资料集](https://github.com/dastergon/awesome-chaos-engineering)<br>
[Netflix混沌工程手册](https://www.oreilly.com/library/view/chaos-engineering/9781491988459/)</p>
## 总结
在这一讲中我给你介绍了一个应对复杂分布式系统可用性挑战的新学科——混沌工程。实际上混沌工程采用了一种全新的思路在系统中主动注入混沌进行实验以此来发现潜在的真实世界的问题。在服务可用性方面我们一直在努力实践比如故障演练、服务降级、全链路压测已经成为了大型系统的标配。最后我给你介绍了混沌工程的5个实践原则希望可以帮助你建立更加全面的认知。
不可否认,目前国内在混沌工程领域的实践还处于摸索实验阶段,但是随着系统的复杂性越来越高,混沌工程也注定会跨越技术发展的鸿沟,成为解决复杂系统可用性问题的利器。
## 思考题
关于真实世界中发生的异常事件,你有哪些独特的经历呢?结合混沌工程的实践,你有什么新的思路吗?
欢迎在留言区写下你的思考和答案,我们一起讨论,共同学习进步。如果你觉得这篇文章对你有所帮助,也欢迎你把文章分享给你的朋友。

View File

@@ -0,0 +1,154 @@
<audio id="audio" title="19 | 正向度量如何建立完整的DevOps度量体系" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/e2/da/e28631fd0f6eb29a47f5b2ad366018da.mp3"></audio>
你好我是石雪峰。到今天为止我用14讲的篇幅给你通盘梳理了DevOps的工程实践基本涵盖了工程实践的方方面面。但是就像那句经典的“不仅要低头看路还要抬头看天”说的一样我们花了这么大的力气投入工程实践的建设结果是不是符合我们的预期呢
所以在工程实践的最后两讲我想跟你聊聊度量和持续改进的话题今天先来看看DevOps的度量体系。
我相信对于每个公司来说度量都是必不可少的实践也是管理层最重视的实践。在实施度量的时候很多人都把管理学大师爱德华·戴明博士的“If you cant measure it, you cant manage it”奉为实践圭臬。
但是,回过头来想想,有多少度量指标是为了度量而度量的?花了好大力气度量出来的数据会有人看吗?度量想要解决的,到底是什么问题呢?
所以,**度量不是目的,而是手段,也就是说度量的目标是“做正确的事”,而度量的手段是“正确地做事”**。
那么什么才是度量领域正确的事情呢如果想要弄清楚DevOps中的度量长什么样子关键就是要回到**DevOps对于软件交付的核心诉求**上。
简而言之对于IT交付来说DevOps希望做到的就是**持续、快速和高质量的价值交付**。价值可以是一个功能特性,可以是用户体验的提升,也可以是修复阻塞用户的缺陷。
明确了这一点也就明确了DevOps的度量想要达到的目标就是为了证明经过一系列的改进工作与过去相比**团队的交付速度更快了,交付质量更高了**。如果度量的结果不能导向这两个核心目标,那么显然就走错了方向,也就得不到实际想要的结果了。
如果只有大方向,往往还是不知道具体要怎么做。这个时候,就需要把目标和方向拆解成一系列的度量指标了。那么,怎样定义好的度量指标和不好的度量指标呢?
## 如何定义指标?
前几天,我被派到某仓库做流水线工人,这个经历让我深刻地理解了工业制造和软件行业的巨大差异。
如果你现在问我,决定工业生产流水线速度的是什么?我可以告诉你,答案就是,流水线本身。因为流水线的传送带的速度是一定的,产线速度也就可以直观地量化出来。
但是,软件开发不像工业制造,开发的过程看不见摸不着,除了工程师真正编写代码的时间,还要包括构思、设计和测试的时间,以及完成各类流程的时间等等。这个过程中可能还存在着各种并行工作的切换和打断,所以,没法用工业流水线的方式来衡量开发人员的效率。
于是,为了达到量化的目的,很多指标就被人为地设计出来了。
比如以准时提测率这个指标为例这个指标采用的是百分制的形式按时提测得100分延期一天得90分延期两天得70分以此类推要是延期五天及以上就只能0分了。这样的指标看起来似乎足够客观公平但是仔细想想延期1天1小时和延期1天23小时似乎也没有太大区别得分的高低并不能反映真实的情况。
在各个公司的度量体系中,类似的人造指标可谓比比皆是。可见,不好的指标总是五花八门,各有各的样子。不过,好的指标大多具备一些典型的特征。
**1.明确受众。**
指标不能脱离受众而单独存在,**在定义指标的同时,要定义它所关联的对象,也就是这个指标是给谁看**。
不同的人关注点自然也不一样,即便指标本身看起来没有什么问题,但是如果使用错位了,也很难产生预期的价值。比如,给非技术出身的老板看单元测试的覆盖率,就没有什么太大意义。
**2.直指问题。**
在NBA中优秀的球员总是自带体系的。所谓体系就是围绕这个球员的核心能力的一整套战术打法可以解决球队的实际问题所以这个球员的表现就成了整支球队的“晴雨表”。
而好的指标也应该是直指问题的,你一看到这个指标,就能意识到问题所在,并自然而然地进行改进,而不是看了跟没看见一样,也不知道具体要做什么。
比如,构建失败率很高,团队就会意识到代码的提交质量存在问题,需要加强事前的验证工作。
**3.量化趋势。**
按照SMART原则**好的指标应该是可以衡量的,而且是可以通过客观数据来自证的**。
比如,用户满意度这种指标看起来很好,但很难用数据衡量;再比如,项目达成率这个指标,如果只是靠手工填写,那就没啥说服力。
同时,**好的度量指标应该能展现趋势**。也就是说,经过一段时间的沉淀,指标是变好了,还是变坏了,距离目标是更近了,还是更远了,这些都应该是一目了然的。
**4.充满张力。**
指标不应该孤立存在,而是应该相互关联构成一个整体。好的指标应该具有一定的张力,**向上可以归并到业务结果,向下可以层层分解到具体细节**。这样通过不同维度的数据抽取,可以满足不同视角的用户需求。
比如,单纯地度量需求交付个数,就没有太大意义。因为需求的颗粒度会直接影响数量,如果只是把一个需求拆成两个,从而达到需求交付速度加倍的效果,这就失去了度量的意义。
## 定义指标有哪些原则?
明白了好的度量指标的典型特征接下来我们就来看看定义DevOps度量的五条原则
1. **全局指标优于局部指标**:过度的局部优化可能对整体产出并无意义,从而偏离了度量的核心,也就是**提升交付速度和交付质量**。
1. **综合指标优于单一指标**:从单一维度入手会陷入只见树木不见森林的困境,综合指标更加客观。所以,要解决一个问题,就需要一组指标来客观指引。
1. **结果指标优于过程指标**:首先要有结果指标,以结果为导向,以过程为途径,一切过程指标都应该归结到结果指标。
1. **团队指标优于个人指标**:优先考核团队指标而非个人指标,团队共享指标有助于形成内部合力,减少内部的割裂。
1. **灵活指标优于固化指标**:指标的设立是为了有针对性地实施改进,需要考虑业务自身的差异性和改进方向,而非简单粗暴的“一刀切”,并且随着团队能力的上升,指标也需要适当的调整,从而不断挑战团队的能力。
## 哪些指标最重要?
基于以上的指标特征和指导原则并结合业界大厂的一些实践我给你推荐一套DevOps度量体系。
虽然各个公司的度量指标体系都不尽相同,但是我认为这套体系框架足以满足大多数场景,如下图所示:
<img src="https://static001.geekbang.org/resource/image/e5/76/e5ee032923d611854e005bf392b24676.jpeg" alt="">
**1.交付效率**
- **需求前置时间**:从需求提出到完成整个研发交付过程,并最终上线发布的时间。对业务方和用户来说,这个时间是最能客观反映团队交付速度的指标。这个指标还可以进一步细分为需求侧,也就是从需求提出、分析、设计、评审到就绪的时长,以及业务侧,也就是研发排期、开发、测试、验收、发布的时长。对于价值流分析来说,这就代表了完整的价值流时长。
- **开发前置时间**:从需求进入排期、研发真正动工的时间点开始,一直到最终上线发布的时长。它体现的是研发团队的交付能力,也就是一个需求进来后,要花多久才能完成整个开发过程。
**2.交付能力**
- **发布频率**:单位时间内的系统发布次数。原则上发布频率越高,代表交付能力越强。这依赖于架构结构和团队自治、独立发布的能力。每个团队都可以按照自己的节奏安全地发布,而不依赖于关联系统和发布窗口期的约束。
- **发布前置时间**指研发提交一行代码到最终上线发布的时间是团队持续交付工程能力的最直观的考查指标依赖于全流程自动化的流水线能力和自动化测试能力。这也是DevOps状态报告中的核心指标之一。
- **交付吞吐量**:单位时间内交付的需求点数。也就是,单位时间内交付的需求个数乘以需求颗粒度,换算出来的点数,它可以体现出标准需求颗粒度下的团队交付能力。
**3.交付质量**
- **线上缺陷密度**:单位时间内需求缺陷比例,也就是平均每个需求所产生的缺陷数量,缺陷越多,说明需求交付质量越差。
- **线上缺陷分布**:所有缺陷中的严重致命等级缺陷所占的比例。这个比例的数值越高,说明缺陷等级越严重,体现了质量的整体可控性。
- **故障修复时长**:从有效缺陷提出到修复完成并上线发布的时间。一方面,这个指标考查了故障定位和修复的时间,另外一方面,也考查了发布前置时间,只有更快地完成发布上线过程,才能更快地修复问题。
这三组、八项指标体现了团队的交付效率、交付能力和交付质量从全局视角考查了关键的结果指标可以用于展现团队DevOps改进的效果和价值产出。不过定义指标只能说是DevOps度量的一小步只有让这些指标发挥价值才能说是有意义的度量。
## 如何开启度量工作?
在企业内部开启度量工作,可以分为四个步骤。
**第1步细化指标。**
一个完整的指标,除了定义之外,还需要明确指标名、指标描述、指标级别(团队级/组织级)、指标类型、适用场景范围及目标用户、数据采集方式和标准参考值。
以交付指标为例,我汇总了一份细化后的指标内容,你可以参考下表。其实不仅仅是核心结果指标,只要是在度量体系内定义的指标,都需要进行细化。
<img src="https://static001.geekbang.org/resource/image/81/cf/81227920cc306a7fae29afa3d77a02cf.jpg" alt="">
关于指标的参考值,对于不同的业务形态,参考值也有所不同。比如就单元测试覆盖率而言,无人车的业务和普通的互联网业务的差别可能会非常大。
所以参考值的选定,需要结合业务实际来分析并达成共识。而且,度量指标本身也需要建立定期更新的机制,以适应于整个团队的能力。
**第2步收集度量数据**
度量指标需要客观数据的支撑,而数据往往都来源于各个不同的平台。所以,在定义指标的时候,你需要评估是否有足够的客观数据来支撑这个指标的衡量。
在采集度量数据的初期,我们面临的最大问题不仅是系统众多、数据口径不一致,还包括数据的准确性。
举个例子,比如开发交付周期这个指标,一般都是计算一个需求从开始开发到线上发布的时间长度。但是,如果开发人员迟迟不把这个需求设置为“已解决”或者“待测试”状态,那么统计出来的开发周期就存在大量的失真,很难反映出客观、真实的情况。
这就需要从流程和平台两个层面入手解决。比如,一方面,从流程层面制定研发操作规范,让每一名研发人员都清楚在什么时间点需要改变需求卡片状态;另一方面,建设平台能力,提供易用性的方式辅助研发,甚至自动流转需求状态。
**第3步建立可视化平台。**
度量指标毕竟是要给人看的,度量数据也需要有一个地方可以收集和运算,这就依赖于度量可视化平台的建设了。关于如何建设一个支持多维度视图、对接多系统数据,以及灵活可编排的度量平台,我会在工具篇给你分享一个案例,帮助你破解度量平台建设的关键问题。
**第4步识别瓶颈并持续改进。**
当数据做到了可信和可视化之后,团队面临的问题和瓶颈会自然而然浮现出来。如何通过指标牵引并驱动团队实施改进,这也是下一讲我们要讨论的核心内容。
我给你提供一些常用的度量指标和相关定义,你可以点击[网盘链接](https://pan.baidu.com/s/1cZKd__yAhcvvrcYNZx9uAA)获取提取码是c7F3。需要注意的是指标宜少不宜多宜精不宜烂对于企业的DevOps度量而言这也是最常见的问题定义了一大堆的指标却不知道要拿来做什么。
只有将指标的定义细化,并在团队内部达成共识,仔细甄别数据的完整和有效性,并做到满足不同维度视角的可视化,才具备了驱动团队进行改进的基础,这一点请你一定要记住。
## 总结
总结一下DevOps度量想要达到的目标就是证明团队经过一系列的改进工作与过去相比交付速度更快了交付质量也更高了。所以交付效率和交付质量是最为核心的两个目标。只有围绕这两个目标建立的度量体系才没有走错方向。
好的指标一般都具备四种特性:明确受众、直指问题、量化趋势和充满张力。结合指标特征和指导原则,以及业界大厂的一些实践,我给你介绍了三组、八项核心结果指标,包括效率指标、能力指标和质量指标。最后,我给你介绍了建立度量体系的四个步骤,希望可以帮助你一步步地搭建持续改进的基石。
度量是把双刃剑,做得不好反而会伤害团队的士气。如果本末倒置,把度量结果跟个人的绩效相绑定,就很容易使度量这个事情变了味道。很多大公司反反复复地在建立度量体系,就是因为前一个体系被人摸透,变成了数字游戏,于是就失去了原有的目的,只能推倒重来。
还是那句话,度量只是一种手段,而非目的。归根结底,度量的真正目的还是团队效率的提升和业务的成功。只有通过度量激起团队自发的改进意愿,提升团队改进的创造性和积极性,才是所谓的“正向度量”,这也是我最想传达给你的理念。
## 思考题
你所在的企业是否也在建设DevOps的度量体系呢你觉得这些度量指标数据对改进当前的工作是否起到了正面作用呢
欢迎在留言区写下你的思考和答案,我们一起讨论,共同学习进步。如果你觉得这篇文章对你有所帮助,也欢迎你把文章分享给你的朋友。

View File

@@ -0,0 +1,143 @@
<audio id="audio" title="20 | 持续改进PDCA体系和持续改进的意义" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/f0/0b/f0c9f5f40ec94f0545b2707daf29700b.mp3"></audio>
你好,我是石雪峰。
今天是“工程实践篇”的最后一节课如果你现在问我在这么多的工程实践中什么能力是团队在推行DevOps时最应该具备的我会毫不犹豫地告诉你那就是**持续改进**。
很多同学在留言区问我“雪峰老师我们公司已经搭建了Gitlab也跟Jenkins实现了打通做到了自动化的编译打包和发布工作。可是接下来我们还有啥可以做的呢我感到很迷茫啊。”
所以这就引申出来一个问题“一个团队做到什么程度才算是达到了DevOps呢
每每遇到这样的问题,我就会回想起,几年前我去国内一家知名公司的杭州总部交流的经历。
当时负责跟我们对接的是这家公司DevOps的主要推动人可以说他见证了这家巨头公司的DevOps转型全过程。在交流时我问了他一个问题他的回答让我印象特别深刻。
我问他“你觉得你们公司是在什么时候实现DevOps转型的呢”他想了想“现在我们公司已经没有专职的测试和专职的运维了基础架构也早就容器化了。这些事情都是业务发展到一定阶段之后自然而然发生的只不过DevOps火起来以后我们才发现原来我们一直在做的就是DevOps。所以很难说在哪个时间点完成了DevOps转型。对我们来说最重要的就是团队具备了一种能力就是**始终能够找到新的突破,持续追求更好的状态**。”
我想这段话应该非常能够代表一个团队实施DevOps转型时期望达到的状态吧。
其实如果你有机会去跟谷歌、Netflix的工程师交流一下你就会发现这些业界DevOps做得特别牛的公司内部都不怎么提DevOps的概念。因为他们早就对DevOps的这些实践习以为常了。很多知名的工具平台都是内部员工自发地为了解决一些问题而开发出来的。
比如像Gerrit这种非常流行的代码在线评审和管理工具最开始就是为了解决谷歌内部缺少一种基于Git并且具备权限管控的代码评审工具的问题才被开发出来的你可以了解下这段[历史](https://www.gerritcodereview.com/about.html)。
你看,遇到一个钉子,从而造个锤子,和拿着一把锤子,满世界找钉子就是两种截然不同的做法。但很多时候,我们采用的都是后一种做法,手里拿着一堆锤子,却找不到钉子在哪里。
所以如果一定要让我来回答DevOps做到什么程度就算是实现转型落地了那么我的回答是**核心就是团队已经具备了持续改进的能力,而不只是简简单单地引入了几个工具,建立了几个度量指标而已**。
说到这儿,你可能会说,这个所谓的持续改进,怎么感觉无处不在呢?似乎很多工程实践的落地方法中,最后一步都是持续改进。那么,持续改进的意义到底是什么呢?为什么一切活动的终极目标都是持续改进呢?
这是因为每家公司面临的问题都不一样从0到1的过程相对比较简单可以对照着工程实践快速地引入工具建立流程补齐能力短板。但是**从1到N的过程就需要团队根据业务需要自行识别改进目标了**。
还以最开始那个问题为例基于Gitlab和Jenkins搭建了自动化构建和发布的能力之后你觉得还有哪些可行的改进方向呢比如测试是否注入其中了呢是否建立了质量门禁机制呢数据库变更是否实现了自动化呢构建发布的速度是否足够理想构建资源是否存在瓶颈
能想到的方向有很多,但哪个才是现阶段最重要、价值最大化的点,说到底,还是要看业务的需求,没办法泛泛而谈。
谈到持续改进有一个非常著名的方法体系叫作PDCA也称为戴明环。没错你从名称就能看出这套方法体系同样来自于质量管理大师戴明博士。PDCA是四个英文单词的缩写也就是Plan计划、Do实施、Check检查和Action行动
PDCA提供了一套结构化的实施框架任何一项改进类工作都可以划分为这四个实施阶段。**通过PDCA循环的不断迭代驱动组织进入一种良性循环不断识别出新的待改进问题**。针对这些问题,首先要进行根因分析,制定具体的实施计划。然后,不定期地检查实施的结果和预期目标是否一致。最后,要对改进结果进行复盘,把做得好的地方保留下来,把做得不好的地方纳入下一阶段的循环中,继续改进。
<img src="https://static001.geekbang.org/resource/image/60/39/605228cf06160834253f25b7801f6c39.png" alt="">
这个方法听起来也没什么复杂的,每个人都能够理解,关键在于是否真正地用心在做。
我再给你分享一个真实的例子。
大概两年前我参与到一家中型企业的DevOps转型工作当中。这家企业刚开始接触DevOps时的状态呢我就不细说了反正就是基本啥都没有。代码库使用的是SVN构建打包都在本地完成版本发布要两个月而且经常是多版本并行的节奏光同步代码就需要专人完成。
经过半年多的改造之后,团队内部的整体工具链体系初具规模,版本发布节奏也缩短到了一个月一次,团队对达到的成绩非常满意。
当然,这并不是重点,重点是,我上个月又碰到了这个项目的负责人。她跟我说,他们现在的发布节奏已经实现了两周一次,甚至不定期还有临时版本发布。我很好奇,他们究竟是怎么做到的。
原来最开始导入改进方案的时候我给项目组提到过容器化的思路但是因为当时客观条件不具备就没有继续推进下去。没想到在短短不到一年的时间里他们已经实现了容器化部署自建的PaaS平台也有模有样即便是跟很多大公司相比也毫不逊色。
她说“这段DevOps转型的过程带给我们的不仅仅是一些常见的工程实践和工具平台更重要的是一双总能发现不完美的眼睛和追求极致的态度以及对这类问题的认知方法。这些驱动我们不断地找到新的方法解决新的问题。”
的确,很多工程实践和工具平台,在公司内部其实只是一小步,之后遇到的问题和挑战还会有很多。这时候,我们能够依靠的终极奥义就是持续改进的思想,而**构建持续改进的核心,就在于构建一个学习型组织**。
那么,究竟要从哪里开始学习呢?在学习和改进的过程中又有哪些比较推荐的做法呢?我总结了四个实践,你可以参考一下。
## 鼓励正向回溯和总结
从失败中学习是我们从小就懂的道理。**一个团队对待故障的态度,很大程度上就反映了他们对于持续改进的态度**。系统出现故障是谁都不愿意遇到的事情,但在真实世界中,这是没法避免的。
在很多公司里面,出现故障之后,有几种常见的做法:
- 把相关方拉到一起,定级定责,也就是确定问题级别和主要的责任方;
- 轻描淡写地回个改进邮件,但是没有明确的时间节点,即便有,也没人跟踪;
- 把问题归结为不可复现的偶发事故,最后不了了之。
与这些做法相比,更好的方法是建立一种正向回溯和总结的机制。也就是说,当问题发生之后,事先准备一份详尽的故障分析报告,并拉上相关方一起彻底分析问题的根因,并给出改进任务的具体时间点。
**故障回溯并不一定以确定责任为第一要务,更重要的是,要识别系统流程中的潜在问题和漏洞,并通过后续机制来进行保障**,比如增加测试用例、增加产品走查事项等等。
**其实,大到线上故障,小到日常错误,都值得回溯和总结**
比如,我们每天都会遇到形形色色的编译错误,如果每个人遇到同样的问题,都要爬一次同样的坑,显然是非常低效的。
这就需要有团队来负责收集和总结这些常见的错误,并提取关键错误信息和常见解决方法,形成一个案例库。同时,在构建系统中嵌入一个自动化服务,下次再有人遇到编译错误的时候,就可以自动匹配案例库,并给他推送一个问题分析报告和解决建议,帮助团队成员快速解决问题。
这样随着团队智慧的不断积累越来越多的问题会被识别出来从而实现组织知识共享和研发辅助的能力这在很多大公司里面都是一个重点建设方向。仔细想想这本身就是一个PDCA的过程。
不过,这里要补充一点,团队实施持续改进的过程,不应该是一次大而全的变革,而应该是一系列小而高频的改进动作。因为大的变革往往影响众多,很容易半途而废,而小的改进更加温和,也更加容易成功。为了方便你理解,我跟你分享一张示意图。
<img src="https://static001.geekbang.org/resource/image/07/b4/076bbd81826e4f506232b4ec390899b4.png" alt="">
## 预留固定时间进行改进
很多时候团队都处于忙碌的状态时间似乎成了推行DevOps的最大敌人。于是团队就陷入了一种太忙以至于没时间改进的状态中。
如果团队选择在同等时间内去做更多的功能那就说明至少在当前这个阶段业务开发的重要性要高于DevOps建设的重要性。
可问题是业务的需求是没有止境的。有时候我去问一线员工“你觉得有什么地方是DevOps可以帮你的吗”要么大家会说“没什么特别的现在挺好”要么就是一些非常琐碎的点。实际上这只能说明要么是没想过这个事情要么就是不知道还有更好的做法。但是如果不能调动一线员工的积极性持续改进也就无从谈起了。
所以,正确的做法是,在团队的日常迭代中,事先给改进类工作预留一部分时间,或者是在业务相对不那么繁忙的时候(比如大促刚刚结束,团队在调整状态的时候),在改进工作上多花些时间。
这些工作量主要用于解决非功能需求、技术改进类问题,比如修复技术债务、单元测试用例补充、度量识别出来的改进事项等。通过将这部分改进时间固定下来,可以培养团队持续改进的文化。
我比较推荐的做法是,**在团队的Backlog中新增一类任务专门用于记录和跟踪这类持续改进的内容**。在迭代计划会议上,对这类问题进行分析,并预估工作量,保证团队有固定的时间来应对这些问题。
另外很多公司也开始流行举办Hackathon Day黑客马拉松是说在有限的时间里通过编程实现自身的想法和创意在这个过程中充满了积极探索的精神、自由散发的思维和挑战极限的理念通过团队协作与互相激发实现创意到开发的全过程。
我们团队最近也在准备参加今年的黑客马拉松希望通过这个途径寻求合作共建除了解决内部效率提升的“老大难”问题还能提升团队成员的积极性在更大的舞台上展现DevOps的价值一举两得。
## 在团队内部共享业务指标
很多时候团队成员都像是临时工一样,对于自己所负责的需求和业务的表现一概不知。如果团队成员对一件事情没有归属感,那么又如何激发他们的责任感和自我驱动意识呢?
所以,对于业务的指标和表现,需要尽可能地在团队内部做到透明,让团队成员可以接触真实世界的用户反馈和评价,以及业务的度量信息。
在一个新功能开发完成上线之后,要能实时查看这个需求的上线状态。如果需求分析时已经关联了业务考核指标,那么,同样可以将该业务关联的指标数据进行展示。这样,研发就会知道自己交付的内容有多少问题,用户的真实反馈是怎样的,从而促使团队更多地站在用户的视角思考问题。
**除了业务指标DevOps的指标体系也应该对内部公开透明**。大家可以查看自己所在团队的表现,以及在公司内部的整体水平。
适当的侧向压力,会促使大家更加主动地接受改进工作,并且通过度量数据展示改进的效果,从而形成正向的循环。
## 激励创造性,并将价值最大化
每个团队中都不乏有创新意愿和思想的员工,他们总是能从墨守成规的规范中找到可以进行优化的点。
比如,之前,我们团队的一个测试人员发现,日常埋点测试费时费力,而且没有数据统计。于是,她就自己利用业余时间开发了一个小工具,用工具来承载这部分工作,效率大幅提升。
如果更多人知道这样的创新,并且在更大范围内使用,不仅可以提升更多人的效率,让团队整体受益,而且还可以减少类似的重复建设,让有想法的员工一起参与工具优化。
比较好的做法是,**在团队成员的绩效目标中,增加对团队贡献和技术创新的要求,在团队内部鼓励创新类工作**。另外,在团队内部建立对应的选拔和激励机制,为好的想法投入资源,把它们变成可以解决类似问题的工具。
很多公司也开始注意到这种**内部知识复用**的重要性,所以,无论是代码库开源,还是公共基础组件的市的建设,甚至是公司级的平台治理系统,都可以帮助你快速地复用已有的能力,避免一直重复造轮子。
## 总结
就像每个工程实践的终点都是持续改进一样,我们专栏的“工程实践篇”同样以持续改进的实践作为收尾。
我始终认为团队是否建立了持续改进的文化是评估团队的DevOps实践效果的重要参考。在这一讲中我给你介绍了PDCA的持续改进方法体系也就是通过计划、实施、检查、行动这四个步骤的持续迭代不断把团队推向更优的状态促使团队进入正向发展的车道。
另外我给你介绍了四个持续改进落地的方法包括在失败中总结和学习建立固定的改进时间在团队内部共享指标、培养团队的责任感以及激发团队的创造力并将价值最大化。这些方法的核心就是想打造一个学习型的组织和文化给DevOps的生根发芽提供丰饶的养分。
从下一讲开始,我们将进入“工具实践篇”,我会给你介绍一些核心工具的设计思想、建设路径,以及一些常见开源工具的使用方法等,敬请期待。
## 思考题
除了我提到的这四种持续改进的手段,你所在的公司,有什么活动可以促进持续改进文化的建设吗?
欢迎在留言区写下你的思考和答案,我们一起讨论,共同学习进步。如果你觉得这篇文章对你有所帮助,也欢迎你把文章分享给你的朋友。