92-DevOps实战笔记

开篇词 | 从默默无闻到风靡全球，DevOps究竟有什么魔力？

你好，我是石雪峰，目前在京东商城负责工程效率体系建设和平台研发。从业十多年，我一直在软件行业深耕，尤其是从 2015 年接触 DevOps 至今，我一直在企业内部从事 DevOps 的落地实践工作，也曾帮助多家大型企业进行 DevOps 的相关能力评估，积累了很多实战经验。

在写开篇词的时候，我才意识到，DevOps 从诞生至今已经整整十个年头了。十年之间，DevOps 从默默无闻到风靡全球，很多人都在反思和总结 DevOps 究竟有什么魔力。

十年前的 2009 年，我在一家日本软件公司工作，长期被外派到日本尼康公司做项目。虽然当时敏捷已经兴起，但在日本，软件开发还是瀑布模式的天下。每当一个新项目来临时，我们经常不分白天黑夜地埋头苦干几个月，完全不敢想象，如果不能顺利交付会怎么样。

可是，怕什么就来什么。有一次，我负责开发一款客户端软件，给客户交付的方式是事先刻录一张光盘，把光盘带去现场，一边部署，一边演示。刚开始还挺顺利的，可是到了生产数据拉取的环节，系统竟然异常退出了。我至今都还记得那位项目负责人不满的表情。

调试后我发现，客户的生产环境使用的是 Oracle 数据库，而我们使用的是微软的 Access 数据库，数据访问协议不一致，数据自然会同步失败。

之后的三个月，我总共休息了两天，每天的节奏就是吃饭睡觉写程序，干到搭乘最后一班电车回家，唯一的娱乐活动就是在吃加班餐的时候吐槽老板。

所以，当时我就在想，一定会有一种更好的软件开发方式，在这种方式下，团队间沟通和协作的重要性一点也不亚于写代码、写文档、做测试之类的常规工作。但我不知道的是，远在大洋彼岸，DevOps 的旅程才刚刚开始。

十年后，也就是 2019 年，以移动互联网、云计算、微服务、大数据、人工智能等为代表的技术日新月异，技术的迭代和演进都在以十倍速的方式向前发展，数字化转型浪潮正在席卷各行各业。“软件正在吞噬世界”“每一家企业终将成为软件企业”……行业领袖口中的这些预言，都在慢慢地变成现实。

如今，软件正在深刻地改变着我们的生活方式。前段时间，我去新疆旅行。在旅行途中，我发现即便是在沙漠边缘的小镇，微信支付也是畅通无阻。另外，用户喜新厌旧的成本已经低到可以忽略不计，企业之间的竞争已经升级为软件即服务的竞争。

所以，如何快速地持续交付高质量的软件，满足用户的多样化需求，并借此提升企业的利润和市场占有率，已经成为企业必须要面对的现实问题。

可问题是，现在很多企业采用的软件开发方式，同十年前我所在的公司其实并没有什么区别，甚至由于组织分工的细化，内部沟通的消耗成本更加高昂。

你应该也遇到过这样的场景吧？两个部门为了数据打通，来回拉锯，各种方案和排期一天一个样，还美其名曰“PK”。原本特别简单的一件事情，非要扯上几天甚至几周才能有点眉目。每当这个时候，我都忍不住想说：“嘿，兄弟，我不是来抢你饭碗的，我只是想通过系统间的打通来简化一些工作而已，何必搞得这么复杂呢？”

所以你看，软件开发过程的改进，除了依赖于技术进步，还依赖于流程、理念、文化等全方位的改进，而这正是 DevOps 带给软件开发方式的一场革命。

从 2017 年 DevOpsDays 大会北京站举办以来，DevOps 在国内的发展正式驶向了快车道。作为从业者之一，我深刻地感受到 DevOps 的影响力与日剧增，不仅仅是互联网行业，就连传统的电信、金融，甚至是政府机构，也都把 DevOps 作为核心能力在快速建设。

现在已经很少有人会问 DevOps 有什么用、DevOps 是否适合我之类的问题了，更多人开始关注要如何落地实践 DevOps，并且让 DevOps 充分发挥它的价值，真正改善软件交付方式，提高 IT 工程师的幸福指数。

除此之外，越来越多的企业开始招聘 DevOps 方面的人才，对 DevOps 的技能和经验背景的要求越来越高，DevOps 专家的岗位薪资甚至仅次于高级管理层，一跃成为 IT 行业的金字塔顶端。

我个人认为，DevOps 已经成为了所有 IT 从业人员应知应会的必备技能。在这些技能中，技术和实践当然非常重要，但文化和理念更是尤为珍贵。如果每个从业者都认同 DevOps 的文化和理念，认同快速交付价值远胜于部门间的零和博弈，认同我们应该共享一个目标，并从自身做起持续改善上下游的关系，那么，怎么可能还会出现刚刚我提到的 PK 的例子呢？

也许你从各种渠道了解过 DevOps 的相关信息，但是因为市场上资料庞杂、个人精力有限等原因，还存在着以下几个困惑：

如何梳理出一套清晰的 DevOps 理念和完整的知识体系？

如何获得一线大厂的实践经验，让 DevOps 真正落地？

如何获得一条渐进式的 DevOps 学习曲线，让自己在正确的方向上不断增值？

这些问题，正是多年来我一直在思考的，也希望在这个专栏中传递给你的核心内容。

学习 DevOps 的过程，对你来说将会是一场探索之旅。DevOps 涉及软件开发的方方面面，因此，你将漫步于需求、开发、测试、运维的完整开发流程，途经管理实践和工程实践的领域，探寻方法论、最佳实践和工具平台的有机结合方式，让自己在全栈工程师和斜杠青年的道路上更进一步。

DevOps 涉及的领域如此之广，想在一个专栏中学遍所有内容几乎是不可能的事情，所以我从实战的角度出发，臻选出最重要的内容，帮你梳理出一条 DevOps 的最佳学习路径。

本专栏主要由 4 个部分组成。

第 1 部分是“基础知识篇”。我将详细介绍 DevOps 的定义、价值、实施与衡量，在最开始帮你建立起正确的 DevOps 体系认知。

第 2 部分是“落地实践篇”。这一部分占据整个专栏一半的篇幅，是最核心的部分。我将带你通盘梳理 DevOps 的转型路径，你一定不要错过。

第 3 部分是“平台工具篇”。它涵盖平台建设的 3 个阶段、产品研发和设计、不可忽视的开源工具等，帮你找到快速搭建平台的钥匙。

第 4 部分是“转型案例篇”。我将分享 1～2 个实际案例，将前面提到的理论、落地实践和工具融入其中，让你能够融会贯通。

另外，我还设置了特别放送环节。在这个环节，我会跟你分享一些经典的学习资料、DevOps 工程师的必备技能等内容，让你全方位、多层次地掌握 DevOps。

其实，整个专栏的整理和写作，对我来说也是一场修行。毕竟，作为 DevOps 多年的实践者，我在用它解决问题的同时也发现了更多的问题，好奇心和对效率建设的执着追求让我乐此不疲。现在能够静下心来，把我多年的经验与反思整理出来跟你分享，也是一件非常有意义的事情。

在这个过程中，我也越发地感受到，DevOps 的思想和文化的落地依然任重道远。每个时代都会有一群先锋走在时代的前沿，中流击水，鹰击长空，希望通过本专栏的学习，你也可以成为 DevOps 的思想者和实践者，实现个人价值和企业价值的双赢。

最后，我想请你聊一聊，关于 DevOps，你都有哪些困惑？对于专栏，你又有哪些期待？欢迎你写在留言区，我们一起交流，期待你的反馈。

好了，从现在开始，就让我们一起踏上这场 DevOps 的奇妙旅程，一路同行，不断进步。

01 | DevOps的“定义”：DevOps究竟要解决什么问题？

你好，我是石雪峰。今天我们来聊一聊 DevOps 的“定义”。

近些年来，DevOps 在我们身边出现的频率越来越高了。各种大会上经常出现 DevOps 专场，行业内的公司纷纷在都招聘 DevOps 工程师，企业的 DevOps 转型看起来迫在眉睫，公司内部也要设计和开发 DevOps 平台……这么看来，DevOps 似乎无处不在。

可回过头来想想，关于 DevOps，很多问题我们真的想清楚了吗？所谓的 DevOps 平台，是否等同于自动化运维平台，或持续交付平台呢？DevOps 工程师的岗位描述中又需要写哪些技能要求呢？另外，该如何证明企业已经实现了 DevOps 转型呢？这些问题真是难倒了一众英雄好汉。说到底，听了这么久的 DevOps，它的“定义”到底是什么，好像从来没有人能说清楚。

现在，我们先来看看维基百科对 DevOps 的定义。不过，估计也没谁能看懂这到底是在说什么。

DevOps（开发 Development 与运维 Operations 的组合词）是一种文化、一场运动或实践，强调在自动化软件交付流程及基础设施变更过程中，软件开发人员与其他信息技术（IT）专业人员彼此之间的协作与沟通。它旨在建立一种文化与环境，使构建、测试、软件发布得以快速、频繁以及更加稳定地进行。

于是乎，每当提及 DevOps 是什么的时候，最常出现的比喻就是“盲人摸象”。有意思的是，DevOps 之父 Patrick 第一次参加 DevOpsDays 中国站活动的时候，也使用了这个比喻，看来在这一点上，中西方文化是共通的。毕竟每个人的视角都不相同，看到的 DevOps 自然也是千差万别。

DevOps 大潮汹涌而来，很多人都被裹挟着去探索和实践 DevOps，甚至有一种极端的看法认为一切好的实践都属于 DevOps，而一切不好的实践都是 DevOps 的反模式。

当年敏捷开始流行的时候，似乎也是相同的论调，但这种笼统的定义并不能帮助我们理清思路，甚至会带来很多负面的声音，比如 DevOps 就是开发干掉运维，又或者，DevOps 就是要让运维抛弃老本行，开始全面转型做开发。这让很多 IT 从业人员一度很焦虑。

客观来说，从 DevOps 运动诞生开始，那些先行者们就从来没有试图给 DevOps 下一个官方的定义。当然，这样做的好处很明显，由于不限定人群和范围，每个人都能从自己的立场来为 DevOps 做贡献，从而使 DevOps 所涵盖的范围越发宽广。

但是，坏处也是显而易见的。随着 DevOps 的不断发展，刚开始接触 DevOps 的人往往不得要领，只见树木不见森林，认知的偏差使得 DevOps 越发地神秘起来。

与其纠结于 DevOps 的定义，不如让我们一起尝试回归原始，来看看 DevOps 究竟要解决的是什么问题。

其实，DevOps 的秘密就来源于它的名字所代表的两种角色——开发和运维。那么这两种角色之间究竟有什么问题呢？我们从软件工程诞生以来所历经的三个重要发展阶段说起。

瀑布式开发模式

瀑布式开发模式将软件交付过程划分成几个阶段，从需求到开发、测试和运维，它的理念是软件开发的规模越来越大，必须以一种工程管理的方式来定义每个阶段，以及相应的交付产物和交付标准，以期通过一种重流程，重管控，按照计划一步步推进整个项目的交付过程。

可是，随着市场环境和用户需求变化的不断加速，这种按部就班的方式有一个严重的潜在问题。

软件开发活动需要在项目一开始就确定项目目标、范围以及实现方式，而这个时间点往往是我们对用户和市场环境信息了解最少的时候，这样做出来的决策往往带有很大的不确定性，很容易导致项目范围不断变更，计划不断延期，交付上线时间不断推后，最后的结果是，即便我们投入了大量资源，却难以达到预期的效果。

从业界巨头 IBM 的统计数字来看，有 34% 的新 IT 项目延期交付，将近一半的应用系统因为缺陷导致线上回滚，这是一件多么令人沮丧的事情。

敏捷式开发模式

基于这种问题，敏捷的思潮开始盛行。它的核心理念是，既然我们无法充分了解用户的真实需求是怎样的，那么不如将一个大的目标不断拆解，把它变成一个个可交付的小目标，然后通过不断迭代，以小步快跑的方式持续开发。

与此同时，将测试工作从研发末端的一个独立环节注入整个开发活动中，对开发交付的内容进行持续验证，保证每次可交付的都是一个可用的功能集合，并且由于质量内建在研发环节中，交付功能的质量也是有保障的。

很显然，敏捷是一种更加灵活的研发模式。经常有人会问，敏捷会直接提升团队的开发速度吗？答案是否定的。试想一下，难道说采用了敏捷方法，研发编码的速度就会提高两倍甚至三倍吗？回想一下很多年前在 IT 行业广为流传的“人月神话”，我们就能发现正确的认知有多么重要。

敏捷之所以更快，根本原因在于持续迭代和验证节省了大量不必要的浪费和返工。关于这一点，我会在敏捷和精益的相关内容中做更加详细的介绍。

说到底，敏捷源于开发实践，敏捷的应用使得开发和测试团队抱团取暖。可是问题又来了，开发和测试团队发现，不管研发的速度变得多快，在软件交付的另一端，始终有一群人在冷冰冰地看着他们，一句“现在没到发布窗口”让多少新开发的功能倒在了上线的门槛上。

毕竟，无论开发了多少“天才”的功能，如果没有经过运维环节的部署上线，并最终发布给真实用户，那么这些功能其实并没有什么用。

DevOps 模式

于是，活在墙的另一端的运维团队成了被拉拢的对象。这些在软件交付最末端的团队始终处于一种“背锅”的状态，他们也有改变的意愿，所以 DevOps 应运而生，也就是说，DevOps 最开始想要打破的就是开发和运维之间的对立和隔阂。

在传统模式下，度量开发团队效率的途径就是看开发完成了多少需求。于是，开发为了达成绩效目标，当然也是为了满足业务需求，不断地堆砌新功能，却很少有时间认真思考这些功能的可运维性和可测试性，只要需求状态流转到开发完成就万事大吉了。

而对于运维团队而言，他们的考核指标却是系统的稳定性、可用性和安全性。但现代 IT 系统是如此复杂，以至于每一次的上线发布都是一场战役，整个团队如临大敌，上线失败的焦虑始终如影随形。

很多时候，我们并不知道上线之后会发生什么，只能按照部署手册一步步操作，完成之后就听天由命。所以，每逢大促活动，就会有各种“拜服务器教”的照片广为流传。

另一方面，在无数次被开发不靠谱的功能缺陷蹂躏得体无完肤之后，运维团队意识到，变更才是影响他们绩效目标的最大敌人。于是，预先设立的上线窗口就成了运维团队的自留地，不断抬高的上线门槛也使得开发团队的交付变成了不可能完成的任务，最后，“互相伤害”就成了这个故事注定的结局。

即便到了今天，部署上线在大多数公司依然是一件很神圣的事。我给你讲一件有趣的事情。

去年我在欧洲拜访 DevOps 之父 Patrick 的时候，曾经去过他的公司。那天风雪交加，比利时根特显得非常冷清。我们停好车后，刚要推门进入他们公司，恰好碰到 Patrick 和他的一个同事下楼抽烟。

简单寒暄之后，我们才知道，原来 Patrick 公司负责的一个系统要在 15 分钟后上线，他们趁这个间歇出来换换脑子，然后再回去大干一场。所以你看，连 DevOps 之父在面临上线的时候都如此正式，可见，DevOps 的发展之路依然任重而道远啊。

从一开始想要促进开发和运维的协作，团队慢慢发现，其实在整个软件交付过程中，不仅只有开发和运维，业务也是重要的一环。

比方说，如果业务制定了一个不靠谱的需求，那么无论开发和运维怎样协作，得到的终究是一个不靠谱的结果，以及对人力的浪费。可是业务并不清楚用户的真实情况，于是运维团队慢慢转向运营团队，他们需要持续不断地把线上的真实数据和用户行为及时地反馈给需求团队，来帮助需求团队客观评估需求的价值，并及时作出有利于产品发展的调整，这样一来，业务也被引入到了 DevOps 之中，甚至诞生了 BizDevOps 这样一个专门的词汇。

那么，既然沟通协作放之四海皆准，安全也开始积极地参与进来。安全不再是系统上线发布之后的“定时炸弹”，而是介入到整个软件开发过程中，在每个过程中注入安全反馈机制，来帮助团队在第一时间应对安全风险，那么，对于安全团队来说，DevSecOps就成了他们眼中的 DevOps。

这样的例子比比皆是，包括职能部门、战略部门等，都纷纷加入其中，使得 DevOps 由最开始的点，扩展为线，再到面，不断发展壮大。每个人都参与其中，这使得 DevOps 成了每一个 IT 从业人员都需要学习和了解的知识和技能体系。

说到最后，我还是希望基于我对 DevOps 的理解，给出一个我自己的“定义”：

DevOps 是通过平台（Platform）、流程（Process）和人（People）的有机整合，以 C（协作）A（自动化）L（精益）M（度量）S（共享）文化为指引，旨在建立一种可以快速交付价值并且具有持续改进能力的现代化 IT 组织。

总结

今天，我带你一起梳理了 DevOps 的发展历程，以及软件开发模式的变迁。有人说，DevOps 是软件工程发展至今的第三次革命，可见它带给整个行业的影响是很深远的。人云亦云并不能帮助我们更好地理解 DevOps，建立正确的认知才是体系化学习的第一步，希望你能通过今天的课程，建立起你自己对于 DevOps 的独特认知。

思考题

最后，给你提一个问题：我给出的定义符合你心目中对 DevOps 的预期吗？DevOps 具有与生俱来的开放性，你能谈一谈你对 DevOps 的理解和定义吗？

欢迎在留言区写下你的思考和答案，我们一起讨论，共同学习进步。如果你觉得这篇文章对你有所帮助，欢迎你把文章分享给你的朋友。

02 | DevOps的价值：数字化转型时代，DevOps是必选项？

你好，我是石雪峰。今天我们来聊聊 DevOps 的价值。

前段时间，因为工作的缘故，我参访了一家在国内数一数二的金融企业。在跟他们科技处的同事交流的过程中，有一件事情让我非常吃惊，想跟大家分享一下。

虽然在一般人眼中，这家企业是典型的传统企业，但他们的绩效目标采用的却是OKR 模式。

我简单介绍一下 OKR。OKR 也就是目标与关键成果法，是在硅谷互联网公司很流行的绩效制定方法。简单来说，O 代表目标，也就是我们要做什么，KR 代表关键结果，用于验证我们是否已经达到了目标。

这家金融企业的大老板，也就是科技处的老大，给全体员工制定的众多 OKR 中，有且只有一条属于愿景指标。说出来你可能不相信，这个愿景指标就是，到今年年底，让 DevOps 在全行的三个试点项目中成功落地。

而且，这并不是简单的说说而已，如果最终达成了这个愿景指标，所有员工的年终奖将在原有的基础上上浮 10%～20%。由此可见，关于实施 DevOps，他们是在玩真的了。

全行的核心系统改造都没能成为愿景指标，那为啥 DevOps 会有如此大的魔力，让大老板都为之着迷，并且成为愿望清单列表中的第一名呢？这就是我今天要跟大家讨论的话题：DevOps 的价值以及它对现代企业的意义。

如果要选一个近年来在各大企业战略中曝光率最高的关键词，数字化转型绝对是排名最高的，没有之一。

比如，传统汽车巨头大众公司今年宣布启动全面数字化转型，计划到 2023 年年底投资约 40 亿美元，实现管理和生产的数字化。而且，预计到 2025 年，大众集团的软件研发的比例将从目前的不到 10% 增长到 60%。

为什么软件如此重要？

对于软件从业人员来说，这绝对是令人欢欣鼓舞的事情。同时，这也再一次印证了那句流传已久的名言，每一家公司都将成为软件公司。那么问题来了，在数字化转型时代，为什么软件会如此重要呢？

互联网的普及和移动通讯技术的发展所带来的移动互动网的兴起，深刻地影响了我们每个人的生活方式。

举个最简单的例子，几年前如果我们要办理银行业务，我们首先要找到附近的营业厅，抽空跑过去排号，经过很长时间的等待，才能坐到柜台前，同银行的柜员面对面地完成业务办理。当然这还是在顺利的情况下，如果忘记带证件或者排队人太多，可能还要再跑一次，办事成本相当高。

现在呢，大多数情况下，我们只要掏出手机，打开银行的 APP，点击几下屏幕，业务就办好了，完全不用受时间和空间的限制。用户对银行服务的体验直接来源于手机应用本身。如果哪家银行的应用界面很丑，操作还总是出现各种问题，就会直接影响用户对这家银行的印象，甚至会在潜意识里觉得这家银行不靠谱。显然，没有任何一家银行愿意给人留下这样的印象。

所以，软件慢慢从企业内部的支撑系统和成本中心，变成了企业服务的直接载体和利润中心。企业通过软件降低运营成本，提升服务水平，而用户在获得便利的同时，也加强了同企业之间的联系。

这本是一件双赢的事情，可问题是，我们所身处的是一个VUCA的时代，VUCA 是指易变性（Volatility）、不确定性（Uncertainty）、复杂性（Complexity）和模糊性（Ambiguity），它代表了这个时代的典型特征。比如共享单车这个行业从冉冉兴起炙手可热，到逐渐归于平静，前后不过短短几年的时间。

企业能快速满足用户的需求，在行业大势之下灵活转身，在跨界打击越发普遍的情况下脱颖而出，已经不仅仅是 good to have 的能力，而是 must have 的能力。

可以说，软件交付的效率和质量成了当今企业的核心价值和核心竞争力，所以，任何一家企业，无论是行业巨头还是初创公司，无论是互联网行业还是传统行业，无论是领先者还是颠覆者，都有强烈的意愿去改善自身的软件交付能力，而这恰恰和 DevOps 的理念和诞生背景不谋而合。这么看来，DevOps 能够成为企业愿望清单中的第一名也就不足为奇了吧。

可是，即便软件如此重要，却依然有很多公司在用一种手工作坊的方式开发软件，引用国家智库的某位领导的话来说，“工业革命消灭了绝大多数的手工业群体，却催生了程序员这个现存最大的手工业群体”。这句话看似危言耸听，但这种开发软件的方式的确存在，其中伴随着大量的效率浪费。企业内部的软件开发交付效率已经成了一座值得探索挖掘的金矿，效率经济可能成为新的业绩增长点。

DevOps 的价值

那么，实施 DevOps 带给企业的价值究竟是什么呢？要回答这个问题，我们就不得不提到 DevOps 业内非常著名的现状调查报告了。

高效的软件交付方式

从 2014 年至今，这个报告每年都会发布一份，由业内大咖和行业领袖基于科学的分析方法，通过大量的数据分析得出，可以说是业内最具权威性的报告，其中的很多数据和理念都被广为传播。我发现，在这洋洋洒洒大几十页的报告中，被引用频率或者说出镜率最高的，就是 DevOps 的 4 个结果指标。

部署频率：指应用和服务向生产环境部署代码的频率。

变更前置时间：指代码从提交到成功运行在生产环境的时长。

服务恢复时间：指线上应用和服务出现故障到恢复运行的时长。

变更失败率：指应用和服务在生产环境部署失败或者部署后导致服务降级的比例。

每年，这个报告都会基于这 4 个核心指标统计行业内高效能团队和低效能团队之间的差距。从去年的数据来看，与低效能团队相比，高效能团队的部署频率高了 46 倍，变更前置时间快了 2500 多倍，服务恢复时间也快了 2600 多倍，失败率低了 7 倍。

我们先不管这份数据是怎么计算出来的，当你第一次看到这个数据的时候，它带给你的冲击是不是很强大呢？用具体的数字形式来呈现企业之间效率的差距，是很有震撼力的。

而世界上最令人“绝望”的事情，就是那些比你优秀的人，实际上比你还要更加努力。当你仔细查看这份报告的时候，你会发现，那些常年被人提及的明星公司，很多都在践行 DevOps，甚至很多来源于这些公司的实践案例，都成为了 DevOps 行业的经典案例。

另一方面，DevOps 状态报告中提到的四项结果指标，分别代表了软件交付的两个最重要的方面，也就是交付效率和交付质量。而且，从数据结果中，我们还能得到一个惊人的发现，那就是高效能的组织不仅做到了高效率，还实现了高质量，由此可见，鱼与熊掌可以兼得。

可是，这就颠覆了很多人心目中的“慢工出细活”的传统软件开发理念。因为按照传统软件开发的 V 模式来说，软件开发完成后，需要经过单元测试、集成测试、系统测试和验收测试等层层关卡，以此来保证软件的质量符合预期。但是，对于现代软件开发而言，如此重的流程和管控显然有点跟不上时代的节奏。

我们在不断提高软件交付效率时，往往是以牺牲质量为代价的，结果做得越多，错得越多，从而陷入进退两难的境地。

DevOps 却反其道而行之，它试图通过体系化的研发实践导入、软件架构的整体革新、组织管理理念的不断升级和企业文化的影响塑造，来帮助企业改善整个软件交付过程，在实现高吞吐量的同时保证服务的总体稳定性，从而真正实现又快又好的软件交付目标。

激发团队的创造力

我们刚刚谈到的这些内容，当然是 DevOps 带给企业的重要价值，但并非全部。在专栏中，我不仅希望能跟你分享知识，还希望能跟你分享一些不同的观点，我们一起思考和讨论，获取灵感和新知。

之前，我在跟 Jenkins 创始人 KK 聊天的时候，他提出过这样一个问题：熟悉云计算的同学可能或多或少地了解过容器编排领域的事实标准 Kubernetes 以及它背后的 CNCF 基金会，那么，企业为什么热衷于加入这样的基金会呢？即使要付出一笔不菲的费用也在所不惜，企业这么做的收益究竟是什么？

不可否认，CNCF 是一个非常成功的运营案例，成为会员还能享受白纸黑字上的福利，但是，对于很多中小企业而言，他们的诉求可能不止如此。

很多时候，企业加入这样的组织，也是为了向内部员工表态，我们正和世界上最著名的公司站在同一条起跑线上，关注着同样的问题。这对他们的员工来说，既能起到激励作用，也能增强对企业自身的信心。

对于 DevOps 而言，道理也是同样的，因为说到底，企业的问题都是人的问题，最核心的价值最终都会归结到人身上，所以，单纯关注软件交付的能力而忽视人的感受，结果往往都是片面的。

在企业内部建设 DevOps 工具平台的时候，我也经常在思考这个问题，我们费尽心思通过平台能力建设提升了 5% 的交付效率，即便节省下来的时间只是让员工多休息了一会儿，也是非常有意义的事情。因为DevOps 本身也包含了改善软件从业人员的生存状态，提升他们的幸福水平的理念。

这么看来，实施 DevOps，一方面可以通过种种流程优化和自动化能力，改善软件开发团队的工作节奏，另一方面，也可以让大家关注同一个目标，彼此信任，高效协作，调动员工的积极性和创新能力，从而让整个团队进入一种积极创造价值的状态，而这所带来的影响远非建设一两个工具平台可比拟的。

总结

DevOps 作为软件工程的第三次革命，在数字化转型的大潮之下，几乎成了所有通过交付软件来提供服务的企业的必选项。因为，DevOps 不仅可以改善企业的软件交付过程，实现高质量和高效率兼得，同时也可以持续改善企业内部的工程师文化，提升员工信心，激发员工的活力和价值创造，从而帮助企业在 VUCA 时代占得先机，获得更大的成功。如果一家企业真的可以通过 DevOps 落地达到以上目标，而只需要多付出 10%～20% 的年终奖，岂不是大大赚到了吗？

思考题

最后，给你留一个思考题：如果你觉得 DevOps 可以解决公司现有的问题，想要跟领导申请立项的话，你会如何说明 DevOps 的价值呢？

欢迎在留言区写下你的思考和答案，我们一起讨论，共同进步。如果你觉得这篇文章对你有所帮助，欢迎你把文章分享给你的朋友。

03 | DevOps的实施：到底是工具先行还是文化先行？

你好，我是石雪峰。

当一家企业好不容易接纳了 DevOps 的思想，并下定决心开始实施的时候，总会面临这样一个两难的选择：工具和文化，到底应该哪个先行？

的确，在 DevOps 的理论体系之中，工具和文化分别占据了半壁江山。在跟别人讨论这个话题的时候，我们往往会划分为两个不同的“阵营”，争论不休，每一方都有自己的道理，难以说服彼此。在 DevOps 的世界中，工具和文化哪个先行的问题，就好比豆浆应该是甜的还是咸的一样，一直没有一个定论。

可是，对于很多刚刚接触 DevOps 的人来说，如果不把这个问题弄清楚，后续的 DevOps 实践之路难免会跑偏。所以无论如何，这碗豆浆我先干为敬，今天我们就先来聊聊这个话题。

DevOps 工具

随着 DevOps 理念的深入人心，各种以 DevOps 命名的工具如雨后春笋般出现在我们身边，甚至有很多老牌工具，为了顺应 DevOps 时代的发展，主动将产品名称改为 DevOps。最具代表性的，就是去年 9 月份微软研发协作平台 VSTS（Visual Studio Team Services）正式更名为 Azure DevOps，这也进一步地印证，DevOps 已经成为了各类工具平台建设的核心理念。

在上一讲中，我提到高效率和高质量是 DevOps 的核心价值，而工具和自动化就是提升效率最直接的手段，让一切都自动化可以说是 DevOps 的行为准则。

一切软件交付过程中的手动环节，都是未来可以尝试进行优化的方向。即便在运维圈里面，ITIL（IT 基础架构库) 一直是运维赖以生存的基石，也并不妨碍自动化的理念逐步深入到 ITIL 流程之中，从而在受控的基础上不断优化流程流转效率。

另外，正因为所有人都认可自动化的价值，工具平台的引入和建设就成为了 DevOps 打动人的关键因素之一。

同时，现在业界的很多开源工具已经相当成熟，以 Netflix、Amazon、Etsy 等为代表的优秀公司也在不断将内部的工具平台进行对外开放，各方面的参考资料和使用案例比比皆是。

无论是单纯使用，还是基于这些工具进行二次开发，成本都已经没那么高了，一个稍微成熟点的小团队可以在很短的时间内完成一款工具的开发。以我之前所在的团队为例，从 0 开始组建到第一款产品落地推广，前后不过两个多月的时间，而且与业内的同类产品相比较，毫不逊色。

不过，这也带来一个副作用，那就是企业内部的工具平台泛滥，很多同质化的工具在完成从 0 到 1 的过程后就停滞不前，陷入重复的怪圈，显然也是一种资源浪费。

当然，对于工具决定论的支持者来说，这并不是什么大问题，因为引入工具就是 DevOps 的最佳实施路径。

有时候，当你问别人“你们公司的 DevOps 做得怎么样啦？”你可能会得到这样的回答：“我们的所有团队都已经开始使用 Jenkins 了。”听起来感觉怪怪的。如果只是使用了最新最强大的 DevOps 工具，就能实现软件交付效率的腾飞，那么世界 500 强的公司早就实现 DevOps 了。

很多公司引入了完整的敏捷项目管理工具，但是却以传统项目管理的方式来使用这套工具，效率跟以前相比并没有明显的提升。对于自研平台来说，也是同样的道理。如果仅仅是把线下的审批流程搬到线上执行，固然能提升一部分执行效率，但是对于企业期望的质变来说，却是相距甚远。

说到底，工具没法解决人的问题，这样一条看似取巧的路径，却没法解决企业的根本问题。这时候，就需要文化闪亮登场了。

DevOps 文化

在谈论 DevOps 文化之前，我先跟你分享一个故事。

上世纪 80 年代，美国加州有一家汽车制造公司，叫作 NUMMI。当时这家公司隶属于通用公司，但是由于劳资关系紧张，这家公司一直以来都是通用旗下效益最差的公司。员工整天上班喝酒，赌博，整个工厂乌烟瘴气，旷工率甚至一度达到了 20%。通用公司忍无可忍，最后关闭了这家公司。

后来，日本丰田公司想在美国联合建厂，于是跟通用达成了合资协议。美国联合汽车工会（UAW）希望新公司可以重新雇佣之前遭到解雇的员工，通用公司本来不想接受，但是令人惊讶的是，丰田公司却同意了。因为他们认为，NUMMI 工厂之前的情况更多是系统的原因，而不是人的原因。

接下来，丰田公司将新招募的员工送到日本进行培训。短短三个月后，整个公司的面貌焕然一新，半年后，一跃成为整个通用集团效益最好的公司。

由此可见，在不同的文化制度下，相同的人发挥出来的生产力也会有天壤之别。

类似的故事并非个例，曾经有一群美国专家到日本参观和学习生产流水线，他们发现了一件有趣的事情。

在美国公司的生产线里面，总有一个人拿着橡胶的锤子在敲打车门，目的是检查车门是否安装完好。但即便如此，车门的质量依然很差。可是，在日本公司的工厂里面，却没有这样的角色。

他们就好奇地问道：“你们如何保障车门没有问题呢？”日方的专家回复说：“我们在设计车门的时候，就已经保证它不会出问题了。”你看，同样是采用流水线技术的两家公司，结果却大不相同。

类比 DevOps，如果在我们的软件交付过程中，始终依靠这个拿锤子的人来保障产品的质量，出了问题总是抱怨没有会使用锤子的优秀人才，或许这个流程本身就出了问题。

回到文化本身，良好的文化不仅可以让流程和工具发挥更大的作用，更重要的是，它能够诱发人们思考当前的流程和工具哪里是有问题的，从而引出更多有关流程和工具的优化需求，促使流程和工具向更加有力的支持业务发展的方向持续改进。

可是，企业内部的 DevOps 文化本身就是虚无缥缈的事情，你很难去量化团队的文化水平，进而改变企业的文化。盲目地空谈文化，对组织也是一种伤害。因为脱离实践，文化就会变成无根之水。当组织迟迟无法看到 DevOps 带来的实际收益时，就会丧失转型的热情和信心。

所以，我们需要先改变行为，再通过行为来改变文化。而改变行为最关键的，就是要建立一种有效的机制。就像我一直强调的那样，机制就是人们愿意做，而且做了有好处的事情。

回想之前提到的某金融公司的案例，如果他们的老板只是喊了句口号“我们要在年底完成 DevOps 试点落地”，那么年底即便项目成功，本质上也不会有什么改变。相反，他们在内部建立了一种机制，包括 OKR 指标的设定、关键指标达成后的激励、成立专项的工作小组、引入外部的咨询顾问，以及一套客观的评判标准，这一切都保证了团队走在正确的道路上。而承载这套客观标准的就是一套通用的度量平台，说到底，还是需要将规则内建于工具之中，并通过工具来指导实践。

这样一来，当团队通过 DevOps 获得了实实在在的改变，那么 DevOps 所倡导的职责共担、持续改进的文化自然也会生根发芽。

所以你看，DevOps 中的文化和工具，本身就是一体两面，我们既不能盲目地奉行工具决定论，上来就大干快干地采购和建设工具，也不能盲目地空谈文化，在内部形成一种脱离实际的风气。

DevOps 的 3 个支柱

对工具和文化的体系化认知，可以归纳到 DevOps 的 3 个支柱之中，即人（People）、流程（Process）和平台（Platform）。3 个支柱之间两两组合，构成了我们实施 DevOps 的“正确姿势”，只强调其中一个维度的重要性，明显是很片面的。

人 + 流程 = 文化

在具体的流程之下，人会形成一套行为准则，而这套行为准则会潜移默化地影响软件交付效率和质量的方方面面。这些行为准则组合到一起，就构成了企业内部的文化。

一种正向的文化可以弥合流程和平台方面的缺失，推动二者的持续改进，同时可以让相同的流程和平台在不同的人手中产生迥异的效果。就好像《一代宗师》里面的那句经典台词：“真正的高手，比拼的不是武功，而是思想。”而指导 DevOps 落地发展的思想，就是 DevOps 的文化了。

举个例子，在谷歌 SRE 的实践中，研发交付的应用需要自运维一段时间，并且要在达到一定的质量指标之后才会交接给 SRE 进行运维。但是，为了避免出现“研发一走，运维背锅”的情况，他们还建立了“打回”的流程，也就是当 SRE 运维一段时间后，如果发现应用稳定性不达标，就会重新交还给开发自己负责维护，这样一来，研发就会主动地保障线上应用的质量。而且在这个过程，SRE 也会给予技术和平台方面的支持，从而形成了责任共担和质量导向的文化。

类似的，有些公司设有线上安全点数的机制，在一定的额度范围内，允许团队出现问题，并且不追究责任。这就可以激励团队更加主动地完成交付活动，不必每一次都战战兢兢，生怕出错。通过流程和行为的改变，团队的文化也在慢慢地改进。

由此看来，虽然我们很难直接改变文化，但是却可以定义期望文化下的行为表现，并通过流程的改进来改变大家的行为，从而让文化得以生根发芽，茁壮成长。

流程 + 平台 = 工具

企业内部流程的标准化，是构成自动化的前提。试想一下，如果没有一套标准的规则，每一项工作都需要人介入进行判断和分析，那么结果势必会受到人的因素的影响，这样的话，又如何做到自动化呢？

而平台的最大意义，就是承载企业内部的标准化流程。当这些标准化流程被固化在平台之中时，所有人都能够按照一套规则沟通，沟通效率显然会大幅提升。

平台上固化的每一种流程，其实都是可以用来解决实际问题的工具。很多人分不清工具和平台的关系，好像只要引入或者开发了一个工具，都可以称之为平台，也正因为这样，企业内部的平台比比皆是。

实际上，平台除了有用户量、认可度、老板加持等因素之外，还会有 3 个显著特征。

吸附效应：平台会不断地吸收中小型的工具，逐渐成为一个能力集合体。

规模效应：平台的成本不会随着使用方的扩展而线性增加，能够实现规模化。

积木效应：平台具备基础通用共享能力，能够快速搭建新的业务实现。

简单来说，平台就是搭台子，工具来唱戏。平台提供场所，进行宣传，吸引用户，同时还能提供演出的道具，以及数据方面的分析。观众的喜好各不相同，但是平台将各种戏汇集在一起，就能满足大多数人的需求。如果平台把唱戏的事情做了，难以聚焦“台子”的质量，就离倒闭不远了。同样，如果唱戏的整天琢磨着建平台，那么戏本身的品质就难以不断精进。所以是做平台，还是做工具，无关好坏，只关乎选择。

平台 + 人 = 培训赋能

平台是标准化流程的载体，一方面可以规范和约束员工的行为，另一方面，通过平台赋能，所有人都能以相同的操作，获得相同的结果。这样一来，跨领域之间的交接和专家就被平台所取代，当一件事情不再依赖于个人的时候，等待的浪费就会大大降低，平台就成了组织内部的能力集合体。

但与此同时，当我们定义了期望达到的目标，并提供了平台工具，那么对人的培训就变得至关重要，因为只有这样，才能让工具平台发挥最大的效用。更加重要的是，通过最终的用户使用验证，可以发现大量的可改进空间，进一步推动平台能力的提升，从而带动组织整体的飞轮效应，加速组织的进化。

所以你看，文化、工具和培训作为 DevOps 建设的 3 个重心，折射出来的是对组织流程、平台和人的关注，三位一体，缺一不可。

最后，跟你分享一个关于美国第一资本的例子。他们最初在实施 DevOps 时，采用的是外包方式，修改一个很小的问题都需要走复杂的变更流程，需要几天的时间。后来，他们决定采用“开源为先”的策略，并且严格审查原本的商业采购流程。除此之外，他们还基于开源工具搭建自己的平台，并在公司内部进行跨领域角色的交叉培养，交付效率大幅提升，实现了从每天迭代一次到每天多次的线上部署。

总结

讲到这里，我们今天的专栏内容就到尾声了。在这一讲中，我跟你讨论了 DevOps 中的工具和文化的实际价值，以及潜在的问题和挑战，最终推导出 DevOps 的 3 个支柱，也就是人、流程和平台，这 3 个支柱缺一不可。只有通过人、流程和平台的有机结合，在文化、工具和人员培训赋能领域共同推进，才能实现 DevOps 的真正落地实施。

思考题

最后，给你留一个思考题：你们公司的哪些文化是非常吸引你的？这些文化对于 DevOps 的实施又有哪些帮助呢？

欢迎在留言区写下你的思考和答案，我们一起讨论，共同学习进步。如果你觉得这篇文章对你有所帮助，欢迎你把文章分享给你的朋友。

04 | DevOps的衡量：你是否找到了DevOps的实施路线图？

你好，我是石雪峰。今天我们来聊聊 DevOps 的实施路线图。

商业领域有一本特别经典的书，叫作《跨越鸿沟》，这本书中提出了一个“技术采纳生命周期定律”，对高科技行业来说，它的地位堪比摩尔定律。

简单来说，这个定律描述了一项新技术从诞生到普及要经历的 5 个阶段，这 5 个阶段分别对应一类特殊人群，即创新者、早期使用者、早期大众、晚期大众和落后者。这个定律表明，技术的发展不是线性的，需要经历一段蛰伏期，才能最终跨越鸿沟为大众所接受，成为业界主流。

当然，DevOps 这项所谓的新技术，在企业内部的落地也注定不是一帆风顺的。那么在这种情况下，你是否找到了 DevOps 的实施路线图呢？

从 2017 年第一届 DevOpsDays 大会中国站举办以来，DevOps 正式在国内驶入了发展的快车道。从一门鲜为人知的新技术思想，到现在在各个行业的蓬勃发展，各种思想和实践的激烈碰撞，DevOps 的理念和价值可谓是深入人心。

这样看来，DevOps 已经成功地跨越了技术发展的鸿沟，从早期使用者阶段进入了早期大众的阶段，而这也意味着越来越多的公司开始尝试 DevOps。

在 2017 年底，Forrester 的一组调查数据显示，将近 50% 的受访公司表示已经引入并正在实施 DevOps，30% 的公司表示有意向和计划来开启这项工作，而对 DevOps 完全不感兴趣的仅占 1%。可以说，2018 年就是企业落地 DevOps 的元年。

但是，就像你要去往一个未知的目的地时，需要导航帮你规划路径、实时定位，并在出现意外情况时及时提示你是否要重新规划路径一样，企业在实施 DevOps 的过程中，其实也面临着相似的问题。企业自身难以清晰定位 DevOps 的现状，客观评估 DevOps 相关的能力水平，识别当前所面临的最大瓶颈以及实施 DevOps 的阶段性成果预期……

回顾整个 IT 行业的发展历程，新思想和新技术的发展，总是同标准化的模型和框架相伴相生的。

我认为，任何技术的成熟，都是以模型和框架的稳定为标志的。因为当技术跨越初期的鸿沟，面对的是广大受众，如果没有一套模型和框架来帮助大众快速跟上节奏，找准方向，是很难大规模推广并健康发展的。

比如，软件开发领域的 CMMI 模型（软件能力成熟度模型）、运维行业的 ITIL 模型等，在各自的领域都久负盛名，甚至一度被各个领域的从业者奉为圭臬和行为准则，成为衡量能力高低的标尺。

我曾经在国内某大型通讯设备公司参与过 CMMI 评级项目。当时，就算业务压力再大，只要是关于通过评级的事情，所有部门都会高优先级支持。由此可见，整个公司都非常重视这个认证评级项目。

那么问题来了，在 DevOps 这项新思想和新技术不断走向成熟的过程中，是否也有类似的模型和框架，能够指导企业内部的 DevOps 转型落地工作呢？

答案是有的，而且有很多。只要你去谷歌上搜一下 DevOps 框架、模型等关键词，就能看到非常多的结果。尤其是国外的一些知名公司，比如 Atlassian、CloudBees、CA 等，基本上都有一套自己的模型和框架，来帮助企业识别当前的 DevOps 能力水平并加以改进。

我之前参与过工信部旗下的中国信息通讯研究院牵头制定的一套 DevOps 能力成熟度模型。这套模型覆盖了软件交付的方方面面，包括敏捷开发管理、持续交付和技术运营三大部分，同时，也有与应用架构设计、安全和组织结构对应的内容。

不仅如此，对于开发 DevOps 工具的企业来说，系统和工具模型更加偏向于平台能力，稍加整理就可以作为平台需求输入到开发团队中。目前已经有不少公司在参考这套模型进行 DevOps 实践。下图展示了这个模型的整体框架，如果你正在企业内部推进 DevOps 落地的话，可以参考一下。

步骤与原则

业界有这么多模型和框架，是不是随便找一个，直接照着做就行了呢？当然不是。

毕竟，每家企业所处的行业现状、竞争压力、市场竞争态势都不尽相同，组织架构、战略目标、研发能力、资源投入等方面也千差万别，很难有一条标准的路径，让大家齐步走。比如，同样是金融企业，让万人规模的大银行和百人规模的城商行同台竞技，本身就有点强人所难。

所以，在实际参考模型和框架的时候，我认为应该尽量遵循以下步骤和原则：

1.识别差距

从“道法术器”的角度来说，DevOps 的成熟度模型和框架处于“法”这个层面，也就是一整套实施 DevOps 的方法论，相当于是一幅战略地图，最重要的就是对 DevOps 实施所涉及到的领域和能力图谱建立全面的认知。

通过和模型、框架进行对标，可以快速识别出企业当前存在的短板和差距，并建立企业当前的能力状态基线，用于对比改进后所取得的效果。

2.锚定目标

数字化转型的核心在于优化软件交付效率。通过对标模型框架，企业需要明确什么是影响软件交付效率进一步提升的最大瓶颈，当前存在的最大痛点是什么，哪些能力的改善有助于企业达成预定的目标……同时，要根据企业的现状，甄别对标的差距结果，识别出哪些是真实有效的，哪些可以通过平台能力快速补齐。

比如，对于一家提供 CRM 软件的公司来说，容器化部署虽然在环境管理、部署发布等领域有非常多的优势，但并非当前的核心瓶颈和亟需解决的问题，那么就不应该纳入近期的改进列表中。

通过现状分析，企业可以把有限的资源聚焦在那些高优先级的任务上，识别出改进目标和改进后要达到的预期效果。这些效果需要尽量客观和可量化，比如缩短 50% 的环境准备时长。

3.关注能力

模型和框架是能力和实践的集合，也就是道法术器的“术”这个层面，所以在应用模型的过程中，核心的关注点应该在能力本身，而不是单纯地比较数字和结果。

比如，亚马逊每天 23000 次部署的案例经常会被拿来举例子。这个数字的确相当惊人，但反过来想想，所有企业都需要达到这么高的部署频率吗？举个例子，一个客户端应用可以在几分钟内构建完成，但同样是构建，对于大型系统软件来说可能需要几个小时，那么到底多长时间才算达标呢？

我们不能只关注这些明星企业所达到的成就，而忽略了自身的需求。所以，正确的做法是根据锚定的目标识别所需要的能力，再导入与能力相匹配的实践，不断强化实践，从而使能力本身得到提升。

4.持续改进

模型和框架本身也不是一成不变的，也需要像 DevOps 一样不断迭代更新，以适应更高的软件交付需要。另外，从今年的 DevOps 状态报告就可以看出，达到精英级别的比例从 2018 年的 7% 快速提升到 2019 年的 20%，也就是说，行业整体的能力也在不断提升，这就对企业的软件交付能力提出了更高的要求。

好了，以上这些就是我总结的企业应用 DevOps 能力模型和框架的步骤和原则。DevOps 作为一个系统性工程，同样需要与之配套的立体化实施方法，只有将方法、实践和工具结合起来，全方位推进，才有可能获得成效。

为了帮助你更好地理解 DevOps 实施的过程，我贴了一幅经典的部署引力图。

可以看出，当软件发布的频率从 100 天 1 次进化到 1 天 100 次的时候，分支策略、测试能力、软件架构、发布策略、基础设施能力，以及数据库能力都要进行相应的改动。比如分支策略要从长线分支变成基于特性的主干开发模式，而架构也要从大的单体应用，不断解耦和服务化。在实际应用中，企业涉及的领域甚至更多，因为这些仅仅是技术层面的问题，而组织文化方面也不可或缺。

实践案例

最后，我再跟你分享一个我之前参与改进的一个客户的案例。

刚开始跟这个客户交流的时候，他千头万绪，抓不准重点，甚至由于组织严格划分职责边界，基本上每讲到一块内容，他就要拉相应的人过来聊，在许多人都聊完之后，项目的全貌才被拼凑出来。我相信这并不是个例，很多公司其实都是如此。

于是，我们引入了能力成熟度模型，并基于模型对企业现有的能力水平进行了一次全盘梳理，并初步识别出了 100 多个问题点和 40 多个差距项。下面这张图就是汇总的大盘图，当然，部分数据进行了处理。

接下来，针对识别出来的这些差距点，我逐项跟企业进行了沟通，重点在于锚定一期的改进目标和具体工作事项。在沟通过程中，我发现由于企业所处行业的特殊性，或者客观条件不具备，有些内容并非优先改进事项，于是将改进事项缩减为 30 个，并识别出这些改进事项的相互依赖和预期目标。比如，这个企业之前初始化一套环境需要 2 周左右的时间，为了加快整体交付能力，我们将改进目标定到 1 周以内完成。

好啦，有了改进目标和预期效果之后，就要分析哪些关键能力制约了交付效率的提升。还拿刚才那个例子来说，核心问题在于环境的初始化过程复杂以及审批流程冗长。其中，原有的初始化过程是研发整理一份部署需求文档，来说明应用所依赖的环境和版本信息，并且这个需求还被整合到一个 40 多页的文档中。运维团队根据这个文档部署，每次都很不顺利，因为软件功能迭代所依赖的环境也在不断更新，但文档写出来就再也没人维护了。所以，很多人说文档即过时，就是这个道理。

识别出核心能力在于自动化环境管理之后，团队决定引入基础设施即代码的实践来解决这个问题。关于具体的技术细节，我会在后面的内容中展开，这里你只需要知道，通过将写在文档中的环境配置说明，转变成配置化的信息，并维护在专门的版本控制系统中，从而使得基础环境的初始化可以在分钟级完成。

当然，审批环境的优化属于非技术问题，而是流程和组织方面的问题。当大家认识到这些审批在一定程度上制约了发布频率的提升，就主动改进了现有流程。针对不同的环境进行不同级别的审批，使得单次审批可以在当天完成。

这样优化下来，环境准备的时长大大缩短，从当初的 2 周缩短到了 2 天，改进效果非常明显。接下来，团队又识别出新的差距，锚定新的目标和预期效果，并且有针对性地补齐能力建设，走上了持续改进的阶段。

由此可以看出，DevOps 的能力实践和能力框架模型相辅相成：能力实践定义了企业落地 DevOps 的路线图和主要建设顺序，能力模型可以指导支撑方法的各类实践的落地建设；能力实践时刻跟随企业价值交付的导向，而能力模型的积累和沉淀，能够让企业游刃有余地面对未来的各种挑战。

至于 ITIL 和 CMMI，这些过往的框架体系自身也在跟随 DevOps 的大潮在持续演进，比如以流程合规为代表的 ITIL 最近推出了第 4 个版本。我们引用一下 ITIL V4 的指导原则，包括：关注价值、关注现状、交互式流程和反馈、协作和可视化、自动化和持续优化、极简原则和关注实践。

看起来是不是有点 DevOps 的味道呢？需要注意的是，DevOps 不会彻底颠覆 ITIL，只会在保证合规的前提下，尽可能地优化现有流程，将流动、反馈和持续学习改进的方法注入 ITIL 之中，从全局视角持续优化企业的价值交付流程。

总结

总结一下，今天我给你介绍了新技术和新思想的发展需要面对的鸿沟，而能力模型和框架是技术和思想走向成熟的标志，对于 DevOps 而言，也是如此。在面对诸多模型和框架的时候，企业需要立足自身，识别差异，锚定目标，关注能力，并持续改善软件的开发交付效率。DevOps 的实施需要立体化的实施框架，通过模型、方法、能力和实践的相互作用，实现全方位的能力提升。

到此为止，我们整体介绍了 DevOps 的基本概念、核心价值、实施方法和路线图，帮助你建立了一套有关 DevOps 的宏观概念。接下来我们就会开始深入细节，尤其是针对每一项核心实践，我会介绍其背后的理念、实施步骤，以及所依赖的能力模型，手把手地帮助你真正落地 DevOps。

思考题

最后，给你留一道思考题：关于 CMMI、ITIL 和 DevOps，你觉得它们之间的关系是怎样的呢？企业该如何兼顾多套模型框架呢？

欢迎在留言区写下你的思考和答案，我们一起讨论，共同学习进步。如果你觉得这篇文章对你有所帮助，欢迎你把文章分享给你的朋友。

05 | 价值流分析：关于DevOps转型，我们应该从何处入手？

你好，我是石雪峰。

关于“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 点是你必须要了解的。

前置时间（Lead Time，简称 LT）。前置时间在 DevOps 中是一项非常重要的指标。具体来说，它是指一个需求从提出（典型的就是创建一个需求任务）的时间点开始，一直到最终上线交付给用户为止的时间周期。这部分时间直接体现了软件开发团队的交付速率，并且可以用来计算交付吞吐量。DevOps 的核心使命之一就是优化这段时长。

增值活动时间和不增值活动时间（Value Added Time/Non-Value Added Time，简称 VAT/NVAT）。在精益思想中，最重要的就是消除浪费，也就是说最大化流程中那些增值活动的时长，降低不增值活动的时长。在软件开发行业中，典型的不增值活动有很多，比如无意义的会议、需求的反复变更、开发的缺陷流向下游带来的返工等。

完成度和准确度（% Complete/Accurate，简称 %C/A）。这个指标用来表明工作的质量，也就是有多少工作因为质量不符合要求而被下游打回。这里面蕴含了大量的沟通和返工成本，从精益的视角来看，也是一种浪费。

在实践中，企业往往将需求作为抓手，来串联打通各个环节，而前置时间是需求管理的自然产物，采集的难度不在于系统本身，而在于各环节的操作是否及时有效。有的团队也在使用需求管理工具，但是前置时长大多只有几秒钟。问题就在于，他们都是习惯了上线以后，一下子把任务状态直接从开始拖到最后，这样就失去了统计的意义。

需要注意的是，关于前置时间，有很多种解释，一般建议采用需求前置时间和开发前置时间两个指标进行衡量，关于这两个指标的定义，你可以简单了解一下。

需求前置时间：从需求提出（创建任务），到完成开发、测试、上线，最终验收通过的时间周期，考查的是团队整体的交付能力，也是用户核心感知的周期。

开发前置时间：从需求开始开发（进入开发中状态），到完成开发、测试、上线，最终验收通过的时间周期，考查的是团队的开发能力和工程能力。

对于增值活动时长，我的建议是初期不用过分精细，可以优先把等待时长统计出来，比如一个需求从准备就绪，到进入开发阶段，这段时间就是等待期。同前置时间一样，很多时候，研发的操作习惯也会影响数据的准确性，比如有的研发喜欢一次性把所有的需求都放到开发阶段，然后再一个个处理掉，这就导致很多实际的等待时间难以识别。所以，如果完全依靠人的操作来确保流程的准确性，就会存在很大的变数。通过流程和平台的结合，来驱动流程的自动化流转，这才是 DevOps 的正确姿势。

举个例子，研发开发完成发起提测后，本次关联的需求状态可以自动从“开发中”变成“待测试”状态，而不是让人手动去修改状态，这样就可以避免人为因素的影响。通过代码，流水线和需求平台绑定，从而实现状态的自动流转。

关于完成度和准确度，在使用 VSM 的初期可以暂不处理。实际上，我见过一些公司在跑通主流程之后，着手建设质量门禁相关的指标，比如研发自测通过率，这些指标就客观地反映了 VSM 的完成度和准确度。关于质量门禁，在专栏后面我会花一讲的时间来介绍，你一定不要错过。

方式

关于 VSM 的关键要素，知道这些就足够了。那么作为企业 DevOps 转型工作的第一步，我们要如何开展一次成功的 VSM 活动呢？一般来说，有 2 种方式。

1.召开一次企业内部价值流程梳理的工作坊或者会议。

这是我比较推荐的一种方式。对于大型企业而言，可以选取改进项目对象中某个核心的业务模块，参加会议的人员需要覆盖软件交付的所有环节，包括工具平台提供方。而且，参会人员要尽量是相对资深的，因为他们对自身所负责的业务和上下游都有比较深刻的理解，比较容易识别出问题背后的根本原因。

不过，这种方式的实施成本比较高。毕竟，这么多关键角色能够在同一时间坐在一起本身就比较困难。另外，面对面沟通的时候，为了给对方保留面子，大家多少都会有所保留，这样就会隐藏很多真实的问题。

所以，一般情况下，像团队内部的敏捷回顾会，或者是版本发布总结会，都是很合适的机会，只需要邀请部分平常不参会的成员就行了。

2.内部人员走访。

如果第 1 种方式难以开展，你可以退而求其次地采用第 2 种方式。通常来说，企业内部的 DevOps 转型工作都会有牵头人，甚至会成立转型小组，那么可以由这个小组中的成员对软件交付的各个环节的团队进行走访。这种方式在时间上是比较灵活的，但对走访人的要求比较高，最好是 DevOps 领域的专家，同时是企业内部的老员工，这样可以跟受访人有比较深入坦诚的交流。

无论哪种方式，你都需要识别出几个关键问题，缩小谈话范围，避免漫无目的地东拉西扯，尽量做到有效沟通。比如，可以建立一个问题列表：

在价值交付过程中，你所在团队的主要职责是什么？

你所在团队的上下游团队有哪些？

价值在当前环节的处理方式，时长是怎样的？

有哪些关键系统支持了价值交付工作？

是否存在等待或其他类型的浪费？

工作向下游流转后被打回的比例是多少？

为了方便你更好地理解这些问题，我给你提供一份测试团队的访谈示例。

通过访谈交流，我们就可以对整个软件交付过程有一个全面的认识，并根据交付中的环节、上下游关系、处理时长、识别出来的等待浪费时长等，按照 VSM 模型图画出当前部门的价值流交付图，以及各个阶段的典型工具，如下图所示：

当然，实际交付流程相当复杂，涉及到多种角色之间的频繁互动，是对 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 转型之旅。

思考题

最后，给你留一道思考题：你认为在公司内部梳理价值流的最大障碍是什么？在提取价值流图中的 3 个关键要素的数据时，你遇到过什么挑战吗？

欢迎在留言区写下你的思考和答案，我们一起讨论，共同学习进步。如果你觉得这篇文章对你有所帮助，欢迎你把文章分享给你的朋友。

06 | 转型之路：企业实施DevOps的常见路径和问题

你好，我是石雪峰。今天我来跟你聊聊企业实施 DevOps 的常见路径和问题。

由于种种原因，我曾直接或者间接地参与过一些企业的 DevOps 转型过程，也跟很多企业的 DevOps 负责人聊过他们的转型故事。这些企业的转型过程并不是一帆风顺的，在最开始引入 DevOps 的时候，他们也面临很多普遍的问题，比如企业业务都忙不过来了，根本没有时间和精力投入转型工作之中，或者是企业内部的系统在经历几代建设之后变得非常庞大，以至于谁都不敢轻易改变。

但是，即便存在着种种问题，我也始终认为，DevOps 转型之路应该是有迹可循的。很多企业所面临的问题并不是独一无二的，甚至可以说，很多公司都是这样一步步走过来的。所以，在转型之初，如果能够参考借鉴一条常见的路径，并且对可能遇到的问题事先做好准备，企业的转型过程会顺利很多。

两种轨迹

其实，对于企业的转型来说，DevOps 也并没有什么特别之处，跟更早之前的敏捷转型一样，如果想在企业内部推行一种新的模式，无外乎有两种可行的轨迹：一种是自底向上，一种是自顶向下。

自底向上

在这种模式下，企业内部的 DevOps 引入和实践源自于一个小部门或者小团队，他们可能是 DevOps 的早期倡导者和实践者，为了解决自身团队内部，以及上下游团队交互过程中的问题，开始尝试使用 DevOps 模式。由于团队比较小，而且内部的相关资源调动起来相对简单，所以这种模式比较容易在局部获得效果。

当然，DevOps 的核心在于团队间的协作，仅仅一个小团队内部的改进还算不上是 DevOps 转型。但是，就像刚刚提到的那样，如果企业太大以至于很难一次性改变的话，的确需要一些有识之士来推动这个过程。如果你也身处在这样一个团队之中，那么我给你的建议是采用“羽化原则”，也就是首先在自己团队内部，以及和自己团队所负责的业务范围有强依赖关系的上下游团队之间建立联系，一方面不断扩展自己团队的能力范围，另一方面，逐步模糊上下游团队的边界，由点及面地打造 DevOps 共同体。

当然，如果想让 DevOps 转型的效果最大化，你一定要想方设法地让高层知晓局部改进的效果，让他们认可这样的尝试，最终实现横向扩展，在企业内部逐步铺开。

自顶向下

你还记得我在专栏第 2 讲中提到的那家把 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 讲复习一下。

第 3 步：快速建立初期成功

找到了合适的团队，也识别出了一大堆改进事项，你是不是感觉前景一片大好，准备撸起袖子加油干了呢？打住！这个时候，切记不要把面铺得太广，把战线拉得太长，这其实是 DevOps 转型初期最典型的一个陷阱。

首先，转型初期资源投入有限，难以支撑大量任务并行。其次，由于团队成员之间还没有完全建立起信任关系，那些所谓的最佳实践很容易水土不服。如果生搬硬套的话，很可能会导致大量摩擦，从而影响改进效果。最后，管理层的耐心也没有想象中那么多，如果迟迟看不到效果，很容易影响后续资源的投入。

所以，最关键的就是识别一个改进点，定义一个目标。比如，环境申请和准备时间过程，那么就可以定义这样一个指标：优化 50% 的环境准备时长。这样一来，团队的目标会更加明确，方便任务的拆解和细化，可以在几周内见到明显的成果。

第 4 步：快速展示和持续改进

取得阶段性的成果之后，要及时向管理层汇报，并且在团队内部进行总结。这样，一方面可以增强管理层和团队的信心，逐步加大资源投入；另一方面，也能够及时发现改进过程中的问题，在团队内部形成持续学习的氛围，激发团队成员的积极性，可以从侧面改善团队的文化。

当然，类似这样的案例在企业内部都极具价值。如果可以快速扩展，那么效果就不仅仅局限于小团队内部，而是会上升到公司层面，影响力就会更加明显了。

以上这四个步骤，基本涵盖了企业 DevOps 转型的通用路径。不过即便完全按照这样的路径进行转型，也很难一帆风顺。在这条路径之下，也隐藏着一些可以预见的问题，最典型的就是DevOps 转型的 J 型曲线，这也是在 2018 年 DevOps 状态报告中的一个重点发现。

在转型之初，团队需要快速识别出主要问题，并给出解决方案。在这个阶段，整个团队的效能水平比较低，可以通过一些实践引入和工具的落地，快速提升自动化的能力和水平，从而帮助团队获得初期的成功。

但是，随着交付能力的提升，质量能力和技术债务的问题开始显现。比如，由于大量的手工回归测试，团队难以压缩测试周期，从而导致交付周期陷入瓶颈；项目架构的问题带来的技术债务导致集成问题增多，耦合性太强导致改动牵一发而动全身……

这个时候，团队开始面临选择：是继续推进呢？还是停滞不前呢？继续推进意味着团队需要分出额外的精力来加强自动化核心能力的预研和建设，比如优化构建时长、提升自动化测试覆盖率等，这些都需要长期的投入，甚至有可能会导致一段时间内团队交付能力的下降。

与此同时，与组织的固有流程和边界问题相关的人为因素，也会制约企业效率的进一步提升。如何让团队能够有信心减少评审和审批流程，同样依赖于质量保障体系的建设。如果团队迫于业务压力，暂缓 DevOps 改进工作，那就意味着 DevOps 难以真正落地发挥价值，很多 DevOps 项目就是这样“死”掉的。

那么说到这儿，你可能会问，这些到底应该由哪个团队来负责呢？换句话说，企业进行 DevOps 转型，是否需要组建一个专职负责的团队呢？如果需要的话，团队的构成又是怎样的呢？

关于这些问题，我的建议是，在转型初期，建立一个专职的转型工作小组还是很有必要的。这个团队主要由 DevOps 转型关联团队的主要负责人、DevOps 专家和外部咨询顾问等牵头组成，一般是各自领域的专家或者资深成员，相当于 DevOps 实施的“大脑”，主要负责制定 DevOps 转型项目计划、改进目标识别、技术方案设计和流程改造等。

除了核心团队，管理团队和工具团队也很重要。我挂一个转型小组的团队组成示意图供你参考。当然，DevOps 所倡导的是一专多能，跨领域的人才对于企业 DevOps 的实施同样不可或缺，在挑选小组成员的时候，这一点你也需要注意下。

总结

今天，我给你介绍了企业 DevOps 转型的常见轨迹，分别是自底向上和自顶向下。无论采用哪种轨迹，寻求管理层的支持都至关重要。接下来，我和你一起梳理了 DevOps 转型的通用路径，你要注意的是，任何变革都不会是一帆风顺的，企业的 DevOps 转型也是如此。在经历初期的成功之后，我们很容易陷入“J 型曲线”之中，如果不能突破困局，就很容易导致转型半途而废，回到起点。最后，我们一起探讨了是否需要专职的 DevOps 转型团队。在企业刚刚开始尝试 DevOps 的时候，这样的团队对于快速上手和建立团队的信心还是很有必要的。

无论如何，就像陆游在《冬夜读书示子聿》一诗中写的那样：“纸上得来终觉浅，绝知此事要躬行。”听过了太多实施 DevOps 的方法和路径，却还是无法真正享受到它的巨大效益，差的可能就是：先干再说的信心和动力吧。

思考题

你在企业中实施 DevOps 时，遇到过什么问题吗？你是怎么解决这个问题的呢？你是否走过一些弯路呢？

欢迎在留言区写下你的思考和答案，我们一起讨论，共同学习进步。如果你觉得这篇文章对你有所帮助，欢迎你把文章分享给你的朋友。

07 | 业务敏捷：帮助DevOps快速落地的源动力

你好，我是石雪峰，今天我要跟你分享的主题是业务敏捷，那么，我们先来聊一聊，什么是业务敏捷，为什么需要业务敏捷呢？

先试想这样一个场景：你们公司内部成立了专项小组，计划用三个月时间验证 DevOps 落地项目的可行性。当要跟大老板汇报这个事情的时候，作为团队的负责人，你开始发愁，怎么才能将 DevOps 的价值和业务价值关联起来，以表明 DevOps 对业务价值的拉动和贡献呢？

如果朝着这个方向思考，就很容易钻进死胡同。因为，从来没有一种客观的证据表明，软件交付效率的提升，和公司的股价提升有什么对应关系。换句话说，软件交付效率的提升，并不能直接影响业务的价值。

实际上，软件交付团队一直在努力通过各种途径改善交付效率，但如果你的前提是需求都是靠谱的、有效的，那你恐怕就要失望了。因为，实际情况是，业务都是在不断的试错中摸着石头过河，抱着“宁可错杀一千，也不放过一个”的理念，各种天马行空的需求一起上阵，搞得软件交付团队疲于奔命，宝贵的研发资源都消耗在了业务的汪洋大海中。但是，这些业务究竟带来了多少价值，却很少有人能说得清楚。

在企业中推行 DevOps 的时间越长，就越会发现，开发、测试和运维团队之间的沟通障碍固然存在，但实际上，业务部门和 IT 部门之间的鸿沟，有时候会更加严重。试问有多少公司的业务方能够满意 IT 部门的交付效率，又有多少 IT 团队不会把矛头指向业务方呢？说白了，就一句话：如果业务不够敏捷，IT 再怎么努力也没用啊！所以，我觉得很有必要跟你聊一聊有关需求的话题。

回到最开始的那个问题，如果 DevOps 不能直接提升公司的业务价值，那么为什么又要推行 DevOps 呢？实际上，如果你把 DevOps 的价值拆开业务价值和交付能力两个部分，就很好理解了。

在现在这个多变的时代，没人能够准确地预测需求的价值。所以，交付能力的提升，可以帮助业务以最小的成本进行试错，将新功能快速交付给用户。同时，用户和市场的情况又能够快速地反馈给业务方，从而帮助业务校准方向。而业务的敏捷能力高低，恰恰体现在对功能的设计和需求的把握上，如果不能灵活地调整需求，专注于最有价值的事情，同样会拖累交付能力，导致整体效率的下降。

也就是说，在这样一种快速迭代交付的模式下，业务敏捷和交付能力二者缺一不可。

所以，开发更少的功能，聚焦用户价值，持续快速验证，就成了产品需求管理的核心思想。

开发更少的功能

很多时候，团队面临的最大问题，就是需求太多。但实际上，很多需求一开始就没想好，甚至在设计和开发阶段还在不断变更，这就给交付团队带来了极大的困扰。所以，在把握需求质量的前提下，如何尽可能地减小需求交付批次，采用最小的实现方案，保证高优先级的需求可以快速交付，从而提升上线实验和反馈的频率，就成了最关键的问题。

关于需求分析，比较常见的方法就是影响地图。

影响地图是通过简单的“Why-Who-How-What”分析方法，实现业务目标和产品功能之间的映射关系。

Why 代表目标，它可以是一个核心的业务目标，也可以是一个实际的用户需求。

Who 代表影响对象，也就是通过影响谁来实现这个目标。

How 代表影响，也就是怎样影响用户以实现我们的目标。

What 代表需要交付什么样的功能，可以带来期望的影响。

如果你是第一次接触影响地图，可能会听起来有点晕。没关系，我给你举个例子，来帮你理解这套分析方法。

比如，一个专栏希望可以在上线 3 个月内吸引 1 万名用户，那么，这个 Why，也就是最核心的业务目标。为了达成这个目标，需要影响的角色包含哪些呢？其实就包含了作者、平台提供方、渠道方和最终用户。需要对他们施加哪些影响呢？对作者来说，需要快速地回答用户的问题，提升内容的质量；对平台来说，需要对专栏进行重点曝光，增加营销活动；对渠道方来说，需要提高推广力度和渠道引流；对于用户来说，增加分享有礼、免费试读和个人积分等活动。

那么基于以上这些影响方式，转化为最终的实际需求，就形成了一张完整的影响地图，如下图所示：

你可能会问，需求这么多，优先级要怎么安排呢？别急，现在我就给你介绍一下“卡诺模型”。

卡诺模型（Kano Model），是日本大师授野纪昭博士提出的一套需求分析方法，它对理解用户需求，对其进行分类和排序方面有着很深刻的洞察。

卡诺模型将产品需求划分为五种类型：

兴奋型：指超乎用户想象的需求，是可遇不可求的功能。比如用户想要一个更好的功能手机，乔布斯带来了 iPhone，这会给用户带来极大的满足感。

期望型：用户的满意度会随着这类需求数量的增多而线性增长，做得越多，效果越好，但难以有质的突破。比如，一个电商平台最开始是卖书，后面逐步扩展到卖电脑、家居用品等多个类别。用户更多的线性需求被满足，满意度自然也会提升。

必备型：这些是产品必须要有的功能，如果没有的话，会带来非常大的影响。不过有这些功能的话，也没人会夸你做得有多好，比如安全机制和风控机制等。

无差别型：做了跟没做一样，这就是典型的无用功。比如你花了好大力气做了一个需求，但是几乎没有用户使用，这个需求就属于无差别型。

反向型：无中生有类需求，实际上根本不具备使用条件，或者用户压根不这么想。这类需求做出来以后，通常会给用户带来很大的困扰，成为被吐槽的对象。

对于五类需求来说，核心要做到 3 点：

优先规划期望型和必备型需求，将其纳入日常的交付迭代中，保持一定的交付节奏；

识别无差别型和反向型需求，这些对于用户来说并没有产生价值。如果团队对需求的分类有争议，可以进一步开展用户调研和分析。

追求兴奋型需求，因为它会带来产品的竞争壁垒和差异化。不过，对于大公司而言，经常会遇到创新者的窘境，也就是坚持固有的商业模式，而很难真正投入资源创新和自我颠覆。这就要采用精益创业的思想，采用 MVP（最小可行产品）的思路，进行快速验证，并且降低试错成本，以抓住新的机遇。

在面对一大堆业务需求的时候，首先要进行识别和分类。当然，最开始时，人人都相信自己的需求是期望型，甚至是兴奋型的，这也可以理解。毕竟，这就好比公司里面所有的缺陷问题等级都是最高级一样，因为只要不提最高级，就会被其他最高级的问题淹没，而长期得不到解决。而解决的方法，就是让数据说话，为需求的价值建立反馈机制，而这里提到的价值，就是用户价值。

聚焦用户价值

“以终为始”，这四个字在精益、DevOps 等很多改进的话题中经常会出现。说白了，就是要“指哪打哪，而不是打哪指哪”。产品开发方经常会问：“这个功能这么好，为什么用户就不用呢？”这就是典型的用产品功能视角看问题，嘴上喊着“用户是上帝”的口号，但实际上，自己却用上帝视角来看待具体问题。

如果你所在的公司也在搞敏捷转型，那你应该也听说过用户故事这个概念。需求不是需求，而是故事，这也让很多人不能理解。那么，用户故事是不是换了个马甲的需求呢？

关于这个问题，我曾经特意请教过一位国内的敏捷前辈，他的话让我记忆犹新。他说，从表面上看，用户故事是一种采用故事来描述需求的形式，但实际上是业务敏捷性的重要手段。它改变的不仅仅是需求的书写方式，还是需求达成共识的方式。也就是说，如果所谓的敏捷转型，没有对需求进行拆解，对需求达成共识的方式进行改变，对需求的价值进行明晰，那么可能只是在做迭代开发，而跟敏捷没啥关系。

在以往进行需求讨论的时候，往往有两个极端：一种是一句话需求，典型的“给你一个眼神，你自己体会”的方式，反正我就要做这件事，至于为什么做、怎么做一概不管，你自己看着办；另一种是上来就深入实现细节，讨论表字段怎么设计、模块怎么划分，恨不得撸起袖子就跟研发一起写代码。

每次需求讨论都是一场唇枪舌剑，达成的共识都是以一方妥协为前提的，这样显然不利于团队的和谐发展。更重要的是，始终在功能层面就事论事，而不关注用户视角，这样交付出来的需求很难达到预期。

而用户故事则是以用户的价值为核心，圈定一种角色，表明通过什么样的活动，最终达到什么样的价值。团队在讨论需求的时候，采用一种讲故事的形式，代入到设定的用户场景之中，跟随用户的操作路径，从而达成用户的目标，解决用户的实际问题。这样做的好处在于，经过团队的共同讨论和沟通，产品、研发和测试对需求目标可以达成共识，尤其是对想要带给用户的价值达成共识。

在这个过程中，团队不断探索更好的实现方案和实现路径，并补充关联的用户故事，从而形成完整的待办事项。更重要的是，团队成员逐渐培养了用户和产品思维，不再拘泥于技术实现本身，增强了彼此之间的信任，积极性方面也会有所改善，从而提升整个团队的敏捷性。

用户故事的粒度同样需要进行拆分，拆分的原则是针对一类用户角色，交付一个完整的用户价值，也就是说用户故事不能再继续拆分的粒度。当然，在实际工作中，拆分的粒度还是以迭代周期为参考，在一个迭代周期内交付完成即可，一般建议是 3～5 天。检验用户故事拆分粒度是否合适，可以遵循 INVEST 原则。

那么，什么是 INVEST 原则呢？

Independent（独立的）：减少用户故事之间的依赖，可以让用户故事更加灵活地验证和交付，而避免大批量交付对于业务敏捷性而言至关重要。

Negotiable（可协商的）：用户故事不应该是滴水不漏、行政命令式的，而是要抛出一个场景描述，并在需求沟通阶段不断细化完成。

Valuable（有价值的）：用户故事是以用户价值为核心的，所以每个故事都是在对用户交付价值，所以要站在用户的视角思考问题，避免像最近特别火的那句话一样：“我不要你觉得，我要我觉得。”

Estimatable（可评估的）：用户故事应该可以粗略评估工作量，无论是故事点数还是时间，都可以。如果是一个预研性质的故事，则需要进一步深挖可行性，避免不知道为什么做而做。

Small（小的）：用户故事应该是最小的交付颗粒度，所以按照敏捷开发方式，无论迭代还是看板，都需要在一个交付周期内完成。

Testable（可测试的）：也就是验收条件，如果没有办法证明需求已经完成，也就没有办法进行验收和交付。

持续快速验证

所谓用户价值，说起来多少有些虚无缥缈。的确，就像我们无法预测未来一样，需求的价值难以预测，但是需求的价值却可以定义。所以，需求价值的定义，可以理解为需求价值的度量，分为客观指标和主观 2 个方面。

客观指标：也就是客观数据能够表明的指标，比如对电商行业来说，可以从购买流程角度，识别商品到达率、详情到达率、加入购物车率、完成订单率等等；

主观指标：也就是用户体验、用户满意度、用户推荐率等等，无法直接度量，只能通过侧面数据关联得出。

但是无论是客观指标，还是主观指标，每一个需求在提出的时候，可以在这些指标中选择需求上线后的预期，并定义相关的指标。一方面加强价值导向，让产品交付更有价值的需求，另外一方面，也强调数据导向，尽量客观地展现实际结果。

当然，产品需求是一个复杂的体系，相互之间也会有影响和依赖，怎么从多种指标中识别出关键指标，并跟需求本身进行关联，这就是一门学问了。不过你别担心，我会在度量相关的内容中跟你详细讨论一下。

在很多企业中，精益创业的 MVP 思想已经深入人心了。面对未知的市场环境和用户需求，为了快速验证一个想法，可以通过一个最小化的产品实现来获取真实的市场反馈，并根据反馈数据修正产品目标和需求优先级，从而持续迭代产品需求。

这套思想基本上放之四海而皆准，但是在企业中实际应用的时候，也会出现跑偏的情况。比如，在需求提出的时候，产品预定义了一组指标，但是在上线后由于缺乏数据支撑，需求价值的评估变成了纯粹的主观题，比如业务方自主判断需求是达到预期，符合预期还是未达到预期。这样一来，十有八九统计出来的结果都是符合预期及以上。但问题是，这样推导出来的结果对产品方向是否真的有帮助呢？

所以，采用客观有效的反馈机制就成了必选项。从技术层面来说，一个业务需求的背后，一般都会关联一个埋点需求。所谓埋点分析，是网站分析的一种常用的数据采集方法。设计良好的埋点功能，不仅能帮助采集用户操作行为，还能识别完整的上下文操作路径，甚至进行用户画像的聚类和分析，帮助识别不同类型用户的行为习惯。从用户层面来说，众测机制和用户反馈渠道是比较常见的两种方式，核心就是既要听用户怎么说，也要看用户怎么做。

总结

DevOps 的关注点要从研发环节继续向上游延伸，一直把业务团队包括进来。也就是说，IT 部门不仅仅是被动的按照业务需求交付功能，还要更加快速地提供业务数据反馈，辅助业务决策。同时，交付能力的提升也进一步降低了业务的试错成本，而业务的敏捷性也决定了研发交付的需求价值和交付节奏，通过影响地图进行需求分析，再通过卡诺模型分析需求属性和优先级，通过用户故事和整个团队达成共识，通过持续快速验证，帮助产品在正确的道路上发展前进。

引入业务的 DevOps，就成了 BizDevOps，这也是 DevOps 发展的一种潮流。最后，我帮你梳理下 BizDevOps 的核心理念：

对齐业务和开发目标、指标；

把握安全、合规指标；

及时对齐需求，减少无用开发；

体现 DevOps 的价值；

让开发团队开始接触业务，不单单是执行，调动积极性。

思考题

你所在的企业中对于需求的价值是如何衡量的呢？是否有一套指标体系可以客观地展现需求的价值呢？

欢迎在留言区写下你的思考和答案，我们一起讨论，共同学习进步。如果你觉得这篇文章对你有所帮助，欢迎你把文章分享给你的朋友。

08 | 精益看板（上）：精益驱动的敏捷开发方法

你好，我是石雪峰。

提到敏捷开发方法，你可能会情不自禁地联想到双周迭代、每日站会、需求拆分等。的确，作为一种快速灵活、拥抱变化的研发模式，敏捷的价值已经得到了行业的普遍认可。但是，即便敏捷宣言已经发表了将近 20 个年头，很多公司依然挣扎在敏捷转型的道路上，各种转型失败的案例比比皆是。

我曾经就见过一家公司，一度在大规模推行敏捷。但是，这家公司很多所谓的敏捷教练都是项目经理兼任的，他们的思维和做事习惯还是项目制的方式。即便每天把团队站会开得有模有样，看板摆得到处都是，但从产品的交付结果来看，并没有什么显著的变化。没过多久，由于组织架构的调整，轰轰烈烈的敏捷转型项目就不了了之了。

这家公司虽然表面上采用了业界流行的敏捷实践，也引入了敏捷工具，但是团队并没有对敏捷的价值达成共识，团队领导兼任 Scrum Master，好好的站会变成了每日工作汇报会。甚至在敏捷项目复盘会上，领导还宣称：“敏捷就是要干掉变化，我们的目标就是保证团队按照计划进行。”这种“貌合神离”的敏捷，并不能帮助企业达到灵活响应变化、快速交付价值的预期效果。

作为一种最广泛的敏捷框架，Scrum 的很多理念和实践都深入人心，比如很多时候，迭代式开发几乎等同于跟敏捷开发。但是，Scrum 对于角色的定义并不容易理解，在推行 Scrum 的时候，如果涉及到组织变革，就会举步维艰。

实际上，企业的敏捷转型并没有一条通用的路径，所用的方法也没有一定之规。今天，我就跟你聊聊另外一种主流的敏捷开发方法——精益看板。与 Scrum 相比，看板方法的渐进式改变过程更加容易被团队接受。我之前所在的团队通过长期实践看板方法，不仅使产品交付更加顺畅，还提升了团队的整体能力。

那么，这个神奇的精益看板是怎么回事呢？

如果你之前没听说过精益看板，还是很有必要简单了解下它的背景的。其实，“看板”是一个日语词汇，泛指日常生活中随处可见的广告牌。而在生产制造系统中，看板作为一种信号卡，主要用于传递信息。很多人认为看板是丰田公司首创的，其实并非如此，比如在我之前所在的尼康公司的生产制造车间里，看板同样大量存在。

当然，看板之所以能广为人知，还是离不开丰田生产系统。《改变世界的机器》一书首次提到了著名的丰田准时化生产系统，而看板正是其中的核心工具。

简单来说，看板系统是一种拉动式的生产方式。区别于以往的大规模批量生产，看板采用按需生产的方式。也就是说，下游环节会在需要的时候，通过看板通知上游环节需要生产的工件和数量，然后上游再启动生产工作。

说白了，所谓拉动式生产，就是从后端消费者的需求出发，向前推导，需要什么就生产什么，而不是生产出来一大堆没人要的东西，从而达到减低库存、加速半成品流动和灵活响应变化的目的。我你分享一张有关丰田生产方式的图片，它演示了整个丰田生产方式的运作过程，你可以参考一下。

图片来源：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 部门的信任度就会直线下降。业务部门往往会想：“既然无法预测需求的交付实践，那好吧，我只能一次性压给你一大堆需求。”这样一来，就进一步导致了在制品数量的上升。

可见，一个小小的在制品数量，牵动的是整个研发团队的信心。我把刚刚提到的连环关系整理了一下，如下图所示：

当然，针对刚才加油站的问题，你可能会说：“多加几台加油设备，不就完了吗？何必依赖同一台机器呢？”的确，当并行任务过多的时候，适当增加人员有助于缓解这个问题，但是前置时间的缩短是有上限的。这就好比 10 个人干一个月的事情，给你 100 个人 3 天做完，这就是软件工程管理的经典图书《人月神话》所讨论的故事了，我就不赘述了。这里你只需要知道，随着人数的增多，人与人之间的沟通成本会呈指数级上升。而且，从短期来看，由于内部培训、适应环境等因素，新人的加入甚至会拖慢原有的交付速度。

了解了精益看板的核心理念，以及约束在制品数量的重要性，也就掌握了看板实践的正确方向。那么，在团队中要如何开始一步步地实施精益看板方法呢？在实施的过程中，又有哪些常见的坑，以及应对措施呢？这正是我要重点跟你分享的问题。我把精益看板的实践方法分为了五个步骤。

第一步：可视化流程；

第二步：定义清晰的规则；

第三步：限制在制品数量；

第四步：管理工作流程；

第五步：建立反馈和持续改进。

今天，我先给你介绍精益看板实践方法的第一步：可视化流程。在下一讲中，我会继续跟你聊聊剩余的四步实践。

第一步：可视化流程

在看板方法中，提高价值的流动效率，快速交付用户价值是核心原则，所以第 1 步就是要梳理价值交付流程，通过对现有流程的建模，让流程变得可视化。关于价值流建模的话题，在专栏第 5 讲中我已经介绍过了，如果你不记得了，别忘记回去复习一下。

其实，在组织内部，无论采用什么研发模式，组织结构是怎样的，价值交付的流程一直都是存在的。所以，在最开始，我们只需要忠实客观地把这个现有流程呈现出来就可以了，而无需对现有流程进行优化和调整。也正因为如此，看板方法的引入初期给组织带来的冲击相对较小，不会因为剧烈变革引起组织的强烈不适甚至是反弹。所以，看板方法是一种相对温和的渐进式改进方法。

接下来，就可以根据价值流定义看板了。看板的设计没有一个标准样式，因为每个组织的价值流都不相同。对于刚刚上手看板方法的团队来说，看板的主要构成元素可以简单概括成“一列一行”。

1. 一列。

这是指看板的竖向队列，是按照价值流转的各个主要阶段进行划分的，比如常见的需求、开发、测试、发布等。对识别出来的每一列进一步可以划分成“进行中”和“已完成”两种状态，这也是精益看板拉动式生产的一个显著特征。对于列的划分粒度可以很细，比如开发阶段可以进一步细分成设计、编码、自测、评审、提测等环节，或者就作为一个单独的开发环节存在。划分的标准主要有两点：

是否构成一个独立的环节。比如对于前后端分离的开发来说，前端开发和后端开发就是两个独立的环节，一般由不同的角色负责，这种就比较适合独立阶段。

是否存在状态的流转和移交。看板是驱动上下游协同的信号卡，所以，我们需要重点关注存在上下游交付和评审的环节，这也是提示交付吞吐率和前置时长的关键节点。

除此之外，看板的设计需要定义明确的起点和终点。对于精益看板来说，覆盖端到端的完整价值交付环节是比较理想的状态。但实际上，在刚开始推行看板方法的时候，由于组织架构、团队分工等多种因素，只能在力所能及的局部环节建立看板，比如开发测试环节，这并不是什么大问题，可以在局部优化产出效果之后，再尝试向前或向后延伸。

另外，即便看板可以覆盖端到端的完整流程，各个主要阶段的关注点各不相同，所以，也会采用看板分类分级的方式。对于开发看板来说，起点一般是需求准备就绪，也就是说，需求经过分析评审设计并同研发团队沟通一致准备进入开发的状态，终点可以是提测或者发布状态。流程的起点和终点同样要体现在看板设计中，以表示在局部环节的完整工作流程。

2. 一行。

这是指看板横向的泳道。泳道用于需求与需求之间划清界限，尤其在使用物理看板的时候，经常会因为便利贴贴的位置随意等原因导致混乱，而定义泳道就可以很好地解决这个问题。比如，高速公路上都画有不同的行车道，这样车辆就可以在各自的车道内行驶。

当然，泳道的意义不只如此。泳道还可以按照不同维度划分。比如，有的看板设计中会加入紧急通道，用于满足紧急需求的插入。另外，非业务类的技术改进需求，也可以在独立泳道中进行。对于前后端分离的项目来说，一个需求会拆分成前端任务和后端任务，只有当前后端任务都完成之后才能进行验收。这时，就可以把前后端任务放在同一个泳道中，从而体现需求和任务的关联关系，以及任务与任务之间的依赖关系，快速识别当前阻塞交付的瓶颈点。

当然，看板的设计没有一定之规。在我们团队的看板中，往往还有挂起类需求区域、缺陷区域，以及技术攻关类区域等，用于管理特定的问题类型。比如对于长期挂起的需求，在一定时间之后就可以从看板中移除，毕竟，如果是几个月都没有进入任务队列的需求，可能就不是真正的需求，这些可以根据团队的实际情况灵活安排。如果你在使用 Jira 这样的工具，虽然没有区域的概念，但是可以通过泳道来实现，比如按照史诗任务维度区分泳道，然后新建对应区域的史诗任务就可以啦。

总结

今天，我给你介绍了敏捷常用的两种框架 Scrum 和看板。看板来源于丰田生产系统，以拉动式生产为最典型的特征。关注价值流动，加速价值流动是精益看板的核心，限制在制品数量就是核心实践，因为，在制品数量会直接影响团队的交付周期和产品质量，甚至还会影响团队之间的信任，导致团队进入向下螺旋。

在团队中实践精益看板，可以分为五个步骤，分别是：可视化流程、定义清晰的规则、限制在制品数量、管理工作流程和建立反馈并持续改进。今天我给你介绍了第一个步骤，也就是可视化流程，通过价值流分析将团队的交付路径可视化，建立起看板的主要结构，那么接下来就是开始应用看板了。下一讲，我会跟你聊聊其余的四个步骤，敬请期待。

思考题

最后，给你留一个思考题：你所在的公司是否也在实践敏捷呢？在敏捷转型的过程中，你遇到的最大问题、踩过的最大的坑是什么呢？

欢迎在留言区写下你的思考和答案，我们一起讨论，共同学习进步。如果你觉得这篇文章对你有所帮助，欢迎你把文章分享给你的朋友。

09 | 精益看板（下）：精益驱动的敏捷开发方法

你好，我是石雪峰。在上一讲中，我给你介绍了两种常见的敏捷框架：Scrum 和精益看板。我重点提到，关注价值流动是精益的核心理念，限制在制品数量则是核心实践。此外，我还给你介绍了实施精益看板第一步：可视化流程。那么今天，我会继续介绍剩余的四个步骤。

先提一句，如果你比较关心工具使用方面的问题，我给你分享一份有关常见的工具配置和使用方面的资料，你可以点击网盘下载，提取码是 mrtd。

好了，现在正式开始今天的内容。

第二步：定义清晰的规则

在完成可视化流程之后，看板的雏形就出来啦。接下来你要做的，就是定义清晰的规则。

可视化的意义不仅在于让人看得见，还在于让人看得懂。工作时间久了，我们很容易产生一种感觉，那就是沟通的成本甚至要大于工作的成本。沟通的最主要目的就是同步和传递信息，如果有一种途径可以提升信息传递的效率，那岂不是很好吗？

而看板恰恰有一个重要的意义，就是状态可视化。团队的所有成员可以通过看板了解当前在进行的任务状态、流程中的瓶颈点、任务与任务之间的依赖关系等信息，从而自发地采取相应的活动，来保证价值交付的顺畅，使整个项目能够有条不紊地交付。

当然，如果想要做到这点，光靠可视化流程还远远不够，你还需要在看板的设计中融入一定的规则。这些规则可以大大地降低团队成员之间的沟通成本，统一团队的沟通语言，形成团队成员之间的默契。看板的规则包含两个方面，一个是可视化规则，另一个是显式化规则，我分别来介绍一下。

1. 可视化规则。

在上一讲中，我们提到，看板中的主要构成元素是“一列一行”。实际上，看板中卡片的设计也有讲究，主要有 3 点。

卡片的颜色：用于区分不同的任务类型，比如需求（绿色）、缺陷（红色）和改进事项（蓝色）；

卡片的内容：用于显示任务的主要信息，比如电子看板 ID 号，需求的名称、描述、负责人、预估工作量和停留时长等；

卡片的依赖和阻塞状态：用于提起关注，比如在卡片上通过张贴不同的标志，表示当前卡片的健康程度，对于存在依赖和阻塞状态的卡片，需要团队高优先级协调和处理。这样一来，看板就显得主次分明啦。

2. 显式化规则。

看板除了要让人看得懂，还要让人会操作，这一点非常重要。尤其是在引入看板的初期，大家对这个新鲜事物还比较陌生，所以，定义清晰的操作规则就显得格外重要了。而且，在团队习惯操作之前，需要反复地强调以加深团队的印象，慢慢培养团队的习惯。当团队习惯了使用看板之后，效率就会大大提升。这些规则包括：

谁来负责整理和移动卡片？

什么时间点进行卡片操作？

卡片的操作步骤是怎样的？（比如，卡片每停留一天需要做一次标记。）

什么时候需要线下沟通？（比如缺陷和阻塞）

哪些标识代表当前最高优先级的任务？

看板卡片的填充规则是怎样的？

谁来保障线下和线上看板的状态一致性？

还是那句话，这些规则在团队内部可能一直都存在，属于心照不宣的那种类型，但是，通过看板将规则显示化，无论是对于规则的明确，新人的快速上手，还是团队内部的持续改进，都有着非常大的好处。

第三步：限制在制品数量

限制在制品数量是看板的核心，也是最难把握的一个环节，主要问题就在于把数量限制为多少比较合适的呢？

要回答这个问题，首先要明确一点：应用看板方法只能暴露团队的现有问题，而不能解决团队的现有问题。

怎么理解这句话呢？这就是说，当在制品数量没有限制的时候，团队的交付时间和交付质量都会受到影响，这背后的原因可能是需求把控不到位，发布频率不够高，自动化程度不足以支撑快速交付，组织间的依赖和系统架构耦合太强……这些都是团队的固有问题，并非是使用看板方法就能统统解决掉的。

但看板方法的好处在于，通过降低在制品数量，可以将这些潜在的问题逐步暴露出来。比如，在极端情况下，假设我们将在制品数量设置为 1，也就是说，团队当前只工作在一个需求上，按道理来说，交付的前置时间会大大缩短。但实际上，团队发现由于测试环境不就绪，导致无法验收交付，或者交付窗口过长，错过一个窗口就要再等 2 周的时间，到头来还是不能达到快速交付价值的目标。那么，这里的原因就在于测试环境初始化问题和交付频率的问题。这些都是团队固有的问题，只不过在没有那么高的交付节奏要求时，并没有显现出来而已。

所以，如果你能够摆正心态，正视团队的固有问题，你就会明白，限制在制品数量绝不仅仅是纠结一个数字这么简单的。在我看来，限制在制品数量有两个关键节点：一个是需求流入节点，一个是需求交付节点。

1. 需求流入节点。

这里的关键是限制需求的流入。你可能就会说，这太不靠谱了，面对如狼似虎的业务方，研发团队只能做个小绵羊，毕竟只要你敢 say“no”，业务方就直接立刻写邮件抄送老板了。

其实，需求的 PK 是个永恒的话题，敢问哪个研发经理没经历过几十、上百次需求 PK 的腥风血雨呢？我之前就因为同项目团队需求 PK 得过于激烈，一度做好了被扫地出门的准备。但是，后来我们发现，到头来大家还是一根绳子上的蚂蚱，在资源有限的前提下，一次提 100 个需求和提 10 个需求，从交付时长来看，其实并没有什么区别。所以，限制在制品数量只是换了一个方式 PK 需求，从之前业务方提供一大堆需求，让研发团队给排期的方式，变成了根据需求的优先级限制并行任务数量的方式。

当然，研发团队需要承诺业务方以最快的速度交付最高优先级的需求。如果业务方看到需求的确按照预期的时间上线甚至是提前上线，他们就会慢慢习惯这种做法，团队之间的信任也就一点点建立起来了。

2. 需求流出节点。

这里的关键在于加速需求的流出。在一般的看板中，最容易出现堆积的就是待发布的状态列，因为发布活动经常要根据项目的节奏安排，由专门团队在专门的时间窗口进行。如果发现待发布需求大量堆积，这时候就有理由推动下游加快发布节奏，或者以一种更加灵活的方式进行发布。

毕竟，DevOps 所倡导的是“You build it，you run it”的理念，这也是亚马逊公司最为经典的团队理念，意思是开发团队自己负责业务的发布，每个发布单元都是独立的，彼此没有强依赖关系，从而实现团队自制。通过建立安全发布的能力，将发布变成一件平常的事情，这才真正有助于需求价值的快速交付。说白了，要想做到业务敏捷，就得想发就发，做完一个上一个。

至于要将在制品数量限制为多少，我的建议是采用渐进式优化的方式。你可以从团队人数和需求的现状出发，在每个开发人员不过载的前提下，比如并行不超过三件事，根据当前处理中的任务数量进行约定，然后观察各个环节的积压情况，再通过第四步实践进行调整，最终达到一个稳定高效的状态。

第四步：管理工作流程

在专栏第 5 讲中，我提到过精益理论中的增值环节和不增值环节，而会议一般都会被归为不增值环节。于是，有人就会产生这样一种误解：“那是不是所有不增值的环节都要被消除掉，以达到最高的流动效率呢？”

如果这么想的话，那是不是类似项目经理这样的角色也就不需要了呢？毕竟，他们看起来并没有直接参与到软件开发的活动中。显然，这是很片面的想法。实际上，在精益的不增值活动中，还可以进一步划分出必要不增值活动和不必要不增值活动，有些会议虽然不直接增值，但却是非常必要的。所以，我们不能简单地认为精益就等于不开会、不审批。

看板方法同样根植于组织的日常活动之中，所以，同样需要配套的管理流程，来保障看板机制的顺畅运转。在看板方法中，常见的有三种会议，分别是每日站会、队列填充会议和发布规划会议。

1. 每日站会。

接触过敏捷的团队应该都非常熟悉每日站会。但是，与 Scrum 方法的“夺命三连问”（昨天做了什么？今天计划做什么？有什么困难或者阻塞？）相比，看板方法的站会则略有不同。因为，我们在第二步制定了清晰的规则，团队的现状已经清晰可见，只需要同步下重点任务就可以了。看板方法更加关注两点：

待交付的任务。看板追求价值的快速流动，所以，对于在交付环节阻塞的任务，你要重点关注是什么原因导致的。

紧急、缺陷、阻塞和长期没有更新的任务。这些任务在规则中也有相应的定义，如果出现了这些问题，团队需要最高优先级进行处理。这里有一个小技巧，就是当卡片放置在看板之中时，每停留一天，卡片的负责人就会手动增加一个小圆点标记，通过这个标记的数量，就可以看出哪些任务已经停留了太长时间。而对于使用电子看板的团队来说，这就更加简单了。比如，Jira 本身就支持停留时长的显示。当然，你也可以自建过滤器，按照停留时长排序，重点关注 Top 问题的情况。

每日站会要尽量保持高效，对于一些存在争议的问题，或者是技术细节的讨论，可以放在会后单独进行。同时，会议的组织者也要尽量观察每日站会的执行效果，如果出现停顿或者不顺畅的情况，那就意味着规则方面有优化空间。比如，如果每日站会依赖一名组织者来驱动整个过程，只要这个人不发问，团队就不说话，这就说明规则不够清晰。另外，对于站会中迸发出来的一些灵感或者好点子，可以都记录下来，作为优化事项跟进解决。

2. 队列填充会议。

队列填充会议的目标有两点：一个是对任务的优先级进行排序，一个是展示需求开发的状态。一般情况下，队列填充会议需要业务方、技术方和产品项目负责人参与进来，对需求的优先级达成一致，并填充到看板的就绪状态中。

在初期，我建议在每周固定时间举行会议，这样有助于整个团队共享需求交付节奏，了解需求交付状态，帮助业务方和技术方建立良好的合作和信任关系，在会议上也可以针对在制品数量进行讨论和调整。

3. 发布规划会议。

发布规划会议以最终交付为目标。一般情况下，项目的交付节奏会影响队列填充的节奏，二者最好保持同步。另外，随着部署和发布的分离，研发团队越来越趋近于持续开发持续部署，而发布由业务方统一规划把控，发布规划会议有助于研发团队和业务方的信息同步，从而实现按节奏部署和按需发布的理想状态。

第五步：建立反馈和持续改进

实际上，无论是 DevOps 还是精益看板，任何一套方法框架的终点都是持续改进。因为，作为一种新的研发思想和研发方法，只有结合业务实际，并根据自身的情况持续优化规则、节奏、工具和流程，才能更好地为业务服务。关于这部分的内容，我会在度量和持续改进中进行详细介绍。你要始终记得，没有天然完美的解决方案，只有持续优化的解决方案。看板方法的实践是一个循序渐进的过程。为此看板创始人 David J Anderson 总结了看板方法的成熟度模型，用于指导中大型团队实践看板方法，如下图所示：

图片来源：http://leankanban.com/kmm/

这个模型将看板的成熟度划分为 7 个等级。除此之外，它还针对每一级的每一个实践维度，给出了具体的能力参考，对看板方法的实施有非常强的指导作用，可以用于对标现有的能力图谱。

如果你想获取更加详细的信息，可以点击在这一讲的开头我分享给你的链接，作为补充参考。

总结

好啦，回顾一下，在这两讲中，我先给你介绍了看板的背景和起源。看板来源于生产制造行业，是一种常用的生产信号传递方式，同时，看板也是以丰田生产系统为代表的精益生产的核心工具，也就是以拉动为核心的按需生产方式。

接着，我跟你探讨了为什么要限制在制品数量，以及背后的理念，也就是缩短交付前置时长，以快速、高质量、可预期的交付方式，在业务方和 IT 部门之间建立起合作信任关系。

除此之外，我还给你介绍了精益看板的 5 个核心实践，包括：可视化流程，定义清晰的规则，约束在制品数量，管理工作流程和建立反馈持续改进。掌握了这些，你就获取了开启精益看板之旅的钥匙。在真正进行实践之后，相信你会有更多的收获和感悟。

需要提醒你的是，僵化的实践方法，脱离对人的关注，可以说是影响精益看板在组织内落地的最大障碍。就像《丰田之道》中提到的那样，持续改进和对人的尊重，才是一切改进方法的终极坐标，这一点是我们必须要注意的。

思考题

最后，给你留一个思考题：如果让你现在开始在团队中推行精益看板方法，你觉得有哪些挑战吗？

欢迎在留言区写下你的思考和答案，我们一起讨论，共同学习进步。如果你觉得这篇文章对你有所帮助，欢迎你把文章分享给你的朋友。

10 | 配置管理：最容易被忽视的DevOps工程实践基础

你好，我是石雪峰。从今天开始，专栏正式进入了工程实践的部分。在 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.

test suite does not pass

latest code is not tagged

uncompiled source code is not distributed via PyPI

The Flask-XML-RPC module is essentially dead upstream, but it is

packaged in EPEL 7 and Fedora. This module will get us far enough to

the

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.

(Note, with this change, the Travis CI tests will fail for Python 3.

The

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 工程实践的基础配置管理，以及配置管理的四大理念，分别是版本变更标准化、将一切纳入版本控制、全流程可追溯和单一可信数据源，希望能帮你掌握配置管理的全局概念。

虽然配置管理看起来并不起眼，但是就像那句经典的话一样：“岁月静好，是因为有人替你负重前行。” 对于任何一家企业来说，信息过载都是常态，而配置管理的最大价值正是将信息序列化，对信息进行有效的整理、归类、记录和关联。而软件开发标准和有序，也是协同效率提升的源头，所以，配置管理的重要性再怎么强调都不为过。

思考题

你在企业中遇到过哪些配置管理方面的难题呢？你们的配置管理体系又是如何建立的呢？你遇到过因为缺乏单一可信数据源而导致“鸡同鸭讲”的有趣故事吗？

欢迎在留言区写下你的思考和答案，我们一起讨论，共同学习进步。如果你觉得这篇文章对你有所帮助，欢迎你把文章分享给你的朋友。

11 | 分支策略：让研发高效协作的关键要素

你好，我是石雪峰。今天我们来聊聊分支策略。

在上一讲中，我反复强调过一个理念，那就是将一切纳入版本控制。其实，现代版本控制系统不仅可以记录版本和变更记录，还有一个非常重要的功能，那就是分支管理。

现代软件开发讲究效率和质量，大多依赖于多团队间的协作来实现。对于一些大型软件来说，即便是百人团队规模的协作也没什么奇怪的。如果软件架构没有良好的拆分，很有可能出现几百人在一个代码仓库里面工作的情况。这时，分支管理就成了不可或缺的功能。

一方面，分支可以隔离不同开发人员的改动，给他们提供一个相对独立的空间，让他们能够完成自己的开发任务。另一方面，整个团队也需要根据软件的发布节奏来完成代码提交、审核、集成、测试等工作。

所以，如果说多人软件协作项目中有一个灵魂的话，我认为，这个灵魂就是分支策略。可以说，分支策略就是软件协作模式和发布模式的风向标。选择一种符合 DevOps 开发模式的分支策略，对于 DevOps 的实践落地也会大有帮助。

今天，我会给你拆解一些常见的分支策略，帮你了解这些策略的核心流程、优缺点，以及适用的场景和案例。

主干开发，分支发布

图片来源：

https://paulhammant.com/2013/12/04/what_is_your_branching_model/

在这种分支策略下，开发团队共享一条主干分支，所有的代码都直接提交到主干分支上，主干分支就相当于是一个代码的全量合集。在软件版本发布之前，会基于主干拉出一条以发布为目的的短分支。

你需要注意一下这句话里的两个关键词：

以发布为目的。这条分支存在的意义不是开发新功能，而是对现有功能进行验收，并在达到一定的质量标准后对外发布。一般来说，新功能不会基于这条分支提交，只有一些 Bugfix 会集成进来。所以，对于这种发布分支会有比较严格的权限管控。毕竟，谁都不想让那些乱七八糟、未经验证的功能跑到发布分支上来。

短分支。这条发布分支一般不会存在太长时间，只要经过回归验证，满足发布标准后，就可以直接对外发布，这时，这条分支的历史使命也就结束了。除非上线之后发现一些紧急问题需要修复，才会继续在这条分支上修改验证，并将改动同步回主干分支。所以，只要在主干分支和发布分支并行存在的时间段内，所有发布分支上的改动都需要同步回主分支，这也是我们不希望这条分支存在时间过长的原因，因为这会导致重复工作量的线性累计。

对于以版本节奏驱动的软件项目来说，这种分支策略非常常见，比如客户端产品，或者是那种需要在客户终端升级的智能硬件产品，像智能手机、智能电视等。

早在很多年前，乐视刚刚推出超级电视的时候，喊过一个口号叫“周周更新”。要知道，当时智能电视产品的更新频率普遍是几个月一次。

其实，如果你了解分支策略的话，你就会发现，“周周更新”的背后也没什么特别的。当时，我所在的团队恰好负责智能电视产品线的分支策略，采用的就是主干开发、分支发布的模式。其中基于主干的发布分支提前两周拉出，然后在发布分支上进行回归验证，并在第一周发出体验版本给喜欢尝鲜的用户试用。然后，根据用户反馈和后台收集的问题进行进一步修正，并最终发布一个稳定版本。我把当时的分支策略图分享给你，你可以参考一下。

这种模式的优势有三个：

对于研发团队来说，只有一条主线分支，不需要在多条分支间切换。

在发布分支拉出之后，主干分支依然处于可集成状态，研发节奏可以保持在一个相对平稳的状态。

发布分支一般以版本号命名，清晰易懂，线上哪个版本出了问题，就在哪个分支上修复。

不过，这种模式也存在着缺点和挑战：

它对主线分支的质量要求很高。如果主线分支出了问题，就会 block 所有开发团队的工作。对于一个百人团队、每日千次的提交规模来说，如果不对提交加以约束，这种情况的发生频率就会非常高。

它对团队协作的节奏要求很高。如果主线分支上的功能没有及时合入，但是业务方又坚持要在指定版本上线这个功能，这就会导致发布分支“难产”。甚至有些时候，会被迫允许部分未开发完成的功能在发布分支上继续开发，这会给发布分支的质量和稳定性造成很大的挑战。

在主线和发布分支并存期间，有可能会导致两边提交不同步的情况。比如，发布分支修复了一个线上问题，但是由于没有同步回主线，导致同样的问题在下一个版本中复现。测试出来的问题越多，这种情况出现的概率就越大，更不要说多版本并存的情况了。

这些问题的解决方法包括以下几点：

建立提交的准入门禁，不允许不符合质量标准的代码合入主线。

采用版本火车的方式，加快版本的迭代速度，功能“持票上车”，如果跟不上这个版本就随下个版本上线。另外，可以采用功能开关、热修复等手段，打破版本发布的固定节奏，以一种更加灵活的方式对外发布。

通过自动化手段扫描主线和发布分支的差异，建立一种规则。比如 Hotfix 必须主线和发布分支同时提交，或者发布分支上线后，由专人反向同步等。

分支开发，主干发布

图片来源：https://paulhammant.com/2013/12/04/what_is_your_branching_model/

当开发接到一个任务后，会基于主干拉出一条特性开发分支，在特性分支上完成功能开发验证之后，通过 Merge request 或者 Pull request 的方式发起合并请求，在评审通过后合入主干，并在主干完成功能的回归测试。开源社区流行的 GitHub 模式其实就是属于这种。

根据特性和团队的实际情况，还可以进一步细分为两种情况：

每条特性分支以特性编号或需求编号命名，在这条分支上，只完成一个功能的开发；

以开发模块为单位，拉出一条长线的特性分支，并在这条分支上进行开发协作。

两者的区别就在于特性分支存活的周期，拉出时间越长，跟主干分支的差异就越大，分支合并回去的冲突也就越大。所以，对于长线模式来说，要么是模块拆分得比较清晰，不会有其他人动这块功能，要么就是保持同主干的频繁同步。随着需求拆分粒度的变小，短分支的方式其实更合适。

这种模式下的优势也有两点：

分支开发相对比较独立，不会因为并行导致互相干扰。同时，特性只有在开发完成并验收通过后才会合入主干，对主干分支的质量起到了保护作用；

随着特性分支的流行，在这种模式下，分支成了特性天然的载体。一个特性所关联的所有代码可以保存在一条特性分支上，这为以特性为粒度进行发布的模式来说提供了一种新的可能性。也就是说，如果你想要发布哪个特性，就可以直接将特性分支合并到发布分支上，这就让某一个特性变得“可上可下”，而不是混在一大堆代码当中，想拆也拆不出来。

关于这种特性分支发布的方法，我给你提供一份参考资料，你可以了解一下。不过，我想提醒你的是，特性发布虽然看起来很好，但是有三个前置条件：第一个是特性拆分得足够小，第二是有强大的测试环境作支撑，可以满足灵活的特性组合验证需求，第三是要有一套自动化的特性管理工具。

当然，分支开发、主干发布的模式也有缺点和挑战：

非常考验团队特性拆分的能力。如果一个特性过大，会导致大量并行开发的分支存在，分支的集成周期拉长，潜在的冲突也会增多。另外，分支长期存在也会造成跟主线差异过大的问题。所以，特性的粒度和分支存活的周期是关键要素。根据经验来看，分支存活的周期一般不要超过一周。

对特性分支的命名规范要求很高。由于大量特性分支的拉出，整个代码仓库会显得非常乱。面对一大堆分支，谁也说不清到底哪个还活着，哪个已经没用了。所以，如果能够跟变更管理系统打通，自动化创建分支就最好了。

特性分支的原子性和完整性，保证一个特性的关联改动需要提交到一条分支上，而不是到处都是。同时，特性分支上的提交也需要尽量清晰，典型的就是原子性提交。

我之前所在的一个团队就是采用的这种分支策略。有一次，我为了分支策略的执行细节跟研发负责人争得面红耳赤，争论的核心点就是：当特性分支合并回主干的时候，到底要不要对特性分支上的代码进行整理？

只要做过开发，你就会知道，很少有人能只用一次提交就把代码写对的，因为总是会有这样那样的问题，导致特性分支上的提交乱七八糟。

在合入主干的时候，为了保证代码的原子性，其实是有机会对代码提交进行重新编排的，Git 在这方面可以说非常强大。如果你熟练掌握 git rebase 命令，就可以快速合并分拆提交，将每一个提交整理为有意义的原子性的提交，再合入主干，或者干脆把特性分支上的改动压合成一个提交。当然，这样做的代价就是不断重写特性分支的历史，给研发团队带来额外的工作量。我跟你分享一些常见的命令。

比如：当前特性分支 feature1，主分支 master，那么，你可以执行以下命令整理提交历史：

git checkout feature1 && git fetch origin && git rebase -i origin/master

最常见的操作包括：

p：选择提交；

r：更新提交的注释信息；

e：编辑提交，可以将一个提交拆分成多个；

s：压合提交，将多个提交合并成一个；

f：类似压合提交，但是放弃这个提交的注释信息，直接使用合并提交的注释信息；

当然，在 git rebase 的交互界面中，你也可以调整提交的顺序，比如将特性功能和关联的 Bugfix 整合在一起。

需要提醒你的是，分支策略代表了研发团队的行为准则，每个团队都需要磨合出一套适合自己的模式来。

主干开发，主干发布

图片来源：https://paulhammant.com/2013/12/04/what_is_your_branching_model/

今天给你介绍的第三种分支策略是主干开发、主干发布。武学高手修炼到一定境界之后，往往会发现大道至简，分支策略也是如此。所以，第三种分支策略可以简单理解为没有策略。团队只有一条分支，开发人员的代码改动都直接集成到这条主干分支上，同时，软件的发布也基于这条主干分支进行。

对于持续交付而言，最理想的情况就是，每一次提交都能经历一系列的自动化环境并部署到生产环境上面，而这种模式距离这个目标就更近了一点。

可想而知，如果想要做到主干分支在任何时间都处于可发布状态，那么，这就对每一次提交的代码质量要求非常高。

在一些追求工程卓越的公司里，你要提交一行代码，就必须经历“九九八十一难”，因为有一系列的自动化验收手段，还有极为严格的代码评审机制来保证你的提交不会把主干分支搞挂掉。当然，即便如此，问题也是难以避免的，那我们该怎么做呢？这里我就要给你介绍下 Facebook 的分支策略演进案例了。

Facebook 最早采用的也是主干开发、分支发布的策略，每天固定发布两次。但是，随着业务发展的压力增大，团队对于发布频率有了更高的要求，这种分支策略已经无法满足每天多次发布的需求了。于是，他们开始着手改变分支策略，从主干开发、分支发布的模式，演变成了主干开发、主干发布的模式。

为了保证主干分支的质量，自动化验收手段是必不可少的，因此，每一次代码提交都会触发完整的编译构建、单元测试、代码扫描、自动化测试等过程。在代码合入主干后，会进行按需发布，先是发布到内部环境，也就是只有 Facebook 的员工才能看到这个版本，如果发现问题就立刻修复，如果没有问题，再进一步开放发布给 2% 的线上生产用户，同时自动化检测线上的反馈数据。直到确认一切正常，才会对所有用户开放。

最后，通过分支策略和发布策略的整合，注入自动化质量验收和线上数据反馈能力，最终将发布频率从固定的每天 2 次，提升到每天多次，甚至实现了按需发布的模式。Facebook 最新的分支策略如图所示：

图片来源：https://engineering.fb.com/web/rapid-release-at-massive-scale/

看到这里，你可能会问：“在这三种典型策略中，哪种策略是最好的？我应该如何选择呢？”其实，这个问题也困扰着很多公司。

的确，不同类型、规模、行业的软件项目采用的分支策略可能都不尽相同，同时，发布频率、软件架构、基础设施能力、人员能力水平等因素也在制约着分支策略的应用效果。

所以，很难说有一种通用的分支策略可以满足所有场景的需求。但是，有些分支策略的原则更加适合于快速迭代发布的场景，也就更加适合 DevOps 的发展趋势。所以，我个人比较推荐的是主干开发结合特性分支的模式，也就是团队共享一条开发主干，特性开发基于主干拉出特性分支，快速开发验收并回归主干，同时，在特性分支和主干分别建立不同的质量门禁和自动化验收能力。

这样做的好处在于，可以加快代码集成频率，特性相对独立清晰，并且主干分支又可以保持一定的质量水平。不过，在执行的过程中，你需要遵守以下原则：

团队共享一条主干分支；

特性分支的存活周期要尽量短，最好不要超过 3 天；

每天向主干合并一次代码，如果特性分支存在超过 1 天，那么每天都要同步主干代码；

谨慎使用功能开关等技术手段，保持代码干净和历史清晰；

并行分支越少越好，如果可能的话，尽量采用主干发布。

关于最后一条，你需要注意的是，是否需要发布分支，主要取决于项目的发布模式。对于按照版本方式发布的项目来说，比如 App、智能硬件系统，以及依赖大量外部系统联调的核心系统，可以按照发布固定的节奏拉出发布分支；对于发布节奏较快、系统架构拆分后相对独立的应用来说，可以直接采用主干发布的模式，并结合安全发布策略把控整体的发布质量。

这种分支发布的策略图如下所示：

总结

今天，我给你介绍了三种分支策略，建议你对照我给你分享的分支策略图，好好理解一下。另外， 我还介绍了适合 DevOps 模式的分支策略以及一些使用原则。还记得我最开始说的吗？分支策略就是研发协作和发布模式的风向标，分支策略的变化对整个研发团队的习惯和节奏都是一个非常大的调整，找到适合当前团队的分支策略，才是最重要的。

思考题

你目前所在的团队采用的是哪种分支策略？你觉得当前的分支策略有哪些问题或改进空间吗？你是否经历过分支策略的调整呢？如果有的话，你在这个过程中踩过什么“坑”吗？有没有什么心得呢？

欢迎在留言区写下你的思考和答案，我们一起讨论，共同学习进步。如果你觉得这篇文章对你有所帮助，欢迎你把文章分享给你的朋友。

12 | 持续集成：你说的CI和我说的CI是一回事吗？

你好，我是石雪峰。今天我来跟你聊聊 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 个问题，看看你们是否做到了。

每一次代码提交，是否都会触发一次完整的流水线？

每次流水线是否会触发自动化的测试环节？

如果流水线出现了问题，是否能够在 10 分钟之内修复？

我曾在现场做过很多次这个测试，如果参与者认为做到了，就会举手表示；如果没有做到，就会把手放下。每次面对一群自信满满的 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 环节超过 10～15 分钟还没有反馈结果，那么研发人员就会失去耐心，所以 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 都有哪些问题和心得呢？

欢迎在留言区写下你的思考和答案，我们一起讨论，共同学习进步。如果你觉得这篇文章对你有所帮助，欢迎你把文章分享给你的朋友。

13 | 自动化测试：DevOps的阿克琉斯之踵

你好，我是石雪峰。

在古希腊神话中，战神阿克琉斯英勇无比，浑身刀枪不入，唯独脚后跟是他的致命弱点。在特洛伊战争中，他的脚后跟被一箭射中，倒地身亡，从此，阿克琉斯之踵就被用来形容致命的缺陷。我今天要跟你聊的自动化测试，就是 DevOps 的阿克琉斯之踵。

我之前走访过很多公司，我发现，在工程实践领域，比如配置管理、持续集成等，他们实践得还不错，但是却有两大通病，一个是研发度量，另一个就是自动化测试。

没有人会否认自动化测试的价值，而且很多公司也都或多或少地在实践自动化测试。但从整体来看，自动化测试的实施普遍不成体系，大多都在关注单点工具。另外，团队对自动化测试的真实效果也存在疑惑。如果不能解决这些问题，就很难突破实践 DevOps 的天花板。

那么，自动化测试究竟要解决什么问题，又适合哪些业务形态和测试场景呢？我们该如何循序渐进地推进建设，并且正确地度量效果以免踩坑呢？这些问题，就是我要在这一讲中跟你分享的重点内容。

自动化测试要解决什么问题？

产品交付速度的提升，给测试工作带来了很大的挑战。一方面，测试时间被不断压缩，以前三天的测试工作要在一天内完成。另一方面，需求的变化也给测试工作的开展带来了很大的不确定性。这背后核心的问题是，业务功能的累加导致测试范围不断扩大，但这跟测试时长的压缩是矛盾的。说白了，就是要测试的内容越来越多，但是测试的时间却越来越短。

全面测试会带来相对更好的质量水平，但是投入的时间和人力成本也是巨大的，而快速迭代交付就意味着要承担一定的风险。那么，究竟是要速度，还是要质量，这是一个很难回答的问题。

所以，要想提升测试效率，自然就会联想到自动化手段。实际上，自动化测试适用于以下几种典型场景：

有大量机械的重复操作，并且会反复执行的场景，比如批量的回归测试；

有明确的设计规范且相对稳定的场景，比如接口测试；

大批量、跨平台的兼容性测试，比如覆盖多种版本和多种机型的测试，几十个机型还可以接受，如果覆盖成百上千个机型，就只能依靠自动化了；

长时间不间断执行的测试，比如压力测试、可用性测试等。

这些典型场景往往都具备几个特征：设计明确、功能稳定、可多次重复、长期大批量执行等，核心就是通过自动化手段来解决测试成本的问题，也就是人的问题。但这并不意味着手工测试就没有价值了。相反，当人从重复性劳动中解放出来后，就可以投入到更有价值的测试活动中，比如探索性测试、易用性测试、用户验收测试等，这些都属于手工测试的范畴。

这听上去还挺合理的，可是，为什么很多公司还是倾向于采用手工测试的方式呢？实际上，并非所有的测试活动都适合自动化，而且，自动化测试建设也面临着一些问题。

投入产出比：很多需求基本上只会上线一次（比如促销活动类需求），那么，实现自动化测试的成本要比手动测试高得多，而且以后也不会再用了，这显然有点得不偿失。

上手门槛：自动化测试依赖代码方式实现，要开发一套配置化的测试框架和平台，对架构设计和编码能力都有很大的要求。但是，测试人员的编码能力一般相对较弱。

维护成本高：无论是测试环境、测试用例还是测试数据，都需要随着需求的变化不断进行调整，否则就很容易因为自动化测试过时，导致执行失败。

测试设备投入高：比如，移动 App 的测试需要有大量的手机资源，想要覆盖所有的手机型号、操作系统版本，本身就不太现实。更何况，有限的机器还经常被测试人员拿去做本地调试，这就进一步加剧了线上测试没有可用资源的情况。

自动化测试的设计

这么看来，自动化测试并不是一把万能钥匙，我们也不能指望一切测试都实现自动化。只有在合适的领域，自动化测试才能发挥出最大价值。那么，你可能就要问了，面对这么多种测试类型，到底要从哪里启动自动化测试的建设呢？

首先，我来给你介绍一下经典的测试三角形。这个模型描述了从单元测试、集成测试到 UI 测试的渐进式测试过程。越是靠近底层，用例的执行速度就越快，维护成本也越低。而在最上层的 UI 层，执行速度要比单元测试和接口测试要慢，比手工测试要快，相应的维护成本要远高于单元测试和接口测试。

图片来源：“DevOps Handbook"

这样看来，从靠近底层的单元测试入手是一个投入产出相对比较高的选择。但实际上，单元测试的执行情况因公司而异，有的公司能做到 80% 的覆盖率，但有的公司却寸步难行。毕竟，单元测试更多是由开发主导的，开发领导的态度就决定了运行的效果。但不可否认的是，单元测试还是非常必要的，尤其是针对核心服务，比如核心交易模块的覆盖率。当然，好的单元测试需要研发投入大量的精力。

对于 UI 层来说，执行速度和维护成本走向了另外一个极端，这也并不意味着就没有必要投入 UI 自动化建设。UI 层是唯一能够模拟用户真实操作场景的端到端测试，页面上的一个按钮可能触发内部几十个函数调用，和单元测试每次只检查一个函数的逻辑不同，UI 测试更加关注模块集成后的联动逻辑，是集成测试最有效的手段。

另外，很多测试人员都是从 UI 开始接触自动化的，再加上相对成熟的测试工具和框架，实施不依赖于源码，也是一种比较容易上手的自动化手段。在实际应用中，UI 自动化可以帮助我们节省人工测试成本，提高功能测试的测试效率。不过，它的缺点也是比较明显的：随着敏捷迭代的速度越来越快，UI 控件的频繁变更会导致控件定位不稳定，提高了用例脚本的维护成本。

综合考虑投入产出比和上手难度的话，位于中间层的接口测试就成了一种很好的选择。一方面，现代软件架构无论是分层还是服务调用模式，对接口的依赖程度都大大增加。比如典型的前后端分离的开发模式，前后端基本都是在围绕着接口进行开发联调。另一方面，与单元测试相比，接口测试调用的业务逻辑更加完整，并且具备清晰的接口定义，适合采用自动化的方式执行。

正因为如此，对于基于 Web 的应用来说，我更推荐椭圆形模型，也就是以中间层的 API 接口测试为主，以单元测试和 UI 测试为辅。你可以参考一下分层自动化测试模型图。

自动化测试的开发

有效的自动化测试离不开工具和平台的支持。以接口测试为例，最早都是通过 cURL、Postman、JMeter 等工具单机执行的。但是，一次成功的接口测试，除了能够发起服务请求之外，还需要前置的测试数据准备和后置的测试结果校验。对于企业的实际业务来说，不仅需要单接口的执行，还需要相对复杂的多接口，而且带有逻辑的执行，这就依赖于调用接口的编排能力，甚至是内建的 Mock 服务。

不仅如此，测试数据、用例、脚本的管理，测试过程中数据的收集、度量、分析和展示，以及测试报告的发送等，都是一个成熟的自动化测试框架应该具备的功能。

比如，对于 UI 自动化测试来说，最让人头疼的就是 UI 控件变化后的用例维护成本问题。解决方法就是操作层获取控件和控件本身的定位方法，进行解耦，这依赖于框架的设计与实现。在实际操作控件时，你可以通过自定义名称的方式来调用控件，自定义名称在控件相关配置文件中进行定义。在具体操作时，可以通过操作层之下的代理层来处理。示例代码如下：

public void searchItem(String id) {
  getTextBox("SearchBar").clearText();
  getTextBox("SearchBar").setText(id);
  getButton("Search").click();
}

在代码中，搜索条控件被定义为 SearchBar，通过调用代理层的 getTextBox 方法，得到一个文本输入框类型对象，并调用该对象的清除方法。然后，在对应的控件配置文件中添加对应的自定义名称和控件的定位方法。

这样一来，即便控件发生改变，对于实际操作层的代码来说，由于采用的是自定义名称，所以你不需要修改逻辑，只要在对应的控件配置文件中，替换控件的定位方法就行了。关于具体的控件配置文件，示例代码如下：

<TextBox comment=" 首页搜索框 " id="SearchBar">
  <iOS>
    <appium>
      <dependMethod methodName="findElementByXPath">
        <xpath>
          //XCUIElementTypeNavigatorBar[@name="MainPageView"]/XCUIElementTypeOther/...
        </xpath>
      </dependMethod>
    </appium>
  </iOS>
</TextBox>

当然，为了简化测试人员的编写用例成本，你可以在操作层使用 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(), " 商品添加成功 ")
}

从这些示例中，我们可以看出，一个良好的自动化测试框架，可以显著降低测试人员编写测试用例的门槛，以及测试用例的维护成本。对于一个成熟的平台来说，平台易用性是非常重要的能力，通过 DSL 方式来声明测试过程，可以让测试人员聚焦在测试业务逻辑的设计和构建上，大大提升自动化测试的实现效率。

关于自动化测试框架的能力模型，我给你分享你一份资料，你可以点击网盘获取，提取码是 gk9w。这个能力模型从测试脚本封装、测试数据解耦、测试流程编排、报告生成等多个方面，展示了框架建设的各个阶段应该具备的能力。

自动化测试结果分析

那么，我们该如何衡量自动化测试的结果呢？当前比较常用的方式是覆盖率，不过问题是，测试覆盖率提升就能发现更多的缺陷吗？

一家大型金融公司的单元测试覆盖率达到了 80%，接口覆盖率更是达到了 100%，从这个角度来看，他们的自动化测试做得相当不错。但是，当我问到自动化测试发现的问题数量占到整体问题的比例时，他们的回答有点出人意料。在这么高的覆盖率基础上，自动化测试发现的问题占比仅仅在 5% 左右。那么，花了这么大力气建设的自动化测试，最后仅仅发现了 5% 的有效问题，这是不是说明自动化测试的投入产出比不高呢？

实际上，说自动化测试是为了发现更多的缺陷，这是一个典型的认知误区。在实际项目中，手工测试发现的缺陷数量要比自动化测试发现的缺陷数量多得多。自动化测试更多是在帮助守住软件质量的底线，尤其是应用在回归测试中，自动化测试可以确保工作正常的已有功能不会因为新功能的引入而带来质量回退。可以这么说，如果自动化测试覆盖率足够高，那么软件质量一定不会差到哪儿去。

在自动化测试领域，除了追求覆盖率一个指标以外，自动化测试的结果分析也值得重点关注一下。如果自动化测试的结果并不准确，甚至带来大量误报的话，这对团队来说反而是一种干扰。关于测试误报，是指由于非开发代码变更导致的自动化测试用例执行失败的情况。业界对于误报率的普遍定义是：

自动化测试误报率 = 非开发变更引入的问题用例数量 / 测试失败的用例数量

比如，单次自动化测试执行了 100 个用例，其中有 20 个用例失败，这 20 个失败用例有 5 个是由于本次功能或代码变更引入的，也就是真实的缺陷，那么误报率就等于：（20 - 5）/20 = 75%

测试误报率是体现自动化测试稳定性的一个核心指标。对于不同测试类型和产品形态，误报的的原因有很多。比如测试环境的网络不稳定导致的连接超时、测试脚本和测试工具本身的固有缺陷导致的执行失败、测试数据不齐备、测试资源不可用等等。

由于测试误报的客观存在，即便执行了自动化测试并给出了测试结果，但还是需要人工审查判断之后，才能将真正的问题上报缺陷系统。这样一来，在自动化执行末端加入了人工处理，就导致自动化测试难以大规模推行，这也是自动化测试略显“鸡肋”的原因之一。

那么，要如何解决这个问题呢？这就要依赖于自动化测试结果的分析啦。

对自动化测试的问题进行分类。你要弄清楚一次失败是环境问题、网络问题、功能变更，还是系统缺陷？你需要将失败的用例归纳到这些分类之中。当一个类别的问题非常多的时候，你可以考虑进行拆分，比如网络问题，你可以拆分为网络不可达、延迟超时、域名解析错误等等。

增加已有分类的自动识别能力。比如，对于捕获到的常见异常，可以根据异常信息自动上报到对应的错误分类，从而简化人工识别和归类错误的工作量。

提升自动化测试工具和环境的健壮性，对已知问题增加一定的重试机制。

持续积累和丰富错误分类，有针对性地开展改进工作，从而不断提升自动化测试的稳定性。

我跟你分享一幅某公司的自动化测试结果分析示意图。通过统计错误的分类，可以看出错误的占比情况，并且针对常见的误报类型进行有针对性的优化，并建立度量指标来跟踪长期结果，从而保证自动化测试结果的整体可信度。这些工作都需要长期的投入才能看出成效，这也是让自动化测试价值最大化和团队能力提升的必经之路。

总结

总结一下，这一讲我给你介绍了有关自动化测试的四个方面，包括自动化测试要解决的问题和适用场景、实施的路径、框架工具开发的典型思路以及结果分析的要点。希望能够帮你建立起对自动化测试这个“老大难”问题的全面认知，让你在推进自动化测试能力建设的时候有迹可循。

思考题

你所在的企业在进行自动化建设时，有哪些困境和问题，你们是如何解决的呢？

欢迎在留言区写下你的思考和答案，我们一起讨论，共同学习进步。如果你觉得这篇文章对你有所帮助，欢迎你把文章分享给你的朋友。

14 | 内建质量：丰田和亚马逊给我们的启示

你好，我是石雪峰，今天我来跟你聊一个非常重要的话题：内建质量。

我之前给你讲过一个故事，说的是在美国汽车工厂装配流水线的末端，总是有个人在拿着橡胶锤子敲打车门，以检查车门是否安装良好。我还说，如果一个公司要靠“拿锤子的人”来保证质量，这就说明，这个公司的流程本身可能就有问题。

这个观点并不是我凭空捏造出来的，而是来自于质量管理大师爱德华·戴明博士经典的质量管理 14 条原则。其中，第 3 条指出，不应该将质量依赖于检验工作，因为检验工作既昂贵，又不可靠。最重要的是，检验工作并不直接提升产品质量，只是为了证明质量有缺陷。而正确的做法是将质量内建于整个流程之中，并通过有效的控制手段来证明流程自身的有效性。

为什么内建质量如此重要？

在传统的软件开发过程中，检验质量的“锤子”往往都握在测试团队的手中。他们在软件交付的末端，通过一系列的“锤子”来“敲打”软件产品的方方面面，试图找到一些潜在的问题。

这样做的问题是，测试通过尽可能全面的回归测试来验证产品质量符合预期，成本是巨大的，但是效果却不见得有多好。

因为测试只能基于已知的产品设计进行验证，但那些潜在的风险有可能连开发自己都不知道。比如，开发引入了一些第三方的类库，但这些库本身存在缺陷，那么，如果测试没有回归到这个场景，就很有可能出现漏测和生产事故。

另外，由于测试存在的意义在于发现更多的缺陷，有些团队的考核指标甚至直接关联缺陷提交数量，以及缺陷修复数量。那么，这里的前提就是假设产品是存在缺陷的。于是，测试团队为了发现问题而发现问题，在研发后面围追堵截，这也造成了开发和测试之间的隔阂和对立，这显然不是 DevOps 所倡导的状态。

那么，解决这个问题的正确“姿势”，就是内建质量啦！

关于内建质量，有个经典的案例就是丰田公司的安灯系统，也叫作安灯拉绳。丰田的汽车生产线上方有一条绳子，如果生产线上的员工发现了质量问题，就可以拉动安灯系统通知管理人员，并停止生产线，以避免带有缺陷的产品不断流向下游。

要知道，在生产制造业中，生产线恨不得 24 小时运转，因为这样可以最大化地利用时间，生产更多的产品。可是现在，随随便便一个员工就可以让整条生产线停转，丰田公司是怎么想的呢？

其实，这背后的理念就是“Fail fast”，即快速失败。如果工人发现了有缺陷的产品，却要经过层层审批才能停止生产线，就会有大量带有缺陷的产品流向下游，所以，停止生产线并不是目的，及时发现问题和解决问题才是目的。

当启动安灯系统之后，管理人员、产线质量控制人员等相关人员会立刻聚集到一起解决这个问题，并尽快使生产线重新恢复运转。更重要的是，这些经验会被积累下来，并融入组织的能力之中。

内建质量扭转了看待产品质量的根本视角，也就是说，团队所做的一切不是为了验证产品存在问题，而是为了确保产品没有问题。

几年前，我在华为参加转正答辩的时候，被问到一个问题：“华为的质量观是怎样的？”答案是三个字：“零缺陷。”我当时并不理解，人非圣贤，孰能无过？产品零缺陷简直就是反常理。但是，后来我慢慢明白，所谓零缺陷，并不是说产品的 Bug 数量等于零，这其实是一种质量观念，倡导全员质量管理，构建质量文化。每一个人在工作的时候，都要力争第一时间发现和解决缺陷。

所以，总结一下，内建质量有两个核心原则：

问题发现得越早，修复成本就越低；

质量是每个人的责任，而不是质量团队的责任。

说了这么多，你应该已经对内建质量有了初步的认识。那么接下来，我来给你介绍下内建质量的实践思路、操作步骤、常见问题以及应对方法。

内建质量的实施思路

既然是内建质量，那么，我们就应该在软件交付的各个环节中注入质量控制的能力。

在需求环节，可以定义清晰的需求准入规则，比如需求的价值衡量指标是否客观、需求的技术可行性是否经过了验证、需求的依赖是否充分评估、需求描述是否清晰、需求拆分是否合理、需求验收条件是否明确等等。

通过前置需求质量控制，可以减少不靠谱的需求流入。在很多公司，“一句话需求”和“老板需求”是非常典型的例子。由于没有进行充分沟通，研发就跟着感觉走，结果交付出来的东西完全不是想要的，这就带来了返工浪费。

在开发阶段，代码评审和持续集成就是一个非常好的内建质量的实践。在代码评审中，要尽量确认编码是否和需求相匹配，业务逻辑是否清晰。另外，通过一系列的自动化检查机制，来验证编码风格、风险、安全漏洞等。

在测试阶段，可以通过各类自动化测试，以及手工探索测试，覆盖安全、性能、可靠性等，来保障产品质量；在部署和发布阶段，可以增加数据库监控、危险操作扫描、线上业务监控等多种手段。

从实践的角度来说，每个环节都可以控制质量，那么，我们要优先加强哪个环节呢？

根据内建质量的第一原则，我们知道，如果可以在代码刚刚提交的时候就发现和修复缺陷，成本和影响都是最低的。如果等到产品上线后，发现了线上质量问题，再回过头来定位和修复问题，并重新发布软件，成本将会呈指数级增长。

所以，研发环节作为整个软件产品的源头，是内建质量的最佳选择。那么，具体要怎么实施呢？

内建质量的实施步骤

第一步：选择适合的检查类型

以持续集成阶段的代码检查为例，除了有单元测试、代码风格检查、代码缺陷和漏洞检查、安全检查等等，还有各种各样的检查工具。但实际上，这些并不是都需要的。至少在刚开始实践的时候，如果一股脑全上，那么研发基本上就不用干活了。

所以，选择投入产出比相对比较高的检查类型，是一种合理的策略。比如代码风格与缺陷漏洞相比，检查缺陷漏洞显然更加重要，因为一旦发生代码缺陷和漏洞，就会引发线上事故。所以，这么看来，如果是客户端业务，Infer 扫描就可以优先实施起来。虽然我们不能忽视编码风格问题，但这并不是需要第一时间强制执行的。

第二步：定义指标并达成一致

确定检查类型之后，就要定义具体的质量指标了。质量指标分两个层面，一个是指标项，一个是参考值，我分别来介绍一下。

指标项是针对检查类型所采纳的具体指标，比如单元测试覆盖率这个检查项，可采纳的指标就包括行、指令、类、函数等。那么，我们要以哪个为准呢？这个一般需要同研发负责人达成一致，并兼顾行业的一些典型做法，比如单测行覆盖率就是一个比较好的选择。

另外，很多时候，在既有项目启用检查的时候，都会有大量的技术债。关于技术债，我会在下一讲展开介绍。简单来说，就是欠了一堆债，一时半会儿又还不了，怎么办呢？这个时候，比较合适的做法就是选择动态指标，比如增量代码覆盖率，也就是只关注增量代码的情况，对存量代码暂不做要求。

指标项定义明确之后，就要定义参考值了。这个参考值会直接影响质量门禁是否生效，以及生效后的行为。

我简单介绍下质量门禁。质量门禁就类似一道安全门，通过门禁时进行检查，如果不满足指标，则门禁报警，禁止通过。这就跟交警查酒驾一样，酒精含量如果超过一定的指标，就会触发报警。

参考值的定义是一门艺术。对于不同的项目，甚至是同一个项目的不同模块来说，我们很难用“一刀切”的方式定义数值。我比较推荐的做法是将静态指标和动态指标结合起来使用。

静态指标就是固定值，对于漏洞、安全等问题来说，采取零容忍的态度，只要存在就绝不放过。而动态指标是以考查增量和趋势为主，比如基线值是 100，你就可以将参考值定义成小于等于 100，也就是不允许增加。你还可以根据不同的问题等级，定义不同的参考值，比如严格检查致命和阻塞问题，其余的不做限制。

最后，对于这个指标，你一定要跟研发团队达成共识，也就是说，团队要能够认可并且执行下去。所以，定义指标的时候要充分采纳对方的建议。

第三步：建立自动化执行和检查能力

无论公司使用的是开源工具还是自研工具，都需要支持自动化执行和检查的能力。根据检查时机的不同，你也可以在提测平台、发布平台上集成质量门禁的功能，并给出检查结果的反馈。

按照快速失败的原则，质量门禁的生效节点要尽量靠近指标数据的产生环节。比如，如果要检查编码风格，最佳的时间点是在研发本地的 IDE 中进行，其次是在版本控制系统中进行并反馈结果，而不是到了最后发布的时间点再反馈失败。

现代持续交付流水线平台都具备质量门禁的功能，常见的配置和生效方式有两种：

在持续交付平台上配置规则，也就是不同指标和参考值组合起来，形成一组规则，并将规则关联到具体的执行任务中。这样做的好处是，各个生成指标数据的子系统只需要将数据提供给持续交付平台就行了，至于门禁是否通过，完全依靠持续交付平台进行判断。另外，一般配置规则的都是质量人员，提供这样一个单独的入口，可以简化配置成本。具体的实现逻辑，如图所示：

在各个子系统中配置质量门禁。比如，在 UI 自动化测试平台上配置门禁的指标，当持续交付平台调用 UI 自动化测试的时候，直接反馈门禁判断的结果。如果检查不通过，则流水线直接失败。

第四步：定义问题处理方式

完成以上三步之后，就已经开始进行自动化检查了，而检查的结果和处理方式，对质量门禁能否真正起到作用非常重要。一般来说，质量门禁都具有强制属性，也就是说，如果没有达到检查指标，就会立即停止并给予反馈。

在实际执行的过程中，质量门禁的结果可能存在多种选项，比如失败、告警、人工确认等。这些都需要在制定规则的时候定义清楚，通过一定的告警值和人工确认方式，可以对质量进行渐进式管控，以达到持续优化的目标。

另外，你需要对所有软件交付团队成员宣导质量规则和门禁标准，并明确通知方式、失败的处理方式等。否则，检查出问题却没人处理，这个门禁就形同虚设了。

第五步：持续优化和改进

无论是检查能力、指标、参考值，还是处理方式，只有在运行起来后才能知道是否有问题。所以，在推行的初期，也应该具备一定程度的灵活性，比如对指标规则的修订、指标级别和参考值的调整等，核心目标不是为了通过质量门禁，而是为了质量提升，这才是最重要的。

内建质量的常见问题

内建质量说起来并不复杂，但想要执行到位却很困难，那么，到底有哪些常见的问题呢？我总结了一些常见问题和处理建议，做成了表格，你可以参考一下。

最后，我再给你分享一个亚马逊的故事。2012 年，安灯系统被引入亚马逊公司，一线客服如果收到客户反馈或者观察到商品有潜在的质量和安全风险，就可以发出告警邮件，并将商品设置为“不可购买”的状态，说白了，就是强制下架。客服居然可以不经过任何审批，直接把商品下架，不怕遭到供应商的投诉吗？

实际上，这正是亚马逊践行以客户为中心的理念和原则的真实写照，每个人都为最终质量负责，没有例外。当员工得知自己被赋予了这样大的权限时，每个人都会尽自己的力量为质量工作加分。即便偶尔会有错误操作，这也是团队内部难能可贵的学习经验。

在公司中，无论是建立质量门禁的规则，还是开发一套平台系统，其实都不是最困难的事情，难的是，在实际过程中，有多少正常流程走了特殊审批？有多少发布是走的紧急通道？又有多少人会说开启了质量门禁，就会阻碍业务交付？

说到底，还是要问问自己，你愿意付出多少代价，来践行自己的理念和原则，先上再说？我想，能在这一点上达成共识，才是内建质量落地的终极要素吧。

总结

总结一下，在这一讲中，我通过两个故事给你介绍了内建质量的背景和原则，那就是尽早发现问题，尽早修复，以及每个人都是质量的负责人。另外，我还给你介绍了实施内建质量的五个常见步骤。希望你始终记得，质量是生产出来的，而不是测试出来的。掌握了内建质量，你就揭开了 DevOps 高效率和高质量并存的秘密。

思考题

你所在的企业中是否启用了强制的质量门禁呢？可以分享一些你觉得效果良好的规则吗？

欢迎在留言区写下你的思考和答案，我们一起讨论，共同学习进步。如果你觉得这篇文章对你有所帮助，欢迎你把文章分享给你的朋友。

15 | 技术债务：那些不可忽视的潜在问题

你好，我是石雪峰，今天我来跟你聊聊技术债务。

如果要问软件开发人员在项目中最不愿意遇到的事情，答案很可能是接手了一个别人开发了一半的系统。而且，系统开发的时间越长，开发人员的抵触情绪也就越大。那么，既然是同一种代码语言，同一种语法规则，至少还是一个能运行的东西，开发人员为什么要发自内心地抵触呢？我猜，很可能是不想看别人写的代码。之所以会这样，看不懂和怕改错是一个非常重要的原因，而这些，其实都是技术债务的结果。

什么是技术债务？

那么，究竟什么是技术债务呢？它是从哪里来的呢？好好地写个代码，咋还欠债了呢？

试想这样一种场景，老板拍下来一个紧急需求，要求你在 3 天内开发完成上线。在评估需求和设计的时候，你发现，要实现这个功能，有两种方案：

方案 1：采用分层架构，引入消息队列。这样做的好处是结构清晰，功能解耦，但是需要 1 周的时间；

方案 2：直接在原有代码的基础上修修补补，硬塞进去一块逻辑和页面，这样做需要 2 天时间，还有 1 天时间来测试。

那么，你会选择哪个方案呢？

我想，在大多数情况下，你可能都会选择方案 2，因为业务的需求优先级始终是最高的。尤其是当下，市场竞争恨不得以秒来计算，先发优势非常明显。

而技术债务，就是指团队在开发过程中，为了实现短期目标选择了一种权宜之计，而非更好的解决方案，所要付出的代价。这个代价就是团队后续维护这套代码的额外工作成本，并且只要是债务就会有利息，债务偿还得越晚，代价也就越高。

实际上，带来技术债务的原因有很多，除了压力之下的快速开发之外，还包括不明真相的临时解决方案、新员工技术水平不足，和历史债务累积下来的无奈之举等。总之，代码维护的时间越长，引入的技术债务就会越多，从而使团队背上沉重的负担。

技术债务长什么样？

简单来说，你可以把技术债务理解为不好的代码。但是这里的“不好”，究竟是哪里不好呢？我相信，写过代码的人，或多或少都有过这样的经历：

一份代码里面定义了一堆全局变量，各个角落都在引用；

一个脚本仓库里面，一大堆名字看起来差不多的脚本，内容也都差不多；

一个函数里面修修补补写了上千行；

数据表查询各种神奇的关联；

参数传递纯靠肉眼计算顺序；

因为修改一段代码引发了一系列莫名其妙的问题；

……

那么，究竟要如何对代码的技术债务进行分类呢？我们可以借用“Sonar Code Quality Testing Essentials”一书中的代码“七宗罪”，也就是复杂性、重复代码、代码规范、注释有效性、测试覆盖度、潜在缺陷和系统架构七种典型问题。你可以参考一下这七种类型对应的解释和描述：

除了低质量的代码问题之外，还有很多其他类型的技术债务，比如不合理的架构、过时的技术、冷门的技术语言等等。

比如，我们公司之前基于 Ruby 语言开发了一套系统，但是与 Java、Python 等流行语言相比，Ruby 比较小众，所以很难找到合适的工程师，也影响了系统的进一步发展。再比如，到 2020 年元旦，官方即将停止为 Python 2.x 分支提供任何支持，如果现在你们的新系统还在采用 Python 2 进行开发，那么很快就将面对升级大版本的问题。虽然官方提供了一些减少迁移成本的方案，但是，从系统稳定性等方面来讲，依然有着非常大的潜在工作量。

为什么要重视技术债务？

那么问题来了，为什么要重视技术债务呢？或者说，烂代码会有什么问题呢？

从用户的角度来说，技术债务的多少好像并不影响用户的直观体验，说白了就是不耽误使用，应该有的功能都很正常。那么，回到最开始的那个例子，既然 2 天开发的系统，和 1 周开发的系统，从使用的角度来说并没有什么区别，那是不是就意味着，理应选择时间成本更低的方案呢？

显然没有这么简单。举个例子，一个人出门时衣着得体，但是家里却乱成一团，找点东西总是要花很长时间，这当然不是什么值得骄傲的事情。对于软件来说，也是如此。技术债务最直接的影响就是内部代码质量的高低。如果软件内部质量很差，会带来 3 个方面的影响：

1. 额外的研发成本

对一个架构清晰、代码规范、逻辑有序、注释全面的系统来说，新增一个特性可能只需要 1～2 天时间。但是，同样的需求，在一个混乱的代码里面，可能要花上 1 周甚至是更长的时间。因为，单是理解原有代码的逻辑、理清调用关系、把所有潜在的坑趟出来就不是件容易的事情。更何况还有大量重复的代码，每个地方都要修改一遍，一不小心就会出问题。

2. 不稳定的产品质量

代码质量越差，修改问题所带来的影响可能就越大，因为你不知道改了一处内容，会在哪个边缘角落引发异常问题。而且，这类代码往往也没有可靠的测试案例，能够保证修改前和修改后的逻辑是正确的。如果新增一个功能，导致了严重的线上问题，这时就要面临是继续修改还是回滚的选择问题。因为如果继续修改，可能会越错越多，就像一个无底洞一样，怎么都填不满。

3. 难以维护的产品

正是由于以上这些问题，研发人员在维护这种代码的时候往往是小心加谨慎，生怕出问题。这样一来，研发人员宁愿修修补补，也不愿意改变原有的逻辑，这就会导致代码质量陷入一种不断变坏的向下螺旋，越来越难以维护，问题越积累越多，直到再也没办法维护的那一天，就以重构的名义，推倒重来。其实这压根就不是重构，而是重写。

另外，如果研发团队整天跟这样的项目打交道，团队的学习能力和工作积极性都有可能受到影响。可见，技术债务的积累就像真的债务一样，属于“出来混，迟早要还”的那种，只不过是谁来还的问题而已。

如何量化技术债务？

软件开发不像是银行贷款，技术债务看不见摸不着，所以，我们需要一套计算方法把这种债务量化出来。目前业界比较常用的开源软件，就是 SonarQube。在 SonarQube 中，技术债是基于 SQALE 方法计算出来的。关于SQALE，全称是 Software Quality Assessment based on Lifecycle Expectations，这是一种开源算法。当然，今天的重点不是讲这个算法，你可以在官网查看更多的内容。同时，我再跟你分享一篇关于 SQALE 算法的文章，它可以帮你更深入地研究代码质量。

Sonar 通过将不同类型的规则，按照一套标准的算法进行识别和统计，最终汇总成一个时间，也就是说，要解决扫描出来的这些问题，需要花费的时间成本大概是多少，从而对代码质量有一种直观的认识。

Sonar 提供了一种通用的换算公式。举个例子，如下图所示，在 Sonar 的默认规则中，数据越界问题被定义为严重级别的问题，换算出来的技术债务等于 15 分钟。这里的 15 分钟，就是根据前面提到的 SQALE 分析模型计算得出的。当然，你也可以在规则配置里面对每一条规则的预计修复时间进行自定义。

计算出来的技术债务会因为开启的规则数量和种类的不同而不同。就像我在上一讲中提到的那样，团队内部对规则达成共识，是非常重要的。因为只有达成了共识，才能在这个基础上进行优化。否则，如果规则库变来变去，技术债务指标也会跟着变化，这样就很难看出团队代码质量的长期走势了。

另外，在 Sonar 中，还有一个更加直观的指标来表示代码质量，这就是 SQALE 级别。SQALE 的级别为 A、B、C、D、E，其中 A 是最高等级，意味着代码质量水平最高。级别的算法完全是基于技术债务比例得来的。简单来说，就是根据当前代码的行数，计算修复技术债务的时间成本和完全重写这个代码的时间成本的比例。在极端情况下，一份代码的技术债务修复时长甚至比完全推倒重写还要长，这就说明代码已经到了无法维护的境地。所以在具体实践的时候，也会格外重视代码的 SQALE 级别的健康程度。

技术债务比例 = 修复已有技术债务的时间 / 完全重写全部代码的时间

将代码行数引入进来，可以更加客观地计算整体质量水平。毕竟，一个 10 万行的代码项目和一个 1 千行的代码项目比较技术债务本身就没有意义。其实，这里体现了一种更加可视化的度量方式。比如，现在很多公司在做团队的效能度量时，往往会引入一大堆的指标来计算，根本看不懂。更加高级的做法，是将各种指标汇总成一组算法，并根据算法给出相应的评级。

当然，如果你想知道评级的计算方法，也可以层层展开，查看详细的数据。比如，持续集成能力，它是由持续集成频率、持续集成时长、持续集成成功率、问题修复时长等多个指标共同组成的。如果在度量过程中，你发现持续集成的整体评分不高，就可以点击进去查看每个指标的数据和状态，以及详细的执行历史。这种数据关联和下钻的能力对构建数据度量体系而言非常重要。

通过将技术债务可视化，团队会对代码质量有更直观的认识，那么接下来，就要解决这些问题了。

解决方法和原则

我走访过很多公司，他们都懂得技术债务的危害，不仅把 Sonar 搭建起来了，还定时执行了，但问题是没时间。的确，很多时候，我们没时间做单测，没时间做代码评审，没时间解决技术债务，但是这样一路妥协，啥时候是个头儿呢？

前几天，我去拜访一家国内最大的券商公司，眼前一亮。这样一家所谓的传统企业，在研项目的技术债务居然是个位数。在跟他们深入交流之后，我发现，公司在这方面下了大力气，高层领导强力管控，质量门禁严格执行，所以才获得了这样的效果。

所以，从来没有一切外部条件都具备的时候，要做的就是先干再说。那么，要想解决技术债务，有哪些步骤呢？

共识：团队内部要对技术债务的危害、解决项目的目标、规则的选择和制定达成一致意见。

可见：通过搭建开源的 Sonar 平台，将代码扫描整合进持续交付流水线中，定期或者按需执行，让技术债务变得可视化和可量化。不仅如此，Sonar 平台还能针对识别出来的问题，给出建议的解决方法，这对于团队快速提升编码水平，大有帮助。

止损：针对核心业务模块，对核心指标类型，比如 vulnerability，缺陷的严重和阻塞问题设定基线，也就是控制整体数量不再增长。

改善：创建技术优化需求，并在迭代中留出一定的时间修复已有问题，或者采用集中突击的方式搞定大头儿，再持续改进。

在解决技术债务的过程中，要遵循 4 条原则。

让技术债务呈良性下降趋势。一种好的趋势意味着一个好的起点，也是团队共同维护技术债务的一种约定。

优先解决高频修改的问题。技术债务的利息就是引入新功能的额外成本，那么对于高频修改的模块来说，这种成本会快速累积，这也就意味着修复的产出是最大的。至于哪些代码是高频修改的，只要通过分析版本控制系统就可以看出来。

在新项目中启动试点。如果现有的代码过于庞大，不可能在短时间内完成修复，那么你可以选择控制增长，同时在新项目中试点执行，一方面磨合规则的有效性，另一方面，也能试点质量门禁、IDE 插件集成等自动化流程。

技术债务无法被消灭，也不要等到太晚。只要还在开发软件项目，技术债务就基本上无法避免，所以不需要一下子把目标定得太高，循序渐进就行了。但同时，技术债务的累积也不是无穷无尽的，等到再也无法维护的时候就太迟了。

在刚开始解决技术债务的时候，最大的问题不是参考指标太少，而是太多了。所以团队需要花大量时间来 Review 规则。关于这个问题，我给你两条建议：第一，参考代码质量平台的默认问题级别。一般来说，阻塞和严重的问题的优先级比一般问题更高，这也是基于代码质量平台长时间的专业积累得出的结论。第二，你可以参考业界优秀公司的实践经验，比如很多公司都在参考阿里巴巴的 Java 开发手册，京东也有自己的编码规约。最后，我总结了一些影响比较大的问题类型，建议你优先进行处理。

大量重复代码；

类之间的耦合严重；

方法过于复杂；

条件判断嵌套太多；

缺少必要的异常处理；

多表关联和缺少索引；

代码风险和缺陷；

安全漏洞。

总结

在这一讲中，我给你介绍了什么是技术债。而技术债的成本，就是团队后续开发新功能的额外成本。技术债务有很多形态，典型的就是代码“七宗罪”。除此之外，我还跟你聊了下技术债的影响，以及量化技术债务的方法。最后，我给出了一些解决方法和原则，希望能帮你攻克技术债这个难题。

最近这两年，智能研发的声音不绝于耳，其中关于使用人工智能和大数据技术提升代码质量的方法，是目前的一个热门研究领域。通过技术手段，辅助研发解决技术问题，在未来是一种趋势。如果你在公司中从事的是研发辅助和效率提升类的工作，建议你深入研究下相关的学术文章，这对你的工作会大有裨益。

参考资料：

通过持续监控实现代码克隆的定制化管理

基于代码大数据的软件开发质量追溯体系

代码克隆那点事：开发人员为何克隆？现状如何改变？

思考题

你遇到过印象深刻的烂代码吗？

欢迎在留言区写下你的思考和答案，我们一起讨论，共同学习进步。如果你觉得这篇文章对你有所帮助，欢迎你把文章分享给你的朋友。

16 | 环境管理：一切皆代码是一种什么样的体验？

你好，我是石雪峰。

网上经常流传着一些有关偏见地图的段子，通俗点说，“偏见地图”就是说网友对世界其他地方的印象，比如很多人认为天津人都会说相声。

如果软件开发中也有偏见地图的话，那么，对不熟悉运维的人来说，提到运维团队，可能就觉得是维护环境的那帮人。于是，环境就成了软件行业的“头号背锅侠”。比如，线上出故障了，可以是环境配置错误；测试有些功能没测到，可以是没有测试环境；开发出 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: "{{ .Values.image.tag }}"
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 80

现在，我们来看看这个方案是如何实现的。

首先，开发人员提交新的代码改动到 Git 仓库，这会自动触发持续集成流水线，对于常见的版本控制系统来说，配置钩子就可以实现。当代码经过一系列的构建、测试和检查环节，并最终通过持续集成流水线之后，就会生成一个新版本的应用，并上传到制品库中，典型的就是 Docker 镜像文件或者 war 包的形式。

以上面的配置为例，假如生成了应用的 1.0 版本镜像，接下来，会自动针对测试环境的配置仓库创建一个代码合并请求，变更的内容就是修改镜像名称的版本号为 1.0。这个时候，开发或者测试人员可以通过接受合并的方式，将这段环境变更配置合入主干，并再一次自动化地触发部署流水线，将新版本的应用部署到测试环境中。每次应用的部署采用相同的过程，一般就是将最新版本的应用制品拷贝到服务器并且重启，或者更新容器镜像并触发滚动升级。

这个时候，测试环境就部署完成了，当然，如果使用 Kubernetes，可以利用命名空间的特性，快速创建出一套独立的环境，这是使用传统部署的应用所不具备的优势。在测试环境验收通过后，可以将代码合并到主分支，再一次触发完整的集成流水线环节，进行更加全面的测试工作。

当流水线执行成功后，可以自动针对预发布环境的配置仓库创建一个合并请求，当评审通过后，系统自动完成预发布环境的部署。如果职责分离要求预发布环境的部署必须由运维人员来操作，把合并代码的权限只开放给运维人员就行了。当运维人员收到通知后，可以登录版本控制系统，查看本次变更的范围，评估影响，并按照部署节奏完成部署。而这个操作，只需要在界面点击按钮就可以实现了。这样一来，开发和运维团队的协作就不再是一个黑盒子了。大家基于代码提交评审的方式完成应用的交付部署，整个过程中的配置过程和参数信息都是透明共享的。

我跟你分享一幅流程图，希望可以帮你充分地理解这个分层部署的过程。

那么，GitOps 的好处究竟有哪些呢？

首先，就是环境配置的共享和统一管理。原本复杂的环境配置过程通过代码化的方式管理起来，每个人都能看懂。这对于开发自运维来说，大大地简化了部署的复杂度。

另外，所有最新的环境配置都以 Git 仓库中为准，每一次的变更和部署过程也同样由版本控制系统进行记录。即便仅仅是环境工具的升级，也需要经过以上的完整流程，从而实现了环境和工具升级的层层验证。所以，这和基础设施即代码的理念可以说有异曲同工之妙。

开发环境的治理实践

关于开发环境的治理，我再给你举一个实际的案例。对于智能硬件产品开发来说，最大的痛点就是各种环境和工具的配置非常复杂，每个新员工入职，配置环境就要花上几天时间。另外，由于工具升级频繁和多平台并行开发的需要，开发经常需要在多种工具之间进行来回切换，管理成本很高。

关于这个问题，同样可以采用基础设施即代码的方法，生成一个包含全部工具依赖的 Docker 镜像，并分发给开发团队。在开发时仅需要拉起一个容器，将代码目录挂载进去，就可以生成一个完全标准化的研发环境。当工具版本升级时，可以重新制作一个新的镜像，开发本地拉取后，所有的工具就升级完成了，这大大简化了研发环境的维护成本。

其实，我们也可以发挥创新能力，把多种工具结合起来使用，以解决实际问题。比如，我们团队之前要同时支持虚拟化设备和容器化两种环境，虚拟化可以采用传统的 Ansible 方式完成环境部署，但容器化依赖于镜像的 Dockerfile。这就存在一个问题：要同时维护两套配置，每次升级的时候也要同时修改虚拟化和容器化的配置文件。于是，为了简化这个过程，就可以把两者的优势结合起来，使用单一数据源维护标准环境。

具体来说，在 Dockerfile 中，除了基础环境和启动脚本，环境配置部分同样采用 Ansible 的方式完成，这样每次在生成一个新的镜像时，就可以使用相同的方式完成环境的初始化过程，配置示例如下：

FROM  harbor.devops.com:5000/test:ansible
MAINTAINER XX <xx@devops.com>
ADD ./docker  /docker
WORKDIR /docker
RUN export TMPDIR=/var/tmp && ansible-playbook -v -i playbooks/inventories/docker playbooks/docker_container.yml

开发本地测试的实践

其实，我始终认为，环境管理是 DevOps 推行过程中的一个潜在“大坑”。为了提升开发者的效率，业界也在探索很多新的实践方向。我在前面也给你介绍过快速失败的理念，只有在第一时间反馈失败，才能最小化问题修复成本。而对于研发来说，由于测试环境的缺失，往往要等到代码提交并部署完成之后才能获取反馈，这个周期显然是可以优化的。关于如何解决开发本地测试的问题，在 Jenkins 社区也有一些相关的实践。

比如，你基于 Kubernetes 创建了一套最小测试环境，按照正常过程来说，如果改动一行代码，你需要经过代码提交、打包镜像、上传制品、更新服务器镜像等，才能开始调试。但如果你使用KSync工具，这些过程统统可以省略。KSync 可以帮你建立本地工作空间和远端容器目录的关联，并自动同步代码。也就是说，只要在本地 IDE 里面修改了一行代码，保存之后，KSync 就可以帮你把本地代码传到线上的容器中，对于类似 Python 这样的解释型语言来说特别省事。

谷歌也开源了一套基于容器开发自动部署工具Skaffold，跟 KSync 类似，使用 Skaffold 命令就可以创建一套 Kubernetes 环境。当本地修改一行代码之后，Skaffold 会自动帮你重新生成镜像文件，推送远端，并部署生效，让代码开发变得所见即所得。研发只需要专注于写代码这件事情，其余的全部自动化，这也是未来 DevOps 工程实践的一个发展方向。

总结

今天，我给你介绍了企业环境管理的五个难题：种类多，复杂性，一致性，交付速度和变更追溯，并解释了为什么基础设施即代码是解决环境管理问题的最佳实践，还跟你分享了三个基础设施即代码的案例，希望能够帮助你理解这个过程。

如果你不太了解 Kubernetes 和容器，可能会有些内容难以消化。我想跟你说的是，无论采用什么技术，代码化管理的方式都是未来的发展趋势，建议你结合文章中的代码和流程图仔细梳理一下，并且尝试使用 CAPS 工具重新定义环境部署过程，将环境配置过程实现代码化。如果有问题，可以及时在留言区提问。

思考题

你认为推行开发自运维的最大难点是什么？关于解决这些难点，你有什么建议吗？

欢迎在留言区写下你的思考和答案，我们一起讨论，共同学习进步。如果你觉得这篇文章对你有所帮助，欢迎你把文章分享给你的朋友。

17 | 部署管理：低风险的部署发布策略

你好，我是石雪峰，今天我来跟你聊聊部署管理。

在 DevOps 年度状态报告中，有四个核心的结果指标，其中仅“部署”这一项就占了两个关键指标，分别是部署频率和部署失败率。顺便提一下，另外两个指标是前置时长和平均故障修复时长。

对 DevOps 来说，部署活动就相当于软件交付最后一公里的最后一百米冲刺。只有通过部署发布，软件真正交付到最终用户手中的时候，前面走过的路才真正创造了价值。

部署和发布这两个概念，经常会被混用，但严格来说，部署和发布代表两种不同的实践。部署是一组技术实践，表示通过技术手段，将本次开发测试完成的功能实体（比如代码、二进制包、配置文件、数据库等）应用到指定环境的过程，包括开发环境、预发布环境、生产环境等。部署的结果是对服务器进行变更，但是这个变更结果不一定对外可见。

发布，也就是 Release，更偏向一种业务实践，也就是将部署完成的功能正式生效，对用户可见和提供服务的过程。发布的时机往往同业务需求密切相关。很多时候，部署和发布并不是同步进行的，比如，对于电商业务来说，要在 0 点上线新的活动，那么如果部署和发布不分离，就意味着要在 0 点的前 1 秒，完成所有服务器的变更，这显然是不现实的。

那么，我想请你思考这样一个问题：所谓的低风险发布，是不是要在发布之前确保本次变更的功能万无一失了，才会真正地执行发布动作呢？

事实上，即使没这么说，很多公司也都是这样做的。传统软件工程在流程设计的时候，也是希望通过层层的质量手段，来尽可能全面地验证交付产品的质量。典型的应用就是测试的 V 模型，从单元测试、集成测试、系统测试，到用户验收，还有各类专项测试，其实都是为了在发布之前发现更多的问题，以此来保障产品的质量。

那么，在 DevOps 模式下，是否也倡导同样的质量思想呢？我觉得这是一个有待商榷的问题。

实际上，随着发布频率的加速，留给测试活动的时间越来越有限了。与此同时，现在业务的复杂度，也比十年前高了不知道多少个等级。每次发布涉及 PC 端、移动端，还有小程序、H5 等多种形态，更别提成百上千的终端设备了。要在有限的时间里，完成所有的测试活动，本来就是件很有挑战的事情。而且，各个公司都在衡量测试开发比，更是限制了测试人力投入的增长，甚至还要不断下降。

你当然可以通过自动化手段来提升测试活动的效率，但穷尽测试本来就是个伪命题。那么，明明说了 DevOps 可以又快又好，难道是骗人的吗？

当然不是。这里的核心就在于 DevOps 模式下，质量思想发生了转变。简单概括就是：要在保障一定的质量水平的前提下，尽量加快发布节奏，并通过低风险发布手段，以及线上测试和监控能力，尽早地发现问题，并以一种最简单的手段来快速恢复。

这里面有几个关键词：一定的质量水平，低风险发布手段，线上测试和监控，以及快速恢复。我分别来给你解释一下。

一定的质量水平

这个“一定”要怎么理解呢？对于不同形态的软件来说，质量标准的高低自然是不相同的。比如，我有一个制造卫星的同学，他们对于软件质量的要求就是要做到几年磨一剑，甚至是不计成本的。但对于互联网这种快速迭代的业务来说，大家都习惯了默认会出问题，所以在圈定测试范围和测试覆盖的基础上，只要完成严重问题的修复即可发布，低级别的问题可以在后续的众测和灰度的环节继续处理。

所以，与定义一个发布质量标准相比，更重要的随着 DevOps 的推广，扭转团队的质量观念。质量不再是测试团队自身的事情，而是整个交付团队的事情。如果出现了线上问题，团队要一起来定位和修复，并且反思如何避免类似的问题再次发生，从失败中学习。

而测试能力的向前、向后延伸，一方面，提供了工具和平台以帮助开发更容易地进行自测；另一方面，加强针对线上监控埋点等类型的测试，可以保证线上问题可以快速暴露，正常获取辅助分析用户行为的数据，这会全面提升整体的发布质量。

低风险的发布手段

既然发布是一件不可回避的高风险事情，那么，为了降低发布活动的风险，就需要有一些手段了。典型的包括以下几种：蓝绿部署，灰度发布和暗部署。

1. 蓝绿部署

蓝绿部署就是为应用准备两套一模一样的环境，一套是蓝环境，一套是绿环境，每次只有一套环境提供线上服务。这里的蓝和绿，只是用于区分两套环境的标志而已。在新版本上线时，先将新版本的应用部署到没有提供线上服务的环境中，进行上线前验证，验证通过后就达到了准备就绪的状态。在发布时间点，只要将原本指向线上环境的路由切换成另外一套环境，整个发布过程就完成了。

一般来说，这种方式的实现成本比较高。因为有两套一模一样的环境，只有一套用于真正地提供线上服务。为了减少资源浪费，在实际操作中，另外一套环境可以当作预发布环境使用，用来在上线之前验证新功能。另外，在这种模式下，数据库普遍还是采用同一套实例，通过向下兼容的方式支持多个版本的应用。

图片来源：https://www.gocd.org/2017/07/25/blue-green-deployments.html

2. 灰度发布

灰度发布，也叫金丝雀发布。与蓝绿部署相比，灰度发布更加灵活，成本也更低，所以，在企业中是一种更为普遍的低风险发布方式。

灰度发布有很多种实现机制，最典型的就是采用一种渐进式的滚动升级来完成整个应用的发布过程。当发布新版本应用时，根据事先设计好的灰度计划，将新应用部署到一定比例的节点上。当用户流量打到这部分节点的时候，就可以使用新的功能了。

值得注意的是，要保证同一个用户的行为一致性，不能时而看到新功能，时而看到老功能。当然，解决办法也有很多，比如通过用户 ID 或者 cookie 的方式来识别用户，并划分不同的组来保证。

新版本应用在部分节点验证通过后，再逐步放量，部署更多的节点，依次循环，最终完成所有节点的部署，将所有应用都升级到新版本。分批部署只是实现灰度发布的方法之一，利用配置中心和特性开关，同样可以实现指向性更强的灰度策略。比如，针对不同的用户、地域、设备类型进行灰度。

对于移动端应用来说，灰度发布的过程也是必不可少的。我以 iOS 平台应用为例，带你梳理下发布的步骤。首先，公司的内部用户可以自行下载安装企业包，进行新版本验证和试用。试用 OK 后，再通过官方的 Testflight 平台对外开启灰度，这样只有一部分用户可以收到新版本通知，并且在 Testflight 中安装新版本。灰度指标符合预期后，再开启全量用户升级。

现在很多应用都采用了动态下发页面的方法，同样可以使用特性开关，来控制不同用户看到不同的功能。

图片来源：https://www.gocd.org/2017/07/25/blue-green-deployments.html

3. 暗部署

随着 A/B 测试的兴起，暗部署的方式也逐渐流行起来。所谓暗部署，就是在用户不知道的情况下进行线上验证的一种方法。比如后端先行的部署方式，把一个包含新功能的接口发布上线，这个时候，由于没有前端导向这个接口，用户并不会真实地调用到这个接口。当用户进行了某些操作后，系统会将用户的流量在后台复制一份并打到新部署的接口上，以验证接口的返回结果和性能是否符合预期。

比如，对于电商业务场景来说，当用户搜索了一个关键字后，后台有两种算法，会给出两种返回结果，然后可以根据用户的实际操作，来验证哪种算法的命中率更高，从而实现了在线的功能验证。

图片来源：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 信息，调用参数，查看返回结果，跟踪节点耗时等，甚至还能查看内存占用、反编译源码等，堪称问题诊断利器。

初步对问题进行分析定位后，你可以有两种选择：向前修复和向后回滚。

向前修复就是快速修改代码并发布一个新版本上线，向后回滚就是将系统部署的应用版本回滚到前一个稳定版本。无论选择哪一种，考验的都是自动化的部署流水线和自动化的回滚能力，这也是团队发布能力的最佳体现。而在 DevOps 的结果指标中，部署前置时长描述的恰恰就是这段时长。当然，最佳实践就是自动化的流水线。往往在这个时候，你就会希望流水线更快一些，更自动化一些。

最后，再提一点，你可能在很多大会上听过“故障自愈”，也就是出现问题系统可以自动修复。这听起来有点神奇，但实际上，故障自愈的第一步，就要做好服务降级和兜底策略。这两个听起来很专业的词是啥意思呢？别着急，我给你举个例子，你就明白了。

我给你截了两张某购物 App 的图片，你可以对比看下有什么不同。

如果你仔细看的话，你会发现，单这一个页面就有大大小小 8 个差异。所以，服务降级就是指，在流量高峰的时候，将非主路径上的功能进行临时下线，保证业务的可用性。典型的做法就是通过功能开关的方式来手动或自动地屏蔽一些功能。

而兜底策略是指，当极端情况发生时，比如服务不响应、网络连接中断，或者调用服务出现异常的时候，也不会出现崩溃。常见的做法就是缓存和兜底页面，以及前端比较流行的骨架屏等。

总结

在这一讲中，我给你介绍了 DevOps 模式下质量思想的转变，那就是要在保障一定的质量水平的前提下，尽量加快发布节奏，并通过低风险发布手段，以及线上测试和监控能力，尽早地发现问题，并以一种最简单的手段来快速恢复。

质量活动是有成本的，为了保证快速迭代发布，一定程度的问题发生并不是末日，更重要的是通过质量活动向前向后延伸，并在生产环境加强监控和测试。同时，三种典型的低风险发布方式可以满足不同业务场景的需求。当问题发生时，不仅要做到快速识别，快速修复，还要提前通过服务降级、兜底策略等机制保证系统服务的连续性。

思考题

你所在的企业采用了哪些手段来保障部署活动是安全可靠的呢？

欢迎在留言区写下你的思考和答案，我们一起讨论，共同学习进步。如果你觉得这篇文章对你有所帮助，欢迎你把文章分享给你的朋友。

18 | 混沌工程：软件领域的反脆弱

你好，我是石雪峰。

经济学领域有一本特别有名的书，叫作《反脆弱》。它的核心理念就是，在面对普遍存在又不可预估的不确定性时，通过一种行之有效的方法，不仅可以规避重大风险，还能够利用风险获取超出预期的回报。另外，通过积极地试错，控制损失成本，还能不断提升在不确定性事件发生时的收益。

不仅仅要规避风险，还要在风险中受益，这听起来是不是很神奇？其实，在软件工程领域，也有类似的思想和实践，可以帮助我们在面对极其复杂且规模庞大的分布式系统时，有效地应对不可预见的故障，不仅可以从容不迫地应对，还能从中获益，并且通过频繁、大量地实验，识别并解决潜在的风险点，从而提升对于复杂系统的信心。这就是今天我要给你分享的主题：混沌工程。

什么是混沌工程？

混沌工程作为软件领域的一门新兴学科，就和它的名字一样，让很多人感到非常“混沌”。那么，混沌工程究竟是从何而来，又是要解决什么问题呢？

我们先来看看混沌原则网站对混沌工程的定义：

Chaos Engineering is the discipline of experimenting on a distributed system in order to build confidence in the system’s capability to withstand turbulent conditions in production.

混沌工程是一门在分布式系统上进行实验的学科，目的是建立人们对于复杂系统在生产环境中抵御突发事件的信心。

简单来说，混沌工程要解决的，就是复杂环境下的分布式系统的反脆弱问题。那么，我们所要面对的“复杂的分布式”的真实世界是怎样的呢？

我给你举个例子。对于一个大型的平台来说，每日在线的活动数以万计，服务的用户可以达到千万级别。为了满足这种规模的业务量级，仅客户端就有 300 多个组件，后端服务更是不计其数。

可以想象，这样一套复杂的系统，任何一个地方出了一点小问题，都有可能带来线上事故。

另外，随着微服务、容器化等技术的兴起，业务驱动自组织团队独立发布的频率越来越高，再加上架构的不断更新演进，可以说，几乎没有人能完整地梳理清楚一套系统的服务间调用关系，这就让复杂系统变成了一个“黑洞”。不管外围如何敲敲打打，都很难窥探到核心问题。

为了让你对复杂的真实系统有更加直观的认识，我跟你分享一张 Netflix 公司在 2014 年公开的微服务调用关系图，你可以参考一下。

图片来源：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 的话来说

混沌工程不是为了制造问题，而是为了揭示问题。

必须要强调的是，在引入混沌工程的实践之前，首先需要确保现有的服务已经具备了弹性模式，并且能够在应急响应预案和自动化工具的支撑下尽早解决可能出现的问题。

如果现有的服务连基本的可恢复性这个条件都不具备的话，那么这种混沌实验是没有意义的。我跟你分享一幅混沌工程的决策图，你可以参考一下：

图片来源：https://blog.codecentric.de/en/2018/07/chaos-engineering/

混沌工程的原则

混沌工程不像是以往的工具和实践，作为一门学科，它具有非常丰富的内涵和外沿。你在进入这个领域之前，有必要了解下混沌工程的五大原则：建立稳定状态的假设、真实世界的事件、在生产中试验、持续的自动化实验、最小影响范围。

我们分别来看一下这五条原则要如何进行实践。

1. 建立稳定状态的假设

关于系统的稳定状态，就是说，有哪些指标可以证明当前系统是正常的、健康的。实际上，无论是技术指标，还是业务指标，现有的监控系统都已经足够强大了，稍微有一点抖动，都能在第一时间发现这些问题。

比如，对于技术指标来说，前面在压测部分提到的指标就很有代表性（QPS、TP99、CPU 使用率等）；而对于业务指标来说，根据公司具体业务的不同会有所不同。

举个例子，对于游戏来说，在线用户数和平均在线时长就很重要；对于电商来说，各种到达率、结算完成率，以及更加宏观的 GMV、用户拉新数等，都能表现出业务的健康程度。

与技术指标相比，业务指标更加重要，尤其是对电商这种活动密集型的行业来说，业务指标会受到活动的影响，但基于历史数据分析，总体趋势是比较明显的。

当业务指标发生大量的抖动时（比如瞬时降低提升），就意味着系统出现了异常。比如，几天前微信支付出现问题，从监控来看，支付的成功率就受到了比较明显的影响。

在真实世界中，为了描述一种稳定状态，需要一组指标构成一种模型，而不是单一指标。无论是否采用混沌工程，识别出这类指标的健康状态都是至关重要的。而且，还要围绕它们建立一整套完善的数据采集、监控、预警机制。

我给你提供了一些参考指标，汇总在了下表中。

2.真实世界的事件

真实世界的很多问题都来源于过往踩过的“坑”，即便是特别不起眼的事件，都会带来严重的后果。

比如，我印象比较深的一次故障就是，服务器在处理并发任务的时候，CPU 跑满，系统直接卡死。通过调查发现，在出现问题的时候，系统的 I/O Wait 很高，这就说明磁盘发生了 I/O 瓶颈。经过仔细地分析，最终发现是磁盘 Raid 卡上的电池没电了，从而导致磁盘 Raid 模式的降级。

像这种事情，你很难通过监控所有 Raid 卡的电池容量来规避问题，也不可能在每次模拟故障的时候，故意换上没电的电池来进行演练。

所以，既然我们无法模拟所有的异常事情，投入产出比最高的就是选择重要指标（比如设备可用性、网络延迟，以及各类服务器问题），进行有针对性地实验。另外，可以结合类似全链路压测等手段，从全局视角测试系统整体运作的可用性，通过和稳定状态的假设指标进行对比，来识别潜在的问题。

3.在生产中实验

跟测试领域的“质量右移理念”一样，混沌工程同样鼓励在靠近生产环境的地方进行实验，甚至直接在生产环境中进行实验。

这是因为，真实世界的问题，只有在生产环境中才会出现。一个小规模的预发布环境更多的是验证系统行为和功能符合产品设计，也就是从功能的角度出发，来验证有没有新增缺陷和质量回退。

但是，系统的行为会根据真实的流量和用户的行为而改变。比如，流量明星的一则消息就可能导致微博的系统崩溃，这是在测试环境很难复现的场景。

但客观来说，在生产环境中进行实验，的确存在风险，这就要求实验范围可控，并且具备随时停止实验的能力。还是最开始的那个原则，如果系统没有为弹性模式做好准备，那么就不要开启生产实验。

还以压测为例，我们可以随机选择部分业务模块，并圈定部分实验节点，然后开启常态化压测。通过定期将线上流量打到被测业务上，观察突发流量下的指标表现，以及是否会引发系统雪崩，断路器是否生效等，往往在没有准备的时候才能发现真实问题。这种手段作为混沌工程的一种实践，已经普遍应用到大型公司的在线系统之中了。

4.持续的自动化实验

自动化是所有重复性活动的最佳解决方案。通过自动化的实验和自动化结果分析，我们可以保证混沌工程的诸多实践可以低成本、自动化地执行。正因为如此，以混沌工程为名的工具越来越多。

比如，商业化的混沌工程平台 Gremlins 就可以支持不可用依赖、网络不可达、突发流量等场景。今年，阿里也开源了他们的混沌工具ChaosBlade，缩短了构建混沌工程的路径，引入了更多的实践场景。另外，开源的Resilience4j和Hystrix也都是非常好用的工具。无论是自研，还是直接采用，都可以帮助你快速上手。

我相信，随着越来越多工具的成熟，未来混沌工程也会成为 CI/CD 流水线的一部分，被纳入到日常工作中来。

5.最小的影响范围

混沌工程实践的原则就是不要干扰真实用户的使用，所以，在一开始将实验控制在一个较小的范围内，是非常有必要的，这样可以避免由于实验失控带来的更大问题。

比如，圈定一小部分用户，或者服务范围，可以帮助我们客观地评估实验的可行性。假设要实验一个 API 对错误的处理能力，我们可以部署一个新的 API 实验集群，并修改路由导流 0.5% 的流量用于线上实验。在这个集群中通过故障注入的方式，验证 API 是否能够处理流量带来的错误场景。这有点类似于一个灰度实验环境，或者暗部署的方式。

除了可以用于验证新功能，做线上的 A/B 测试，同样适用于混沌工程的故障注入。

这五大原则共同勾勒出了混沌工程的全景图，描述系统稳定状态的前提下，将真实世界的事件在生产环境中进行实验，并控制最小影响范围，引入自动化方式持续进行。作为一种全新的工程领域，混沌工程还要走很长的路，才能跨越技术演进的鸿沟。

参考资料：

Netflix 混沌工程成熟度模型

混沌工程资料集

Netflix 混沌工程手册

总结

在这一讲中，我给你介绍了一个应对复杂分布式系统可用性挑战的新学科——混沌工程。实际上，混沌工程采用了一种全新的思路，在系统中主动注入混沌进行实验，以此来发现潜在的真实世界的问题。在服务可用性方面，我们一直在努力实践，比如，故障演练、服务降级、全链路压测已经成为了大型系统的标配。最后，我给你介绍了混沌工程的 5 个实践原则，希望可以帮助你建立更加全面的认知。

不可否认，目前国内在混沌工程领域的实践还处于摸索实验阶段，但是随着系统的复杂性越来越高，混沌工程也注定会跨越技术发展的鸿沟，成为解决复杂系统可用性问题的利器。

思考题

关于真实世界中发生的异常事件，你有哪些独特的经历呢？结合混沌工程的实践，你有什么新的思路吗？

欢迎在留言区写下你的思考和答案，我们一起讨论，共同学习进步。如果你觉得这篇文章对你有所帮助，也欢迎你把文章分享给你的朋友。

19 | 正向度量：如何建立完整的DevOps度量体系？

你好，我是石雪峰。到今天为止，我用 14 讲的篇幅给你通盘梳理了 DevOps 的工程实践，基本涵盖了工程实践的方方面面。但是，就像那句经典的“不仅要低头看路，还要抬头看天”说的一样，我们花了这么大的力气投入工程实践的建设，结果是不是符合我们的预期呢？

所以，在工程实践的最后两讲，我想跟你聊聊度量和持续改进的话题，今天先来看看 DevOps 的度量体系。

我相信，对于每个公司来说，度量都是必不可少的实践，也是管理层最重视的实践。在实施度量的时候，很多人都把管理学大师爱德华·戴明博士的“If you can’t measure it, you can’t manage it”奉为实践圭臬。

但是，回过头来想想，有多少度量指标是为了度量而度量的？花了好大力气度量出来的数据会有人看吗？度量想要解决的，到底是什么问题呢？

所以，度量不是目的，而是手段，也就是说度量的目标是“做正确的事”，而度量的手段是“正确地做事”。

那么，什么才是度量领域正确的事情呢？如果想要弄清楚 DevOps 中的度量长什么样子，关键就是要回到 DevOps 对于软件交付的核心诉求上。

简而言之，对于 IT 交付来说，DevOps 希望做到的就是持续、快速和高质量的价值交付。价值可以是一个功能特性，可以是用户体验的提升，也可以是修复阻塞用户的缺陷。

明确了这一点，也就明确了 DevOps 的度量想要达到的目标，就是为了证明，经过一系列的改进工作，与过去相比，团队的交付速度更快了，交付质量更高了。如果度量的结果不能导向这两个核心目标，那么显然就走错了方向，也就得不到实际想要的结果了。

如果只有大方向，往往还是不知道具体要怎么做。这个时候，就需要把目标和方向拆解成一系列的度量指标了。那么，怎样定义好的度量指标和不好的度量指标呢？

如何定义指标？

前几天，我被派到某仓库做流水线工人，这个经历让我深刻地理解了工业制造和软件行业的巨大差异。

如果你现在问我，决定工业生产流水线速度的是什么？我可以告诉你，答案就是，流水线本身。因为流水线的传送带的速度是一定的，产线速度也就可以直观地量化出来。

但是，软件开发不像工业制造，开发的过程看不见摸不着，除了工程师真正编写代码的时间，还要包括构思、设计和测试的时间，以及完成各类流程的时间等等。这个过程中可能还存在着各种并行工作的切换和打断，所以，没法用工业流水线的方式来衡量开发人员的效率。

于是，为了达到量化的目的，很多指标就被人为地设计出来了。

比如，以准时提测率这个指标为例，这个指标采用的是百分制的形式，按时提测得 100 分，延期一天得 90 分，延期两天得 70 分，以此类推，要是延期五天及以上，就只能 0 分了。这样的指标看起来似乎足够客观公平，但是仔细想想，延期 1 天 1 小时和延期 1 天 23 小时，似乎也没有太大区别，得分的高低并不能反映真实的情况。

在各个公司的度量体系中，类似的人造指标可谓比比皆是。可见，不好的指标总是五花八门，各有各的样子。不过，好的指标大多具备一些典型的特征。

1. 明确受众。

指标不能脱离受众而单独存在，在定义指标的同时，要定义它所关联的对象，也就是这个指标是给谁看。

不同的人关注点自然也不一样，即便指标本身看起来没有什么问题，但是如果使用错位了，也很难产生预期的价值。比如，给非技术出身的老板看单元测试的覆盖率，就没有什么太大意义。

2. 直指问题。

在 NBA 中，优秀的球员总是自带体系的。所谓体系，就是围绕这个球员的核心能力的一整套战术打法，可以解决球队的实际问题，所以，这个球员的表现就成了整支球队的“晴雨表”。

而好的指标也应该是直指问题的，你一看到这个指标，就能意识到问题所在，并自然而然地进行改进，而不是看了跟没看见一样，也不知道具体要做什么。

比如，构建失败率很高，团队就会意识到代码的提交质量存在问题，需要加强事前的验证工作。

3. 量化趋势。

按照 SMART 原则，好的指标应该是可以衡量的，而且是可以通过客观数据来自证的。

比如，用户满意度这种指标看起来很好，但很难用数据衡量；再比如，项目达成率这个指标，如果只是靠手工填写，那就没啥说服力。

同时，好的度量指标应该能展现趋势。也就是说，经过一段时间的沉淀，指标是变好了，还是变坏了，距离目标是更近了，还是更远了，这些都应该是一目了然的。

4. 充满张力。

指标不应该孤立存在，而是应该相互关联构成一个整体。好的指标应该具有一定的张力，向上可以归并到业务结果，向下可以层层分解到具体细节。这样通过不同维度的数据抽取，可以满足不同视角的用户需求。

比如，单纯地度量需求交付个数，就没有太大意义。因为需求的颗粒度会直接影响数量，如果只是把一个需求拆成两个，从而达到需求交付速度加倍的效果，这就失去了度量的意义。

定义指标有哪些原则？

明白了好的度量指标的典型特征，接下来，我们就来看看定义 DevOps 度量的五条原则：

全局指标优于局部指标：过度的局部优化可能对整体产出并无意义，从而偏离了度量的核心，也就是提升交付速度和交付质量。

综合指标优于单一指标：从单一维度入手会陷入只见树木不见森林的困境，综合指标更加客观。所以，要解决一个问题，就需要一组指标来客观指引。

结果指标优于过程指标：首先要有结果指标，以结果为导向，以过程为途径，一切过程指标都应该归结到结果指标。

团队指标优于个人指标：优先考核团队指标而非个人指标，团队共享指标有助于形成内部合力，减少内部的割裂。

灵活指标优于固化指标：指标的设立是为了有针对性地实施改进，需要考虑业务自身的差异性和改进方向，而非简单粗暴的“一刀切”，并且随着团队能力的上升，指标也需要适当的调整，从而不断挑战团队的能力。

哪些指标最重要？

基于以上的指标特征和指导原则，并结合业界大厂的一些实践，我给你推荐一套 DevOps 度量体系。

虽然各个公司的度量指标体系都不尽相同，但是我认为这套体系框架足以满足大多数场景，如下图所示：

1. 交付效率

需求前置时间：从需求提出到完成整个研发交付过程，并最终上线发布的时间。对业务方和用户来说，这个时间是最能客观反映团队交付速度的指标。这个指标还可以进一步细分为需求侧，也就是从需求提出、分析、设计、评审到就绪的时长，以及业务侧，也就是研发排期、开发、测试、验收、发布的时长。对于价值流分析来说，这就代表了完整的价值流时长。

开发前置时间：从需求进入排期、研发真正动工的时间点开始，一直到最终上线发布的时长。它体现的是研发团队的交付能力，也就是一个需求进来后，要花多久才能完成整个开发过程。

2. 交付能力

发布频率：单位时间内的系统发布次数。原则上发布频率越高，代表交付能力越强。这依赖于架构结构和团队自治、独立发布的能力。每个团队都可以按照自己的节奏安全地发布，而不依赖于关联系统和发布窗口期的约束。

发布前置时间：指研发提交一行代码到最终上线发布的时间，是团队持续交付工程能力的最直观的考查指标，依赖于全流程自动化的流水线能力和自动化测试能力。这也是 DevOps 状态报告中的核心指标之一。

交付吞吐量：单位时间内交付的需求点数。也就是，单位时间内交付的需求个数乘以需求颗粒度，换算出来的点数，它可以体现出标准需求颗粒度下的团队交付能力。

3. 交付质量

线上缺陷密度：单位时间内需求缺陷比例，也就是平均每个需求所产生的缺陷数量，缺陷越多，说明需求交付质量越差。

线上缺陷分布：所有缺陷中的严重致命等级缺陷所占的比例。这个比例的数值越高，说明缺陷等级越严重，体现了质量的整体可控性。

故障修复时长：从有效缺陷提出到修复完成并上线发布的时间。一方面，这个指标考查了故障定位和修复的时间，另外一方面，也考查了发布前置时间，只有更快地完成发布上线过程，才能更快地修复问题。

这三组、八项指标体现了团队的交付效率、交付能力和交付质量，从全局视角考查了关键的结果指标，可以用于展现团队 DevOps 改进的效果和价值产出。不过，定义指标只能说是 DevOps 度量的一小步，只有让这些指标发挥价值，才能说是有意义的度量。

如何开启度量工作？

在企业内部开启度量工作，可以分为四个步骤。

第 1 步：细化指标。

一个完整的指标，除了定义之外，还需要明确指标名、指标描述、指标级别（团队级 / 组织级）、指标类型、适用场景范围及目标用户、数据采集方式和标准参考值。

以交付指标为例，我汇总了一份细化后的指标内容，你可以参考下表。其实不仅仅是核心结果指标，只要是在度量体系内定义的指标，都需要进行细化。

关于指标的参考值，对于不同的业务形态，参考值也有所不同。比如就单元测试覆盖率而言，无人车的业务和普通的互联网业务的差别可能会非常大。

所以参考值的选定，需要结合业务实际来分析并达成共识。而且，度量指标本身也需要建立定期更新的机制，以适应于整个团队的能力。

第 2 步：收集度量数据

度量指标需要客观数据的支撑，而数据往往都来源于各个不同的平台。所以，在定义指标的时候，你需要评估是否有足够的客观数据来支撑这个指标的衡量。

在采集度量数据的初期，我们面临的最大问题不仅是系统众多、数据口径不一致，还包括数据的准确性。

举个例子，比如开发交付周期这个指标，一般都是计算一个需求从开始开发到线上发布的时间长度。但是，如果开发人员迟迟不把这个需求设置为“已解决”或者“待测试”状态，那么统计出来的开发周期就存在大量的失真，很难反映出客观、真实的情况。

这就需要从流程和平台两个层面入手解决。比如，一方面，从流程层面制定研发操作规范，让每一名研发人员都清楚在什么时间点需要改变需求卡片状态；另一方面，建设平台能力，提供易用性的方式辅助研发，甚至自动流转需求状态。

第 3 步：建立可视化平台。

度量指标毕竟是要给人看的，度量数据也需要有一个地方可以收集和运算，这就依赖于度量可视化平台的建设了。关于如何建设一个支持多维度视图、对接多系统数据，以及灵活可编排的度量平台，我会在工具篇给你分享一个案例，帮助你破解度量平台建设的关键问题。

第 4 步：识别瓶颈并持续改进。

当数据做到了可信和可视化之后，团队面临的问题和瓶颈会自然而然浮现出来。如何通过指标牵引并驱动团队实施改进，这也是下一讲我们要讨论的核心内容。

我给你提供一些常用的度量指标和相关定义，你可以点击网盘链接获取，提取码是 c7F3。需要注意的是，指标宜少不宜多，宜精不宜烂，对于企业的 DevOps 度量而言，这也是最常见的问题，定义了一大堆的指标，却不知道要拿来做什么。

只有将指标的定义细化，并在团队内部达成共识，仔细甄别数据的完整和有效性，并做到满足不同维度视角的可视化，才具备了驱动团队进行改进的基础，这一点请你一定要记住。

总结

总结一下，DevOps 度量想要达到的目标，就是证明团队经过一系列的改进工作，与过去相比，交付速度更快了，交付质量也更高了。所以，交付效率和交付质量是最为核心的两个目标。只有围绕这两个目标建立的度量体系，才没有走错方向。

好的指标一般都具备四种特性：明确受众、直指问题、量化趋势和充满张力。结合指标特征和指导原则，以及业界大厂的一些实践，我给你介绍了三组、八项核心结果指标，包括效率指标、能力指标和质量指标。最后，我给你介绍了建立度量体系的四个步骤，希望可以帮助你一步步地搭建持续改进的基石。

度量是把双刃剑，做得不好反而会伤害团队的士气。如果本末倒置，把度量结果跟个人的绩效相绑定，就很容易使度量这个事情变了味道。很多大公司反反复复地在建立度量体系，就是因为前一个体系被人摸透，变成了数字游戏，于是就失去了原有的目的，只能推倒重来。

还是那句话，度量只是一种手段，而非目的。归根结底，度量的真正目的还是团队效率的提升和业务的成功。只有通过度量激起团队自发的改进意愿，提升团队改进的创造性和积极性，才是所谓的“正向度量”，这也是我最想传达给你的理念。

思考题

你所在的企业是否也在建设 DevOps 的度量体系呢？你觉得，这些度量指标数据对改进当前的工作是否起到了正面作用呢？

欢迎在留言区写下你的思考和答案，我们一起讨论，共同学习进步。如果你觉得这篇文章对你有所帮助，也欢迎你把文章分享给你的朋友。

20 | 持续改进：PDCA体系和持续改进的意义

你好，我是石雪峰。

今天是“工程实践篇”的最后一节课，如果你现在问我，在这么多的工程实践中，什么能力是团队在推行 DevOps 时最应该具备的？我会毫不犹豫地告诉你，那就是持续改进。

很多同学在留言区问我：“雪峰老师，我们公司已经搭建了 Gitlab，也跟 Jenkins 实现了打通，做到了自动化的编译打包和发布工作。可是接下来，我们还有啥可以做的呢？我感到很迷茫啊。”

所以，这就引申出来一个问题：“一个团队做到什么程度，才算是达到了 DevOps 呢？”

每每遇到这样的问题，我就会回想起，几年前我去国内一家知名公司的杭州总部交流的经历。

当时，负责跟我们对接的是这家公司 DevOps 的主要推动人，可以说，他见证了这家巨头公司的 DevOps 转型全过程。在交流时，我问了他一个问题，他的回答让我印象特别深刻。

我问他：“你觉得，你们公司是在什么时候实现 DevOps 转型的呢？”他想了想，说：“现在，我们公司已经没有专职的测试和专职的运维了，基础架构也早就容器化了。这些事情，都是业务发展到一定阶段之后自然而然发生的，只不过，DevOps 火起来以后，我们才发现，原来我们一直在做的就是 DevOps。所以，很难说在哪个时间点完成了 DevOps 转型。对我们来说，最重要的就是团队具备了一种能力，就是始终能够找到新的突破，持续追求更好的状态。”

我想，这段话应该非常能够代表一个团队实施 DevOps 转型时期望达到的状态吧。

其实，如果你有机会去跟谷歌、Netflix 的工程师交流一下，你就会发现，这些业界 DevOps 做得特别牛的公司，内部都不怎么提 DevOps 的概念。因为，他们早就对 DevOps 的这些实践习以为常了。很多知名的工具平台，都是内部员工自发地为了解决一些问题而开发出来的。

比如，像 Gerrit 这种非常流行的代码在线评审和管理工具，最开始就是为了解决谷歌内部缺少一种基于 Git 并且具备权限管控的代码评审工具的问题，才被开发出来的，你可以了解下这段历史。

你看，遇到一个钉子，从而造个锤子，和拿着一把锤子，满世界找钉子就是两种截然不同的做法。但很多时候，我们采用的都是后一种做法，手里拿着一堆锤子，却找不到钉子在哪里。

所以，如果一定要让我来回答，DevOps 做到什么程度，就算是实现转型落地了？那么，我的回答是，核心就是团队已经具备了持续改进的能力，而不只是简简单单地引入了几个工具，建立了几个度量指标而已。

说到这儿，你可能会说，这个所谓的持续改进，怎么感觉无处不在呢？似乎很多工程实践的落地方法中，最后一步都是持续改进。那么，持续改进的意义到底是什么呢？为什么一切活动的终极目标都是持续改进呢？

这是因为，每家公司面临的问题都不一样，从 0 到 1 的过程相对比较简单，可以对照着工程实践，快速地引入工具，建立流程，补齐能力短板。但是，从 1 到 N 的过程，就需要团队根据业务需要，自行识别改进目标了。

还以最开始那个问题为例，基于 Gitlab 和 Jenkins 搭建了自动化构建和发布的能力之后，你觉得还有哪些可行的改进方向呢？比如，测试是否注入其中了呢？是否建立了质量门禁机制呢？数据库变更是否实现了自动化呢？构建发布的速度是否足够理想，构建资源是否存在瓶颈？

能想到的方向有很多，但哪个才是现阶段最重要、价值最大化的点，说到底，还是要看业务的需求，没办法泛泛而谈。

谈到持续改进，有一个非常著名的方法体系，叫作 PDCA，也称为戴明环。没错，你从名称就能看出，这套方法体系同样来自于质量管理大师戴明博士。PDCA 是四个英文单词的缩写，也就是 Plan（计划）、Do（实施）、Check（检查）和 Action（行动）。

PDCA 提供了一套结构化的实施框架，任何一项改进类工作，都可以划分为这四个实施阶段。通过 PDCA 循环的不断迭代，驱动组织进入一种良性循环，不断识别出新的待改进问题。针对这些问题，首先要进行根因分析，制定具体的实施计划。然后，不定期地检查实施的结果和预期目标是否一致。最后，要对改进结果进行复盘，把做得好的地方保留下来，把做得不好的地方纳入下一阶段的循环中，继续改进。

这个方法听起来也没什么复杂的，每个人都能够理解，关键在于是否真正地用心在做。

我再给你分享一个真实的例子。

大概两年前，我参与到一家中型企业的 DevOps 转型工作当中。这家企业刚开始接触 DevOps 时的状态呢，我就不细说了，反正就是基本啥都没有。代码库使用的是 SVN，构建打包都在本地完成，版本发布要两个月，而且经常是多版本并行的节奏，光同步代码就需要专人完成。

经过半年多的改造之后，团队内部的整体工具链体系初具规模，版本发布节奏也缩短到了一个月一次，团队对达到的成绩非常满意。

当然，这并不是重点，重点是，我上个月又碰到了这个项目的负责人。她跟我说，他们现在的发布节奏已经实现了两周一次，甚至不定期还有临时版本发布。我很好奇，他们究竟是怎么做到的。

原来，最开始导入改进方案的时候，我给项目组提到过容器化的思路，但是因为当时客观条件不具备，就没有继续推进下去。没想到，在短短不到一年的时间里，他们已经实现了容器化部署，自建的 PaaS 平台也有模有样，即便是跟很多大公司相比，也毫不逊色。

她说：“这段 DevOps 转型的过程，带给我们的不仅仅是一些常见的工程实践和工具平台，更重要的是一双总能发现不完美的眼睛和追求极致的态度，以及对这类问题的认知方法。这些驱动我们不断地找到新的方法解决新的问题。”

的确，很多工程实践和工具平台，在公司内部其实只是一小步，之后遇到的问题和挑战还会有很多。这时候，我们能够依靠的终极奥义就是持续改进的思想，而构建持续改进的核心，就在于构建一个学习型组织。

那么，究竟要从哪里开始学习呢？在学习和改进的过程中又有哪些比较推荐的做法呢？我总结了四个实践，你可以参考一下。

鼓励正向回溯和总结

从失败中学习是我们从小就懂的道理。一个团队对待故障的态度，很大程度上就反映了他们对于持续改进的态度。系统出现故障是谁都不愿意遇到的事情，但在真实世界中，这是没法避免的。

在很多公司里面，出现故障之后，有几种常见的做法：

把相关方拉到一起，定级定责，也就是确定问题级别和主要的责任方；

轻描淡写地回个改进邮件，但是没有明确的时间节点，即便有，也没人跟踪；

把问题归结为不可复现的偶发事故，最后不了了之。

与这些做法相比，更好的方法是建立一种正向回溯和总结的机制。也就是说，当问题发生之后，事先准备一份详尽的故障分析报告，并拉上相关方一起彻底分析问题的根因，并给出改进任务的具体时间点。

故障回溯并不一定以确定责任为第一要务，更重要的是，要识别系统流程中的潜在问题和漏洞，并通过后续机制来进行保障，比如增加测试用例、增加产品走查事项等等。

其实，大到线上故障，小到日常错误，都值得回溯和总结。

比如，我们每天都会遇到形形色色的编译错误，如果每个人遇到同样的问题，都要爬一次同样的坑，显然是非常低效的。

这就需要有团队来负责收集和总结这些常见的错误，并提取关键错误信息和常见解决方法，形成一个案例库。同时，在构建系统中嵌入一个自动化服务，下次再有人遇到编译错误的时候，就可以自动匹配案例库，并给他推送一个问题分析报告和解决建议，帮助团队成员快速解决问题。

这样，随着团队智慧的不断积累，越来越多的问题会被识别出来，从而实现组织知识共享和研发辅助的能力，这在很多大公司里面都是一个重点建设方向。仔细想想，这本身就是一个 PDCA 的过程。

不过，这里要补充一点，团队实施持续改进的过程，不应该是一次大而全的变革，而应该是一系列小而高频的改进动作。因为大的变革往往影响众多，很容易半途而废，而小的改进更加温和，也更加容易成功。为了方便你理解，我跟你分享一张示意图。

预留固定时间进行改进

很多时候，团队都处于忙碌的状态，时间似乎成了推行 DevOps 的最大敌人。于是，团队就陷入了一种太忙以至于没时间改进的状态中。

如果团队选择在同等时间内去做更多的功能，那就说明，至少在当前这个阶段，业务开发的重要性要高于 DevOps 建设的重要性。

可问题是，业务的需求是没有止境的。有时候，我去问一线员工：“你觉得有什么地方，是 DevOps 可以帮你的吗？”要么大家会说“没什么特别的，现在挺好”，要么就是一些非常琐碎的点。实际上，这只能说明，要么是没想过这个事情，要么就是不知道还有更好的做法。但是，如果不能调动一线员工的积极性，持续改进也就无从谈起了。

所以，正确的做法是，在团队的日常迭代中，事先给改进类工作预留一部分时间，或者是在业务相对不那么繁忙的时候（比如大促刚刚结束，团队在调整状态的时候），在改进工作上多花些时间。

这些工作量主要用于解决非功能需求、技术改进类问题，比如修复技术债务、单元测试用例补充、度量识别出来的改进事项等。通过将这部分改进时间固定下来，可以培养团队持续改进的文化。

我比较推荐的做法是，在团队的 Backlog 中新增一类任务，专门用于记录和跟踪这类持续改进的内容。在迭代计划会议上，对这类问题进行分析，并预估工作量，保证团队有固定的时间来应对这些问题。

另外，很多公司也开始流行举办 Hackathon Day（黑客马拉松），是说在有限的时间里通过编程实现自身的想法和创意，在这个过程中，充满了积极探索的精神、自由散发的思维和挑战极限的理念，通过团队协作与互相激发，实现创意到开发的全过程。

我们团队最近也在准备参加今年的黑客马拉松，希望通过这个途径寻求合作共建，除了解决内部效率提升的“老大难”问题，还能提升团队成员的积极性，在更大的舞台上展现 DevOps 的价值，一举两得。

在团队内部共享业务指标

很多时候团队成员都像是临时工一样，对于自己所负责的需求和业务的表现一概不知。如果团队成员对一件事情没有归属感，那么又如何激发他们的责任感和自我驱动意识呢？

所以，对于业务的指标和表现，需要尽可能地在团队内部做到透明，让团队成员可以接触真实世界的用户反馈和评价，以及业务的度量信息。

在一个新功能开发完成上线之后，要能实时查看这个需求的上线状态。如果需求分析时已经关联了业务考核指标，那么，同样可以将该业务关联的指标数据进行展示。这样，研发就会知道自己交付的内容有多少问题，用户的真实反馈是怎样的，从而促使团队更多地站在用户的视角思考问题。

除了业务指标，DevOps 的指标体系也应该对内部公开透明。大家可以查看自己所在团队的表现，以及在公司内部的整体水平。

适当的侧向压力，会促使大家更加主动地接受改进工作，并且通过度量数据展示改进的效果，从而形成正向的循环。

激励创造性，并将价值最大化

每个团队中都不乏有创新意愿和思想的员工，他们总是能从墨守成规的规范中找到可以进行优化的点。

比如，之前，我们团队的一个测试人员发现，日常埋点测试费时费力，而且没有数据统计。于是，她就自己利用业余时间开发了一个小工具，用工具来承载这部分工作，效率大幅提升。

如果更多人知道这样的创新，并且在更大范围内使用，不仅可以提升更多人的效率，让团队整体受益，而且还可以减少类似的重复建设，让有想法的员工一起参与工具优化。

比较好的做法是，在团队成员的绩效目标中，增加对团队贡献和技术创新的要求，在团队内部鼓励创新类工作。另外，在团队内部建立对应的选拔和激励机制，为好的想法投入资源，把它们变成可以解决类似问题的工具。

很多公司也开始注意到这种内部知识复用的重要性，所以，无论是代码库开源，还是公共基础组件的市的建设，甚至是公司级的平台治理系统，都可以帮助你快速地复用已有的能力，避免一直重复造轮子。

总结

就像每个工程实践的终点都是持续改进一样，我们专栏的“工程实践篇”同样以持续改进的实践作为收尾。

我始终认为，团队是否建立了持续改进的文化，是评估团队的 DevOps 实践效果的重要参考。在这一讲中，我给你介绍了 PDCA 的持续改进方法体系，也就是通过计划、实施、检查、行动这四个步骤的持续迭代，不断把团队推向更优的状态，促使团队进入正向发展的车道。

另外，我给你介绍了四个持续改进落地的方法，包括在失败中总结和学习，建立固定的改进时间，在团队内部共享指标、培养团队的责任感，以及激发团队的创造力并将价值最大化。这些方法的核心就是想打造一个学习型的组织和文化，给 DevOps 的生根发芽提供丰饶的养分。

从下一讲开始，我们将进入“工具实践篇”，我会给你介绍一些核心工具的设计思想、建设路径，以及一些常见开源工具的使用方法等，敬请期待。

思考题

除了我提到的这四种持续改进的手段，你所在的公司，有什么活动可以促进持续改进文化的建设吗？

欢迎在留言区写下你的思考和答案，我们一起讨论，共同学习进步。如果你觉得这篇文章对你有所帮助，也欢迎你把文章分享给你的朋友。

21 | 开源还是自研：企业DevOps平台建设的三个阶段

你好，我是石雪峰，从今天开始，专栏正式进入了“平台工具篇”。

在这个全新的章节，我重点想讲三个方面的内容：

帮助你梳理企业内部 DevOps 平台的实施路径，理清平台建设的主体脉络；

给你分享一些核心平台的建设经验，这些经验都来自于生产一线；

给你分析一下 DevOps 平台的发展方向和热门趋势，让你在进行平台建设时，能够跟上潮流。

我想跟你说的是，没有人天生就是 DevOps 平台的产品经理，但每一个人都能成为 DevOps 平台的产品经理。

因为，DevOps 平台的产品与业务方向的产品不同，它要解决的就是一线研发交付团队的实际问题。

普通的产品经理没有研发交付的背景，很难理解研发交付的困境，而研发交付团队又缺少产品经理的技能和思路。所以，这个领域的人才少之又少，基本只能靠内部培养，我希望你能通过专栏的学习，摸索出一些产品设计的门道。

好了，今天，我们就来聊一聊企业 DevOps 平台建设的话题。

就像我之前提到的那样，在企业内部推行 DevOps，工具不是万能的，但是没有工具，却是万万不能的。

当企业决定引入 DevOps 工具的时候，无外乎有三种选择：直接使用开源工具；采购商业工具；自己研发工具。

你可能会说，如果有能力，当然是选自研工具啊，自主可控，又有核心竞争力。可是，在 DevOps 状态报告中，却有一些不同的发现。

那些倾向于使用完全自建工具的企业，效能水平往往不高。所谓的完全自建工具，是指不依赖于开源解决方案，整个工具完全由自己来实现。而那些大部分采用开源工具的企业，效能水平反而不差。

这就有点反常理了。企业花了这么大的时间和精力来建设内部工具，到最后却没有达到预期的效果，究竟是为什么呢？

在我看来，这是因为没有找到企业内部平台建设的正确路径。我们要在正确的时候，做正确的事情，太超前，或者太落后，都是会有问题的。

那么，接下来，我就跟你聊聊企业 DevOps 平台建设的三个阶段。

阶段一：从无到有

在这个阶段，企业的 DevOps 平台建设处于刚刚起步的状态，在整个交付过程中，还有大量的本地操作和重复性的操作。

另外，企业内部一般也没有一个成体系的工具团队，来专门负责平台能力建设。

那么，对于这个阶段，我给你的建议是：引入开源工具和商业工具，快速补齐现有的能力短板。

所谓能力短板，其实就是当前交付工具链体系中缺失的部分，尤其是高频操作，或者是涉及多人协作的部分，比如，需求管理、持续集成等。

无论是开源工具，还是商业工具，基本都是比较成熟的、拿来即用的，这种“即战力”是当前企业最需要的。因为，工具的引入解决了从无到有的问题，可以直接提升单点效率。这也是在 DevOps 转型初期，团队的效率能够飞速提升的主要原因。

看到这里，你可能会问两个问题：“如何选择工具？”“为什么商业工具也是可选项？”

其实，这也是团队在引入工具的初期，最头疼的两个典型问题，我们一一来看下。

如何选择工具？

现在，以 DevOps 为名的工具太多了。想要在这么多工具中，选择一款合适的，你要怎么做呢？

有的人可能会把相关工具的功能列表拉出来，然后逐项比对，看哪个工具的功能更加强大。其实，我觉得，在从无到有的阶段，不需要这么复杂，核心原则就是选择主流工具。

主流工具就是业内大家用得比较多的，在各种分享文章里面高频出现的，使用经验一搜一大把的那种工具。我给你提供一些工具，你可以参考一下：

需求管理工具 Jira；

知识管理工具 Confluence；

版本控制系统 GitLab；

持续集成工具 Jenkins；

代码质量工具 SonarQube；

构建工具 Maven/Gradle；

制品管理 Artifactory/Harbor；

配置管理工具 Ansible；

配置中心 Apollo；

测试工具 RF/Selenium/Appium/Jmeter/TestNG；

安全合规工具 BlackDuck/Fortify；

……

在初期，工具要解决的大多是单点问题，主流工具意味着更好的可扩展性，比如有完整的接口列表，甚至对其他工具已经内置了插件支持。

另外，很多开发实践都是基于主流工具来设计的。业内对于这些工具摸索得也比较深，有很多现成的实践经验，这些都对应了快速补齐能力短板的目标。

我之前见过一家大型金融机构，他们也在考虑将代码管理从 SVN 切换到 Git。但是，他们选择的 Git 平台既不是开源的 GitLab、Gerrit，也不是商业化的主流工具，而是一个听都没听过的开源工具。

这个工具的操作流程跟一般工具都不太一样，配套的评审、集成功能也都不够完善。最后，这家机构还是改用主流工具了。

为什么商业工具也是可选项？

随着开源工具的成熟和完善，越来越多的公司，甚至是传统企业，都开始积极拥抱开源，似乎开源就是代表未来的趋势。

那么，是不是只选择开源工具就行了，不用考虑商业工具了呢？我觉得，这种想法也是比较片面的。

商业工具的优势一直都存在，比如，专业性、安全性、扩展性、技术支持力度等。其实，很多开源工具都有商业版本。

比如，很多公司即便有开源的 Nexus，制品管理工具 Artifactory 也都是标配。因为，Artifactory 无论是在支持的制品类型、分布式部署、附加制品安全漏洞检查，还是在与外部工具的集成等方面，都有着明显的优势。

另外，像 Jira 这种需求和缺陷管理工具，与 Confluence 深度集成的话，足够满足绝大多数公司的需求。

再举个例子，安卓开发最常见的 Gradle 工具，它的商业版本可以直接让你的编译速度提升一个数量级。在最开始时，你可能觉得够用就行，但是当你开始追求极致效率的时候，这些都是核心竞争力。

选择商业工具的理由有很多，不选的理由大多就是一个字：贵。针对这个问题，我要说的是，要分清一笔支出到底是成本，还是投资。

就跟购买黄金一样，虽然也花了钱，但这是一笔投资，未来可以保值和增值，甚至是变现。对于商业工具来说，也是同样的道理。如果一款商业工具可以大幅提升团队效率，最后的产出可能远超最开始的投资。如果我们组建一个团队，仿照商业工具，开发一套自研工具，重复造轮子的成本也可能一点不少。所以，重点就是要看怎么算这笔账。

阶段二：从小到大

经过了第一个阶段，企业交付链路上的工具基本都已经齐全了。团队对于工具的需求开始从够用到好用进行转变。另外，随着业务发展，团队扩大，差异化需求也成了摆在面前的问题。再加上，人和数据都越来越多，工具的重要性与日俱增。

那么，工具的稳定性、可靠性，以及大规模使用的性能问题，也开始凸显出来。

对于这个阶段，我给你的建议是：使用半自建工具和定制商业工具，来解决自己的问题。

所谓半自建工具，大多数情况下，还是基于开源工具的二次开发，或者是对开源工具进行一次封装，在开源工具上面实现需要的业务逻辑和交互界面。

比如，基于 Jenkins 封装一套自己的构建打包平台，完全可以利用 Jenkins API 和插件扩展实现。我附上了一幅架构示意图，你可以参考一下。

那么，半自建工具有哪些注意事项呢？虽然各个领域的工具职能千差万别，但从我的经验来看，主要有两点：设计时给扩展留出空间；实现时关注元数据治理。

设计时给扩展留出空间

刚开始建设平台的时候，很容易就事论事，眼前有什么问题，就提供什么功能。这固然是比较务实的态度，但对于平台而言，还是要有顶层设计，给未来留出扩展性。这么说可能比较抽象，我来给你举几个实际的例子，也是我们之前踩过的“坑”。

案例一：

平台的初期设计没有考虑租户的特性，只是为了满足单一业务的使用。当功能比较成熟，想要对外输出的时候，我们发现，要重新在更高的维度插入租户，导致系统需要进行大幅改造，不仅功能页面需要调整，连权限模型都要重新设计。

如果在设计平台之初，就考虑到未来的扩展需求，把单一业务实现为一个平台租户，会不会更好些呢？

案例二：

为了满足快速上线的需要，我们对 Jenkins 进行了简单封装，实现了在线打包平台。但是，打包页面的参数都“写死”在了页面中。另外，每接入一个项目，就需要单独实现一个页面。后来，面对上百个应用的接入所带来的差异化需求，平台只能推倒重来。

如果最开始在设计的时候，就采用接口获取的方式，将参数实现配置化，会不会更好些呢？

除此之外，在技术选型的时候，前后端分离的开发方式、主流的技术栈选型、一些典型的设计模式、相对统一的语言类型，其实都有助于平台空间的后续扩展。

功能可以快速迭代，人员可以快速进入团队，形成战斗力，在设计平台的时候，这些都是需要思考的问题。

当然，顶层规划，不代表过度设计。我只是说，要在可以预见的范围内，预留一些空间，从而规避后期的尴尬。

实现时关注元数据治理

所谓元数据，也就是常说的 meta-data，可以理解为钥匙链，这些数据可以串起整个平台的数据结构。比如应用名称、模块名称、安全 ID 等等。

各个平台在组织数据结构的时候，都需要用到这些元数据，而且一旦使用了，轻易都不好改变。因为，在数据模型里面，这些元数据很有可能已经作为各种主键、外键的约束存在了。

对于单一平台来说，怎么维护这些元数据，都没什么大问题，但是，对于后续平台间的打通而言，这些元数据就成了一种标准语言。如果平台间的语言不通，就需要加入大量的翻译处理过程，这就导致系统性耦合加大，连接变得脆弱。

比如，同样是购物车模块，在我的平台里面叫购物车，而在你的平台里面叫 shopping-cart，而且还按照平台划分，比如 shopping-cart-android、shopping-cart-ios，甚至还有一些特性维度，比如 shopping-cart-feature1 等等。显然，想让两边的数据对齐，并不容易。

当然，元数据的治理并不是单一平台能够解决的事情，这同样需要顶层规划。

比如，在公司内部建立统一的 CMDB，在其中统一管理应用信息。或者，建立应用创建审批流程，通用一个标准化流程，来管控应用的生命周期，同时管理应用的基础信息。这些都属于技术债务，做得越晚，还债的成本就越高。

阶段三：从繁到简

到了第三个阶段，恭喜你已经在 DevOps 平台建设方面有了一定的积累，在各个垂直领域也积累了成功案例。那么，在这个阶段，我们要解决的主要问题有 3 点：

平台太多。做一件事情，需要各种切来切去；

平台太复杂。想要实现一个功能，需要对相关人员进行专业培训，他们才能做对；

平台价值说不清。比如，使用平台，能带来多大价值？能给团队和业务带来多大贡献？

对于这个阶段，我给你的建议是：使用整合工具来化繁为简，统一界面，简化操作，有效度量。

整合工具，就是包含了开源工具、半自研工具、商业工具的集合。

你要提供的不再是一个工具，而是一整套的解决方案；不是解决一个问题，而是解决交付过程中方方面面的问题。

企业工具平台治理

如果最开始没有一个顶层规划，到了这个时候，企业内部大大小小的工具平台应该有很多。你需要做的第一步，就是平台化治理工作。

首先，你要识别出来有哪些工具平台，使用情况是怎样的，比如有哪些业务在使用，实现了哪些功能。

如果要把所有工具平台收编起来，这不是一件容易的事情，甚至超出了技术的范畴。尤其是对很多大企业来说，工具平台是很多团队的根基，如果不需要这个平台，就意味着团队的重心也得调整。

所以，我给你的第一条建议是比较温和可行的，那就是，找到软件交付的主路径。用一个平台覆盖这条主路径，从而串联各个单点上的能力，让一些真正好的平台能够脱颖而出。而要做到这个事情，就需要持续交付流水线了。

这些年来，我一直在从事持续交付平台的建设，也总结了很多经验。我会在后面的内容中，跟你好好聊聊，如何设计一个现代的持续交付流水线平台。

流水线平台与一体化平台之间，还是有很大差距的。毕竟，各种工具平台的设计思路、操作路径、界面风格，差别很大。

所以，在实际操作的过程中，我给你的第二条建议就是，区分平台和工具，让平台脱颖而出。

比如，测试环境存在大量的工具，而一整套测试平台，实际上可以满足测试方方面面的需求，也就是说，测试人员只要在这个平台上工作就够了。当企业内部繁杂的工具收敛为几个核心平台之后，对于用户来说，就减少了界面切换的场景，可以通过平台和平台对接完成日常工作。

打造自服务的工具平台

到了这个阶段，自服务就成了平台建设的核心理念。

所谓自服务，就是用户可以自行登录平台实现自己的操作，查看自己关心的数据，获取有效的信息。

而想要实现自服务，简化操作是必经之路。说白了，如果一件事情只要一键就能完成，这才是真正地实现了自服务。

这么说可能有点夸张。但是，打破职能间的壁垒，实现跨职能的赋能，依靠的就是平台的自服务能力。很多时候，当你在埋怨“平台设计得这么简单，为啥还是有人不会用”的时候，其实这只能说明一个问题，就是平台依然不够简单。

之前，Jenkins 社区就发起过一个项目，叫作“5 Click，5 Minutes”，意思是希望用户只需要 5 次点击，花 5 分钟时间，就能完成一个 Jenkins 服务的建立。

这个项目的结果，就是现在的 Jenkins 创建导航，通过把建立服务的成本降到最低，从而帮助更多的用户上手使用。

你看，用户体验是否简单，与技术是否高深无关，重点在于是否能够换位思考。所以，在建设平台的时候，要始终保有一份同理心。

总结

企业内部的平台化建设是个长期问题，如果你要问我，企业要建设 DevOps 平台，有什么经验总结吗？我的回答就是“四化”：标准化、自动化、服务化和数据化。实际上，这些也是指导平台建设的核心理念。

标准化：一切皆有规则，一切皆有标准；

自动化：干掉一切不必要的手工操作环节，能一键完成的，绝不操作两次；

服务化：面向用户设计，而不是面向专家设计，让每个人都能在没有外界依赖的前提下，完成自己的工作；

数据化：对数据进行收集、汇总、分析和展示，让客观数据呈现出来，让数据指导持续改进。

思考题

最后，关于平台化建设，你有什么私藏的好工具吗？可以分享一下吗？

欢迎在留言区写下你的思考和答案，我们一起讨论，共同学习进步。如果你觉得这篇文章对你有所帮助，欢迎你把文章分享给你的朋友。

22 | 产品设计之道：DevOps产品设计的五个层次

你好，我是石雪峰。

在上一讲中，我们聊到了企业 DevOps 平台建设的三个阶段。那么，一个平台产品到底做到什么样，才算是好的呢？不知道你有没有想过这个问题，反正做产品的这些年来，我一直都在思考这个事儿。直到我听到了梁宁的专栏里面讲到的用户体验的五层要素，才发现，无论什么产品，其实都是为了解决一群特定的人在特定场景的特定问题。

那么，回到我们的 DevOps 产品，我们可以借鉴一下梁宁老师的思路，来看看 DevOps 产品设计体验的五个层次：战略存在层、能力圈层、资源结构层、角色框架层和感知层。

这么多专有名词一股脑地蹦出来，估计你头都大了吧？没关系，接下来我会逐一解释一下。

第一个层次：战略存在层

在决定开发一个 DevOps 产品的时候，我们首先要回答的根本问题就是，这个产品解决了什么样的痛点问题？换句话说，我们希望用户通过这个产品得到什么？显然，目标用户和痛点问题的不同，会从根本上导致两套 DevOps 产品之间相距甚远。

举个例子，业界很多大公司在内部深耕 DevOps 平台很多年，有非常多很好的实践。但是，当他们准备把这些内部平台对外开放，提供给 C 端用户使用的时候，会发现存在着严重的水土不服问题。

有些时候，内外部产品团队有独立的两套产品，对外提供的产品版本甚至比对内的版本要差上几年。这就是用户群体的不同造成的。C 端用户相对轻量级，需要的功能大多在具体的点上，而企业内部因为多年的积累，有大量的固有流程、系统、规则需要兼顾。所以，整套产品很重，甚至是完全封闭的一套体系，难以跟用户现有的平台进行打通。

所以，我见过很多产品团队，他们对自己初期的产品定位并非在用户需求本身，而是在同类竞争对手身上。也就是说，他们先从模仿业界做得比较好的同类产品开始，从产品设计、功能模块到用户交互等，一股脑地参考同类产品，美其名曰“至少先赶上业界主流水平再说”。于是乎，团队开足马力在这条路上渐行渐远。

当然，借鉴同类产品的先进经验，这个做法本身并没有什么问题，毕竟，这些经验已经经过市场和用户的检验，至少走偏的风险不大。可问题是，同类产品的经验并不能作为自己产品的战略。

亚马逊的 CEO 贝佐斯就说过一句特别著名的话：“要把战略建立在不变的事物上。”比如，如果竞争对手推出了一项新的功能，或者他们改变了自己的方向，那么我们的战略是否要随之变化，继续迎头赶上呢？这是一个值得产品团队深思的问题。

以我所在的电商行业为例，我们的产品始终在强调用户体验，但好的产品设计和用户体验绝不是因为友商做了什么花哨的改变，而是始终着眼于那些长久不变的事物之上，也就是多、快、好、省。因为，不管什么时候，用户选择在你的平台购物，肯定不会是因为你的产品比其他家的要贵吧？同样的道理，对于 DevOps 产品来说，也是这样。

那么，有没有永远不变的内容可以作为 DevOps 产品的战略定位呢？显然也是有的，那就是：效率、质量、成本和安全。归根结底，产品的任何功能都是要为战略服务的。比如，构建加速，要解决的就是效率问题，而弹性资源池，自然更加关注成本方面的问题。在任何时候，如果你的产品能在某个点上做到极致，那么恭喜你，你就找到了自己产品的立身之本。

明确目标用户，定义刚性需求，服务于典型场景，并最终在某一个点上突出重围，这就是我们在准备做 DevOps 产品的时候首先要想清楚的问题。无论是对内产品，还是对外产品，道理都是一样的。

第二个层次：能力圈层

战略很好，但是不能当饭吃。为了实现战略目标，我们需要做点什么，这就是需要产品化的能力。所谓产品化，就是将一个战略或者想法通过产品分析、设计、实验并最终落地的过程。

很少公司会有魄力一上来就投入百人团队开发 DevOps 产品，大多数情况下，都是一两个有志青年搭建起草台班子，从一个最简单的功能开始做起。资源的稀缺性决定了我们永远处于喂不饱的状态，而在这个时候，最重要的就是所有为，有所不为。

我们一定要明确，哪些是自己产品的核心竞争力，而哪些是我们的边界和底线，现阶段是不会去触碰的。当我们用这样一个圈子把自己框起来的时候，至少在短期内，目标是可以聚焦的。

当然，随着产品的价值体现，资源会随之而扩充，这个时候，我们就可以调整、扩大自己的能力圈。但说到底，这些能力都是为了实现产品战略而存在的，这一点永远不要忘记。

我还是拿个实际的案例来说明这个问题。之前在企业内部启动持续交付流水线项目的时候，我们这个草台班子总共才 4 个人，而我们面对的是千人的协同开发团队。在每个业务领域内部，都有很多的产品工具平台在提供服务，缺少的就是平台间的打通。

对于企业而言，一套完整覆盖端到端的研发协作平台看起来很美，但是，要做这么一套东西，投入巨大不说，还会同现有的工具平台产生冲突，这样就变成了一个零和游戏。

所谓零和游戏，就是所有玩家资源总和保持固定，只是在游戏过程中，资源的分配方式发生了改变。

就现在的这个例子来说，如果平台潜在用户总量是一定的，有一方向前一步，必定有另外一方向后一步，这显然不是我们这个“小虾米团队”现阶段能做到的。

所以，我们就给自己的产品定义了一个能力圈，它的边界就在于不去替换现有的工具平台，而是只专注于做链路打通的事情。这样一来，既有平台仍然可以单独提供服务，也可以通过标准化的方式提供插件，对接到我们的平台上来，我们的平台就成了它们的另外一套入口，有助于用户规模的扩大。

而对于我们自己来说，这些平台能力的注入，也扩展了我们自己的能力圈外沿，这些既有平台的用户就成了我们的潜在用户群体。这种双赢的模式，后来被证明是行之有效的，平台获得了很大的成功。

在跟很多朋友交流产品思路的时候，我总是把主航道和护城河理论挂在嘴边。所谓主航道，就是产品的核心能力，直接反射了产品战略的具体落地方式。对于流水线产品来说，这个能力来源于对软件交付过程的覆盖，而不论你将来开发任何产品，这条主路径都是无法回避的。那么，产品就有了茁壮成长的环境和土壤。而护城河就是你这个产品的不可替代性，或者是为了替代你的产品需要付出的高额代价。

还是引用流水线产品的例子，我们的护城河一方面来源于用户数据的沉淀，另一方面就在于这些外部能力的接入。你看，随着接入平台的增多，我们自身产品的护城河也越发难以逾越，这就是对于能力圈更加长远的考量了。

第三个层次：资源结构层

为什么做和做什么的问题，我们已经解决了，接下来，我们就要掂量掂量自己在资源方面有哪些优势了。

资源这个事儿吧，就像刚才提到的，永远是稀缺的，但这对于所有人来说都是公平的。所以，对资源的整合和调动能力就成了核心竞争力。当你没有竞争对手的时候，用户选择你的产品并不是什么难事，因为既然解决了一个痛点问题，又没有更好的选择，用一用也无妨。

可现实情况是，无论是企业内部，还是外部，我们都身处在一个充满竞争的环境，最开始能够吸引用户的点，说起来也很可笑，很多时候就在于让用户占了你的资源的便宜，也就是用户认为你的产品有一些资源是他们不具备的。

举个例子，在很长一段时间内，App 的构建和打包都是基于本地的一台电脑来做的，这样做的风险不用多说，但是大家也没什么更好的选择。尤其是面对 iOS 这种封闭的生态环境，想要实现虚拟化、动态化也不是一句话的事情，甚至有可能触犯苹果的规则红线。

这时，如果你的产品申请了一批服务器，并且以标准化的方式部署在了生产机房，那么这些资源就成了产品的核心能力之一。

随着越来越多的用户跑来占便宜，产品对于大规模资源的整合能力就会不断提升，从而进一步压低平均使用成本，这就形成了一个正向循环。

产品蕴含的资源除了这些看得见、摸得着的机器以外，还有很多方面，比如，硬实力方面的，像速度快、机器多、单一领域技术沉淀丰富，又比如，强制性的，像审批入口、安全规则，还有软性的用户习惯，数据积累等等。

对于内部 DevOps 产品来说，还有一项资源是至关重要的，那就是领导支持。这一点我们已经在专栏第 6 讲中深入讨论过了，我就不再赘述了。

第四个层次：角色框架层

当用户开始使用你的产品时，不要忘了，他们是来解决问题的，而每一个问题背后都存在一个场景，以及在这个场景中用户的角色。脱离这个场景和角色的设定，单纯讨论问题是没有意义的。

所以，我们总说，要站在用户的角度来看待问题，要在他们当时的场景下，去解决他们的问题，而不是远远地观望着，甚至以上帝视角俯视全局。

举个例子，当你和其他部门在为了一个功能设计争得面红耳赤，差点就要真人 PK 的时候，你们的领导走进了会议室，你猜怎样，瞬间气氛就缓和起来，似乎刚才什么也没发生过。这难道是因为我们的情绪管理能力很强吗？其实不然，这主要是因为我们身处的场景发生了变化，我们的角色也发生了改变。

再举个产品的例子，当我们在开发流水线产品的时候，为了满足用户不同分支构建任务的需求，我们提供了分支参数的功能。但是，在收集反馈的时候，全都是负面声音，难道这是个“伪需求”吗？

其实不是。通过实际数据，我们可以看到，很多用户已经开始使用这个功能了。这不是得了便宜又卖乖吗？问题就在于，我们没有站在用户当时的角色框架下，来思考这个问题。

因为，分支功能是需要用户手动输入的，但分支名又长又容易出错，每次都要从另外一个系统或者本地复制粘贴。当这个场景出现一次的时候并不是什么大事，但是，如果每个人每天都要做几十次的话，这就是大问题了。其实，解决思路很简单，增加历史信息或者自动关联的功能就可以啦。

所以你看，有时候我们不需要多么伟大的创造和颠覆，基于核心场景的微创新也能起到正向的作用。

说到底，其实就是一句话：不要让你的产品只有专业人士才会使用。

为了兼容灵活性，很多产品都提供了很多配置，但是，对于当时这个场景来说，绝大多数配置，都是没人关心的。产品应该提供抽象能力屏蔽很多细节，而不是暴露很多细节，甚至，好的产品自身就是使用说明书。这一点，在注意力变得格外稀缺的现在，重要性不可忽视。

第五个层次：感知层

现在，我们来看看最后一个层次：感知层，这也是距离用户最近的一个层次。

不可否认，这是一个看脸的时代，但是产品终究是给人用的，而不是给人看的。所以，很多人甚至强调，对于内部产品来说，UI 完全不重要，家丑不外扬就好了。

可是，换位思考一下，你希望自己每天打交道的是一个设计凌乱、完全没有美感的产品吗？

答案很有可能是否定的。可这对于很多 DevOps 的产品经理来说，是最难的一点。这是因为，没有人天生就是 DevOps 产品经理，很多人都是半路出家，做开发的，做测试的，甚至是当老板的。

让不专业的人做专业的事情，结果可想而知，好多产品功能的设计都堪称是“反人类”的。

关于这个层次，我提供两点建议：

多跟前端工程师交流。现在的前端框架已经非常成熟了，基于模板，我们可以快速地搭建出一个平台。而且，模板的框架自身，也蕴含着很多的设计思想。

多学习一些基本的设计原则。你可以参考Element 官网上的设计理念章节，里面谈到了一致、反馈、效率和可控四个方面，每个方面又涉及很多细节。参照着成熟的产品，再对照这些基本设计理念，你放心，你会进步神速的。

总结

今天，我们介绍了 DevOps 产品设计的五个层次，包括：战略存在层、能力圈层、资源结构层、角色框架层和感知层。其实，当用户吐槽你的产品，或者产品迟迟没有提升的时候，我们可能就要沉下心来，对照着这五个层次，来看看问题到底出在哪里了。

思考题

你有用到过什么好的 DevOps 产品吗？它们有哪些功能，让你眼前一亮，不由得为这个产品点赞吗？

欢迎在留言区写下你的思考和答案，我们一起讨论，共同学习进步。如果你觉得这篇文章对你有所帮助，欢迎你把文章分享给你的朋友。

23 | 持续交付平台：现代流水线必备的十大特征（上）

你好，我是石雪峰。

作为 DevOps 工程实践的集大成者和软件交付的“理想国”，持续交付对企业的 DevOps 落地起到了举足轻重的作用。我接触过的企业全都在建设自己的流水线平台，由此可见，流水线是持续交付中最核心的实践，也是持续交付实践最直接的体现。

那么，如何建设一个现代流水线平台呢？这个平台，应该具备哪些特性呢？

根据我自己在企业内部建设落地流水线平台的经验，以及业界各家公司的平台设计理念，我提取、总结了现代流水线设计的十大特性。

在接下来的两讲中，我会结合平台设计，给你逐一拆解这些特性背后的理念，以及如何把这些理念落地在平台设计中。我把这十个特性汇总在了下面的这张图片里。今天，我先给你介绍下前五个特性。

特性一：打造平台而非能力中心

与其他 DevOps 平台相比，流水线平台有一个非常典型的特征，那就是，它是唯一一个贯穿软件交付端到端完整流程的平台。正因为这样，流水线平台承载了整个软件交付过程方方面面的能力，比如，持续集成能力、自动化测试能力、部署发布能力，甚至是人工审批的能力等。

那么，我们把软件交付过程中所需要的能力都直接做到流水线平台上，是不是就可以了呢？

这个想法是好的，但是在企业中，这并不具备可操作性。因为软件交付的每一个环节都是一项非常专业的工作，比如，仅仅是自动化测试能力这一项做好，就需要一个具备专业技能的团队的长期投入。

而且，把所有能力都做到流水线平台中，会使平台变得非常臃肿。再说了，我们也很难组建一个这么大的团队，来实现这个想法。

另外，企业的 DevOps 平台建设并不是一两天的事情。每家企业内部都有很多固有平台，这些平台长期存在，已经成为了团队软件交付日常操作的一部分。如果全部推倒重来，不仅会打破团队的习惯，影响短期效率，还会带来重复建设的巨大成本，这并不利于流水线平台的快速落地。

那么，既然这条路走不通，流水线平台如何定位才比较合理呢？我认为，正确的做法是，将持续交付流水线平台和垂直业务平台分开，并定义彼此的边界。

所谓的垂直业务平台，就是指单一专业领域的能力平台，比如自动化测试平台、代码质量平台、运维发布平台等等，这些也是软件交付团队日常打交道最频繁的平台。

流水线平台只专注于流程编排、过程可视化，并提供底层可复用的基础能力。比如，像是运行资源池、用户权限管控、任务编排调度流程等等。

垂直业务平台则专注于专业能力的建设、一些核心业务的逻辑处理、局部环节的精细化数据管理等。垂直业务平台可以独立对外服务，也可以以插件的形式，将平台能力提供给流水线平台。

这样一来，我们就可以快速复用现有的能力，做到最小成本的建设。随着能力的不断扩展，流水线平台支持的交付流程也会变得非常灵活。

借用《持续交付 2.0》中的一句话来说，流水线平台仅作为任务的调度者、执行者和记录者，并不需要侵入垂直业务平台内部。

这样设计的好处很明显。

从流水线平台的角度来看，通过集成和复用现有的垂直业务能力，可以快速拓展能力图谱，满足不同用户的需求。

从垂直业务平台的角度来看，它们可以持续向技术纵深方向发展，把每一块的能力都做精、做透，这有助于企业积累核心竞争力。另外，流水线可以将更多用户导流到平台中，让垂直业务平台接触更多的用户使用场景。

不仅如此，在执行过程中，流水线携带了大量的软件开发过程信息，比如本次任务包含哪些需求，有哪些变更，这些信息可以在第一时间通知垂直业务平台。垂直业务平台拿到这些过程信息之后，可以通过精准测试等手段，大大提升运行效率。这里的核心就是构建一个企业内部 DevOps 平台的良好生态。

业界很多知名的软件设计都体现了这个思路。比如，Jenkins 的插件中心、GitHub 的 Marketplace。它们背后的理念，都是基于平台，建立一种生态。

我之所以把这个特性放在第一个来介绍，就是因为，这直接决定了流水线平台的定位和后续的设计理念。关于具体怎么设计平台实现能力的快速接入，我会在第八个特性中进行深入介绍。

特性二：可编排和可视化

在现代软件开发中，多种技术栈并存，渐渐成为了一种常态。

举个最简单的例子，对于一个前后端分离的项目来说，前端技术栈和后端技术栈显然是不一样的；对于微服务风格的软件架构来说，每个模块都应该具备持续交付的能力。

所以，传统的标准化软件构建发布路径已经很难满足多样化开发模式的需要了。这样看来，流水线平台作为软件交付的过程载体，流程可编排的能力就变得必不可少了。

所谓的流程可编排能力，就是指用户可以自行定义软件交付过程的每一个步骤，以及各个步骤之间的先后执行顺序。说白了，就是“我的模块我做主，我需要增加哪些交付环节，我自己说了算”。

但是，很多现有的“流水线”平台采用的还是几个“写死”的固定阶段，比如构建、测试、发布，以至于即便有些技术栈不需要进行编译，也不能跳过这个环节。

我之前就见过一家企业，他们把生成版本标签的动作放在了上线检查阶段。我问了之后才知道，这个步骤没有地方可以放了，只能被临时扔在这里。你看，这样一来，整个交付过程看起来的样子和实际的样子可能并不一样，这显然不是可视化所期待的结果。

流程可编排，需要平台前端提供一个可视化的界面，来方便用户定义流水线过程。典型的方式就是，将流水线过程定义为几个阶段，每个阶段按顺序执行。在每个阶段，可以按需添加步骤，这些步骤可以并行执行，也可以串行执行。

前端将编排结果以一种标准化的格式进行保存（一般都是以 JSON 的形式），传递给后端处理。后端流程引擎需要对用户编排的内容进行翻译处理，并传递给执行器，来解释运行即可。

你可以参考一下下面这张流程编排的示意图。在实际运行的过程中，你可以点击每一个步骤，查看对应的运行结果、日志和状态信息。

从表面上看，这主要是在考验平台前端的开发能力，但实际上，编排的前提是系统提供了可编排的对象，这个对象一般称为原子。

所谓原子，就是一个能完成一项具体的独立任务的组件。这些组件要具备一定的通用性，尽量与业务无关。

比如下载代码这个动作，无论是前端项目，还是后端项目，做的事情其实都差不多，核心要实现的就是通过几个参数，完成从版本控制系统拉取代码的动作。那么，这就很适合成为一项原子。

原子的设计是流水线平台的精髓，因为原子体现了平台的通用性、可复用性和独立性。

以我们比较熟悉的 Jenkins 为例，一个原子就是流水线中的一个代码片段。通过封装特性，将实现隐藏在函数实现内部，对外暴露调用方法。用户只需要知道如何使用，不需要关心内部实现。

要想自己实现一个原子，其实并不复杂，在 Jenkins 中添加一段 Groovy 代码就行了。示例代码如下：

// sample_atom_entrance.groovy
def Sample_Atom(Map map) {
    new SampleAtom(this).callExecution(map)
}

// src/com/sample/atoms/SampleAtom.groovy
class SampleAtom extends AbstractAtom {

    SampleAtom(steps) {
        super(steps)
    }

    @Override
    def execute() {
        // Override execute function from AbstractAtom
        useAtom()
    }

    private def useAtom(){
        steps.echo "RUNNING SAMPLE ATOM FUNCTION..."
    }

特性三：流水线即代码

这些年来，“什么什么即代码”的理念已经深入人心了。在应用配置领域，有 Configuration As Code，在服务器领域，有 Infrastructure As Code……流水线的设计与实现，同样需要做到 Pipeline As Code，也就是流水线即代码。

比如，Jenkins 2.0 中引入的 Jenkinsfile 就是一个典型的实现。另外，Gitlab 中提供的 GitlabCI，同样是通过一种代码化的方式和描述式的语言，来展示流水线的业务逻辑和运行方式。

流水线代码化的好处不言而喻：借助版本控制系统的强大功能，流水线代码和业务代码一样纳入版本控制系统，可以简单追溯每次流水线的变更记录。

在执行流水线的过程中，如果流水线配置发生了变化，同样需要体现在本次流水线的变更日志里面。甚至是，在版本的 Release Notes 中也增加流水线、环境的变更记录信息。一旦发生异常，这些信息会大大提升问题的定位速度。

当然，如果只是想要实现流水线变更追溯，你也可以采用其他方式。比如，将流水线配置存放在后台数据库中，并在每次流水线任务执行时，记录当时数据库中的版本信息。

实际上，流水线即代码的好处远不止于此。因为它大大地简化了流水线的配置成本，和原子一样，是构成现代流水线的另外一个支柱。

我跟你分享一个流水线即代码的示例。在这个例子中，你可以看到，整个软件交付流程，都以一种非常清晰的方式描述出来了。即便你不是流水线的专家，也能看懂和使用。

image: maven:latest

stages:
  - build
  - test
  - run

variables:
  MAVEN_CLI_OPTS: "--batch-mode"
  GITLAB_BASE_URL: "https://gitlab.com"
  DEP_PROJECT_ID: 8873767

build:
  stage: build
  script:
    - mvn $MAVEN_CLI_OPTS compile

test:
  stage: test
  script:
    - mvn $MAVEN_CLI_OPTS test

run:
  stage: run
  script:
    - mvn $MAVEN_CLI_OPTS package
    - mvn $MAVEN_CLI_OPTS exec:java -Dexec.mainClass="com.example.app.A

特性四：流水线实例化

作为软件交付流程的建模，流水线跟面向对象语言里面的类和实例非常相似。一个类可以初始化多个对象，每个对象都有自己的内存空间，可以独立存在，流水线也要具备这种能力。

首先，流水线需要支持参数化执行。

通过输入不同的参数，控制流水线的运行结果，甚至是控制流水线的执行过程。

比如，一条流水线应该满足不同分支的构建需要，那么，这就需要将分支作为参数提取出来，在运行时，根据不同的需要，手动或者自动获取。

考虑到这种场景，在平台设计中，你可以事先约定一种参数的格式。这里定义的标准格式，就是以“#”开头，后面加上参数名称。通过在流水线模板中定义这样的参数，一个业务可以快速复用已有的流水线，不需要重新编排，只要修改运行参数即可。

其次，流水线的每一次执行，都可以理解为是一个实例化的过程。

每个实例基于执行时间点的流水线配置，生成一个快照，这个快照不会因为流水线配置的变更而变更。如果想要重新触发这次任务，就需要根据当时的快照运行，从而实现回溯历史的需求。

最后，流水线需要支持并发执行能力。

这就是说，流水线可以触发多次，生成多个运行实例。这考察的不仅是流水线的调度能力、队列能力，还有持久化数据的管理能力。

因为，每次执行都需要有独立的工作空间。为了加速流水线运行，需要在空间中完成静态数据的挂载，比如代码缓存、构建缓存等。有些流水线平台不支持并发，其实就是因为没有解决好这个问题。

特性五：有限支持原则

流水线的设计目标，应该是满足大多数、常见场景下的快速使用，并提供一定程度的定制化可扩展能力，而不是满足所有需求。

在设计流水线功能的时候，我们往往会陷入一个怪圈：我们想要去抽象一个通用的模型，满足所有的业务场景，但是我们会发现，业务总是有这样或者那样的特殊需求。这就像是拿着一张大网下水捞鱼，总是会有漏网之鱼，于是，网做得越来越大。对于平台来说，平台最后会变得非常复杂。

比如，拿最常见的安卓应用构建来说，目前绝大多数企业都在使用 Gradle 工具，通用命令其实只有两步：

gradle clean
gradle assemblerelease / gradle assembledebug

但是，在实际的业务场景中，应用 A 用到了 Node.js，需要安装 npm；应用 B 用到了 Git-lfs 大文件，需要先执行安装指令；应用 C 更甚，需要根据选项，配置执行 Patch 模式和完整打包模式。

如果试图在一个框架中满足所有人的需求，就会让配置和逻辑变得非常复杂。无论是开发实现，还是用户使用，都会变得难以上手。

以 Jenkins 原生的 Xcode 编译步骤为例，这个步骤提供了 53 个参数选项，满足了绝大多数场景的需求，但是也陷入到了参数的汪洋大海中。

所以，流水线设计要提供有限的可能性，而非穷举所有变量因素。

在设计参数接口的时候，我们要遵循“奥卡姆剃刀法则”，也就是，“如无必要，勿增实体”。如果有用户希望给原子增加一个变量参数，那么，我们首先要想的是，这个需求是不是 90% 的人都会用到的功能。如果不是，就不要轻易放在原子设计中。

你可能会问，这样的话，用户的差异化诉求，该如何满足呢？其实，这很简单，你可以在平台中提供一些通用类原子能力，比如，执行自定义脚本的能力、调用 http 接口的能力、用户自定义原子的能力，等等。只要能提供这些能力，就可以满足用户的差异化需求了。

总结

在这一讲中，我给你介绍了现代流水线设计的前五大特性，分别是打造平台而非能力中心、可编排和可视化、流水线即代码、流水线实例化，以及有限支持原则。在下一讲中，我会继续介绍剩余的五大特性，敬请期待。

思考题

你所在的企业有在使用流水线吗？你觉得，流水线还有什么必不可少的特性吗？

欢迎在留言区写下你的思考和答案，我们一起讨论，共同学习进步。如果你觉得这篇文章对你有所帮助，也欢迎你把文章分享给你的朋友。

24 | 持续交付平台：现代流水线必备的十大特征（下）

你好，我是石雪峰。今天，我来接着跟你聊聊现代流水线必备的十大特性的下半部分，分别是流程可控、动静分离配置化、快速接入、内建质量门禁和数据采集聚合。

特性六：流程可控

在上一讲中，我提到过，流水线是覆盖软件交付端到端完整过程的平台，也就是说，流水线的主要作用是驱动软件交付过程的效率提升和状态可视化。

在线下交流的时候，我发现，不少同学对这个概念的理解都存在着一些误区，他们觉得需要建设一条大而全的流水线，在这条流水线上完成软件交付的所有过程。

其实，流水线是要覆盖端到端的流程，但这并不是说，一定要有一条流水线跑通从代码提交开始到软件发布为止的全流程。实际上，在企业中，往往是多条流水线覆盖不同的环节，比如开发阶段流水线、集成阶段流水线，以及部署阶段流水线。这些流水线一起覆盖了整个软件交付流程。

这就体现了流水线的流程可控性，流水线可以为了满足不同阶段的业务目标而存在，并且每条流水线上实现的功能都不相同。为了达到这个目的，流水线需要支持多种触发方式，比如定时触发、手动触发、事件触发等。其中，事件触发就是实现持续集成的一个非常重要的能力。

以 Gitlab 为例，你可以在代码仓库中添加 Webhook，Webhook 的地址就是触发流水线任务的 API，这个 API 可以通过 Gitlab 的 API 实现自动注册。

需要注意的是，要实现 Webhook 的自动注册，访问 Gitlab 的账号时必须要有对应代码仓库的 Master 级别权限，否则是无法添加成功的。

当注册完成 Webhook，代码仓库捕获到对应的事件后，比如代码 Push 动作，会自动调用 Webhook，并且将本次代码提交的基础信息（比如分支、提交人等）传递给注册地址。

流水线平台接收到接口访问后，可以根据规则过滤请求，最典型的就是触发分支信息。当满足规则条件后，则执行流水线任务，并将结果再次通过 Gitlab 的 API 写回到代码仓库中。这样一来，每次提交历史都会关联一个流水线的执行记录，可以用于辅助代码合并评审。

我画了一张流程图，它展示了刚刚我所描述的过程以及调用的接口信息。

除了多种触发方式以外，流水线还需要支持人工审批。这也就是说，每个阶段的流转可以是自动的，上一阶段完成后，就自动执行下一阶段；也可以是手动执行的，必须经过人为确认才能继续执行，这里的人为确认需要配合权限的管控。

其实，人工审批的场景在软件交付过程中非常常见。如果是自建流程引擎，人工审批就不难实现，但是，如果你是基于 Jenkins 来实现这个过程，虽然 Jenkins 提供了 input 方法来实现人为审批的功能，但我还是比较推荐你自己通过扩展代码来实现。比如，将每个原子的执行过程抽象为 before()、execute() 和 after() 三个阶段，可以将人工审批的逻辑写在 before() 或者 after() 方法中。

这样一来，对于所有原子都可以默认执行基类方法，从而获得人工审批的能力。是否开启人工审批，可以通过原子配置中的参数实现。你就不需要在每个原子中人工注入 input 方法了，流水线的执行过程会更加清晰。

我给你分享一个抽象原子类的设计实现，如下面的代码所示：

abstract class AbstractAtom extends AtomExecution {
  def atomExecution() {
        this.beforeAtomExecution()
        // 原子预处理步骤，你可以将通用执行逻辑，比如人工审批等写在这里
        echo('AtomBefore')
        before()
        // 原子主体核心逻辑
        echo('AtomExecution')
        execute()
        // 原子后处理步骤，你可以将通用执行逻辑，比如人工审批等写在这里
        echo('AtomAfter')
        after()
        this.afterAtomExecution()
    }
}

特性七：动静分离配置化

流水线的灵活性不仅体现在流程可编排、流程可控方面，每一个原子都需要持续迭代功能。那么，如何在不改变代码的情况下，实现原子的动态化配置呢？

这就需要用到动静分离的设计方法了。那么，什么是动静分离呢？

其实，动静分离就是一种配置化的实现方式。这就是指，将需要频繁调整或者用户自定义的内容，保存在一个静态的配置文件中。然后，系统加载时通过读取接口获取配置数据，并动态生成用户可见的交互界面。

你可能觉得有点抽象，我来给你举个例子。你可以看一下下面这张截图。

如果我想对某一个原子扩展一个新的功能，提供一个新的用户配置参数，传统的做法就是在前端页面中增加一段 html 代码。这样的话，原子功能的每一次变更都需要前端配合调整，原子的独立性就不复存在了，而是跟页面强耦合在一起。

另外，前端页面加入了这么多业务逻辑，如果哪天需要同时兼容不同的原子版本，那么前端页面也需要保存两套。一两个应用这么玩也就罢了，如果有上百个应用，那简直没法想象。

那么，具体要怎么做呢？最重要的就是定义一套标准的原子数据结构。

比如，在上面这张图的左侧部分，我给你提供了一个参考结构。对于所有的原子来说，它对外暴露的功能都是通过这套标准化的方式来定义的。前端在加载原子的时候，后端提供的接口获取原子的数据结构，并按照约定的参数类型，渲染成不同的控件类型。

不仅如此，控件的属性也可以灵活调整，比如控件的默认值是什么，控件是否属于必填项，是否存在可输入字符限制等等。那么，当你想增加一个新的参数的时候，只需要修改原子配置，而不需要修改前端代码。结构定义和具体实现的分离，可以大幅简化原子升级的灵活性。

无论在原子结构设计，还是前后端交互等领域，定义一个通用的数据结构是设计标准化的系统的最佳实践。

对于流水线平台来说，除了原子，很多地方都会用到配置化的方式。比如，系统报告中体现的字段和图表类型等，就是为了满足用户差异化的需求。而且，将配置纳入版本控制，你也可以快速查询原子配置的变更记录，达到一切变更皆可追溯的目标。

特性八：快速接入

前面我提到过，流水线的很多能力都不是自己提供的，而是来源于垂直业务平台。那么，在建设流水线平台的时候，能否快速地实现外部平台能力的接入，就成了一个必须要解决的问题。

经典的解决方式就是提供一种插件机制，来实现平台能力的接入。比如，Jenkins 平台就是通过这种方式，建立了非常强大的插件生态。但是，如果每个平台的接入都需要企业内部自己来实现插件的话，那么，企业对于平台接入的意愿就会大大降低。

实际上，接入成本的高低，直接影响了平台能力的拓展，而流水线平台支持的能力多少，就是平台的核心竞争力。

那么，有没有一种更加轻量化的平台接入方法呢？我给你提供一个解决思路：自动化生成平台关联的原子代码。

在第七个特性中，我们已经将原子的数据结构通过一种标准化的描述式语言定义完成了，那原子的实现代码是否可以也自动化生成呢？实际上，在大多数情况下，外部平台打通有两种类型。

平台方提供一个本地执行的工具，也就是类似 SonarQube 的 Scanner 的方式，通过在本地调用这个工具，实现相应的功能。

通过接口调用的方式，实现平台与平台间的交互，调用的实现过程无外乎同步和异步两种模式。

既然平台接入存在一定的共性，那么，我们就可以规划解题方法了。

首先，流水线平台需要定义一套标准的接入方式。以接口调用类型为例，接入平台需要提供一个任务调用接口、一个状态查询接口以及一个结果上报接口。

任务调用接口：用于流水线触发任务，一般由接入平台定义和实现。对于比较成熟的平台来说，这类接口一般都是现成的。接口调用参数可以直接转换成原子的参数，一些平台的配置化信息（比如接口地址、接口协议等），都可以定义在原子的数据结构中。

状态查询接口：用于流水线查询任务的执行状态，获取任务的执行进度。这个接口也是由接入平台定义和实现的，返回的内容一般包括任务状态和执行日志等。

数据上报接口：用于任务将执行结果上报给流水线平台进行保存。这个接口由流水线平台定义，并提供一套标准的数据接口给到接入方。接入方必须按照这个标准接口上报数据，以简化数据上报的过程。

通过将平台接入简化为几个标准步骤，可以大幅简化平台接入的实现成本。按照我们的经验，一套平台的接入基本都可以在几天内完成。

特性九：内建质量门禁

在第 14 讲中，我给你介绍了内建质量的理念，以及相关的实施步骤。你还记得内建质量的两大原则吗？

问题发现得越早，修复成本就越低；

质量是每个人的责任，而不是质量团队的责任。

毫无疑问，持续交付流水线是内建质量的最好阵地，而具体的展现形式就是质量门禁。通过在持续交付流水线的各个阶段注入质量检查能力，可以让内建质量真正落地。

一般来说，流水线平台都应该具备质量门禁的能力，我们甚至要把它作为流水线平台的一级能力进行建设。在流水线平台上，要完成质量规则制定、门禁数据收集和检查，以及门禁结果报告的完整闭环。质量门禁大多数来源于垂直业务平台，比如，UI 自动化测试平台就可以提供自动化测试通过率等指标。只有将用于门禁的数据上报到流水线平台，才能够激活检查功能。

那么，质量门禁的功能应该如何设计呢？

从后向前倒推，首先是设置门禁检查功能。这个功能也是一种流水线的通用能力，所以和人工审核的功能类似，也可以放在原子执行的 after() 步骤中，或者独立出来一个步骤就叫作 qualityGates()。

每次原子执行时都会走到这个步骤，在步骤中校验当前流水线是否已经开启了门禁检查功能，并且当前原子是否提供了门禁检查能力。如果发现已配置门禁规则，而且当前原子在检查范围内，就等待运行结果返回，提取数据，并触发检查工作。你可以参考下面的示例代码。

def qualityGates() {
  // 获取质量门禁配置以及生效状态
  boolean isRun = qualityGateAction.fetchQualityGateConfig(host, token, pipelineId, oneScope)
  // 激活检查的情况等待结果返回，最多等待 30 分钟
  if (isRun) {
    syncHandler.doSyncOperation(
      30,
      'MINUTES',
      {
        // 等待执行结果返回，质量门禁功能必须同步执行
        return httpUtil.doGetToExternalResult(host, externalMap.get(oneScope), token)
      })
    // 提取返回数据
    qualityGateAction.fetchExecutionResult(host, token, externalMap.get(oneScope), buildId)
    // 验证质量门禁
    qualityGateAction.verify(oneScope)
  }
}

解决了如何检查的问题，我们再往前一步，看看质量门禁的规则应该如何定义。

在企业内，定义和管理质量规则的一般都是 QA 团队，所以需要给他们提供一个统一入口，方便他们进行规则配置和具体数值的调整。

对质量门禁来说，检查的类型可以说是多种多样的。

从比较类型来说，可以比较结果大于、等于、小于、包含、不包含等；

从比较结果来说，可以是失败值、警告值。失败值是指，只要满足这个条件，就直接终止流水线执行。而警告值是说，如果满足这个条件，就给一个警告标记，但是不会终止流水线执行。

这些条件，往往需要根据 QA 团队定义的规则来适配。

质量规则可以由一组子规则共同组成，比如，单元测试通过率 100%、行覆盖率大于 50%、严重阻塞代码问题等于 0……

所以，你看，想要定义一个灵活的质量门禁，就需要在系统设计方面花点功夫了。在之前的实践中，我们就采用了适配器加策略模式的方式，这样可以满足规则的灵活扩展。

策略模式是 23 种设计模式中比较常用的一种。如果你之前没有了解过，我给你推荐一篇参考文章。如果想要深入学习设计模式，极客时间也有相应的专栏，或者你也可以购买经典的《设计模式》一书。其实，核心就在于面向接口而非面向过程开发，通过实现不同的接口类，来实现不同的检查策略。

特性十：数据聚合采集

作为软件交付过程的载体，流水线的可视化就体现在可以在流水线上看到每一个环节的执行情况。这是什么意思呢？

在系统没有打通的时候，如果你想看测试的执行结果，就要跑到测试系统上看；如果想看数据库变更的执行状态，就得去数据库管理平台上看。这里的问题就是，没有一个统一的地方可以查看本次发布的所有状态信息，而这也是流水线的可视化要解决的问题。

当平台的能力以原子的形式接入流水线之后，流水线需要有能力获取本次执行相关的结果数据，这也是在平台对接的时候，务必要求子系统实现数据上报接口的原因。至于上报数据的颗粒度，其实并没有一定之规，原则就是满足用户对最基本的结果数据的查看需求。

以单元测试为例，需要收集的数据包括两个方面，一个是单元测试的执行结果，比如一共多少用例，执行多少，成功失败分别多少。另外，即使收集覆盖率信息，至少也要包含各个维度的覆盖率指标。但是，对于具体每个文件的覆盖率情况，这种粒度的数据量比较大，可以通过生成报告的方式来呈现，不用事无巨细地都上报到流水线后台进行保存。

在企业内部没有建立独立的数据度量平台之前，流水线平台承载了全流程数据的展示功能。但是，毕竟流水线的目标是为了展示客观的数据结果，而不是在于对数据进行分析挖掘。所以，当企业开始建设数据度量平台时，流水线也可以作为数据源之一，满足度量平台对于各项工程能力的度量需求。

总结

到此为止，我给你完整地介绍了现代流水线必备的十大特性。其实，流水线的功能特性远不止这 10 个。随着云计算和云原生应用的发展，云原生流水线也成为了越来越多人讨论的话题。关于这方面的内容，我会在后续的课程中给你分享我的一些想法。

可以说，一个好的持续交付流水线平台，就是企业 DevOps 能力的巅峰展现。这也难怪，越来越多的公司开始在这个领域发力，甚至把它作为核心能力对外输出，成为企业商业化运作的一份子。深入掌握这 10 个特性，并把它们落实在流水线平台的建设中，是企业 DevOps 平台建设的必经之路。

就像美国著名女演员莉莉·汤姆林（Lily Tomlin）的那句经典名言所说的那样：

The road to success is always under construction.（通往成功的道路，永远在建设之中）

企业迈向持续交付的成功之路也不是一帆风顺的，永无止境的追求是指引我们前进的方向，也希望你能在流水线建设之路上不断思考，不断实践，持续精进。

思考题

你目前在使用的流水线平台有哪些不好用、待改进，或者是“反人类”的设计吗？看完这两讲的内容，你有什么新的想法和改进建议吗？

欢迎在留言区写下你的思考和答案，我们一起讨论，共同学习进步。如果你觉得这篇文章对你有所帮助，也欢迎你把文章分享给你的朋友。

25 | 让数据说话：如何建设企业级数据度量平台？

你好，我是石雪峰。今天我来跟你聊聊数据度量平台。

先说个题外话。在 2019 年的 DevOps World | Jenkins World 大会上，CloudBees 公司重磅发布了他们的全新产品：SDM - Software Delivery Management 。在我看来，这注定是一个跨时代的产品。

简单来说，SDM 想要解决的问题就是，将割裂的软件开发流程收敛到一个平台上，通过收集软件开发全流程的数据，并进行智能分析，从而让整个软件交付过程的方方面面对所有人都可视化。

无论这个产品最终是否能够获得成功，它背后的设计理念绝对是非常超前的，因为这是第一次有一个解决方案把业务视角和开发视角连接了起来。

对业务人员来说，他们能够实时看到特性的交付进度；对开发人员来说，他们也能实时看到交付特性的业务指标和用户反馈；对管理人员来说，他们可以纵观整个流程，发现交付过程中的阻塞和效率瓶颈。

这听起来是不是很神奇呢？别急，关于这个产品的更多特性，我会在后续的特别放送中给你带来更多的介绍，敬请期待。

言归正传，我走访过的公司无一例外地都在花大力气建设数据度量平台。这些度量平台虽然看起来长得都不一样，但是他们想要解决的核心问题都是一致的，那就是软件研发过程可视化。

为什么可视化对于软件研发来说这么重要呢？这是因为，可视化可以大幅降低软件开发的协作成本，增加研发过程的透明度，从而大大减少研发过程中的浪费和返工。

举个最简单的例子，每周开会的时间成本一般都比较高，但如果老板能对项目的状态有清晰的了解，何必还要费这么大力气汇报工作呢？

在专栏的第 19 讲中，我给你介绍了 DevOps 度量体系的相关内容。你还记得好的度量指标一般都具有的典型特征吗？这些特征就是明确受众、直指问题、量化趋势、充满张力。

其实，在评价一个度量平台的时候，这些特征同样适用。因为，在数据度量平台上呈现的内容，正是度量指标。这也就是说，将度量指标的数据和详情汇总起来，再根据度量指标的维度，展现出各式各样的视图，从而满足不同用户的需求。

这样一来，整个团队的交付情况，包括交付效率和质量，就可以通过客观数据展示出来，而不再依赖于个人的主观臆测。有了客观的数据做尺子，团队的改进空间也就一目了然了。

听起来是不是特别美好？但实际上，度量平台要想满足这种预期，可不是一件简单的事情。

我认为，在数据度量平台的建设和落地过程中，事前、事中和事后这三个阶段都存在着大量的挑战。接下来，我就从这三个阶段入手，给你聊聊度量平台建设的一些思路。

事前：指标共识

毫无疑问，度量指标是数据度量平台的基础。在建设平台之前，如果指标本身的定义、数据来源、计算方法、统计口径等没有在团队内部达成共识的话，那么，数据度量平台呈现出来的数据也同样是有问题的。

我给你举个例子。需求流转周期这个指标，一般是计算需求卡片在需求的各个状态的停留时长的总和，包括分析、设计、开发、测试、发布等。

其中的测试流转周期计算的是，从需求卡片进入待测试状态到测试完成进入待发布状态的时长，例如 5 天。但是，在真正支持测试任务的系统中，也有一个测试流转周期。这个流转周期计算的是每个测试任务的平均执行时间，这样算出来的测试周期可能只有 1 天。

先不说这两种计算方式谁对谁错，我想表达的是，即便是针对同一个指标，在不同平台、根据不同计算方法得到的结果也大不相同。

如果不能把指标的定义对齐，那么在实施度量的过程中，大家就会不清楚到底哪个数据是正确的，这显然不利于度量工作的推进。

另外，在定义度量指标的时候，一般都会召开指标评审会议。但这个时候，因为拿不出具体的数据，大家光盯着指标定义看，往往也看不出什么问题。等到平台上的数据出来了，才发现有些数据好像不太对。于是，要再针对指标重新梳理定义，而这往往就意味着平台开发的返工和数据重新计算。在平台建设的过程中，数据校准和指标对齐工作花费的时间很有可能比开发平台本身的时间都要多。

“数据本身不会说话，是人们赋予了数据意义”，而“这个意义“就是度量指标。

在定义指标的时候，大家都愿意选择对自己有利的解释，这就导致大家看待数据的视角无法对齐。

所以，在实施度量平台建设之前，最重要的就是细化度量指标的数据源和计算方法，而且一定要细化到可以落地并拿出数据结果的程度。

比如，开发交付周期这个指标一般是指从研发真正动工的时间点开始，一直到最终上线发布为止的时长。但是这个描述还是不够细化，所以，我们团队对这个指标的描述是：从研发在需求管理平台上将一个任务拖拽到开始的开发阶段起，一直到这个任务变成已发布状态为止的时间周期。

这里的任务类型包括特性、缺陷和改进任务三种，不包含史诗任务和技术预研任务类型。我们会对已达到交付状态的任务进行统计，未完成的不在统计范围中。你看，只有描述到这种颗粒度，研发才知道应该如何操作，数据统计才知道要如何获取有效的数据范围。

我建议你在着手启动数据度量平台建设之前，至少要保证这些指标数据可以通过线下、甚至是手工的方式统计出来，并在内部达成共识。

切忌一上来就开始盲目建设！很多时候，我们虽然花了大力气建设平台，最终也建设出来了，但结果却没人关注，核心问题还是出在了指标上。

数据平台作为企业内部的公信平台，数据的准确性至关重要。如果数据出现了偏差，不仅会导致错误的判断，带来错误的结果，还会对平台自身的运营推广造成很大的伤害。

事中：平台建设

随着软件交付活动复杂性的上升，在整个交付过程中用到的工具平台也越来越多。虽然通过持续交付流水线平台实现了交付链路的打通，通过交付流水线来驱动各个环节的工具平台来完成工作，但是，客观来说，企业内部的工具平台依然是割裂的状态，而非完整的一体化平台。

这就带来一个问题：每个平台或多或少都有自己的数据度量能力，甚至也有精细化维度的数据展示，但是这些数据都是存储在各个工具平台自身的数据库中的。

我给你举个例子。Jira 是一个业界使用比较普遍的需求管理平台，也是一个成熟的商业工具，所以，对于这类商业化系统都提供了比较完善的 API。再加上 Jira 自带的 JQL 查询语言，可以相对比较简单地查询并获取元数据信息。但是，对于一个自研平台来说，对外开发的 API 可能相对简单，甚至有的系统都没有对外暴露 API。在这种情况下，如果想要获取平台数据，要么依赖于开发新的 API，要么就只能通过 JDBC 直接访问后台数据库的形式来提取数据。

不仅如此，还有些平台的数据是通过消息推送的方式来获取的，无法主动地获取数据，只能通过订阅消息队列广播的方式来获取。

所以，你看，对于不同的元数据平台，数据获取的方式也是千差万别的。

挑战一：大量数据源平台对接

那么，作为一个统一的数据度量平台，面对的第一个挑战就是，如何从这些种类繁多的平台中提取有用的数据，并且保证数据源接入的隔离性，做到灵活接入呢？

我给你的建议还是采用流水线设计的思路，那就是插件化，只不过，这次要实现的插件是数据采集器。你可以看一下这张简单的架构示意图：

采集器是针对每一个对接的数据源平台实现的，它的作用就是对每个数据源进行数据建模，从而对平台屏蔽各种数据获取方式，将采集到的数据进行统一格式化上报和存储。在采集器上面可以设计一个 Operation 层，用来调整采集器的执行频率，控制采集数据的范围。

如果数据量比较大，你也可以让采集器对接类似 Kafka 这样的消息队列，这些都可以按需实现。这样一来，新平台如果想要接入，只需要针对这个平台的数据特性实现一个采集器即可，平台的整体架构并不需要变化。

你可以看看下面的这段采集器的示例代码：

@Override
  public void collect(FeatureCollector collector) {
    logBanner(featureSettings.getJiraBaseUrl());
    int count = 0;

    try {
      long projectDataStart = System.currentTimeMillis();
      ProjectDataClientImpl projectData = new ProjectDataClientImpl(this.featureSettings,
          this.projectRepository, this.featureCollectorRepository, jiraClient);
      count = projectData.updateProjectInformation();
      log("Project Data", projectDataStart, count);
    } catch (Exception e) {
      // catch exception here so we don't blow up the collector completely
      LOGGER.error("Failed to collect jira information", e);
    }
  }

挑战二：海量数据存储分析

一般来说，常见的数据存储方式无外乎 RDMS 关系型数据库和 NoSQL 非关系型数据库两种类型。那么，究竟应该如何选择，还是要看数据度量平台的数据特征。

第一个典型特征就是数据量大。对于一个大型公司而言，每天的代码提交就有近万笔，单单这部分数据就有几十万、上百万条。

第二个特征就是数据结构不统一。这个其实很好理解，毕竟需求相关的数据字段和代码相关的数据字段基本上没有什么共性，而且字段的数量也会根据指标的调整而调整。

第三个特征就是数据访问频繁。度量平台需要在大规模的数据集中进行随机访问、数据的读取运算等操作，这就要求很好的横向扩展能力。

另外，数据度量平台一般都会保存元数据和加工数据。所谓元数据，就是采集过来的、未加工过的数据，而加工数据则是经过数据清洗和数据处理的数据。

我还是举个代码库的例子来说明一下。元数据就是一条条用户的代码提交记录，而加工数据则是按照分钟维度聚合过的提交信息，包括数量、行数变化等。这些加工过的数据可以很简单地提供给前端进行图表展示。存储加工数据的原因就在于，避免每次实时的大量数据运算，以提升度量平台的性能。

基于这些典型特征和场景，不难看出，非关系型数据库更加适合于大量元数据的保存。

我推荐你使用 HBase，这是一个适合于非结构化数据存储的数据库，天生支持分布式存储系统。而对于加工数据的保存，你可以采用关系型数据库 MySQL。

当然，数据库的选型不止这一种，业界还有很多开源、商业工具。比如，开源的数据度量平台 Hygieia 就采用的是 MongoDB，而商业工具中的 Insight 也在业内的很多大型公司在大规模使用。

我再给你分享一幅数据度量的架构图。从这张图中，你可以看到，底层数据都是基于 HBase 和 HDFS 来存储的。

挑战三：度量视图的定制化显示

度量平台需要满足不同维度视角的需求，所以一般都会提供多个 Dashboard，比如管理层 Dashboard、技术经理 Dashboard、个人 Dashboard 等。但是，这种预置的 Dashboard 很难满足每个人的差异化需求，就像“一千个人眼里有一千个哈姆雷特”一样，度量平台的视图也应该是千人千面的。

那么如果想要实现度量视图的自定义，比如支持图标位置的拖拽和编辑，自己增加新的组件、并按照自定义视图发送报告等，那就需要在前端页面开发时下点功夫了。好在对于现代前端框架，都有现成的解决方案，你只需要引用对应的组件即可。

我给你推荐两个前端组件，你可以参考一下：

插件一

插件二

这两个组件都可以支持 widget 的拖拽、缩放、自动对齐、添加、删除等常见操作。这样一来，每个人都可以自由地按需定制自己的工作台视图，不同角色的人员也可以定制和发送报告，而不需要从度量平台提取数据，再手动整理到 PPT 里面了。

以 vue-grid-layout 为例，在使用时，你可以将 echarts 图表放在自定义组件里面，同时你也可以自己实现一些方法，具体的方法可以参考一下这篇文章。

在了解了刚开始建设度量平台的三个常见挑战之后，你应该已经对度量平台的架构有了一个大体的认识，接下来，我们来看看第三个阶段。

事后：规则落地

以现在的开发效率来说，建设一个数据度量平台并不是件困难的事情。实际上，建设度量平台只能说是迈出了数据度量的第 1 步，而剩余的 99 步都依赖于平台的运营推广。

这么说一点也不夸张，甚至可以说，如果根本没人关心度量平台上的数据，那么可能连第 1 步的意义都要画上个问号。

在开始运营的时候，度量平台面临的最大挑战就是数据的准确性，这也是最容易被人 challenge 的地方。

造成数据不准确的原因有很多，比如，度量指标自身的计算方式问题、一些异常数据引入的问题、部门维度归类聚合的问题。但是实际上，往往带来最多问题的还是研发操作不规范。

举个例子，像需求交付周期这种数据强依赖于需求卡片流转的操作是否规范，如果研发上线后一次性把卡片拖拽到上线状态，那么这样算出来的需求交付周期可能只有几秒钟，显然是有问题的。

正确的做法是，根据真实的状态进行流转，比如研发提测关联需求，后台自动将需求卡片流转到待测试状态；测试验收通过后，卡片再次自动流转到测试完成状态等。尽量实现自动化操作，而不是依赖于人的自觉性。

再举个例子，像需求关联的代码行数，如果研发提交的时候并没有对代码和需求建立关联，那么统计出来的数据也会有很大的失真。这些不规范的数据并不会因为后续操作的改变而改变，也很难进行数据的修复和清理，会一直留存在度量系统的数据池中，是抹不掉的印记。

所以，度量平台只有通过项目自上而下的驱动才能起到真正的作用。要对不规范的操作建立规则，对恶意操作的数据进行审计，把度量发现的问题纳入持续改进，对每项指标的走势进行跟踪和定位。

另外，为了让数据可以直指问题，在度量平台中，也需要体现出来当前的数据是好还是坏。

方式和方法有很多，比如，建立参考值（比如对于单测覆盖率制定最低 50% 的参考值），这样在度量图表中就能体现出当前数据和参考值的差距。或者，你也可以在每一项可以横向比较的指标旁边，体现当前处在大部门的哪个位置，是前 10%，还是后 10%？这样的数据都有助于推动改进行为。

说到底，度量的目的是持续改进。如果统计了 100 个指标的数据，并都体现在度量平台上，却说不出来到底哪个指标给团队带来了改进，以及改进是如何实现的，那么，这种度量平台的价值又在哪里呢？

总结

好啦，在这一讲中，我给你介绍了建设数据度量平台的核心价值，也就是让软件交付过程变得可视化。在这一点上，业界各大公司的思路都是一致的。也正因为如此，数据度量平台是当前企业 DevOps 平台建设不可或缺的一环。

在平台建设的时候，你需要关注事前、事中和事后三个阶段的事情。

事前就是要对指标的定义达成共识。这里的指标要细化到数据源和详细的计算公式层面，即便没有度量平台，也可以计算出相应的结果；

事中就是平台建设方面，面对多数据源平台可以采用采集器插件的方式灵活适配，建议使用 HBase 等非关系型数据库进行数据存储，可以利用现有的前端组件来实现可视化界面展示。

事后就是数据的运营和规则落地。只有度量数据能够反映出问题，并驱动团队改进，度量才有意义。

思考题

你在企业中建设和应用度量平台的时候，还遇到过哪些问题呢？你又是如何解决的呢？

欢迎在留言区写下你的思考和答案，我们一起讨论，共同学习进步。如果你觉得这篇文章对你有所帮助，也欢迎你把文章分享给你的朋友。

26 | 平台产品研发：三个月完成千人规模的产品要怎么做？

你好，我是石雪峰。

虽然我们之前聊了这么多的平台建设思路，但是，可能很多人都没有机会经历一个平台从构思到开发、再到推广落地的完整过程。

如果要开发一个千人使用的 DevOps 产品，需要多长时间呢？你可能会说需要半年甚至是更长的时间，我之前也是这么觉得的。

但是，2018 年，在启动流水线平台建设的时候，老板“大手一挥”，要求在三个月内见到成效，我都快惊呆了。

因为，我们要真正地从零开始：原型图都没有一张，代码都没有一行，临时组建的一个草台班子还分散在北京、上海两地，团队成员之前都没怎么打过招呼，这能行吗？

今天，我想给你分享的就是这个真实的故事。我来跟你一起复盘下这次“急行军”的历程，看看我们做对了什么，又做错了什么，有哪些干货是可以拿来就用的，又有哪些“坑”是你一定要努力回避的。

其实，作为一个非专业的 DevOps 产品经理，你终将面对这样的挑战，但你要相信，只要开始去做了，就没有什么是不可能的。

项目启动

时间回到一年前，当时我所在的这个“草台班子”是个啥情况呢？团队组成是这样的：两个后台开发在北京，一个半前端开发在上海，还有一个基础设施工程师和一个流水线开发工程师，再加上半个全能打杂的产品经理，也就是我，满打满算一共 6 个人。

项目从 11 月中旬开始构思，12 月初开启动会，当时，除了我之外，没有任何人清楚我们要做的到底是个什么玩意儿。这该怎么办呢？

玩过游戏的同学应该都知道打好开局有多重要，所以，为了这个 Kickoff 会议，我事先做了大量的准备工作，其中就包括 0.2 版本的产品原型图。与其说是一个原型图，不如说就是一个草稿，简陋得不能再简陋了。

项目的 Kickoff 会议是项目组成员和未来产品的第一次见面，留下一个积极的印象非常重要。所以，从第一刻开始，我就铆足了精神。

首先，我发出了一封热情洋溢的会议邀请。在会议邀请中，我仔细地陈述了我们为什么要做这件事，为什么是现在，为什么不做不行。

在正式开会的时候，我再一次明确了项目的重要性和紧急性，并给大家演示了第一版的系统原型图（没错，就是简陋到极致的刚刚的这张原型图）。

即便这样，三个月的工期也让大家非常焦虑。为了缓解紧张情绪，证明这个项目的可行性，我还做了两件事：

搭建了一个系统 demo，几个简单的页面；

由于用到了另外一个开源产品的核心技术，于是，我就对这个技术进行了简单演示。

虽然我自己心里对这个计划也相当“打鼓”，但我还是希望告诉大家，这并不是不可能的任务，努力帮助大家树立信心。

在项目启动会上，团队达成了两个非常关键的结论：一个是系统方案选型；另一个是建立协作机制。

首先，由于时间紧任务重，我们决定使用更易于协作的前后端分离的开发模式。后来，事实证明，这是一个非常明智的选择。这不仅大幅提升了开发效率，也大大降低了之后向移动端迁移的成本。在开发移动端产品的时候，后端接口大部分都可以直接拿来使用。

在技术框架方面，由于大家对前后端分离的模式达成了共识，我们就采用 Python+Django+VUE 的方式来做。你可能会问，为啥不用基于 Java 的 Spring 系列呢？因为我觉得，对于内部系统来说，这些典型的框架应付起来基本都绰绰有余，关键还是要选你熟悉的、易上手的那个。从这个角度来看，Python 显然有着得天独厚的优势。即便之前只是写写脚本，想要上手 Python 也不是一件困难的事情。

在项目协作方面，我等会儿会专门提到，由于团队成员分散在北京、上海两地，彼此之间不够熟悉和信任，所以，建立固定的沟通机制就非常重要。

至少，在项目初期，我们每周都要开两次电话会议：

一次是面向全员的。一方面同步项目的最新进展，另一方面，也给大家一些紧迫感，让大家觉得“其他人都在按照计划执行，自己也不能落后”。

另外一次是面向跨地域骨干的。这主要还是为了增进联系，并且对一些核心问题进行二次的进展确认。不拉上全员，也是为了避免过多地浪费项目成员的时间。

最后，项目毕竟还是有一些技术风险的，所以还需要启动预研。我们这个项目的主要风险是在前端交互上。

这是一个从来没人实现过的场景，有大量的用户界面编排操作在里面。所以，我们专门指定了一位同学，让他啥也别想，一门心思地进行技术攻关。

事实证明，但凡能打硬仗的同事，在后来都是非常靠谱且独当一面的，这与年龄无关，哪怕是应届生，也同样如此。

讲到这里，我要先给你总结一下在项目启动阶段要重点关注的几件事情：

明确项目目标，树立团队的信心；

沟通开发模式和技术架构选型，以快速开发和简单上手为导向；

建立沟通渠道，保持高频联系；

识别项目的技术风险，提前开启专项预研。

开发策略

人类社会活动的每一个环节，都需要越来越多的人为了同一个目标推进工作，软件开发也不例外。那么，我们是怎么做的呢？

首先，就是研发环境容器化。

对于接触一个全新技术栈的开发来说，本地搭建一套完整可运行的环境总是绕不过去的坎。即便是对照着文档一步步操作，也总会有遗漏的地方。除此之外，项目依赖的各种中间件，哪怕稍微有一个版本不一致，最后一旦出现问题，就要查很久。

既然如此，为什么不一上来就采用标准化的环境呢？这就可以发挥容器技术的优势了。主力后台开发同学自己认领了这个任务，先在本地完成环境搭建并调试通过，接着把环境配置容器化。这样一来，新人加入项目后，几分钟就能完成一套可以工作的本地开发环境。即便后续要升级环境组件，比如 Django 框架版本，也非常简单，只要推送一个镜像上去，再重启本地环境就可以了。

其次，就是选择分支策略。虽然 DevOps 倡导的是主干开发，但是我们还是选择了“三分支”的策略，因为我们搭建了三套环境。

测试环境对应 dev 分支作为开发主线，所有新功能在特性分支开发，自测通过后，再通过 MR 到 dev 分支并部署到测试环境进行验收测试，一般验收测试由需求提出方负责。

接下来，定期每周两次从 dev 上 master 分支，master 分支对应了预发布环境，保证跟生产环境的一致性，数据也会定期进行同步。只有在预发布环境最终验收通过后，才具备上线生产环境的条件。通过将 master 分支合并到 release 分支，最后完成生产环境部署。这种分支策略的示意图如下：

为什么要采用三套环境的“三分支”策略呢？

这里的主要原因就是，团队处于组建初期，磨合不到位，经常会出现前后端配置不一致的情况。更何况，我们这个项目不只有前后端开发，还有核心原子业务开发，以及基础设施维护。任何一方的步调不一致，都会导致出现问题。

另外，内部平台开发往往有个通病，就是没有专职测试。这也能理解，总共才几个人的“草台班子”，哪来的测试资源啊？所以，基本上只能靠研发和产品把关。

但是，毕竟测试也是个专业的工种，这么一来，总会有各种各样的问题。再加上，产品需求本身就没有那么清晰、灵活多变，所以，多一套环境，多一套安全。

但不可否认的是，这种策略并非是最优解，只不过是适应当时场景下的可行方案。当团队磨合到位，而且也比较成熟之后，就可以简化一条分支和一套环境了。不过，前提是，只有快速迭代，快速上线，才能发挥两套环境的优势。

Use what you build to build what you use.（使用你开发的工具来开发你的工具）

这是我们一以贯之的理念。既然是 DevOps 平台，那么团队也要有 DevOps 的样子，所以，作为一个全功能团队，研发自上线和研发自运维就发挥到了极致。

同时，我们并没有使用公司统一的上线流程，而是自己建立了一个标准化的上线流程并固化在工具里面，团队的每一个人都能完成上线动作。

这样一来，就不会再依赖于某个具体的人员了，这就保持了最大的灵活性。即便赶上大促封网，也不会阻塞正常的开发活动。

开发协作流程

仅仅是做到上面这几点，还不足以让整个团队高效运转起来，因为缺少了最重要的研发协作流程。

作为项目负责人，我花了很大的精力优化研发协作流程，制定研发协作规范。当这一切正常运转起来后，我发现，这些前期的投入都是非常值得的。

在工具层面，我们使用了 Jira。对于小团队来说，Jira 的功能就足够优秀了，可以满足大多数场景的需求。但是 Jira 的缺点在于，使用和配置门槛稍微有点高。因此，团队里面需要有一个熟悉 Jira 的成员，才能把这套方法“玩”下去。

在 Jira 里面，我们采用了精益看板加上迭代的方式，基本上两周一个迭代，保持开发交付的节奏。这种开发工作流刚好适配我们的分支策略和多环境部署。

需求统一纳入 Backlog 管理，当迭代开始时，就拖入待开发状态，研发挑选任务启动开发，并进入开发中。当开发完成后，也就意味着功能已经在测试环境部署。这个时候，就可以等待功能验收。只有在验收通过之后，才会发布到预发布环境。并经过二次验收后，最终上线发布给用户。

开发流程并不复杂，你可以看一下下面这两版流程图。

图片版：

文字版：

定义好开发工作流之后，接下来，就需要明确原则和规范了。对于一个新组建的团队来说，规则是消除分歧和误解的最好手段，所以一定要让这些规则足够得清晰易懂。比如，在我们内部就有一个“3-2-1”原则：

3：创建任务三要素

有详细的问题说明和描述

有清晰的验收标准

有具体的经办人和迭代排期

2：处理任务两要素

在开发中，代码变更要关联 Jira 任务号

在开发完成后，要添加 Jira 注释，说明改动内容和影响范围

1：解决任务一要素

问题报告人负责任务验收关闭

当然，团队规则远不止这几条。你要打造自己团队内部的规则，并且反复地强调规则，帮助大家养成习惯。这样一来，你会发现，研发效率提升和自组织团队都会慢慢成为现实。

除此之外，你也不要高估人的主动性，期望每个人都能自觉地按照规则执行。所以，定期和及时的提醒就非常必要。比如，每天增加定时邮件通知，告诉大家有哪些需求需要验收，有哪些可以上线发布，尽量让每个人都明白应该去哪里获取最新的信息。

另外，每次开周会时，都要强调规则的执行情况，甚至每天的站会也要按需沟通。只有保持短促、高频的沟通，才能产生理想的效果。

产品运营策略

关于产品运营策略，“酒香不怕巷子深”的理念已经有些过时了。想要一个产品获得成功，团队不仅要做得好，还要善于运营和宣传，而这又是技术团队的一大软肋。

开发团队大多只知道如何实现功能，却不知道应该怎么做产品运营。往往也正因为如此，团队很难获取用户的真实反馈，甚至开发了很多天才的功能，用户都不知道。产品开发变成了“自嗨”，这肯定不符合产品设计的初衷。

考虑到这些，我们在平台运营的时候，也采取了一些手段。我想提醒你的是，很多事情其实没有没有多难，关键就看有没有想，有没有坚持做。

比如，你可以建立内部用户沟通群，在产品初期尽量选择一些活跃的种子用户来试用。那些特别感兴趣、愿意尝试新事物、不断给你提建议的都是超级用户。这些用户未来都是各个团队中的“星星之火”，在项目初期，你一定要识别出这些用户。

另外，每一次上线都发布一个 release notes，并通过邮件和内部沟通群的方式通知全员，一方面可以宣传新功能，另一方面，也是很重要的一方面，就是保持存在感的刷新。你要让用户知道这个产品是在高速迭代的过程中的，而且每次都有不一样的新东西，总有一样会吸引到他们，或者让他们主动提出自己的问题。

在用户群里面，注意要及时响应用户的问题。你可以在团队内部建立 OnCall 机制，每周团队成员轮值解决一线用户的问题，既可以保证问题的及时收敛，也能让远离用户的开发真真切切地听到用户的声音。这样的话，在需求规划会和迭代回顾会的时候，开发就会更多地主动参与讨论。

以上这些都是比较常规的手段，在我们的产品运营中，还有两个方法特别有效，我也推荐给你。

平台运营就跟打广告是一样的，越是在人流最大、关注度最高的地方打广告，效果也就越好。每个公司一般都有类似的首页，比如公司内部的技术首页、技术论坛、日常办公的 OA 系统等等，这些地方其实都会有宣传的渠道和入口。你要做的就是找到这个入口，并联系上负责这个渠道的人员。我们的产品就一度实现了热门站点的霸屏，宣传效果非常明显，用户量直线上升。

另一个方法有些取巧，但对于技术团队来说，也非常适用，那就是通过技术分享的渠道来宣传产品。

相信每个团队都会有定期的技术分享渠道，或者是技术公众号等，你可以把平台的核心技术点和设计思想提炼出来，拟定一个分享话题，并在内部最大范围的技术分享渠道中进行分享。

很多时候，单纯地宣传一个产品，很多人是“不感冒”的。但是，如果你在讲一些新技术，并结合产品化落地的事情，对技术人员的吸引力就会大很多。所以，换个思路做运营，也是提升产品知名度的好方法。我把我之前总结的产品运营渠道和手段汇总成了一幅脑图，也分享给你。

团队文化建设

最后，我想再跟你简单聊聊团队文化建设的事情。毕竟，无论什么样的工具、流程、目标，最终都是依靠人来完成的。如果忽略对人的关注，就等同于本末倒置，不是一个成熟的团队管理者应该做的事情。我给你分享我的两点感受。

1. 让专业的人做专业的事情

很多时候，千万不要小看专业度这个事情。任何一个组织内部的职能都需要专业能力的支撑，这些专业能力都是量变引发的质变。

我举个最简单的例子，你还记得我在前面提到的 0.2 版本的原型草稿吗？实际上，到了 0.3 版本，引用前端工程师话来说，“原型做得比系统还漂亮”。这是为什么呢？难道是我这个“半吊子”产品经理突然开窍了吗？

显然不是。其实答案很简单，就是我去找了专业产品经理做外援，让他帮我改了两天的原型图。对于专业的人来说，这些事情再简单不过了。

找专业的人来做这些事情，不仅可以帮助你快速地跨越鸿沟，也能留下很多现成的经验，供你以后使用，这绝对不是一个人埋头苦干可以做得到的。

不仅是产品方面，技术领域也是一样的。我们要勇于承认自己的无知，善于向别人求助，否则到头来，损失的时间和机会都是自己买单，得不偿失。

2. 抓大放小，适当地忽略细节

在协作的过程中，团队总会在一些细节上产生冲突。如果任由团队成员在细节上争论不休，久而久之，就会影响团队之间的信任感。这个时候，就需要引导团队将注意力集中在大的方向上，适当地暂缓细节讨论，以保证团队的协作效率。

比如，一个业务逻辑是放在前端处理，还是放在后端处理，结果并没有太大区别，说白了，就是放在哪儿都行。但是，前端同学会坚持认为，逻辑处理都应该由后端来解决，以降低前端和业务的耦合性，这样说也没有错。可是，后端同学也会有自己的想法，比如针对前端拦截器的处理机制，后端到底要不要配合着返回前端要求的返回码，而不是直接抛出 http 原始的返回码呢？

类似的这些问题，没有谁对谁错之分，但是真要是纠结起来，也不是一两句话就能说清楚的。

这个时候，就需要有人拍板，选择一条更加符合常规的方式推进，并预留出后续的讨论空间。甚至，为了促进多地合作，自己人这边要适当地牺牲一些，以此来换取合作的顺利推进。这样一来，你会发现，有些不可调和的事情，在项目不断成功、人员不断磨合的过程中，也就不是个事情了。

总结

在这一讲中，关于如何开发产品，可以说，我是把自己在过去几个项目经历中的总结倾囊相授了。

其实，就像我在讲“DevOps 工程师需要的技能”中提到的那样，软实力（比如沟通协作、同理心、持续改进等）对促进产品快速迭代开发演进有着重大的作用。作为非专业产品经理，我也在慢慢地积累自己的产品心经，有机会再给你好好聊聊。

你可能还在想，最终千人的目标是否实现了呢？我想说的是，有些时候，真实生活比故事还要精彩。

就在预订目标的倒数第二天，平台用户只有 997 个。当时，我跟同事吐槽这个数字，他们说要不要拉几个用户进来，我说：“算了吧，随它去吧。“结果你猜怎样？在当天周五下班的时候，我又去平台上看了一眼，不多不少刚好 1000 个注册用户。当时我的第一感觉就是，要相信，当我们把自己的全身心和热情都灌注在一个产品的开发过程中时，美好的事情会自然而然地发生。

思考题

你对这一讲的哪部分内容印象最深刻呢？你有什么其他有助于产品快速研发落地的观点吗？

欢迎在留言区写下你的思考和答案，我们一起讨论，共同学习进步。如果你觉得这篇文章对你有所帮助，也欢迎你把文章分享给你的朋友。

27 | 巨人的肩膀：那些你不能忽视的开源工具

你好，我是石雪峰。

自研工具平台对公司来说是一件高成本和高投入的事情，对于技术人员的要求也非常高。很少有公司能够像 BAT 一样投入近百人的团队来开发内部系统工具，毕竟，如果没有这么大规模的团队，平台产生的收益也比较有限。

另外，也很少有公司像一些行业头部公司一样，会直接投入大量资金购买成熟的商业化工具或者通过乙方合作的方式联合共建。

这些方法的长期投入都比较大，不太适用于中小型企业。那么，有其他可以低成本、快速见效的解决方案吗？

实际上，现在的开源工具已经非常成熟了，只要稍加熟悉，就能快速地基于开源工具搭建一整套研发交付工具链平台。

几年前，我跟几个朋友利用业余时间就搭建了这样一套开源的端到端流水线解决方案。我依稀记得，这个解决方案架构图是在北京开往上海的高铁上完成的。目前，这个方案在行业内广为流传，成为了很多公司搭建自己内部工具链平台的参考资料。这个系统的架构图如下：

今天，我会基于这个解决方案，给你介绍几个主要阶段的工具的使用技巧，希望可以手把手地帮助你快速搭建一套完整的持续交付平台。

对于持续交付工具链体系来说，工具的连通性是核心要素，所以我不会花太多时间介绍工具应该如何搭建，毕竟这类资料有很多，或者，你参考一下官网的搭建文档就可以了。尤其是现在很多工具都提供了容器化的部署方式，进一步简化了自身工具的建设成本。

需求管理 - Jira

在 Jira 官网上的醒目位置，写着一句话：敏捷开发工具的第一选择。在我看来，Atlassian 公司的确有这个底气，因为 Jira 确实足够优秀，跟 Confluence 的组合几乎已经成为了很多企业的标配。这也是为什么我没有选择开源工具 Redmine 或者其他诸如 Teambition 等的 SaaS 化服务。

当然，近些年来，各大厂商也在积极地对外输出研发工具能力，以腾讯的 TAPD 为代表的敏捷协同开发工具，就使用得非常广泛。但是，其实产品的思路都大同小异，搞定了 Jira，其他工具基本也就不在话下了。

作为敏捷协同工具，Jira 新建工程可以选择团队的研发模式是基于 Scrum，还是看板方法，你可以按需选择。在专栏的第 8 讲和第 9 讲中，我给你介绍了精益看板，你完全可以在 Jira 中定制自己团队的可视化看板。

看板的配置过程并不复杂，我把它整理成了文档，你可以点击网盘链接获取，提取码是 mrtd。需要提醒你的一点是：别忘了添加 WIP 在制品约束，别让你的精益看板变成了可视化看板。

需求作为一切开发工作的起点，是贯穿整个研发工作的重要抓手。对于 Jira 来说，重点是要实现跟版本控制系统和开发者工具的打通。接下来，我们分别来看下应该如何实现。

如果你也在使用特性分支开发模式，你应该知道，一个特性就对应到一个 Jira 中的任务。通过任务来创建特性分支，并且将所有分支上的提交绑定到具体任务上，从而建立清晰的特性代码关联。我给你推荐两种实现方式。

第一种方式是基于 Jira 提供的原生插件，比如 Git Integration for Jira。这个插件配置起来非常简单，你只需要添加版本控制系统的地址和认证方式即可。然后，你就可以在 Jira 上进行查看提交信息、对比差异、创建分支和 MR 等操作。但是这个插件属于收费版本，你可以免费使用 30 天，到期更新即可。

第二种方式，就是使用 Jira 和 GitLab 的 Webhook 进行打通。

首先，你要在 GitLab 项目的“设置 - 集成”中找到 Jira 选项，按下图添加相应配置即可。配置完成之后，你只需要在提交注释中添加一个 Jira 的任务 ID，就可以实现 Jira 任务和代码提交的关联，这些关联体现在 Jira 任务的 Issue links 部分。

另外，你也可以实现 Jira 任务的状态自动流转操作，无需手动移动任务卡片。我给你提供一份 配置说明 ，你可以参考一下。

不过，如果只是这样的话，还不能实现根据 Jira 任务来自动创建分支，所以接下来，还要进行 Jira 的 Webhook 配置。在 Jira 的系统管理界面中，你可以找到“高级设置 - Webhook”选项，添加 Webhook 后，可以绑定各种系统提供的事件，比如创建任务、更新任务等，这基本可以满足绝大多数场景的需求。

假设我们的系统在创建 Jira 任务的时候，要自动在 GitLab 中基于主线创建一条分支，那么你可以将 GitLab 提供的创建分支 API 写在 Jira 触发的 Webhook 地址中。参考样例如下：

https : // 这里替换成你的 GitLab 服务地址 /repository/branches?branch=${issue.key}&ref=master&private_token=[这里替换成你的账号 Token]

到这里，Jira 和 GitLab 的打通就完成了。我们来总结下已经实现的功能：

GitLab 每次代码变更状态都会同步到 Jira 任务中，并且实现了 Jira 任务和代码的自动关联（Issue links）；

可以在 MR 中增加关键字 Fixes/Resolves/Closes Jira 任务号，实现 Jira 的自动状态流转；

每次在 Jira 中创建任务时，都会自动创建特性分支。

关于 Jira 和开发者工具的打通，我把操作步骤也分享给你。你可以点击网盘链接获取，提取码是 kf3t。现在很多工具平台的建设都是以服务开发者为导向的，所以距离开发者最近的 IDE 工具就成了新的效率提升阵地，包括云 IDE、IDE 插件等，都是为了方便开发者可以在 IDE 里面完成所有的日常任务，对于管理分支和 Jira 任务，自然也不在话下。

代码管理 - GitLab

这个示例项目中的开发流程是怎样的呢？我们一起来看下。

第 1 步：在需求管理平台创建任务，这个任务一般都是可以交付的特性。你还记得吗？通过前面的步骤，我们已经实现了自动创建特性分支。

第 2 步：开发者在特性分支上进行开发和本地自测，在开发完成后，再将代码推送到特性分支，并触发提交阶段的流水线。这条流水线主要用于快速验证提交代码的基本质量。

第 3 步：当提交阶段流水线通过之后，开发者创建合并请求（Merge Request），申请将特性分支合并到主干代码中。

第 4 步：代码评审者对合并请求进行 Review，发现问题的话，就在合并请求中指出来，最终接受合并请求，并将特性代码合入主干。

第 5 步：代码合入主干后，立即触发集成阶段流水线。这个阶段的检查任务更加丰富，测试人员可以手动完成测试环境部署，并验证新功能。

第 6 步：特性经历了测试环境、预发布环境，并通过部署流水线最终部署到生产环境中。

在专栏的第 12 讲中，我提到过，持续集成的理念是通过尽早和及时的代码集成，从而建立代码质量的快速反馈环。所以，版本控制系统和持续集成系统也需要双向打通。

这里的双向打通是指版本控制系统可以触发持续集成系统，持续集成的结果也需要返回给版本控制系统。

接下来，我们看看具体怎么实现。

代码提交触发持续集成

首先，你需要在 Jenkins 中安装GitLab 插件。这个插件提供了很多GitLab 环境变量，用于获取 GitLab 的信息，比如，gitlabSourceBranch 这个参数就非常有用，它可以提取本次触发的 Webhook 的分支信息。毕竟，这个信息只有 GitLab 知道。只有同步给 Jenkins，才能拉取正确的分支代码执行持续集成过程。

当 GitLab 监听到代码变更的事件后，会自动调用这个插件提供的 Webhook 地址，并实现解析 Webhook 数据和触发 Jenkins 任务的功能。

其实，我们在自研流水线平台的时候，也可以参考这个思路：通过提供 Webhook 接口并注册到 GitLab 中，从而实现代码变更事件的监听和自动任务执行。

当 GitLab 插件安装完成后，你可以在 Jenkins 任务的 Build Triggers 中发现一个新的选项，勾选这个选项，就可以激活 GitLab 自动触发配置。其中比较重要的两个信息，我在下面的图片中用红色方块圈出来了。

上面的链接就是 Webhook 地址，每个 Jenkins 任务都不相同；

下面的是这个 Webhook 对应的认证 Token。

你需要把这两个信息一起添加到 GitLab 的集成配置中。打开 GitLab 仓库的“设置 - 集成”选项，可以看到 GitLab 的 Webhook 配置页面，将 Jenkins 插件生成的地址和 Token 信息复制到配置选项中，并勾选对应的触发选项。

GitLab 默认提供了多种触发选项，在下面的截图中，只勾选了 Push 事件，也就是只有监听到 Git Push 动作的时候, 才会触发 Webhook。当然，你可以配置监听的分支信息，只针对特性分支执行关联的 Jenkins 任务。在 GitLab 中配置完成后，可以看到新添加的 Webhook 信息，点击“测试”验证是否可以正常执行，如果一切正常，则会提示“200-OK”。

持续集成更新代码状态

打开 Jenkins 的系统管理页面，找到 GitLab 配置，添加 GitLab 服务器的地址和认证方式。注意，这里的 Credentials 要选择 GitLab API Token 类型，对应的 Token 可以在 GitLab 的“用户 - 设置 - Access Tokens”中生成。由于 Token 的特殊性，只有在生成的时候可见，以后就再也看不到了。所以，在生成 Token 以后，你需要妥善地保存这个信息。

那么，配置完成后，要如何更新 GitLab 的提交状态呢？这就需要用到插件提供的更新构建结果命令了。

对于自由风格类型的 Jenkins 任务，你可以添加构建后处理步骤 - Publish build status to GitLab，它会自动将排队的任务更新为“Pending”，运行的任务更新为“Running”，完成的任务根据结果更新为“Success”或者是“Failed”。

对于使用流水线的任务来说，官方也提供了相应的示例代码，你只需要对照着写在 Jenkinsfile 里面就可以了。

updateGitlabCommitStatus name: 'build', state: 'success'

这样一来，每次提交代码触发的流水线结果也会显示在 GitLab 的提交状态中，可以在查看合并请求时作为参考。有的公司更加直接：如果流水线的状态不是成功状态，那么就会自动关闭提交的合并请求。其实无论采用哪种方式，初衷都是希望开发者在第一时间修复持续集成的问题。

我们再阶段性地总结一下已经实现的功能：

每次 GitLab 上的代码提交都可以通过 Webhook 触发对应的 Jenkins 任务。具体触发哪个任务，取决于你将哪个 Jenkins 任务的地址添加到了 GitLab 的 Webhook 配置中；

每次 Jenkins 任务执行完毕后，会将执行结果写到 GitLab 的提交记录中。你可以查看执行状态，决定是否接受合并请求。

代码质量 - SonarQube

SonarQube 作为一个常见的开源代码质量平台，可以用来实现静态代码扫描，发现代码中的缺陷和漏洞，还提供了比较基础的安全检查能力。除此之外，它还能收集单元测试的覆盖率、代码重复率等。

对于刚开始关注代码质量和技术债务的公司来说，是一个比较容易上手的选择。关于技术债务，在专栏的第 15 讲中有深入讲解，如果你不记得了，别忘记回去复习一下。

那么，代码质量检查这类频繁执行的例行工作，也比较适合自动化完成，最佳途径就是集成到流水线中，也就是需要跟 Jenkins 进行打通。我稍微介绍一下执行的逻辑，希望可以帮你更好地理解这个配置的过程。

SonarQube 平台实际包含两个部分：

一个是平台端，用于收集和展示代码质量数据，这也是我们比较常用的功能。

另外一个是客户端，也就是 SonarQube 的 Scanner 工具。这个工具是在客户端本地执行的，也就是跟代码在一个环境中，用于真正地执行分析、收集和上报数据。这个工具之所以不是特别引人注意，是因为在 Jenkins 中，后台配置了这个工具，如果发现节点上没有找到工具，它就会自动下载。你可以在 Jenkins 的全局工具配置中找到它。

了解了代码质量扫描的执行逻辑之后，我们就可以知道，对于 SonarQube 和 Jenkins 的集成，只需要单向进行即可。这也就是说，只要保证 Jenkins 的 Scanner 工具采集到的数据可以正确地上报到 SonarQube 平台端即可。

这个配置也非常简单，你只需要在 Jenkins 的全局设置中添加 SonarQube 的平台地址就行了。注意勾选第一个选项，保证 SonarQube 服务器的配置信息可以自动注入流水线的环境变量中。

在执行 Jenkins 任务的时候，同样可以针对自由风格的任务和流水线类型的任务，添加不同的上报方式。关于具体的内容，你可以参考 SonarQube 的官方网站，这里就不赘述了。

到此为止，我们已经实现了 GitLab、Jenkins 和 SonarQube 的打通。我给你分享一幅系统关系示意图，希望可以帮助你更好地了解系统打通的含义和实现过程。

环境管理 - Kubernetes

最后，我们再来看看环境管理部分。作为云原生时代的操作系统，Kubernetes 已经成为了云时代容器编排的事实标准。对于 DevOps 工程师来说，Kubernetes 属于必学必会的技能，这个趋势已经非常明显了。

在示例项目中，我们同样用到了 Kubernetes 作为基础环境，所有 Jenkins 任务的环境都通过 Kubernetes 来动态初始化生成。

这样做的好处非常多。一方面，可以实现环境的标准化。所有环境配置都是以代码的形式写在 Dockerfile 中的，实现了环境的统一可控。另一方面，环境的资源利用率大大提升，不再依托于宿主机自身的环境配置和资源大小，你只需要告诉 Kubernetes 需要多少资源，它就会帮助你找到合适的物理节点运行容器。资源的调度和分配统一通过 Kubernetes 完成，这就进一步提升了资源的有效利用率。想要初始化一套完整的环境，对于中小系统来说，是分分钟就可以完成的事情。关于这一点，我会在讲“云原生时代应用的平台建设”时跟你探讨。

那么，想要实现动态初始化环境，需要打通 Jenkins 和 Kubernetes。好在 Jenkins 已经提供了官方的Kubernetes 插件来完成这个功能。你可以在 Jenkins 系统配置中添加云 - Kubernetes，然后再参考下图进行配置。

需要注意的是，必须正确配置 Jenkins 的地址（系统配置 - Jenkins Location），否则会导致新建容器无法连接 Jenkins。

生成动态节点时，需要使用到 JNLP 协议，我推荐你使用 Jenkins 官方提供的镜像。

JNLP 协议的全称是 Java Network Launch Protocol，是一种通用的远程连接 Java 应用的协议方式。典型的使用场景就是在构建节点（也就是习惯上的 Slave 节点）上发起向 Master 节点的连接请求，将构建节点主动挂载到 Jenkins Master 上，供 Master 调度使用。区别于使用 SSH 长连接的方式，这种动态连接的协议特别适合于 Kubernetes 这类的动态节点。镜像配置如下图所示：

在配置动态节点的时候，有几个要点你需要特别关注下。

静态目录挂载。由于每次生成一个全新的容器环境，所以就需要将代码缓存（比如.git 目录）、依赖缓存（.m2, .gradle, .npm）以及外部工具等静态数据通过 volume 的方式挂载到容器中，以免每次重新下载时影响执行时间。

如果你的 Jenkins 也是在 Kubernetes 中运行的，注意配置 Jenkins 的 JNLP 端口号（使用环境变量：JENKINS_SLAVE_AGENT_PORT）。否则，在系统中配置的端口号是不会生效的。

由于每次初始化容器有一定的时间损耗，所以你可以配置一个等待时长。这样一来，在任务运行结束后，环境还会保存一段时间。如果这个时候有新任务运行，就可以直接复用已有的容器环境，而无需重新生成。

如果网络条件不好，可以适当地加大创建容器的超时时间，默认是 100 秒。如果在这个时间内无法完成容器创建，那么 Jenkins 就会自动杀掉创建过程并重新尝试。

如果一切顺利，动态 Kubernetes 环境就也可以使用了。这时，我们就可以完整地运行一条流水线了。在设计流水线的时候，你需要注意的是流水线的分层。具体的流水线步骤，我已经写在了系统架构图中。比如，提交阶段流水线需要完成拉取代码、编译打包、单元测试和代码质量分析四个步骤，对应的代码如下：

// pipeline 2.0 - Commit stage - front-end
pipeline {
    agent {
        // Kubernetes 节点的标签
        label 'pipeline-slave'

    }
    environment {
        // 镜像仓库地址
        HARBOR_HOST= '123.207.154.16'
        IMAGE_NAME = "front-end"
        REPO = 'front-end'
        HOST_CODE_DIR = "/home/jenkins-slave/workspace/${JOB_NAME}"
        GROUP = 'weaveworksdemos'
        COMMIT = "${currentBuild.id}"
        TAG = "${currentBuild.id}"
        TEST_ENV_NAME = 'test'
        STAGE_ENV_NAME = 'staging'
        PROD_ENV_NAME = 'prod'
        BUILD_USER = "${BUILD_USER_ID}"
        // 需要挂载到容器中的静态数据
        COMMON_VOLUME = ' -v /nfs/.m2:/root/.m2  -v /nfs/.sonar:/root/.sonar -v /nfs/.npm:/root/.npm '
    }
    stages {
        stage('Checkout') {
            steps {
                git branch: 'xxx', credentialsId: '707ff66e-1bac-4918-9cb7-fb9c0c3a0946', url: 'http://1.1.1.1/shixuefeng/front-end.git'
            }
        }
        stage('Prepare Test') {
            steps {
                sh '''
                docker build -t ${IMAGE_NAME} -f test/Dockerfile .
                docker run --rm -v ${HOST_CODE_DIR}:/usr/src/app ${IMAGE_NAME} /usr/local/bin/cnpm install
                '''
            }
        }
        stage('Code Quality') {
            parallel {
                stage('Unit Test') {
                    steps {
                        sh '''
                        docker run --rm -v ${HOST_CODE_DIR}:/usr/src/app ${IMAGE_NAME} /usr/local/bin/cnpm test
                        '''
                    }
                }
                stage('Static Scan') {
                    steps {
                        sh 'echo "sonar.exclusions=node_modules/**" >> sonar-project.properties'
                        script {
                            def scannerHome = tool 'SonarQubeScanner';
                            withSonarQubeEnv('DevOpsSonar') {
                                sh "${scannerHome}/bin/sonar-scanner"
                                updateGitlabCommitStatus name: 'build', state: 'success'
                            }
                        }
                    }
                }
            }
        }
    }
}

完整的流水线演示效果如下：

结合 Jenkins 自身的人工审批环节，可以实现多环境的自动和手动部署，构建一个真正的端到端持续交付流水线。

总结

在今天的课程中，我通过一个开源流水线的解决方案，给你介绍了如何建立一个开源工具为主的持续交付流水线平台。你应该也有感觉，对于 DevOps 来说，真正的难点不在于工具本身，而在于如何基于整个研发流程将工具串联打通，把它们结合在一起，发挥出最大的优势。这些理念对于自建平台来说也同样适用，你需要在实践中多加尝试，才能在应用过程中游刃有余。

思考题

关于这套开源流水线解决方案，你对整体的工具链、配置、设计思路还有什么疑问吗？在实施过程中，你遇到了哪些绕不过去的问题呢？

欢迎在留言区写下你的思考和答案，我们一起讨论，共同学习进步。如果你觉得这篇文章对你有所帮助，也欢迎你把文章分享给你的朋友。

28 | 迈向云端：云原生应用时代的平台思考

你好，我是石雪峰。

最近几年，相信你一定从各种场合听到过“云原生”这个词。比如云原生应用的12 要素、最近大火的现象级技术 Docker，以及容器编排技术 Kubernetes。其中，Kubernetes 背后的 CNCF，也就是云原生应用基金会，也成了各大企业争相加入的组织。

DevOps 似乎也一直跟云技术有着说不清的关系，比如容器、微服务、不可变基础设施以及服务网格、声明式 API 等都是 DevOps 技术领域中的常客。云原生应用似乎天生就和 DevOps 是绝配，自带高可用、易维护、高扩展、持续交付的光环。

那么，所谓的云原生，到底是什么意思呢？我引用一下来自于 CNCF 的官方定义：

Cloud native computing uses an open source software stack to deploy applications as microservices, packaging each part into its own container, and dynamically orchestrating those containers to optimize resource utilization.

云原生使用一种开源软件技术栈来部署微服务应用，将每个组件打包到它自己的容器中，并且通过动态编排来优化资源的利用率。

我总结一下这里面的关键字：开源软件、微服务应用、容器化部署和动态编排。那么，简单来说，云原生应用就是将微服务风格的架构应用，以容器化的方式部署在云平台上，典型的是以 Kubernetes 为核心的云平台，从而受益于云服务所带来的各种好处。

我在专栏中也反复强调过，容器技术和 Kubernetes 是划时代的技术，是每一个学习 DevOps 的工程师的必备技能。就像很多年前要人手一本《鸟哥的 Linux 私房菜》在学习 Linux 一样，Kubernetes 作为云时代的 Linux，同样值得你投入精力。

今天，我并不是要跟你讲 Kubernetes，我想通过一个项目，以及最近两年我的亲身经历，给你分享一下，云原生究竟会带给 DevOps 怎样的改变。这个项目就是 Jenkins X。

在 2018 年初，我分享过有关 Jenkins X 的文章，在短短几天的时间内，阅读量就过万了。这一方面体现了 Jenkins 在国内的巨大影响力，另外一方面，也凸显了 Jenkins 与这个时代的冲突和格格不入。为什么这么说呢？因为 Jenkins 作为一个 15 年的老系统，浑身上下充满了云原生的反模式 ，比如：

Jenkins 是一个 Java 单体应用，运行在 JVM 之上，和其他典型的 Java 应用并没有什么区别；

Jenkins 使用文件存储，以及各种加载模式、资源调度机制等，确保了它天生不支持高可用；

Jenkins 虽然提供了流水线，但是流水线依然是执行在主节点上，这就意味着随着任务越来越多，主节点消耗的资源也就越来越多，不仅难以扩展，还非常容易被随便一个不靠谱的任务搞挂掉。

举个最简单的例子，如果一个任务输出了 500MB 的日志，当你在 Jenkins 上点击查看全部日志的时候，那就保佑自己的服务器能挺过去吧。因为很多时候，服务器可能直接就死掉了。当然，我非常不建议你在生产环境做这个实验。

那么，如果想让 Jenkins 实现云原生化，要怎么做呢？有的同学可能会说：“把 Jenkins 放到容器中，然后丢给 Kubernetes 管理不就行了吗？”如果你也是这么想的，那就说明，无论是对 Kubernetes 还是云原生应用，你的理解还不够到位。我来给你列举下，如果要把 Jenkins 改造为一个真正的云原生应用，要解决哪些问题：

可插拔式的存储（典型的像是 S3、OSS）

外部制品管理

Credentials 管理

Configuration 管理

测试报告和覆盖率报告管理

日志管理

Jenkins Job

……

你看，我还只是列举了其中一部分，以云原生应用 12 要素的标准来说，要做的改造还有很多。

以日志为例，当前 Jenkins 的所有日志都是写在 Master 节点上的，如果想改造成云原生应用的方法，首先就是要把日志看作一种输出流。输出流不应该由应用管理，写在应用运行节点的本地，而是应该由专门的日志服务来负责收集、分析、整理和展示。比如 ElasticSearch、Fluent，或者是 AWS 的 CloudWatch Logs，都可以实现这个功能。

那么，Jenkins X 是怎么解决这个问题的呢？

我们来试想一个场景：当开发工程师想要开发一个云原生应用的时候，他需要做什么？

首先，他需要有一套可以运行的 Kubernetes 环境。考虑到各种不可抗力因素，这绝对不是一件简单的事情。尤其是在几年前，如果有人能够通过二进制的方式完成 Kubernetes 集群的搭建和部署，这一定是一件值得吹牛的事情。好在现在公司里面都有专人负责 Kubernetes 集群维护，各大公有云厂商也都提供了这方面的支持。

现在，我们继续回到工程师的视角。

当他接到一个需求后，他首先需要修改代码，然后把代码编译打包，在本地测试通过。接下来，他要将代码提交到版本控制系统，手动触发流水线任务，并等待执行完毕。如果碰巧这次调整了编译命令，他还要修改流水线配置文件。最后，经过千辛万苦，生成了一个镜像文件，并把镜像文件推送到镜像服务器上。这还没完，他还需要修改测试环境的 Kubernetes 资源配置，调用 kubectl 命令完成应用的更新并等待部署完成。如果对于这次修改，系统验证出了新的问题，那么不好意思，刚刚的这些步骤都需要重头来过。

你看，虽然云原生应用有这么多好处，但是大大提升了开发的复杂度。一个工程师必须要熟悉 Kubernetes、流水线、镜像、打包、部署等一系列的环节和新技术新工具，才有可能完成一次部署。如果这些操作都依赖于外部门或者其他人，那你就且等着吧。这么看来，这条路是走不下去的。

在云时代，一切皆服务。那么，在云原生应用时代，DevOps 或持续交付理应也是以一种服务的形式存在。就好比你在用电的时候，一定不会去考虑电厂是怎么运转的，电是怎么送到家里来的，你只要负责用就可以了。

那么，我们来看看 Jenkins X 是怎么一步步地把 Jenkins“干掉”的。其实，我希望你能记得，是不是 Jenkins X 本身并不重要，在这个过程中使用到的工具和技术，以及它们背后的设计理念，才是更重要的。

1. 自动化生成依赖的配置文件

对于一个云原生应用来说，除了源代码本身之外，还依赖于哪些配置文件呢？其中就包括：

Dockerfile：用于生成 Docker 镜像

Jenkinsfile：应用关联的流水线配置

Helm Chart：把应用打包并部署运行在 Kubernetes 上的资源文件

Skaffold：用于在 Kubernetes 中生成 Docker image 的工具

考虑到你可能不太熟悉这个 Skaffold 工具，我简单介绍一下。

实际上，如果想在 Kubernetes 环境中生成 Docker 镜像，你会发现，一般来说，这都依赖于 Docker 服务，也就是 Docker daemon。那么常见的做法无外乎 Docker-in-Docker 和 Docker-outside-Docker。

其中，Docker-in-Docker 就是在基础镜像中提供内建的 Docker daemon 和镜像生成环境，这依赖于官方镜像的支持。而 Docker-outside-Docker 比较好理解，就是将宿主机的 Docker daemon 挂载到 Docker 镜像里面。

有三种典型的实现方式：第一种是挂载节点的 Docker daemon，第二种就是使用云平台提供的外部服务，比如 Google Cloud Builder，第三种就是使用无需 Docker daemon 也能打包的方案，比如常见的 Kaniko。

而 Skaffold 想要解决的就是，你不需要再关心如何生成镜像、推送镜像和运行镜像，它会通通帮你搞定，依赖的就是 skaffold.yaml 文件。

这些文件如果让研发手动生成，那会让研发的门槛变得非常高。好在你可以通过 Draft 工具来自动化这些操作。Draft 是微软开源的一个工具，它包含两个部分。

源代码分析器。它可以自动扫描你的源代码，根据代码特征，识别出你所用到的代码类型，比如 JavaScript、Python 等。

build pack。简单来说，build pack 就是一种语言对应的模板。通过在模板中定义好预设的环境依赖配置文件，包括上面提到的 Dockerfile、Jenkinsfile 等，从而实现依赖项的自动生成和创建。当然，你也可以定义自己的 build pack，并作为模板在内部项目中使用。

很多时候，模板都是一种特别好的思路，它可以大大简化初始配置成本，提升环境和服务的标准化程度。对于流水线来说，也是如此，毕竟，不是很多人都是这方面的专家，只要能针对 90% 的场景提供一组或几组最佳实践的模板就足够了。

这样一来，无论是已经存在的代码，还是权限初始化的项目，研发都不需要操心如何实现代码打包、生成镜像，以及部署的过程。这也会大大节省研发的精力。毕竟，就像我刚刚提到的，不是每个人都是容器和构建方面的专家。

2. 自动化流水线过程

当应用初始化完成之后，流水线应该是开箱即用的状态。也就是说，比如项目采用的是特性分支加主干开发分支发布的策略，那么，build pack 中就预置了针对每条分支的流水线配置文件。这些文件定义了每条分支需要经过的检查过程。

那么，当研发提交代码的时候，对应的流水线就会被自动触发。对于研发来说，这一切都是无感知的。只有在必要的时候（比如出现了问题），系统才会通知研发查看错误信息。这就要求流水线的 Jenkinsfile 要自动生成，版本控制系统和 CI/CD 系统也需要自动打通。比如，Webhook 的注册和配置、MR 的评审条件、自动过滤的分支信息等等，都是需要自动化完成的。

这里所用到的技术主要有三点。

流水线即代码。毕竟，只有代码化的流水线配置才有可能自动化。

流水线的抽象和复用。以典型的 Jenkinsfile 为例，大多数操作应该提取到公共库，也就是 shared library 中，而不应该 hard code 在流水线配置文件里面，以提升抽象水平和能力复用。

流水线的条件判断。对于同一条流水线来说，根据不同的条件，可以实现不同的执行路径。

3. 自动化多环境部署

对于传统应用来说，尤其是对上下游依赖比较复杂的应用来说，环境管理是个老大难的问题。Kubernetes 的出现大大简化了这个过程。当然，前提是云原生应用部署在 Kubernetes 上时，所有依赖都是环境中的资源。

依靠 Kubernetes 强大的资源管理能力，能够动态初始化出来一套环境，是一种巨大的进步。

Jenkins X 默认就提供了预发环境和生产环境。不仅如此，对于每一次的代码提交所产生的 PR，Jenkins X 都会自动初始化一个预览环境出来，并自动完成应用在预览环境的部署。这样一来，每次代码评审的时候，都能够打开预览环境查看应用的功能是否就绪。通过借助用户视角来验收这些功能，也提升了最终交付的质量。

这里面所用到的技术，除了之前我在第 16 讲中给你介绍过的 GitOps，主要就是 Prow 工具。

你可以把 Prow 看作 ChatOps 的一种具体实现。实际上，它提供的是一种高度扩展的 Webhook 时间处理能力。比如，你可以通过对话的方式，输入 /approve 命令，Prow 接收到这个命令后，就会触发对应的 Webhook，并实现流水线的自动执行以及一系列的后台操作。

4. 使用云原生流水线

在今年年初，Jenkins X 进行了一次全面的升级，开始支持 Tekton 流水线。Tekton 的前身是 2018 年初创建的 KNative 项目，这是一个面向 Kubernetes 的 Serverless 解决方案。但随着这个项目边界的扩大，它渐渐地把整个交付流程的编排都纳入了进来，于是就成立了 Tekton 项目，用来提供 Kubernetes 原生的流水线能力。

Tekton 提供了最底层的能力，Jenkins X 提供了上层抽象，也就是通过一个 yaml 文件的形式来描述整个交付过程。我给你分享了一个流水线配置文件的例子：

agent:
  label: jenkins-maven
  container: maven
pipelines:
  pullRequest:
    build:
      steps:
      - sh: mvn versions:set -DnewVersion=$PREVIEW_VERSION
      - sh: mvn install
  release:
    setVersion:
      steps:
      - sh: echo \$(jx-release-version) > VERSION
        comment: so we can retrieve the version in later steps
      - sh: mvn versions:set -DnewVersion=\$(cat VERSION)
      - sh: jx step tag --version \$(cat VERSION)
    build:
      steps:
      - sh: mvn clean deploy

在这个例子中，你可以看到，流水线过程是通过 yaml 格式来描述的，而不是通过我们之前所熟悉的 groovy 格式。另外，在这个文件中，你基本上也看不到 Tekton 中的资源类型，比如 Task、TaskRun 等。

实际上，Jenkins X 基于 Jenkins 原有的流水线语法结构，重新定义了一套基于 yaml 格式的语法。你依然可以使用以前的命令在 yaml 中完成整个流水线的定义，但是，在后台，Jenkins X 会将这个文件转换成 Tekton 需要使用的 CRD 资源并触发 Kubernetes 执行。

说白了，用户看起来还是在使用 Jenkins，但实际上，流水线的执行引擎已经从原来的 JVM 变成了现在 Kubernetes。流水线的执行和调度由 Kubernetes 来完成，整个过程中每一步的环境都是动态初始化生成的容器，所有的数据都是通过外部存储来保存的。

经过这次升级，终于实现了真正意义上的平台云原生化改造。关于这个全新的 Jenkins 流水线语法定义，你可以参考下官方文档。

我再给你分享一幅 Serverless Jenkins 和 Tekton 的关系示意图，希望可以帮助你更好地理解背后的实现机制。

https://dzone.com/articles/move-toward-next-generation-pipelines

最终，我们希望达到的目的，就是不再有一个一直存在的 Jenkins Master 实例等待用户调用，而是一种被称为是“Ephemeral Jenkins”的机制，也就是一次性的 Jenkins，只有在需要的时候才会启动一个 Master 实例，用完了就关闭掉，从一种静态服务变成了一种转瞬即逝的动态服务，也就是看似不在、又无处不在的形式，以此来驱动云原生应用的 CI/CD 之旅。

讲到这里，我们回头再看看最开始的那个场景。对于享受了云原生流水线服务的工程师而言，他所需要关注的就只有把代码写好这一件事情，其他原本需要他操心的事情，都已经通过后台的自动化、模板化实现了。

即便是在本地开发调试，你也完全可以利用 Kubernetes 提供的环境管理能力，甚至在 IDE 里面，只要保存代码，就能完成从打包、镜像生成、推送、环境初始化和部署的完整过程。我相信，这也是云原生工具赋能研发的终极追求。

总结

最近这两年，经常有人问我，Jenkins 是不是过时了？类似 Argo、Drone 等更轻量化的解决方案是否更加适合云原生应用的发展？

其实，社区的开发者也在问自己这样的问题，而答案就是 Jenkins X 项目。这个项目整合了大量的开源工具和云原生解决方案，其中包括：

基于 Kubernetes 的云原生开发体验

自动化的 CI/CD 流程

多套预置的环境，并能够灵活初始化环境

使用 GitOps 在多环境之间进行部署晋级

云原生的流水线架构和面向用户的易用配置

可插接自定义的流水线执行引擎

我必须要承认，云原生带给平台的改变是巨大且深刻的。这两年，我一方面惊叹于社区的巨大活力和创新力，另一方面，我也深刻地意识到“未来已来”，这种变更的脚步越来越近。

在云原生时代，我们需要打造的也应该是一个自动化、服务化、高度扩展的平台。这也就是说，用于打造云原生应用的平台自身也应该具备云原生应用的特征，并通过平台最大化地赋能研发工程师，提升他们的生产力水平。

思考题

对于 DevOps 的落地推行来说，建设工具仅仅是完成了第一步，那么，如何让工具发挥真正的威力，并在团队中真正地进行推广落地呢？你有哪些建议呢？

欢迎在留言区写下你的思考和答案，我们一起讨论，共同学习进步。如果你觉得这篇文章对你有所帮助，也欢迎你把文章分享给你的朋友。

29 | 向前一步：万人规模企业的DevOps实战转型案例（上）

你好，我是石雪峰。

“向前一步”这个名字，来源于 Facebook 的首席运营官谢丽尔·桑德伯格的一本书《向前一步：女性，工作及领导意志》。她在书中鼓励女性在职场中向前一步，勇于面对挑战，追求自己的人生目标。

我之所以选择用这个名字作为案例的标题，是因为在企业中，DevOps 转型并不是一件容易的事情，我们也需要有勇气向前迈出一小步，去承担这个使命。哪怕只是改变了一个小问题，也是转型过程中不可忽视的力量源泉。

在专栏最后的案例环节，我会用两讲给你介绍下微软这些年的 DevOps 转型故事，以及我在国内企业中的实践总结和经验。

今天，我们先从管理实践和文化层面入手，来看看这家传统的软件巨头是如何在经历了移动互联网时代的迷失之后，在容器云和 AI 时代再一次独占鳌头的。

微软的 DevOps 转型并不是一个突然的决定，随着云服务的兴起，用户需求激增，对发布节奏的要求越来越高。这些通过需求的数量就能体现出来。2016 年的用户需求数量比过去 4 年的总量还要多，到了 2017 年，需求数量达到了 2016 年的 2 倍，这就要求团队能够以更快的速度完成交付。

要知道，如果你期望的优化水平是提升 10% 的交付能力，那在原有的组织架构、流程规则下做局部优化就有可能实现。但是，如果要达到 200% 的优化效果，就需要做出巨大的改变了。

建立面向交付的特性团队

微软之前的组织架构跟很多公司一样，也是按照职能划分的，比如分为项目管理团队、开发团队、测试团队和运维团队。每个团队都比较封闭，部门墙的问题非常严重，给团队内部的协作效率造成了很大的影响。

为了应对需求交付的压力，微软首先进行了一次组织架构调整，将开发团队和测试团队整合为工程团队。于是，测试的职能在团队中消失了，转而变成了面向开发的开发工程师和面向测试的开发工程师，他们和产品管理团队一起完成项目的敏捷推进。在敏捷的理念中，测试活动应该内嵌于开发环节之中，通过把两个部门整合起来，就完成了测试注入研发的工作。

虽然开发和测试团队融合到了一起，但是交付工作依然依赖于独立的运维团队来完成，这就造成了一个问题：即便开发效率再高，如果运维能力跟不上，那也是没有意义的。

于是，微软开启了第二次组织变革，这一次的核心是构建特性交付团队，并赋予团队自治的能力。

所谓的特性交付团队，就是我们常说的“全功能团队”，实际上，这就是把横向的按照职能划分的组织变成垂直跨职能的组织。这个团队中包含了要完成功能交付的所有角色（比如产品、开发、测试和运维），可以闭环地完成整个交付工作。

在这个过程中，微软引入了一种叫作自组织团队的形式。与传统的管理层自上而下安排组织的方式不同的是，员工可以自由地选择想要加入的特性团队。这种新的自由组队的方式为每个人都提供了学习新知识的机会。

你可能觉得，这么搞的话，组织不是乱掉了？高手都希望跟高手在一起，那剩下的同学怎么办呢？其实，我在国内的一家公司也见过类似的玩法，他们解决这个问题的核心方法就是“传帮带”模式。

比如，一个职能依赖某种特殊技能，但这种技能在团队内部非常稀缺，无论拥有这种特殊技能的这名成员去到哪个小队，剩下的组都会出问题。所以，这家公司就强制采用“老带新”的模式，也就是师傅对新人进行集中培训，给新人快速赋能。而且，这种“师徒关系”会长期存在，如果新人遇到什么问题，都可以请教师傅。当然，对于新人来说，也会有相应的考查机制。这种模式就有助于公司达成内部成员互相学习的目标。

根据数据统计，虽然只有不到 20% 的员工选择了岗位变化，但是这种方式却给 100% 的员工提供了选择的可能性。对于一家官僚政治出名的公司来说，这就可以大大地调动员工的积极性。

实际上，特性交付团队还有几个显著的特征：

拥有团队独立的办公空间，大家都坐在一起，在沟通时基本可以靠“吼”；

一般由 10～12 个团队成员组成；

具有明确的工作目标和职责；

为了保证稳定性，一旦组队成功，未来的 12～18 个月不再改变；

自己管控特性向生产环境部署；

团队自治。

无独有偶，国内某大型公司在推进 DevOps 转型的初期，也做了类似的事情。为了加速研发和运维的融合，它们将一个大的应用运维团队拆分到了各个业务线里面。

不仅如此，研发开始向全栈转型，承接运维工作，而运维自身的工作释放出去后，就要求团队进行能力升级。运维团队需要具备研发能力，来不断地开发和优化运维工具，以降低研发、运维的成本。

这个过程说起来轻松，但实际在做的时候，就需要非常强的组织执行力，甚至还需要高层背书，自上而下地贯彻这样的要求。转型的过程对于每个人来说都是很痛苦的，但也只有经过这样剧烈的变革，才让 DevOps 转型成为了现实，而不仅仅只是说说而已，或者只是在几个小部门之间搞来搞去。

我经常说一句话：“想在不改变流程的前提下，实现企业的 DevOps 转型是不现实的。”至于团队的组织架构是否要调整，还是由交付效率来决定的。

转型初期的引入工具和推广阶段对组织的冲击力没有那么大，但是，当转型到达了“深水区”之后，组织的变革就成了一个非常现实的问题。

根据“康威定律”，一个团队交付的系统结构和他们的组织结构是相同的。其实换个角度来说，软件交付的流程也是跟当前的组织结构保持一致的。只要有一个独立的测试团队，就总会有一个独立的测试阶段。而正是因为这样的一个个阶段，才带来了内部协作的部门墙和效率瓶颈，而这都是 DevOps 转型需要考虑的事情。

自组织敏捷团队

回到案例部分，为了促进特性交付团队的自治，微软在敏捷开发计划方面也进行了一定的调整。

首先，按照不同的维度，他们分为四种计划。

迭代维度：设定为 3 周一个迭代；

计划维度：包含了 3 个迭代；

Season 维度：6 个月包含了两个计划周期；

Scenario 维度：长达 18 个月的远景图。

其中，管理层负责规划长期目标和全景图，也就是回答“我们要去哪里”的问题；而中短期目标，也就是迭代和计划，由自组织团队自行决定，这回答的就是“我们如何去到那里”的问题。

交付节奏按照迭代来进行，每 3 周的迭代会有一部分价值产出。随着迭代的不断推进，再逐步更新、优化计划目标，并反馈给长期规划，进行互动和调整。也就是说，6～18 个月的长期计划并不是一成不变的，团队会基于每个迭代和计划的交付增量以及用户的反馈进行调整，建立起一种“计划 - 交付 - 学习”的闭环路径，不断地校准产品目标和整体方向，保证长期规划的有效性，从而规避了原本瀑布模式下的在项目初期决定未来开发路径的潜在问题。

毕竟，在这个快速变化的时代，谁也无法保证你的计划是一成不变、永远有效的。

现在，特性交付团队的迭代和计划是由自己来决定了，但是你别忘了，每个成功的项目都需要成百上千人的协作。那么，如何保证团队目标的一致性和互相的配合度呢？

微软引入了三种实践方法，分别是迭代邮件、团队交流、体验评审。

1. 迭代邮件

在每个迭代的开始和结束时，团队都会发出迭代计划和状态邮件。在邮件中，除了明确本次迭代的特性完成情况以及下个迭代的交付计划之外，为了帮助其他团队成员更好地了解这个迭代的功能，他们还将这些功能录制成视频附在邮件里。不仅如此，待办事项的列表和看板状态也都以链接的形式被附在了邮件中。

2. 团队交流

在每次迭代完成的时候，团队成员都要问自己三个问题：

下一步的待办事项中包含哪些内容？

有哪些技术债务的累积和非功能特性？

有哪些遗留问题？

团队中的每个成员都要亲自完成这项任务，这不仅是为了减少信息传递的损失，更重要的是建立一种仪式感，帮助大家更加理性地安排迭代计划。毕竟，一旦把任务安排好了，就要按时完成。

3. 体验评审

在分析需求之初，采用用户故事的形式，站在用户的角度，以场景化的方式来描述用户所处的现状，以及这个特性想要解决的问题。那么，不同团队的成员就可以站在用户的视角来实现这个功能。

特别有意思的是，微软在管理特性的时候，会尽量保持对原始用户需求的关联。他们会在特性旁边附上原始的用户需求。

很多时候，开发要处理的任务都是被产品人员翻译过的用户需求，而并非原始的用户需求，以至于在开发的时候，我们并不知道要解决的核心问题是什么。通过关联原始用户需求，每个人都能在开发、测试、交付的过程中，站在用户的视角来重新审视一下，我们交付的功能到底是不是用户想要的。

这些环节的变化带来了一系列积极的影响。

首先，团队成员的积极性大大提高。因为他们觉得自己是用户体验的首要负责人，他们有责任自己修复并解决用户的实际问题。

其次，团队无需再等待领导的规划。在符合整体项目计划的前提下，他们可以自行制定计划。

最后，计划的更新是由持续学习来驱动的。比如，团队会给用户经常使用的功能添加埋点，观察用户使用的数据情况，定期关注和解决用户反馈信息。

持续的增量交付和不断的反馈建议，也是现在保证产品需求有效性的最佳手段。毕竟，业务敏捷是 DevOps 的源头，如果业务自己对需求都没有明确的衡量方法，那么即便拥有了最强的持续交付能力，也是跟“蒙眼狂奔”一样。所以，想要推进 DevOps，敏捷开发实践和需求价值分析都是必不可少的要素。

在微软，为了促进有效反馈，他们的度量体系也很好，非常值得一说。对于微软来说，获取用户的真实行为数据至关重要。他们在建设指标体系的时候，出发点大多落脚在考量哪些指标对业务衡量有直接作用上，而不是衡量团队的产出以及个人的产出。

他们采用的指标包括以下几个方面：

使用维度：用户增长、用户满意度、特性交付情况等；

效率维度：构建时长、自测时长、部署时长等。

在线站点健康度：错误定位时长、用户影响时长、线上问题的遗留时长等。

但是，某些国内流行的指标却并没有被纳入绩效考核，比如完成时长、代码行数、缺陷数量等。

你可能会说，这也没什么特殊的啊，但是，你要知道，微软对于用户的关注不止如此。

我给你举个具体的例子。一般情况下，我们在度量系统可用性的时候，都是面向系统整体的，比如保证整体可用性达到 4 个 9，也就是在 99.99% 的情况下是可用的。但是，微软认为，系统可用性应该更进一步，要以账号的维度来进行度量和统计。

当我们站在系统整体的视角时，很多个人用户的行为就被整体数据掩盖了，也就是我们常说的“被平均”了。但是，如果站在账号的视角，也就是每一个用户的视角来看待这个问题的时候，我们就会发现，用户是真真切切地遇到了一些问题。

比如，某一个账号下服务不可用的情况出现频率比较高，那么，与其等着用户上网吐槽，倒不如提前跟用户取得联系，主动帮助他们解决问题。在联系用户的邮件中，不仅要清楚地描述团队观察到的客观情况，还要提供建议的解决方案。如果用户无法自主完成定位和修复，还可以通过邮件中的联系方式和团队取得联系，寻求进一步的帮助。

微软对用户的关注不仅体现在系统可用性的度量方面，在特性开关方面也是如此。

特性开关是一种比较常见的在运行时控制特性是否对外可见的技术手段。在微软的产品中，也大量地使用到了特性开关的技术，但他们的特性开关可以细化到用户级别，也就是可以将用户添加到或者移出列表中，从而控制每一个用户的可见特性。

这样一来，如果某些新特性影响了特定用户的使用，就可以通过这种方式处理，无需部署，直接将特性下线。这不仅有助于问题的快速解决，还提供了一种更加精细化的实验机制。与灰度发布相比，基于特性的发布也更加灵活。

团队转型从中型团队入手

在转型团队的选择方面，微软的经历带给我们的启示是，尽量避免从大型团队开始入手。

在 DevOps 转型的过程中，常见的思维方式是，先把企业内部最核心和最大的团队搞定。只要把最复杂的部分搞定了，其他中小团队的需求也就都可以满足了，他们会自然而然地跟上转型的节奏。

但是事实上，这些大团队往往都有一些独特的流程以及特殊的需求，对系统工具和流程的定制化程度较高，实现起来也最复杂，甚至对他们来说，转型工作的优先级并不是最高的，总会因为这样那样的需求导致转型工作一拖再拖。这对于转型工作来说，并不是一件好事。

所以，微软调整了他们的策略，采用了“middle-out”的方法，也就是专注于中型团队（40 到 100 人）。这些团队由于资源不像大团队那样充足，对外有充分的需求。而且，这种规模的团队可以快速地评估现状，收集团队的必要信息，而不是猜测他们到底需要什么。

通过持续细小的改进，帮助这样的团队做得更好，内部的传播让更多的团队主动联系他们并寻求帮助，从而建立了一个有效的持续改进循环。

总结

今天，我给你介绍了微软 DevOps 转型的上半部分内容。我们来简单总结一下。

为了满足快速交付的需求，他们打破组织的原有架构，建立了面向特性交付的跨职能组织；

通过团队自治，他们将计划分为短期目标和长期目标，短期目标（包括迭代和计划）都由特性团队来自主决定；

在度量方面，他们更加关注业务指标的表现。而且，无论是在系统可用性方面，还是在特性开关方面，他们都细化到了具体的用户级别，以保证每个用户的使用体验；

在选择转型团队方面，他们主动避开了最复杂的团队，而是从能够把握住的中型团队做起，积累成功经验，然后不断传播。

最后，我再提一点自己的想法。这两年来，在 DevOps 领域，特性的出镜率越来越高。因为特性是更加符合 DevOps 快速交付原则的需求颗粒度。所以，业界的各大公司在基于特性的需求管理、基于特性的分支策略、基于特性的发布和价值追踪策略等层面，都有很多实践和思考。比如，今年 CloudBees 公司发布的 SDM 产品就是基于特性维度的。

我相信，未来的 DevOps 也会朝着这个方向发展。打造一整套基于特性开发的研发模式，是一个值得我们花精力好好思考的点。

思考题

你认为，基于特性维度的开发和交付，有哪些流程、工具、规则是有效的呢？

欢迎在留言区写下你的思考和答案，我们一起讨论，共同学习进步。如果你觉得这篇文章对你有所帮助，也欢迎你把文章分享给你的朋友。

30 | 向前一步：万人规模企业的DevOps实战转型案例（下）

你好，我是石雪峰。今天，我们接着上一讲的内容，继续来聊一聊微软 DevOps 转型的故事。

经常有人会问，企业的 DevOps 转型应该由哪个团队来负责，是否要组建一个全新的 DevOps 团队呢？带着这个问题，我们来看看微软是怎么做的。

1ES

微软有一个特殊的团队，叫作 1ES。1ES 是 One Engineering System 的缩写，直译过来就是“一套工程系统”的意思。从这个名字，相信你就可以看出来，在微软内部，有一套统一的工程能力平台来支撑微软内部各种形态产品的研发交付工作。没错！这个 1ES 团队包含了近 200 名工程师，作为组织级的研发效能团队，他们的目标就是通过一整套通用的工程能力平台，来提升内部的研发交付效率。

1ES 团队的工作职责可不仅仅是开发通用工具平台，他们还要负责公司的文化转型、最新的工程方法导入试验、研发过程改进、安全合规性检查、内部研发效率咨询以及在工程团队推广最佳实践等等，可以说是一个“全功能”的企业研发效能和生产力团队。截至 2018 年，数据显示，总共有近 10 万名用户在 1ES 提供的平台上协同办公。

但国内的现状是，很多企业对于研发效能的关注才刚刚起步。即便有人员负责类似的事情，也大多分散在各个业务内部，难以形成合力。组建了企业级统一的研发效能团队，而且规模能够跟微软的 1ES 相提并论的企业，基本上一只手就可以数得过来，就更别提建立一套统一的工程能力平台了。我曾见过一家大型企业，他们内部的工具平台有 1700 多个，殊不知，这里面有多少的重复建设和资源浪费。

那么，你以为微软的 1ES 团队天生就是这样“一统天下”的吗？还真不是这么回事。

事实上，1ES 团队的历史可以追溯到 2014 年。当时，微软新上任的 CEO 萨提亚·纳德拉非常重视研发能力建设，他致力于通过最好的工具来赋能研发团队。结果，微软的每个部门都会根据自己的实际情况采购自己习惯的工具平台，这就导致整个公司内部的工具、流程和成熟度差异巨大。差异化的工具和流程进一步增强了不同团队之间的共享和协作，内部人员转岗的成本极高，因为他们到了新团队以后，要从头开始适应一切。

为了解决这个问题，1ES 团队识别了三大领域：工作计划管理、版本控制和构建能力。他们先在企业内部识别哪些团队没有使用公司构建的统一工具，然后自顶向下强推。这背后的核心理念就是“Use what we ship to ship what we use”，也就是使用他们对外发布的工具来研发团队自己的工具。

不知道你发现没有，这三个领域都是软件交付的主路径，需求和任务管理、版本控制和构建系统无一不是核心系统。当你想要建立一个统一的效能平台的时候，最重要的就是抓住主路径上的核心系统。

关于“如何基于核心系统扩展一整套解决方案”，我给你推荐一篇 GitHub 的博客，你可以看看他们是如何思考这个问题的。

在接下来的几年里面，1ES 团队推动 VSTS（也就是现在的 Azure DevOps）成为了微软内部的工具平台标准，平台的用户也从最开始的几千个人增长到了后来的 10 万多人。

正是从 2010 年开始至今 150 个迭代的千锤百炼，才造就了后来 Azure DevOps 产品的大放异彩。可以说，无论是从设计理念、功能，还是用户体验等方面，微软的 Azure DevOps 平台在当今业界都是首屈一指的。

持续交付

持续交付是 DevOps 转型的核心部分，1ES 提供的统一工程能力平台让这一切成为了可能。那么，微软的持续交付做到了什么程度呢？

从 2019 年 3 月份的数据来看，他们每天部署 82,000 次、创建 28,000 个工作项，每个月有 44 万个提交请求、460 万次构建和 240 万次的提交数量。

无论把这些数据的哪一项拿出来，都是非常惊人的，这体现了微软卓越的工程能力水平。

那么，微软是如何一步步走到今天的呢？我们先来看看 DevOps 中最重要的、也是“老大难”的测试部分，看看微软是如何实现在 6 分钟内完成 6 万个测试用例的。

其实，早在 2014 年，微软在测试中遇到的问题跟大多数公司没什么两样：测试耗时太长、测试频繁失败、主线质量不可靠、迭代周期末端的质量远远达不到发布门槛。

这些问题严重到什么程度呢？我给你列举几个数字，你就明白了。

每天的自动化测试耗时 22 个小时；

全功能自动化测试长达 2 天；

仅有 60% 的 P0 级别用例可以执行成功；

在过往的 8 年里面，甚至没有一次每日自动化测试是全部通过的。

不仅如此，团队成员之间对单元测试存在着巨大的分歧：研发不愿意花时间写单元测试；团队不认为可以通过单元测试替代功能测试；甚至连用不用 Mock，他们在理念上也存在着冲突。

历史总是惊人的相似。在我之前的公司里面，研发总能找到各种理由苦口婆心地说服你他们不需要写单元测试，或者是，各种环境问题导致单元测试压根没法执行完成，因为引用了大量的外部服务。

微软的解法是，停止这种无意义的争论，为了达成预期目标前进。他们先从能达成共识的部分开始推进，并重新整理了内部的测试模型，如下图所示：

L0 级：这是没有外部依赖的单元测试。这部分在代码合并请求中执行，执行时长小于 60ms；

L1 级：这是存在外部依赖的单元测试，测试时间一般小于 2 秒，平均 400ms 左右；

L2 级：是面向接口的功能测试，在预发环境执行；

L3 级：也就是在生产环境下执行的线上测试。

在明确了整体策略之后，团队开始对测试活动进行改造。整个改造过程可以划分为四个阶段：

阶段一：从 L0/L1 级测试入手

在这个阶段，尽可能地简化 L0/L1 级测试的执行成本，编写高质量的测试用例。

根据我在企业里面推行单测的经验，抛开“到底应不应该写单测”这个事情不说，最大的争议点就是分工的问题。从做事的角度来说，包含几个方面：工具和框架选型、规则整理输出、工具平台开发、数据的度量和可视化建设。

为了加快单测的推行，我建议，前期工具和框架选型，由自身的开发和测试工程师或者有经验的 DevOps 工程师一起完成，并在试点项目跑通。接下来，研发完成规则的梳理，包括单测的书写规则、工具环境配置规则等等，平台方面启动单测相关的能力建设，目的就是研发只需要写单测代码，具体的执行、数据分析、报告统计都交给平台完成。最后，在团队内部进行推广，并持续更新迭代规则和工具。在这个阶段，尽量不要新增每日测试用例。

阶段二：分析已有的每日测试用例

在这个阶段，重点要识别几个方面的内容：

哪些测试用例已经过时，可以删掉？

哪些测试用例可以转移到 L0/L1 级完成？

哪些测试可以整合进 SDK 中专项进行（比如性能测试）？

这一步骤的目的就是让每日测试用例集合尽可能地“瘦身”，加快执行速度。毕竟，每次跑几十个小时，一旦失败的话，就没有第二次机会了。

阶段三：将每日测试转化为 L2 级测试

接口测试是一种性价比相对更高的测试类型，所以，推进面向接口的自动化测试建设可以兼顾测试的执行效率和业务的覆盖情况。

在这个阶段，我们需要完善接口自动化测试框架，提供代码、配置和多接口验证等多种测试类型。除此之外，要集中统一的管理系统的 API，一方面进行 API 的治理，另一方面，加强研发和测试基于 API 的协作，把所有的变更版本线上化。一旦研发更新了 API 定义，测试可以在同一个地方更新他们的测试用例和 Mock 数据，从而实现基于 API 的在线协同工作。

阶段四：建设 L3 级测试

这就是在生产环境的线上测试，主要是通过监控机制来诊断系统的健康度。这部分内容我在第 17 讲中提到过，如果你不记得了，可以回去复习一下。

随着 L0/L1 级测试的不断增多，这些测试都可以纳入到代码合并请求中自动执行。另外，L2 级的 API 接口测试同样可以纳入到流水线中。

通过 40 多个迭代的持续努力，以及考核机制的促进作用，整个测试的分布情况发生了明显的反转。

你可以看到，每日测试的数量不断减少，L0 级别的测试不断增多，到后来，L1/L2 级的测试也相对稳定下来。你要知道，这 40 多个迭代可是花了将近 3 年的时间。如果以后谁再跟你说“3 个月就能搞定单测”，你可千万别跟他聊天。

持续部署

持续交付的终点是持续部署，那么，微软在部署层面又做了哪些事情呢？

首先，微软不承认半自动化部署这个事情。其实很多时候，部署动作都不是一次性完成的。有些命令或者步骤并没有线上化，或者就是非高频的动作没有做到工具里面，还是需要通过手动复制一段命令的方式来实现。

经常有人会问：“我们的大部分操作都实现了自动化，这算不算做得不错了呢？”我的回答也很简单：“对于一个没有基础或者非专业的人来说，他是否可以完成这项任务？”坦率地说，这有点“抬杠”的性质，但事实上，如果一个平台做完了，结果还是要依赖于指定人去操作，那你就得想想这个事情的意义和未来的价值了。

之前我在做一个项目的时候，就遇到过类似的案例。为了解决配置变更的问题，团队成员实现了一个非常复杂的任务，但是在评审的时候，我们发现，这个任务并不能解决所有问题，到头来还是需要他手动入库操作。手动入库的成本其实还好，但是为了自动而自动，结果得不偿失，这就有点浪费时间和精力了。

那么，要想解决所有人都能部署的需求，要做的就是完全的自动化。把所有的操作都内嵌于流水线之中，并且纳入版本控制，用于记录变更信息。使用同一套工具实现多环境部署，通过配置中心完成不同环境的配置下发。

这样做的好处有很多，一方面，可以在不同的环境中完善部署工具的健壮性，避免由于部署方式或者工具的差异带来的潜在风险。另一方面，与生产环境的部署相比，测试环境的部署心理压力没有那么大。当大家都熟悉测试环境的部署过程之后，对生产环境的部署就是小菜一碟了。

为了实现安全低风险的部署，微软引入了“部署环”的概念，你可以把部署环理解为将部署活动拆分成了几个阶段。每一次生产部署都需要经过五环验证过程，即便是配置变更，也是如此，不存在额外的紧急通道。这五个部署环分别是：

金丝雀（内部用户）

小批量外部用户

大批量外部用户

国际用户

其他所有用户

通过渐进式的部署方式，每一个新的版本都缓慢地经过每一环的验证，并逐步放量，开放给所有用户。其中有几个点值得我们借鉴。

1. 通过流水线打通 CI/CD

我们可以这样理解 CI/CD：

CI 的目的是生成一个可以用于部署的包。这个包可以是 war 包、tar 包、ear 包，也可以是镜像，这取决于系统的部署方式。

CD 的目的是将这个包部署到生产环境，并发布给用户。

所以，CI 和 CD 的结合点就在于制品库，通过流水线调度部署包在制品库中的流转，从而完成制品的晋级。我发现，很多大厂都是用部署前重新打包的方式，人为地将 CI 和 CD 的过程割裂开来，这并不是一种好的处理方式。

2. 持续部署并不意味着全自动

我们都知道，持续部署能力是考查一个公司 DevOps 能力的最好指标（比如前面我提到的微软每天能够部署 8 万多次）。那么，这是不是说，每次变更都要经过自动化过程部署到生产环境呢？答案是不一定。

你可以看一下这幅微软开发的全景图，其中，在 CD 过程中，每一环的部署都需要人工确认来完成，这背后的核心理念是控制“爆炸半径”。

既然无法彻底阻止失败，那么是否能够控制影响范围呢？“部署环”的设计理念正是如此，为了做到这一点，适当的人工管控还是很有必要的。

那么，如何确认部署是成功的呢？

微软定义了非常详细的保障在线服务可用性的规则，其中最重要的就是，明确线上服务状态永远处于第一优先级。你可能觉得，本来不就应该是这样的吗？但是，在实际工作中，我们会发现，内部工具团队经常专注于实现新功能，而把线上的报警放在一边。

要想解决这个问题，除了明确线上为先的理念之外，制定相应的规则也是很重要的。比如，微软的值班工程师叫作 DRI（Designated Responsible Individual），也就是“指定责任人”。微软明确要求，每个在岗工程师必须在工作日 5 分钟内、休息日 15 分钟内响应问题，并把这纳入到了人员和团队的考核之中。另外，通过每周、每月的线上服务状态报告，以及每次事故的详尽故障分析，不断在内部强化线上为先的理念。

总结

在这个案例中，我给你介绍了微软在转型过程中的几个重点，包括自动化测试能力、统一工程平台和工程团队、分级持续部署、组织变革、团队自治和文化转变等。这些都是在实际的 DevOps 转型过程中，企业所面对的最为头疼的事情。微软的经历是否给你带来了一些启发呢？当然，想要做好 DevOps，可绝对不只是做好这几点就够了的。

对于 DevOps 的转型过程，微软的理念是：

A journey of a thousand miles begins with a single sprint.

这就是咱们常说的“千里之行，始于足下”。DevOps 不是一种魔法，可以立即见效，而是每次变好一点点，每个人都在不断地思考“我能为 DevOps 建设做点什么”。这就像微软的自动化测试转型过程一样，你能看到整个趋势在不断变好，慢慢变成了现在这样，每次提交可以在 10 分钟左右完成近 9 万个自动化测试。

微软一直在致力于推广 DevOps，并且不断把自己的经验通过各种形式分享出来。仅仅从这一点上，我们就能看出微软的文化转变、向开放开源的转变。我再跟你分享一些微软 DevOps 转型的资料，你可以参考一下。

资料 1. https://docs.microsoft.com/en-us/azure/devops/learn/devops-at-microsoft/

资料 2. https://azure.microsoft.com/en-us/solutions/devops/devops-at-microsoft/

你还记得我在第 6 讲中提到的 DevOps 转型的 J 型曲线吗？其实无论是 DevOps 转型，还是研发效率建设，都是一个长期、琐碎的过程。你要做的，就是树立自己的信心，做正确的事情，并期待美好的事情自然发生。

思考题

通过案例学习 DevOps 是一种特别好的方法，在案例中，你不仅能借鉴别人的经验，也能学习到系统背后的设计理念。那么，你有什么好的案例学习途径吗？可以分享一下吗？

欢迎在留言区写下你的思考和答案，我们一起讨论，共同学习进步。如果你觉得这篇文章对你有所帮助，也欢迎你把文章分享给你的朋友。

特别放送（五）| 关于DevOps组织和文化的那些趣事儿

你好，我是石雪峰，今天又到了特别放送环节。写到这儿，专栏已经接近尾声了，我想再跟你聊聊 DevOps 的组织和文化。

DevOps 文化好像是一个矛盾结合体：一方面，文化这种东西似乎只可意会不可言传；另一方面，文化对 DevOps 实践的重要性又是毋庸置疑的。

在各种行业大会上，关于文化的议题总是屈指可数。原因也很简单，关于文化，一般都说不明白，即便能说明白，也改变不了什么。因为文化的改变可不是像引入一个工具那么简单，很多时候都需要思想上的转变。

谈到 DevOps 文化，我想到去年我和几个朋友一起组织《DevOps 实践指南》的拆书帮活动。这个活动就是，通过连续几周的线上分享，我们帮助大家总结提炼书中的核心知识。

在分享的过程中，有这样一件事，我印象特别深刻。事情的起源是原书的第 14 章中有这样一段描述：

团队在客户面前没有任何需要隐藏的，对自己也同样如此。与其把影响线上系统的问题视为一种秘密，不如尽可能地将它透明化，主动将内部的问题广而告之给外部用户。

某大型公司的 IT 负责人刚好负责分享这个章节，他表示，为了尊重原文，他保留了这段描述，但是在国内的环境下，这并不现实。即便是他自己，一个坚定的 DevOps 实践者，也很难做到这种程度。因为如果把公司内部的问题通通开放给客户，那估计转天就可以收拾东西回家了。

也正因为公司一般不会在第一时间对外公布故障，所以也难怪，这些事情基本都是通过“云头条”这类公众号第一时间公布出来的。

但是，似乎大家的记忆力也都不太好，很多时候，这些事情过去了也就不了了之了，除了听说“谁又背锅了，谁又被牵连了“之类的流言蜚语之外，也没有什么特别之处。

这也可以理解，毕竟家丑不可外扬，内部吐吐槽也就罢了，如果凡事都到外面去宣传，那公司岂不是形象全无？更有甚者，还会影响用户对公司的信心。你想，如果天天就你问题最多，那谁还敢用你的服务呢？

我们都知道 DevOps 文化的几个关键词：协作、分享共担、无指责文化、在错误中学习……这些道理大家都懂，但真正遇到问题、需要平衡不同部门利益的时候，是否还能以这些文化为准则，来指导行为模式，就是另外一码事了。

说白了，如果想看团队是否具备 DevOps 文化，与嘴上说说相比，更重要的是看怎么做。所以，今天我给你分享几个故事，看看在面对同样的问题时，其他公司是怎么做的，并思考一下，为什么这样是一种更好的做法？

GitLab 删库的故事

时间回到 2017 年 1 月 31 日，全球最大的代码托管协作平台之一的 GitLab 出现了一次长达 18 小时的停机事故，原因居然是一个 IT 工程师把生产数据库的数据给清空了。

由于遇到了爬虫攻击，主备数据库之间的同步延迟已经超过了 WAL 的记录上限，导致数据同步无法完成。当时，遇到这种问题的操作就是移除所有备份数据库上的数据记录，然后全量触发一次新的同步。但是，由于数据库配置并发数和连接数等一系列的配置问题，导致数据库的数据备份一直失败。

这个时候，时间已经来到了标准国际时间的晚上 11 点半。由于时差的关系，对于身在荷兰的工程师来说，这时已经是深夜 1 点半了。当值工程师认为有可能是之前失败的同步遗留的数据导致的数据库备份失败，所以决定再一次手动清空备份服务器的数据。

但是，也许是由于疏忽，他并没有意识到，当时他操作的是生产数据库。几秒钟后，当他回过神来取消操作的时候，一切都已经来不及了。最终的结果是，总共有超过 300G 的线上数据丢失，直接导致了服务进入恢复模式。

按道理说，这种事情虽然难以接受，但其实并不少见。更加严重的是，当 GitLab 尝试恢复数据的时候才发现，他们所谓的“精心设计”的多重备份机制，竟然都无法拯救被删除的数据。

最夸张的是，直到这会儿，他们才发现，由于升级后工具版本不匹配，数据库的定时备份一直处于失败状态。他们原以为邮件会告警这个问题，但巧合再一次出现，针对自动任务的报警也没有生效。

事已至此，要么是隐藏事实，然后给外界一个不疼不痒的解释，要么就是把问题完全公开，甚至是具体到每一个细节，你会选择怎么处理呢？

GitLab 公司的选择是后者。他们第一时间将系统离线，并将事件的所有细节和分析过程记录在一个公开的谷歌文档中。不仅如此，他们还在世界上最大的视频网站 YouTube 上对恢复过程进行全程直播。

考虑到有些用户不看 YouTube，他们还在 Twitter 上同步更新问题状态，硬生生地将一场事故变成了一个热门话题。当时，同时在线观看直播的用户超过 5000 人，甚至一度冲到了热门榜的第二位。

除此之外，在几天后，公司的 CEO 亲自给出了一篇长达 4000 字的问题回溯记录，包含问题发生的背景、时间线、核心原因分析，针对每一种备份机制的说明，以及将近 20 条后续改进事项，由此获取了用户的信任和认可。可以说，在这一点上，他们真的做到了透明、公开和坦诚相待，并且做到了极致。

问题回溯的资料： https://about.gitlab.com/2017/02/10/postmortem-of-database-outage-of-january-31/

至于那位倒霉的工程师的结果，估计你也听说了，对他的惩罚就是强迫他看了几十分钟的《彩虹猫》动画。说实话，这个动画有点无聊。但是，如果这种事情发生在咱们身边，估计直接就被开掉了。我知道你肯定好奇这个《彩虹猫》到底是个啥动画片，我也特别无聊地找来看了下，如下所示：

从此以后，GitLab 的开放越发“变本加厉”。现在你可以在任何时间去查看服务的实时状态，包括每一次过往的事故分析。同时，名叫“GitLab 状态”的 Twitter 账号实时更新当前的问题，目标就是在任何用户发现问题之前，尽量主动地将问题暴露出来，至今已经发布了将近 6000 条问题。

同时，你还可以查看 GitLab 服务的详细监控视图和监控数据，包括 GitLab 的运维标准手册、备份脚本。这些通通都是对外开放的。只要你想用，你就可以直接拿来使用；如果你觉得哪里不靠谱，也可以直接提交改动给他们。我提取了一些截图和地址，你可以参考一下。

1.GitLab 状态 Twitter：https://twitter.com/gitlabstatus

2.GitLab 状态网页：https://status.gitlab.com/

3.GitLab 内部监控大屏：https://dashboards.gitlab.com/

这并不是 GitLab 公司发疯了，实际上，开放已经成为了主流公司的标配。比如，在 GitHub 上，你同样可以看到类似的信息。

故事讲到这儿，就可以告一段落了。面对事故的态度，很大程度上体现了公司的文化。

首先，就是在错误中学习。

GitLab 的分析报告不仅是对问题本身的描述，很大程度上也是希望把他们的经验，尤其是修复过程中的经验分享出来，通过错误来积累经验，改善现有的流程和工具，从而彻底地避免类似问题的出现。

每个人、每个公司都会犯错，对错误的态度和重视程度，决定了成长的高度。所以，假如说我要去一家公司面试，面试官问我有没有问题，那我非常关心的一定是他们公司对错误的态度，以及具体的实际行动。

另外，就是建立信任和及时反馈，公开透明是关键。这不仅是对外部用户而言的，对内部协作的部门和组织来说，也是这样。因为只有充分的透明，才能赢得对方的信任，很多事情才有得聊，否则，建立协作、责任共担的文化，就成了一句空谈。

在开始建立 DevOps 文化的时候，你首先要明白，上下游所需要的信息是否能够自主简单、随时地获取到，如果不能的话，这就是一个很好的潜在改进事项。

Etsy 三只袖子毛衣的故事

Etsy 是美国的一家手工艺电商平台，从 2015 年上市以来，它的市值一度接近 80 亿美元。当然，除了快速增长的市值以外，最为人称道的就是它们的 DevOps 能力，而它们的案例也大量出现在了《DevOps 实践指南》一书中。

那么，为什么这个名不见经传的公司能够做到这种程度呢？实际上，通过一件小事，我们就能看出来原因。

你可能不知道的是，一家在线电子商务公司每日浏览频率最高的单体页面不是首页，也不是具体哪个商品的页面，而是网站的不可用页面，也就是我们习惯说的 502 页面。有些公司甚至为了提升 502 页面的用户体验，利用好这部分流量，在 502 页面做了很多文章，比如把 502 页面作为一个产品推广的阵地等。

当 Etsy 的网站不可用的时候，你看到的是一个小姑娘在织毛衣的画面，而这个毛衣竟然有三只袖子。

实际上，“三只袖子的毛衣”代表了 Etsy 对于错误的态度。我们都知道，一件毛衣应该只有两只袖子，这是常识。如果有人真的织出来第三只袖子，我们的第一反应就是觉得这很可笑，这只是个人的问题，却很少去想他为什么会做这种反常识的事情，背后的根因是什么。

但是，Etsy 公司却不是这样的。在每年的年终总结大会上，公司都会颁发各种奖项，其中一个奖项的奖品就是“三只袖子的毛衣”，获奖者是公司年度引入最大问题的个人。

这是因为，在他们看来，犯错误并不是什么大不了的事情。错误本身并不是个人的问题，而是公司系统和制度的问题，正因为有了这样的错误，才给了公司改进和成长的空间。从某种意义上说，这也是一种贡献。

当然，除了制造噱头之外，通过这种行为，其实公司想表达的是它们对文化的偏好，也就是要建立一种心理安全、快速变化、及时反馈、鼓励创新的文化，由此来激发整个团队的士气和战斗力。

无独有偶，2019 年的 DevOps 状态报告也特别指出，心理安全的文化氛围，有助于团队生产力的提升。更重要的是，状态报告还把它作为一条重要能力，放入了 DevOps 能力模型之中。

因为，只有当员工感受到心理安全时，才会把注意力集中在解决问题和快速完成工作上，而不是花费大量的时间用于互相攻击和部门政治。在跨部门寻求合作的时候，才会思考如何让组织的价值最大化，而不是想“谁过来动了我的奶酪，我要如何制造更高的门槛来保护自己的利益”。对于 DevOps 这种注重协作的研发模式来说，这一点真的太重要了。

Netflix 招聘成年人的故事

美国硅谷聚集了世界上大多数精英的 IT 公司，但是精英中的精英，就是 FAANG，也就是 Facebook、Apple、Amazon、Netflix 和 Google 这五家公司的首字母简称，这五家公司基本引领了硅谷技术的风向标。大多数人对其中的 4 家公司都非常熟悉，但是对 Netflix 却知之甚少。那么，这家公司凭啥能跻身为精英中的精英呢？

如果我告诉你，在 Netflix，每个工程师不仅拿着数一数二的薪水，还可以自己决定什么时候休假，爱休多长时间就休多长时间，而且报销不需要经过审批，填多少就报多少。另外，即便只加入公司一天就离职了，公司给予的补偿也足够他们活上一年半载。

看到这里，你是不是觉得这家公司的老板疯了呢？

这个叫作里德·哈斯廷斯的人还真没疯。我所说的这一切，背后的原因都被记录在了《奈飞文化手册》一书中，这也是号称硅谷最重要的文件的作者在离开 Netflix 之后写的一本阐述 Netflix 文化的书。

Netflix 认为，与其建立种种流程来约束员工，不如砍掉所有不必要的流程，给员工一个自由发挥自我价值的空间。因为，把所有员工都视为一个成年人是他们的行为准则。作为一个成年人，你应该能够为自己的行为负责，同时为公司的发展负责，由此做出最好的选择，并付出最大的努力。

正是这种开放的氛围，使得 Netflix 至今开源了 171 个项目和插件。其中，像混沌工程的鼻祖混乱猴子（Chaos Monkey）、断路器工具Hystrix、服务注册工具Eureka、部署工具Spinnaker ，都是 DevOps 领域最为著名的开源工具。

开源为先的共享精神正在成为越来越多的公司重视开源的动力之一。让真正优秀的人做有价值的事情，而不是让他们整日为复杂的流程、公司的内部政治和无意义的工作所影响，他们才能发挥最大的价值。对 DevOps 来说，也是如此。

总结

说到这儿，三个故事已经讲完了。我们来总结一下在 DevOps 文化中最为知名的几点内容：

建立免责的文化，并在错误中学习；

通过对外开放透明，建立信任，促进协作；

打造心理安全的氛围，鼓励创新；

开源为先的共享精神。

改变企业文化，绝不是一个人、一句话的事情，管理层的认同和导向非常重要。但是，我们并不能期望每家公司都能成为 FAANG 一样的硅谷巨头。所以，从我做起，从力所能及的范围做起，别觉得文化跟自己没有关系，这才是最重要的。

最后，希望你看完这一讲以后，可以重新审视一下，团队内部是否建立了正向的错误回溯机制？是否鼓励内部分享和创新？是否和上下游之间做到了开放和协作为先？是否在身体力行地减少重复建设？

思考题

你对今天的哪些内容印象最深刻呢？你又有哪些跟 DevOps 文化相关的故事可以拿来分享呢？

欢迎在留言区写下你的思考和答案，我们一起讨论，共同学习进步。如果你觉得这篇文章对你有所帮助，也欢迎你把文章分享给你的朋友。

特别放送：Jenkins产品经理是如何设计产品的？

你好，我是石雪峰。这是一期临时增加的特别放送。

前两天，我去葡萄牙里斯本参加了 2019 年的 DevOps World | Jenkins World 大会。这是一年一度的社区聚会，参会人会围绕 Jenkins 和 DevOps 展开为期 3 天的密集交流，信息量非常大。很多新技术、行业趋势、产品设计思路都在大会上涌现了出来，我觉得非常有价值，也很有必要整理出来，分享给你。

2019 年是 Jenkins 诞生 15 周年，对于任何一个软件来说，15 年都不是一个短暂的时间。在这个时间点，社区也在展望过去 15 年来的 Jenkins 发展历程，并憧憬下一个 15 年 Jenkins 的变化。

可以说，从 DevOps 产品的角度来说，Jenkins 本身就是一个非常出色的典型案例。

最开始，这是一个由于 Jenkins 创始人 KK 无法忍受同事天天导致编译失败而开发的一个人项目。到今天，这个项目已经有将近 900 名或全职、或兼职的贡献者，26 万多个 Master 节点，超过 3000 万个任务了。这些数字还仅仅是官方可以统计到的部分，如果再加上企业内网、个人电脑上的实例，那就更加不计其数了。

今年，我印象最深刻的是，Jenkins 创始人 KK 并没有在主会场上讲太多的产品细节、设计思路、发展方向等，而是仅仅用了 10 多分钟回顾了自己的心路历程。在演讲的最后，他将舞台交给了一位 Jenkins 产品经理。这位产品经理是何方神圣呢？为什么是一位产品经理来讲这些内容呢？这激起了我极大的好奇心。

一直以来，KK 都被视为 Jenkins 的头号产品经理。的确，技术专家兼产品经理是比较普遍的一个现象。这是因为，与普通面向用户的产品相比，DevOps 产品有几个非常鲜明的特征。

技术背景要求高。因为 DevOps 产品要解决的很多问题都是一线的技术问题；

面向的用户是开发人员。这就意味着，如果你不了解开发的真实工作方式，就很难设计出开发友好的产品；

专业工具繁多。产品引用到的开源组件和工具都是专业领域的内容，比如 Jenkins 就是一个典型的持续集成系统，如果你不了解 Jenkins，又怎么设计 Jenkins 呢？

在几天的会议过程中，针对 DevOps 产品经理面对的这些挑战，我专门跟这位神奇的 Jenkins 产品经理进行了沟通。他就是 Jeremy Hartley，一个来自荷兰的大哥。

我先给你介绍下社区的运作方式。以 Jenkins 这个产品为例，它背后的主要贡献者都来自于 CloudBees 公司。虽然这些人都属于同一个公司，但实际上，他们大多各自分散在家办公，一年到头也见不了几次面。

比如，产品经理 Jeremy 在荷兰，创始人 KK 在加州，基础设施的负责人 Oliver 在比利时，K8S 的插件维护者在西班牙。因此，每年的 FOSDEM（年初的欧洲最大的开源软件大会），以及年末的 Jenkins World 大会，就成了这些世界各地的开发者汇聚到一起的难得机会。

言归正传，与产品经理的积极外向、滔滔不绝的一般形象不同，Jeremy 可以说是一个异类。他从始至终都给人一种温文尔雅的感觉，甚至在公开演讲的时候，他的语气也非常平和，没有太多的情绪表达，只是把他和他的产品的故事娓娓道来。

Jeremy 早先在一家互联网在线视频公司干了 10 年。他半开玩笑地说，即便干了 10 年，也不如跟腾讯合作一个项目来得出名。后来，他加入 XebiaLabs。这是一家专门做 DevOps 平台产品的公司，在国内可能不是特别出名，但如果提到 DevOps 工具元素周期图，相信你肯定听说过，这就是这家公司迭代更新的。

图片来源：https://xebialabs.com/periodic-table-of-devops-tools/

在今年的 4 月份，他加入了 CloudBees，成为了主管开源和商业版本 Jenkins 的高级产品经理。在跟他交流的过程中，我对产品经理这部分内容的印象非常深刻。我梳理了一些要点，分享给你。如果你已经是 DevOps 产品经理，或者是立志要成为 DevOps 产品经理的话，你一定要认真看一下。

一、自我颠覆

什么叫自我颠覆呢？我给你举个例子。比如，Jenkins 的用户 UI 项目 Blue Ocean，很多人应该都知道，目前这个项目的主要开发已经停止了。社区仍然会修复缺陷和安全漏洞，也会接受开发者共享的 PR，但是不会再投入专职工程师进行开发工作了，新需求也都处于无限暂停的状态。

实际上，不仅仅是 Blue Ocean，去年 Jenkins 大会上星光闪耀的项目，比如 Five super power、Jolt in Jenkins、Evergreen 等项目，也都因为方向调整和人员变动而处于半终止、暂缓开发的状态。那么，为什么在短短一年的时间内，会有这么大的颠覆性变化呢？我把这个问题抛给了 Jeremy。

他的观点是，这些项目并非没有意义，但是确实没有达到项目原本的预期。对于产品经理来说，管理预期是一项非常重要的能力。当需求走到产品经理的时候，做哪个、不做哪个经常是个问题。团队往往会进行协商，挑选出来最有希望的项目，但这并不代表这些项目注定会成功。相反，很多想法只有做了才知道是不是靠谱，用户是不是买单。如果使用场景有限，又没有很好的增长性，及时叫停反而是一种好的选择。

Blue Ocean 项目诞生之初，可以说是让人眼前一亮，充满期待，甚至一度和 Jenkins 流水线一起被视为 2.0 版本的最大功能。但是几年之后，由于产品性能、插件扩展支持等种种原因，真正在企业中大规模使用的机会并不多。正因为项目没有达到预期，产品团队就决定停止这个项目。

但是与此同时，全新的 Jenkins 用户界面项目已经被提到了日程表中。这个全新的用户界面大量借鉴了 Blue Ocean 的设计思路，并最终通过一套用户界面，取代了现有的 Blue Ocean。我想，正是这种不断的自我颠覆，才让一个 15 年的软件始终保持着活力和创新力。

二、化繁为简

对于 Jenkins 这样的产品来说，很多插件都是开发者提供的，但是开发者往往倾向于追求功能的全面性，这从很多插件的设计中就能看出来。

开发者不加筛选地把所有功能都罗列在用户面前，自然是得心应手。但是，对普通用户来说，当他第一眼看到这个复杂产品的时候，他的使用意愿就会大打折扣。

另外，面对这么多的插件，从表面上看，用户好像有很多选择，但是，有些插件的名字长得差不多，你并不知道哪个能用。或者，有些插件适用于当前的 Jenkins 版本，但是一旦 Jenkins 升级，它们就无法正常使用了。但是，用户在升级之前并不知道是否适配，往往是在升级完成之后才会发现问题，只能再进行版本回滚。类似这些插件使用中的问题，都给用户带来了很大的使用障碍。

在探讨这个问题的时候，Jeremy 也认为，系统过于复杂有悖于产品设计的初衷，但是，作为一个公开的平台，他们并不能约束开发者的行为，所以就需要一种方法来平衡功能的全面性和功能的易用性。

比如，在重新考虑 Jenkins 插件生态的时候，一方面，产品团队会针对全新的业务场景提供官方的插件支持。举个例子，在云原生开发场景下，通过和云服务商深度合作，提供更多的官方插件，来满足典型的云服务商的使用场景。无论是对亚马逊的 AWS、微软的 Azure，还是未来国内的主流云服务商，他们都会通过这种方式来进行合作。无论你使用的开源产品，还是商业产品，都能通过这个项目来获得收益。

另一方面，产品团队也会进一步对现有的 1600 多款插件进行分类，并将其中的一部分插件纳入 CloudBees 的保障项目之下。这就意味着，将由 CloudBees 公司来保证这类插件的兼容性和可用性。对于专业用户来说，他们依然可以按照自己的方式自由地选择和开发插件，而对于普通用户来说，官方推荐的插件集合就足够了。

不仅仅是插件，产品的易用性体现在产品设计的方方面面。凡是阻塞用户使用的问题，都是需要优先解决的。

比如，对于一个 10 多年的产品来说，历史积累的文档数量巨大，很多时候，用户都无法找到真正有用的信息。所以，Jenkins 产品团队启动了一个文档治理的项目，会重新梳理所有文档，并把它们迁移到 GitHub 平台上。另外，他们还会结合新的产品功能，整理出最佳实践。比如，对于流水线使用来说，官方也总结了很多最佳实践供入门者参考，你可以结合前面两讲的内容一起学习。

要始终记得，不要让你的产品只有专家才会使用。将复杂的问题简单化，是产品经理不论何时都要思考的问题。

三、退后一步

DevOps 的产品经理大多是技术人员出身，因此会特别容易一上来就深入细节，甚至是代码实现的细节。

Jeremy 同样也是程序员出身，他做过很长一段时间的前端开发。当我问他“一个好的产品应该如何平衡用户视角和实现视角”的时候，他给我的回答是，要尽量退后一步来看问题。

退后一步，就是说不要把关注点只聚焦在问题表面，而是要尽量站在旁边，以第三方的视角来全面审视问题。

他举了个 Jenkins 的流水线即代码的例子。在实际使用的时候，流水线文件中经常会有大量的代码，有时候，流水线代码甚至会有上千行。代码越多，系统的不稳定因素就越多，测试起来也越麻烦。同时，按照现有的运行机制来说，很多代码都是运行在 master 节点上的，这就给集群的 master 节点带来了很大压力。

要想解决这个问题，从实现的角度出发，就是提供一种标准化、结构化的语法格式，也就是声明式流水线语法，以此来降低流水线的编写难度，减少流水线代码量，并且让这个代码结构更加清晰。但是，这些优化依然不能解决集群 master 节点压力过大的问题，这就相当于问题只看了一部分。

退后一步来看，这就需要一种全新的视角，来提升流水线整体的隔离性。所以，产品团队目前就在设计一种新的流水线组件 building block，也就是构建块。

所谓构建块，是指一整块的代码片段，而不是一条条独立的指令。这些构建块结合到一起，就可以满足一个具体场景的问题。比如 Maven 打包构建的场景，构建块可以帮你解决环境、工具、构建命令等一系列问题。这些构建块以代码形式在子节点上运行，既降低了流水线的编写难度，也缓解了 master 节点上的压力。对用户来说，使用构建块也更为简单，可以直接把它放在自定义的步骤中执行。

对于产品经理来说，找到方案、解决问题自然是职责所在，但与此同时，他们往往需要同时保有两种思维，即用户思维和实现思维。能够在这两种思维之间自由切换，是产品经理走向成熟的标志。

总结

说到这儿，我来回答一下最开始的那个问题，也就是“为什么是产品经理来分享产品的规划呢？”这是因为，无论要开发一个多大还是多小的产品，都需要有这样一拨人来退后一步，找到用户的真实问题，化繁为简，实现这个功能，并不断颠覆自己，持续打磨和改进。这对于任何一个想要解决更多人问题的产品来说，都是至关重要的。

思考讨论

关于这次 Jenkins World 大会，你还有什么希望进一步了解的内容吗？欢迎你积极提问，我会知无不言。

如果你觉得这篇文章对你有所帮助，也欢迎你把文章分享给你的朋友。

特别放送：学习DevOps不得不了解的经典资料

你好，我是石雪峰。

今天又到了特别放送的环节，在学习交流 DevOps 的过程中，经常有人会问这样的问题：

我想学习 DevOps，可以推荐一些好的书和资源吗？

DevOps 相关的最新行业案例，我可以在哪里获取呢？

你是怎么知道这么多有趣的故事的呢？

这些问题的“出镜率”特别高，所以，我今天专门来跟你聊聊有关 DevOps 学习资料的事情。

你应该也有感觉，在这个信息爆炸的时代，如果想要了解一个新的事物，相关的信息不是太少，而是太多了。像 DevOps 这种热门话题，相关的资料网上一搜就一大把。各种新书也像“采用了 DevOps 实践”一样，发布频率越来越快。信息一多，我们就很容易焦虑，这么多资料，什么时候才能看完啊？

更何况，如果单单只是臻选有用的资料，就要花费大量的时间，按照精益的理论来说，这也是不增值的活动呀。在这个时间稀缺的时代，想要花大段的时间投入到一件事情上，找到一个靠谱和有价值的信息，就成了很多人开始学习的第一步，

所以，为了让你在专栏之余可以更加有效地持续学习，我特意整理了一份我认为 DevOps 从业人员需要了解和关注的资料，你可以参考一下。

需要强调的是，有针对性地精读一本好书的一部分内容，要比泛泛地读好几本书要更有收获一些，也就是“贵精不贵多”，先定下一个小目标，然后沉下心来反复地学习实践，这个道理在大多数领域都是适用的。

一份报告

如果说，DevOps 领域有行业公认的权威资料的话，DevOps 状态报告自然是不二之选。

从 2014 年开始，这份报告每年发布一次，主要编写方也经历了好几次变迁，从最开始的 Puppet 实验室、IT Revolution 到 DORA（DevOps Research & Assessment）的加入，再到去年，DORA 和 Puppet 分家，两边各自推出了自己的 DevOps 状态报告。

但从影响力来说，我更推荐 DORA 的这份报告，从去年开始，这份报告正式改名为：加速度，DevOps 状态报告。

提到 DORA，你可能不太熟悉，但是如果说到 DORA 的两位核心创始人 Nicole 博士和 Jez Humble，相信你一定有所耳闻，他们也是我今天推荐的一些书的作者。

有意思的是，去年 DORA 宣布加入谷歌，其主要成员也被谷歌云收编，比如 Jez Humble，目前就是谷歌云的技术布道师。

回到报告本身，我在 2017 年就开始进行报告的本地化工作。从近两年来看，报告的体量在持续扩大，比如，今年的报告洋洋洒洒有 80 页内容，而且是全英文的。

那么，关于这份报告，重点是要看什么呢？纵观过去几年的报告模式，我给你画个重点：核心是看趋势、看模型和看实践。

首先看趋势。

每年的报告都会有一些核心发现，这些发现代表了 DevOps 行业的发展趋势。比如，今年的报告就指出，云计算能力的使用依然是高效能组织和中低效能组织的分水岭，所以，如果公司还在纠结是否要上云，不妨从 DevOps 的角度思考一下，使用云计算能力带给交付能力的提升可以有多明显。

另外，公司内的 DevOps 组织比例也从 2014 年的 14% 提升到了今年的 27%。由此可见，越来越多的公司在拥抱 DevOps，至少从组织层面可以看到，越来越多带有 DevOps 职责，或者是以 DevOps 命名的团队出现。这对于公司内部职责的划分和团队架构演进，具有一定的指导意义。

当然，不得不提的，还有衡量 DevOps 实施效果的 4 个核心指标，也就是变更前置时间、部署频率、变更失败率和故障修复时长。

从 2014 年的第一份报告开始，每年的报告都在对比这 4 个核心指标在不同效能团队之间的变化和差异。实际上，就我观察，国内很多公司的 DevOps 度量体系，都深受这些指标的影响，或多或少都有它们的影子。

可以说，这 4 个指标已经成为了衡量 DevOps 效果的事实标准，甚至有人直接把指标拿给老板看，说：“你看，高效能组织比低效能组织的故障恢复时长要快 2000 倍，由此可以证明，DevOps 是势在必行的。”

我个人觉得，没有必要纠结于数字本身，这东西吧，看看就好，更多的还是要透过数据看趋势。

比如，去年的指标数据就显示，在交付能力方面，不同组织间的差距在缩小，相应的质量维度的指标差异却在拉大。这就说明，通过初期的自动化能力建设，团队可以快速地提升交付水平。但是，由于缺少质量能力的配套，很容易产生更多的问题，这就带来一个警示，在快速提升交付能力的同时，质量建设也不能落在后面。

关于报告，其次是看模型。

我在第 4 讲中提到过一个观点：任何技术的走向成熟，都是以模型和框架的稳定为标志的。因为当技术跨越初期的鸿沟，在面对广大的受众时，如果没有一套模型和框架来帮助大众快速跟上节奏，找准方向，是难以大规模推广和健康发展的。

在软件开发领域是这样，在其他行业也是如此，要不然，为啥会有那么多国标存在呢？所以说，模型和框架的建立是从无序到有序的分水岭。

在今年的状态报告中，研发效能模型进一步细化为软件交付运维模型和生产力模型。今天我不会深入解析模型本身，但我会在专栏后面的内容中结合实际案例进行详细解释，从而帮助你更好地理解。

但是，从过往的报告可以看出，每一年关于模型的进化是整个报告的核心内容，报告也在不断覆盖新的领域，试图更加全面地揭示影响软件开发效能的核心要素。在实践 DevOps 的时候，你可以参考这个能力模型，识别当前的瓶颈点，在遇到拿捏不准的决策时，也可以参考模型中要素的影响关系。

比如，公司内部经常会争论是否需要更加严格的审批流程，希望借助严格的审批流程，促使软件交付更加有序和可靠。很多系统和需求在提出的时候，都是以这种思想为指导的。我一直对这种流程的有效性抱有怀疑，加入更多的领导审批环节，除了出问题的时候大家一起“背锅”之外，并没有带来什么增值活动。

在今年的模型中，这种观点得到了印证。重流程管控不利于软件交付效能的提升，轻流程管控也不会影响软件交付质量，关键要看公司是否选择一种“更好”的做法来实现管控的目的。

最后，我们要重点关注实践。

在实施 DevOps 的时候，经常会有这样的困扰：道理都懂，却仍然做不好 DevOps。所以，DevOps 落地的核心无外乎实践和文化，而实践又是看得见摸得着的，这一点当然值得关注。在状态报告中，有很大篇幅都在介绍实践部分，这些实践都是在大多数公司实施总结出来的，并且得到了实际的验证，具有很强的参考性。

比如，今年的报告重点介绍了技术债务、灾难恢复测试和变更管理流程这几个方面的实践，这些都是企业实施 DevOps 时的必经之路。

比如灾难恢复测试，很多公司都有非常详尽的文档，但是如果找他们要操作记录，他们却又很难拿出来。

我之前就见过一家国内 Top 的公司，说是在做关键数据的备份，但实际去看才发现，这个备份任务已经很长时间处于失败状态了。

如果有定期的灾难恢复测试，类似的这种问题是一定可以发现的。而往往在灾难发生的时候，才能体现一家公司的工程能力水平。

比如，Netflix 正是因为混沌工程，才没有受到 AWS 云服务 down 机的影响，这和日常的演练是密不可分的。

从 2014 年至今的 DevOps 状态报告的中英文版本，我已经收集并整理好了，你可以点击网盘链接获取，提取码是 mgl1。

几本好书

讲完了报告，接下来，我再给你推荐几本好书。

1.《持续交付》&《持续交付 2.0》

谈到 DevOps 里面的工程实践，持续交付可以说是软件工程实践的终极目标。对于在企业内部推进 DevOps 工程能力建设的人来说，这两本书可以说是案头必备，常看常新。

对我自己来说，因为 2011 年机缘巧合地拿到了第一版第一次印刷的《持续交付》这本书，我的职业生涯彻底改变了。因为我第一次发现，原来软件交付领域有这么多门道。帮助组织提升交付效率这个事情，真是大有可为。

《持续交付》围绕着软件交付的原则，给出了一系列的思想、方法和实践，核心在于：以一种可持续的方式，安全快速地把你的变更（特性、配置、缺陷、试验），交付到生产环境上，让用户使用。你可以参考一下软件交付的 8 大原则。

为软件交付创建一个可重复且可靠的过程

将几乎所有事情自动化

将一切纳入版本控制

频繁地做痛苦的事情

内建质量

DONE 意味着已发布

交付过程是每个成员的责任

持续改进

很多人都有《持续交付》这本书，但我敢打赌，真正能沉下心来把这本书看透的人并不多，因为这本书里面通篇都是文字，而且有些难懂，如果没有相关的实践背景，基本上就跟看天书差不多了。

所以，通读《持续交付》并不是一个好的选择，我建议你尽量带着问题有选择性地去读。

到了《持续交付 2.0》，乔梁老师创新性地将精益创业的思想和《持续交付》结合起来，更加强调 IT 和业务间的快速闭环，也更加适应当今 DevOps 的发展潮流。

另外，乔梁老师的文笔更加流畅，读起来更加轻松，他会结合案例进行说明，对于实际操作的指导性也更强。毫无疑问，他是国内软件工程领域的集大成者。

如果你对软件开发流程的工程实践不太了解，你可以读一读这两本书。

当然，对于开发、测试、运维人员这些软件交付过程中必不可少的角色来说，也可以用来拓展知识领域。

2.《精益创业》&《Scrum 精髓》&《精益产品开发》&《精益开发与看板方法》

关于管理实践和精益方面，我给你推荐 4 本书。

《精益创业》提出的 MVP（最小可行产品）思想已经被很多的企业奉为圭臬。它的核心是，只有经过真实市场和用户的验证，想法才是真正有效的，产品需要在不断的验证和反馈过程中持续学习，持续迭代，而不是试图一步到位，耗尽所有资源，从而失去了回旋的余地。

《Scrum 精髓》适合于使用 Scrum 框架的敏捷团队学习和实践，以避免 Scrum 实施过程中形似而不神似的问题。同时，这也是立志成为 Scrum Master 的同学的红宝书。

《精益产品开发》是何勉老师在 2017 年出版的一本基于精益思想和精益看板方法的著作。在精益软件开发领域，这本书和李智桦老师的《精益看板方法》，都是看一本就够了的好书。

这几本书比较适合想要了解敏捷，或者是在实际工作中践行敏捷开发方法的同学阅读。另外，精益思想可以说是 DevOps 的理论源泉，很多的文化导向，以及持续改进类工作都跟精益思想有密切的关系。

3.《DevOps 实践指南》&《Accelerate：加速》

如果你想了解 DevOps 的全貌以及核心理论体系和实践，《DevOps 实践指南》和《Accelerate：加速》就是最好的选择了。这两本书的作者都是 DevOps 行业内的领军人物，作为 Thought Leader，他们引领的 DevOps 的体系在不断向前演进。

其中，《DevOps 实践指南》，也就是俗称的 Handbook，重点介绍了 DevOps 实践的三步工作法，还包含了大量 DevOps 实施过程中的参考案例。而《Accelerate：加速》的作者就是 DevOps 状态报告的作者。他在这本书中揭示了状态报告背后的科学方法，并提出了 DevOps 能力成长模型，以帮助你全面提升软件交付能力。

4.《凤凰项目》&《人月神话》&《目标》

最后，我想再推荐三本小说，这也是我读过的非常耐看的几本书了。

其中，《凤凰项目》提出的 DevOps 三步工作法和《DevOps 实践指南》一脉相承；《人月神话》是 IT 行业非常经典的图书，畅销 40 余年；《目标》则是约束理论的提出者高德拉特的经典著作，他所提出的改进五步法构成了现代持续改进的基础。

大会，网站和博客

当然，报告和书只是 DevOps 资源中的一小部分，还有很多信息来源于大会、网站和博客，我挑选了一些优质资源，分享给你。

DEOS ：DevOps 国际峰会，以案例总结著称；

DevOpsDays：大名鼎鼎的 DevOpsDays 社区；

TheNewStack ：综合性网站，盛产高质量的电子书；

DevOps.com ：综合性网站；

DZone ： 综合性网站，盛产高质量的电子书；

Azure DevOps：综合性网站，盛产高质量的电子书；

Martin Fowler ：Martin Fowler 的博客；

CloudBees Devops ：Jenkins 背后的公司的博客。

在这些资源中，有一些值得你重点关注一下。

比如，Gene Kim 发起的 DOES（DevOps 企业峰会）就是获取实践案例的绝佳场地；而 DZone 和 NewStack 经常会推出免费的电子书和报告，也值得订阅；Martin Fowler 的博客，每一篇内容都是精品，对于很多技术细节可以说是起到了正本清源的作用，值得好好品味。

说了这么多，最后我还想再花一点点时间，跟你聊聊学习这个事情。我跟你分享一幅美国学者爱德加·戴尔提出的学习金字塔模型图，这个模型也是目前比较有参考性的模型之一。

图片来源：https://www.businessdirect.bt.com/

在这个模型中，学习的方式分为两种，一种是主动学习，一种是被动学习。其实，无论是读书，看视频，还是听专栏，都属于是被动式的学习，最终收获的知识可能只有输入信息的一半儿，这还是在记性比较好的情况下。大多数时候，看得越多，忘得越多，这并不是一种特别有效的学习方式。

实际上，对于 DevOps 这种理念实践、技术文化、硬技能、软实力交织在一起的内容来说，主动学习的方式是不可或缺的，比如案例讨论，线下交流，在实践中学习等。

所以，希望你能多思考，多总结，结合工作中的实际问题，摸索着给出答案，并积极分享，跟大家讨论。只有主动思考，才能消化吸收，最终总结沉淀出一套自己的 DevOps 体系认知。

总结讨论

好了，今天我跟你聊了 DevOps 的学习资料，包括状态报告、书籍和大会、网站、博客。不过，对于 DevOps 来说，这些也仅仅是点到为止。

我想请你来聊一聊，你自己在学习和实践 DevOps 的过程中，有没有私藏的干货和渠道呢？如果有的话，希望你可以分享出来，我们共建一个 DevOps 相关的资源库，并在 GitHub 上进行开源维护，从而帮助更多人了解和学习 DevOps。

欢迎在留言区写下你的思考和答案，我们一起讨论，共同学习进步。如果你觉得这篇文章对你有所帮助，欢迎你把文章分享给你的朋友。

特别放送：成为DevOps工程师的必备技能（上）

你好，我是石雪峰，今天到了“特别放送”环节。有很多留言问道：“DevOps 专家这个岗位，需要的技能和技术栈有哪些？成长路径是怎样的呢？”

我相信这应该是很多刚开始接触 DevOps 的同学最关心的问题。毕竟，从实用的角度出发，每个人都希望能够尽快上手实践。所以今天，我来跟你聊聊，我认为的 DevOps 工程师的必备技能以及学习路径。不过在此之前，我们要先了解 DevOps 工程师的岗位职责。

全球最大职业社交网站 LinkedIn（领英）2018 年发布的一份报告显示，当今全球最热门的招聘职位分别是DevOps 工程师、企业客户经理和前端开发工程师。其中，排名第一的就是 DevOps 工程师。

无独有偶，2019 年全球最大知识共享平台 Stack Overflow 的开发者调查报告显示，在薪资排行榜上，DevOps 工程师排名第三，仅次于技术经理和 SRE（网站可靠性工程师）。而在去年的调查报告中，DevOps 工程师的收入甚至排名第二。

无论是人才市场需求，还是收入薪资水平，这种种迹象都表明，DevOps 工程师已经成为了当今最炙手可热的岗位，收入也攀升至 IT 行业的金字塔顶端。难怪有越来越多的人开始接触和学习 DevOps。

但是，DevOps 这样一个刚刚诞生 10 年的“新兴事物”，并不像一门专业技术那样，有一条相对清晰的学习路径，以及经典的学习资料，比如你要学习 Java，就可以从《Java 编程思想》看起。

除此之外，DevOps 似乎又跟软件工程的方方面面有着说不清的关系。我跟你分享一幅 DevOps 技能发展路线图，根据这幅路线图，你要从编程语言入手，理解操作系统原理、系统性能、网络安全、基础设施即代码、CI/CD、运维监控和云技术等等。

图片来源：https://roadmap.sh/devops

怎么样，是不是看到这么一堆名词就瞬间头大了吧？如果要把这些所有的技术全部精通，那至少得是 CTO 级别的岗位。对普通人来说，这并不太现实。毕竟，啥都懂点儿，但是啥都不精通，本身就是 IT 从业者在职业发展道路上的大忌。

如果要说清楚这个岗位，核心就是要回答 3 个问题：

DevOps 工程师在公司内承担的主要职责是什么？

为了更好地承担这种职责，需要哪些核心技能？尤其是从我接触过的这些公司来看，有哪些技能是当前最为紧俏的呢？

学习和掌握这些技能，是否存在一条可参考的路径呢？

接下来，我们就重点聊一聊这些内容。

DevOps 工程师的岗位职责

关于 DevOps 工程师这个岗位，一直以来都存在着很大的争议。很多人认为 DevOps 应该是一种文化或者实践，而不应该成为一个全新的职位或者部门，因为这样会增加公司内部的协作壁垒。

其实，我倒觉得没有必要纠结于这个 Title，因为很多时候，DevOps 跟公司内部已有的角色存在着重叠。比如，开发变成了 DevOps 开发，运维变成了 DevOps 运维。另外，在不同的公司里面，类似角色的岗位名称也大不相同。比如，在 DevOps 状态报告中，DevOps 就和 SRE 被归为一类进行统计。而在公司中实际负责推行 DevOps 的部门，至少我见过的就有工程效能团队、运维团队、配管团队，甚至还有项目管理团队。可见，不同公司对于 DevOps 工程师的职责定义也同样存在着差异。

但不管怎样，我觉得谈到 DevOps 工程师职责的时候，除了本职工作的内容以外，至少还应该额外关注 3 个方面：

1. 工具平台开发

关于工具平台开发，争议应该是最小的，而且这也是很多公司推行 DevOps 的起点。因为工具是自动化的载体，而自动化可以说是 DevOps 的灵魂。随着公司规模越来越大，研发内部的协作成本也随之水涨船高，那么工具平台的能力水平就决定了公司交付能力的上限。

但问题是，因为种种原因，很多公司只有大大小小的分散工具，并没有一套完整的研发协同工作平台，这本身就制约了协作效率的提升。你可以想象一下，研发每天要在大大小小的系统里面“跳来跳去”，很多功能甚至还是重复的，这显然是很浪费时间的。

比如，你明明已经在代码托管平台上做了代码评审，结果提测平台上面还有个必填项是“你是否做过了评审？”是不是很让人抓狂呢？这背后的主要原因，就是缺乏顶层设计，或者压根就没有专人或者团队负责这个事情。这样一来，团队各自为战，发现一个痛点就开发一个工具，发现一个场景就引入一个系统，再加上考核指标偏爱从 0 到 1 的创造性工作，也难怪每个高 T 升级都要有自己的系统加持了。但如果任由这种趋势发展下去，内部的重复建设就难以避免了。

所以，对于 DevOps 工程师而言，除了要关注原有的工具重构、新功能的开发之外，更要聚焦于整个软件交付流程，将现有的工具全面打通，以实现可控的全流程自动化。也就是说，不仅仅要追求点状的工具，还要包括整条线上的工具链，从而形成覆盖软件交付完整流程的工具体系。

另外，工具平台同样是标准化流程的载体，同时也是 DevOps 实践的载体，所以在设计实现时，需要考虑这些实践的支持。举个例子，在配置管理领域，将一切纳入版本控制是不二法则。那么，在建设工具平台的时候，就需要始终有这样的意识，比如记录流水线的每一次配置变更的版本，并且能够支持快速的对比回溯。

2. 流程实践落地

其次，无论是工具平台的推广落地，还是结合平台的流程改进，都需要有人来做。毕竟，即便是完全相同的工具，在不同人的手里，发挥的作用也千差万别，把好好的敏捷管理工具用成了瀑布模式的人也不是少数。而针对流程本身的优化，也是提升协作效率的有效手段。

比如在有的公司里，单元测试需要手动执行，那么当工具平台具备自动化执行的能力，并且能够输出相应的报告时，这部分的操作流程就应该线上化完成。再比如，以往申请环境需要走严格的线上审批流程，当环境实现自动化管理之后，这些流程都可以变为自服务，通过工具平台进行跨领域角色的交叉赋能，从而实现流程优化的目标。

另外，我接触过的一些公司倾向于在不改变流程的前提下，推动 DevOps 落地。坦率地说，这种想法是不现实的。如果流程上没有约束开发和测试共同为结果负责，那开发为什么要跟测试共同承担责任呢？出了问题又怎么可能不扯皮呢？因此，如果你在公司内部负责流程改进，遇到问题就应该多问几个为什么，找到问题的本源，然后将流程和工具相结合，双管齐下地进行改进。

所以，理念和实践的宣导，内部员工的培训，持续探索和发现流程的潜在优化点，这些也都是 DevOps 工程师要考虑的事情。

3. 技术预研试点

最后，各种新技术新工具层出不穷，哪些适用于公司现有的业务，哪些是个大坑呢？如果适合的话，要如何结合公司的实际情况，评估潜在的工具和解决方案，而不是盲目地跟随业界最佳实践呢？类似技术债务的识别和偿还这种重要不紧急的事情，到底什么时候做合适呢？

另外，如果公司决定开始推行单元测试，那么，选用什么样的框架，制定什么样的标准，选择什么样的指标，如何循序渐进地推进呢？这些同样非常考验团队的功底。如果步子一下子跨得太大了，到最后就可能成为形式主义了。

你可能会觉得，我就是一个小开发、小运维，怎么能推动这么大的事情呢？但实际上，DevOps 从来都不是某一个人，或者某一个角色的职责，而是整个研发交付团队所共享的职责。在你力所能及的范围内，比如在你所在的部门内部，开展 DevOps 的理念宣导和技术培训，鼓动领导参加行业的大会，在和上下游团队协作的时候向前一步，这些都是 DevOps 所倡导的自服务团队应该具备的能力。

DevOps 工程师的主要技能

说完了 DevOps 工程师主要负责的事情，接下来我们就来看看 DevOps 工程师所要具备的能力。我从实用的角度出发，总结了 DevOps 工程师的核心能力模型。

其中，能力模型分为两个方面：专业能力和通用能力。专业能力也就是常说的硬实力，是 IT 从业人员身上的特有能力，比如软件工程师会写代码，就跟导演会拍电影，司机会开车一样。而通用能力，更加接近于软实力，这些能力并不局限于某一个岗位或者职业，是所有人都应该努力培养的能力。很多时候，当硬实力到达天花板之后，软实力的差异将决定一个人未来的高度，这一点非常重要。

软实力

我们今天先从软实力说起。在讲具体的软实力之前，我先跟你分享一个小故事。

我在国外听过这样一种说法：在企业中，印度裔的工程师往往比华裔工程师的岗位职级要高。为什么会这样呢？我曾经做过一个跨中美印三地的工程团队的负责人，我发现，每次我跟印度工程师交代一个事情，他们总能又快又好地做出一个特别清晰漂亮的 PPT。我特意问过他们是怎么做到的。原来，他们在上学时受过这方面的训练，还专门练习过表达、演讲等技能，可见，事出必有因，软实力对个人的发展至关重要。

那么，作为一名 DevOps 工程师，需要具备什么软实力呢？

1. 沟通能力

DevOps 倡导的核心理念就是沟通和协作，所以，难怪沟通能力会排在软实力的第一名。

在推动 DevOps 落地的过程中，你需要同时具备向上沟通、向下沟通和横向沟通的能力。提炼 DevOps 实施框架和落地价值，寻求领导层的支持，需要向上沟通；打破组织间的边界，建立跨团队的协同，需要横向沟通；引导团队快速完善平台工具能力，表明工作的意义和价值，提升大家的主动性，需要向下沟通。所以你看，其实每天的工作中都充满了大量的沟通。

需要注意的是，沟通能力不仅限于语言能力，很多时候，开发运维的沟通是基于代码完成的。所以，良好的注释风格、清晰结构化的描述方式……这些细节往往也能提升沟通的效率。

比如有一种很 DevOps 的方式，就是 ChatOps，是以 GitHub 的 Hubot 为代表的对话式运维，慢慢扩展为人机交互的一种形式。通过建立一种通用的沟通语言，打破开发和运维之间的隔阂。

2. 同理心

DevOps 希望团队可以共享目标，共担责任，但是实际上，哪个团队不想更加自动化、更加高效地工作呢？所以，DevOps 工程师要能够站在对方的角度来看问题，设身处地地想想他们的困难是什么，我能做些什么来帮助他们。这种同理心也是弥合团队分歧，建立良好的协作文化所必需的能力。

除此之外，培养团队以用户为中心的思想，也是很好的方式。这里的用户，不是外部用户，而是在交付流程中存在交付关系的上下游部门。在交付一个版本的时候，要尽力做到最好，而不是不管三七二十一，先丢过去再说。

我还是要再强调一下，同理心只有在流程和机制的保证之下才能生根发芽。

3. 学习能力

DevOps 工程师需要了解的东西真得很多，因此，能够在有限的时间里快速学习新的技能，并且有意愿主动地改进提升，也是一种能力。

在 DevOps 工程师的眼里，从来没有“完美”二字。比如完美的流程、完美的技术实现、完美的软件架构等。他们似乎天生就有一种能力，那就是能发现问题并时刻想着可以做到更好。但实际上，如果没有日积月累的思考，没有外部优秀实践的学习，没有开放的沟通和交流，是没有办法知道，原来还有一种更好的工作方式的。引用质量管理大师戴明博士的一句话：

Don’t just do the same things better – find better things to do.

很多时候，我们都在等待一个完美的时机，比方说，你打算学习一个新的知识点，但要等到工作都完成了，没人来打扰，有大段的时间投入才开始学习。但实际上，哪来这么多准备就绪的时候呢？真正的学习者都是在没有条件来创造条件的过程中学习的。所以，如果想开始学习 DevOps，我信奉的原则只有一个，那就是先干再说。

总结

今天，我给你介绍了 DevOps 工程师的前景，可以说，现在是这个岗位的黄金时期。我还给你介绍了 DevOps 工程师的主要职责，包括工具平台开发，流程实践落地和技术预研试点，这些都是在完成本职工作的基础上需要额外考虑的。在个人技能要求方面，我重点提到了 3 项软实力，希望你始终记得，软实力不等于玩虚的，这对未来个人的发展高度至关重要。

在下一讲中，我会跟你分享 DevOps 工程师必备的硬技能，以及成长路径，敬请期待。

思考题

你所在的公司是否有 DevOps 工程师的岗位呢？他们的职责要求是怎样的呢？你觉得还有哪些软实力是 DevOps 工程师所必备的呢？

欢迎在留言区写下你的思考和答案，我们一起讨论，共同学习进步。如果你觉得这篇文章对你有所帮助，欢迎你把文章分享给你的朋友。

特别放送：成为DevOps工程师的必备技能（下）

你好，我是石雪峰。在上一讲，我介绍了 DevOps 工程师的具体职责以及 DevOps 工程师必备的 3 项软实力，分别是沟通能力、同理心和学习能力。有了这些认知之后，我们今天来看看“重头戏”：DevOps 工程师必备的硬实力以及学习路径。

DevOps 工程师必备的硬实力

所谓硬实力，说白了就是指一个人的技术能力。软实力通常是“只可意会不可言传”的，但技术本身就具体多了，重要的是，技术水平的高低相对来说也更好衡量。在公司里面，技术人员要想获得晋升，重点就是依靠技术能力。

IT 行业覆盖的技术领域非常广，而且近些年的新技术也是层出不穷的，从入门到精通任何一门技术，都需要大量时间和精力的投入。那么，在面对这么多技术的时候，究竟要选择从哪个开始入手，真是一个难题。对于希望成为 DevOps 工程师，甚至是 DevOps 专家的你来说，究竟有哪些必须掌握的核心技术呢？

1. 代码能力

现在这个时代，代码能力可以说是最重要的硬实力了。IT 行业自然不用说，像运维有运维开发，测试也有测试开发，就连产品经理都要懂代码，不然可能都没办法跟开发同学顺畅交流。

对于工具平台自身的建设而言，代码能力自然是重中之重。这不仅仅在于通过写代码来实现工具平台本身，还在于你能了解开发的完整过程。这些平台的用户每天跟代码打交道的时间可能比跟人打交道的时间还多，如果你不能理解他们的日常工作方式，那么你做出来的工具平台，又怎么能真正解决团队的问题呢？

这里提到的代码能力包含两个方面，分别是脚本语言能力和高级语言编程能力。

脚本语言能力。这对于运维工程师来说自然是驾轻就熟，各种 VIM、Emacs 手到擒来，Shell 和 Python 也是轻车熟路。而对于开发人员来说，难点不在于语法本身，而在于对关联操作系统和命令的理解上。毕竟，脚本语言是一种快速的自动化手段，追求的是高效开发，简单易用。

高级语言编程能力。你需要至少掌握一门高级语言，无论是 Java、Python 还是 Ruby 和 PHP。其实语言只是工具，你不用过度纠结于选择哪门语言，要求只有一个，就是你能用它来解决实际问题，比如能够支持你实现面向移动端或者 Web 端的工具平台开发。为了写出好代码，而不仅仅是写出能用的代码，你也需要对于一些常见的开发框架和开发模式有所了解。这是一个相对漫长的过程，绝对不是什么“21 天精通 XX 语言”就够了。因为看得懂和写得好，完全是两码事。

好的代码是需要不断打磨和推敲的。与其说写好代码是一门技术，不如说是一种信仰。我们团队的内部沟通群名叫作“WBC 团队”，“WBC”也就是“Write Better Code”的缩写，这其实也是我们团队对自己的一种激励。在日常的开发过程中，我们会不断发现和总结更好的实现方式，在内部分享，互相学习，从而持续提升代码能力。我截取了一部分我们最近优化流水线脚本的经验总结，你可以参考一下。其实，每个人都能总结出自己的代码心经。

2. 自动化能力

在自动化方面，你首先需要对 CI/CD，也就是持续集成和持续交付，建立起比较全面的认知。因为 CI/CD 可以说是 DevOps 工程领域的核心实践，目前大部分公司都在集中建设软件的持续交付能力，尤其是以流水线为代表的持续交付平台，很多时候就同 DevOps 平台划上了等号。

接下来，为了实现全流程的自动化，你需要能够熟练使用 CI/CD 各个关键节点上的典型工具，并且了解它们的设计思路。

一方面，目前很多公司都在拥抱开源，参与开源，开源工具自身的成熟度也非常高，并且逐渐取代商业工具，成为了主流方案。通过直接使用开源工具，或者基于开源工具进行二次开发，也是自动化领域投入产出比最高的方式。所以，像版本控制工具 Git、代码托管平台 Gitlab、CI 工具 Jenkins、代码扫描工具 Sonar、自动化配置管理 Ansible、容器领域的 Docker、K8S 等等，这些高频使用的工具都是你优先学习的目标。

另一方面，无论是开源工具，还是自研工具，工具与工具之间的链路打通也是自动化的重要因素。所以，在理解开源工具的实现方式的基础上，就要能做到进可攻，退可守。无论是封装，还是自研，有了工具的加持，CI/CD 也会更加游刃有余。

关于 DevOps 的工具图谱，我跟你分享一个信通院的 DevOps 能力成熟度模型版本，供你参考。值得注意的是，工具不在多，而在精。其实，工具的设计思路和理念有共通之处，只要精通单个节点上的工具，就可以做到以点带面。

3.IT 基础能力

我始终认为，运维是个特别值得尊敬的工种，也是 DevOps 诞生的原点。如果你不是运维出身，那你要重点掌握运维的基础概念，最起码要了解Linux 操作系统方面的基础知识，包括一些常用的系统命令使用，以及网络基础和路由协议等。毕竟，对于开发者来说，他们通常习惯基于 IDE（集成开发环境）图形界面工作。比如，如果问一个 iOS 开发同学怎么通过命令行的方式进行构建调试，或者如何用代码的方式实现工程的自动化配置，他可能就答不上来了。

另外，随着基础设施即代码的技术不断成熟，你还要能看懂环境的配置信息，应用自动化构建、运行和部署的方式等，甚至可以自行修改环境和应用配置，这样才能实现所谓的开发自运维。虽然在大多数公司，运维的专业能力一般都会通过运维平台对外提供服务，但对于基础概念，还是需要既知其然，也知其所以然。

4. 容器云能力

云计算对于软件开发和部署所带来的变化是革命性的。未来企业上云，或者基于云平台的软件开发会慢慢成为主流。而容器技术又天生适合 DevOps，Kubernetes 可以说是云时代的 Linux，基于它所建立的一整套生态环境，为应用云化带来了极大的便利。

所以，无论是容器技术的代表 Docker，还是实际上的容器编排标准 Kubernetes，你也同样需要熟悉和掌握。尤其是在云时代，基于容器技术的应用开发和部署方式，都是 DevOps 工程师必须了解的。

5. 业务和流程能力

在任何时候，DevOps 的目标都是服务于业务目标，DevOps 本身也从来不是墨守成规的方式，而是代表了一种变革的力量。所以，加强对业务的理解，有助于识别出 DevOps 改进的重点方向，而流程化的思维建设，有助于突破单点，放眼全局。

很多时候，企业需要的不仅仅是一个工具，而是工具所关联的一整套解决方案，其中最重要的就是业务流程。

对于 DevOps 工程师来说，要有能力发现当前流程中的瓶颈点，并且知道一个更加优化的流程应该是怎样的，这一点也是制约工程师进一步拓展能力的瓶颈之一。

举个例子，对于开发 DevOps 平台工具来说，你可能认为最合适承担的团队就是开发团队，因为他们的代码能力最强。但是实际上，DevOps 平台的设计，很多时候都是由最熟悉企业内部研发流程的团队来主导的。正因为 DevOps 工程师的工作应该同业务紧密联系，更加关注于全局交付视角，所以很多时候，配置管理、质量管理、项目管理和技术运维团队更多地在承担相近的角色。毕竟，只有方向正确，所做的一切才是加法。

学习路径

那么，要想成为 DevOps 工程师，是否有一条普适性的学习路径呢？实际上，这个问题就跟我们要在公司推行 DevOps，是否存在一条通用的改进路径一样，并不是一个容易回答的问题。

从前面的能力模型可以看出，DevOps 工程师特别符合现在这个时代的要求，他具备多重复合能力，是典型的全栈工程师，或者“梳子型”人才。因为只有这样，才能充分弥合不同角色之间的认知鸿沟，堪称团队内部的万金油。

基于过往在公司内部推行 DevOps 的经验，以及当前行业的发展趋势，我有几条建议送给你：

1. 集中强化代码能力

未来的世界是软件驱动的世界。我们以前总说的必备能力，比如外语、开车等，未来都可以被软件所取代。而编程能力即将成为下一个必备能力，甚至连国务院发布的《新一代人工智能发展规划》中都提到，要在中小学普及推广编程教育。

而写可以用的代码，和写好的代码之间，距离绝不只是一点点而已。你可能会说，以后都用人工智能来编程了，可问题是人工智能从何而来？又是谁来训练和标注人工智能的呢？所以，越是基础的能力，越不会过时，比如数学、核心的编程思想、数据结构，以及基于代码构建对世界的认知和建模能力。

所以，如果你现在只是刚开始接触代码，我建议你给自己定一个目标，专门强化自己的代码能力，至少花 1 年时间，从新手变成熟手，这对于你未来在 IT 行业的发展，至关重要。

跟你分享一个小技巧。你可以基于成熟的开源软件来边学习边应用，比如像 Adminset 这种轻量级的自动化运维平台，已经可以解决大多数中小公司的问题了。其实，代码能力不仅仅是掌握语法和框架，更重要的是基于场景，整体设计数据和业务流程，并通过代码实现出来。毕竟，只有结合实际的应用场景进行学习，才是最有效率的。

2. 培养跨职能领域核心能力

相信经过几年的工作，你已经具备了当前岗位所需要的基本能力，这是你当前赖以为生的根本。那么在这些能力的基础上，逐步发展跨领域跨界的能力，尤其是那些核心能力，就成了投入产出比最高的事情。

举个例子，如果你是软件开发工程师，那么恭喜你，你已经走在了代码的道路上，接下来，运维能力就是你要尝试攻克的下一个目标。而在这些目标中，比如操作系统、自动化部署以及云能力，就是你要最优先发展的跨界能力，因为它们是运维的核心，也是了解运维最好的出发点。反过来说，如果你从事的是运维行业，那么除了常用的脚本以外，核心代码能力就是你的目标。

其实，我们每天的工作其实都离不开跨界，比如，运维每天部署的应用，为什么要部署这么多实例？每个实例之间的调用关系又是怎样的？多问几个为什么，往往就有新的收获。

不仅如此，在接触跨领域的时候，除了基础核心技能，那些最常见的工具，你也要花时间来了解。现在网上的资料足够多，快速入门应该并不困难。

3.DevOps 核心理念和业务思维

如果你不理解 DevOps 到底是什么，那何谈成为 DevOps 工程师呢？因此，像 DevOps 中的核心理念，比如精益敏捷、持续交付，以及很多实践，你都要有所了解。当然，如果你订阅了这个专栏，我将带你走过前面的这段路，你可以快速地进入下一阶段，在实战中练习。

DevOps 在公司的落地是大势所趋，也许你所在的团队也会参与其中，那么除了做好自己的本职工作外，你也可以多参与，多思考，看看推进的过程是怎样的，涉及到的角色又在做些什么，项目的整体进展和计划是什么。在实战中练习和补齐短板，对于积累经验来说，是不可或缺的。很多时候，不是没有学习的机会，只是我们自己不想看到罢了。

另外，可能你现在距离业务还比较远，那么你可以尝试了解一些大的业务目标，多跟你所在团队的上下游进行沟通，看看他们现在的关注点在什么地方。既然业务的目标需要整个团队紧密协作才能完成，那么每个团队都是其中的一份子，所以他们身上也同样体现了业务的目标。

4. 潜移默化的软实力建设

类似沟通能力、同理心、自驱力、学习能力、主动性等，无论从事任何职业，都是你身上的闪光点。很多天生或者从小养成的习惯，需要长时间潜移默化的训练才能有效果。

很多时候，IT 从业人员给人的印象都是不善表达，再加上东方文化的影响，本身就比较含蓄，这对很多沟通和表达来说，都是潜在的障碍。这个时候，就要尽量把握已有的机会，比如多参加团队内部的读书分享、公司内部的讲师培训报名等。即便刚开始分享的内容还不足你脑中的 1%，但至少也是一个好的起点。我的建议就是 6 个字：勤练习，多总结。就像 DevOps 一样，持续改进和持续反馈，培养自己的自信心。

总结

总结一下，我在这两讲给你介绍了 DevOps 工程师要重点关注的 3 大职责，分别是工具平台开发、流程实践落地和技术预研试点。另外，我还基于实用角度提炼了 8 大核心能力模型，分为 3 条软实力和 5 条实力，并给出了 4 条提升 DevOps 核心能力的建议。为了方便你复习和理解，我画了一张脑图，把这两讲内容进行了汇总，你可以参考一下。

最后，我想强调的是，就像 DevOps 没有明确的定义一样，DevOps 工程师的技能也没有明确的限定，所以，你要时刻保持好奇心，持续学习，总结出自己的能力体系，并在实践积累经验，这样才能在激烈的竞争中占得先机。

思考题

针对我们这两讲的内容，你觉得自己需要提升哪方面的能力呢？你有哪些快速提升能力的小窍门吗？

欢迎在留言区写下你的思考和答案，我们一起讨论，共同学习进步。如果你觉得这篇文章对你有所帮助，欢迎你把文章分享给你的朋友。

期中总结：3个典型问题答疑及如何高效学习

你好，我是石雪峰。不知不觉中，专栏已经上线快两个月了，整体进度过半。我在专栏写作之初就给自己定下了一个小目标：认真对待每一条留言。到现在，单单是回复留言，我就已经写了 3 万多字了。

其实，对我来说，每一次看留言和回复留言，都是一个不断反思和学习的过程。实际上，很多时候，很多留言和讨论甚至比文章本身都更精彩，也更接地气。

今天是期中总结，我分为两个部分内容来讲：

第 1 部分：我从众多留言中挑选了 3 个典型问题，进一步展开讲解。

第 2 部分：我想跟你说说心里话。两个月的高强度写作，也让我从一个讲师的角度，重新审视了“如何高效学习”这件事情，我把这些想法分享给你，希望可以帮助你更好地提升自己。

典型问题

首先，我们来看一些典型问题。

问题一

敏捷开发模式没有花费大量时间去研究业务，这会不会出现因为对业务没有分析透，导致方向偏离，甚至系统开发到一半发现总体业务架构不合理，需要返工的情况呢？

相信你也知道，实施 DevOps 有助于产品快速和高质量的交付，那么，我想问的是：快速和高质量的交付，是否就一定意味着业务的成功呢？显然没有这么简单。

实际上，影响业务成功的因素有很多，比如，行业趋势、产品竞争力、用户消费习惯、政策法律法规等等。在这众多因素之中，需求质量的高低，或者说，需求是否靠谱，也很重要。

毕竟，如果交付了一大堆没用的需求，不仅没法提升业务，反而还会浪费大量的时间和精力，错过真正有价值的机会。

我们身处在一个飞速变化的时代，企业对于用户想要什么其实并不清楚。很多需求都是人为拍脑袋拍出来的。在提出一个新需求的时候，需求价值到底有多少呢？这不仅很难预测，而且还很难衡量。

所以，产品人员就倾向于采用“广撒网”的方式，提出一大堆需求，来提升命中的几率。毕竟，如果一次猜不对，打不准，那就多打几次呗。

这么看来，采用敏捷开发方式，还是瀑布开发方式，与需求是否靠谱并没有直接关系。即便是采用瀑布模式，依然也有“大力出悲剧”的案例，比如摩托罗拉的铱星计划。

既然无法事先预测需求是否靠谱，那么要解决这个问题，就需要业务团队和交付团队的通力协作了。

从业务侧来说，就是要采取精益创业的思想，通过最小可行产品，将需求进行拆解，通过原型产品降低市场的试错成本。这就引出了我在“业务敏捷”这一讲中提到的影响地图、卡诺模型、用户故事等一系列的手段和方法，核心还是采用持续迭代、小步快跑的方式来获取市场反馈。正因为如此，更加灵活拥抱变化的敏捷开发模式才被广泛地接受。

说完了业务侧，再来看看交付侧。

一个想法被提出来以后，需要经过软件开发交付过程，才能最终交付到用户手中。那么，就要用尽一切手段来缩短这条交付链路的时长。

如果开发的时间成本是一定的，那么剩余的部分，就是 DevOps 中的各种工程实践试图要去解决的问题。

比如，通过持续集成来降低软件集成中的解决成本，降低软件缺陷在最后一刻被发现的修复成本；通过自动化测试，降低大量手工回归测试用例执行的成本，降低新功能导致已有功能出现回退的修复成本。软件交付过程中的其他部分也大都如此，这也是每个领域都会有自己的实践集合的原因。

反过来看，功能上线之后，依然需要交付侧提取、汇总和及时反馈业务指标，来证明需求的靠谱程度，从而帮助业务侧更加有序地进行决策。对反映不好的功能及时止损，对反映不错的功能加大投入。

这样一来，业务侧的需求拆解、需求分析减小了需求颗粒度，提升了需求的靠谱度；交付侧的工程实践大大缩短了上线交付周期，提升了质量。这就帮助业务在不增加成本的前提下，可以验证更多的需求。这个过程的成本越低，频率越高，企业存活下来的几率和整体竞争力也会越高。这也正是 DevOps 想要解决的核心真问题。

问题二

公司对于配置管理的关注度不是很高，有没有什么好的落地实践方法，来建设完整的配置管理体系呢？

在专栏的第 10 讲，我从 4 个核心原则出发，介绍了配置管理的相关知识，引起了很多同学的共鸣。

的确，作为一个长期被忽视，但是格外重要的实践，配置管理不仅是诸多 DevOps 工程实践的基础，也是工程能力的集大成者。

正因为如此，配置管理体系的建设，并不只是做好配置管理就够了。实际上，这还依赖于其他工程实践的共同实施。

关于配置管理怎么落地，我跟你分享一个案例。

这家公司最早也没有专职的配置管理，软件的集成和发布都是由研发团队自行管理的。推动建立配置管理体系的契机，源于公司决定加快版本发布节奏，从三周一个版本变成两周一个版本。看起来，这只是版本发布周期缩短了一周，但是，就像我在专栏第 4 讲中演示的部署引力图一样，想要达成这个目标，需要方方面面的努力，其中就包括配置管理。

于是，公司决定引入配置管理岗位。初期，他们重点就做两件事：

重新定义分支策略，从长分支改为了短分支加特性分支的模式；

管理集成权限，从任何时间都能集成代码，到按照版本周期管控集成。

在这个过程中，配置管理同学梳理了代码仓库的目录结构和存储方式，并基于开发流程建立了在线提测平台，从而实现了研发过程的线上化以及权限管理的自动化。

接下来，配置管理与平台和流程相结合，开发过程开始向前、向后延展。

向前：在需求管理阶段，建立需求和代码的关联规范，严格约束代码提交检查，并且将构建工具和环境配置等纳入统一管控，可追溯历史变更；

向后：在部署运维阶段，定义版本发布和上线规则，建立单一可信的发布渠道，可统一查询所有正式发布版本的信息，包括版本关联的需求信息、代码信息、测试信息等。

团队在走上有序开发的正轨之后，就针对发现的问题，逐步加强了平台和自动化能力的建设。

代码提交失控：做集成线上化，测试验收通过之后，自动合并代码；

环境差异大：通过容器化和服务端配置管理工具，实现统一的初始化；

构建速度慢：通过网络改造和增量编译等，提升构建速度。

这样一来，版本发布这件事情，从原本耗时耗力的操作，最终变成了一键式的操作，团队也达成了预期的双周发版的目标。

在这个案例中，配置管理更多是从流程和平台入手，通过规则制定、权限管控、统一信息源，以及版本控制手段，重塑了整个开发协作的交付过程。

所以，在把握原则的基础上，面对诸多实践，想要确定哪些实践可以解决实际问题，最好是要从预期结果进行反推。

如果你不知道该从哪里入手，不妨看看现在的软件交付流程是否是由配置管理来驱动的，是否还有一些数据是失控和混乱的状态，版本的信息是否还无法完整回溯。如果是的话，那么，这些都是大有可为的事情。

总之，任何一家公司想要落地配置管理，都可以先从标准化到自动化，然后再到数据化和服务化。这是一条相对通用的路径，也是实施配置管理的总体指南。

问题三

度量指标要如何跟组织和个人关联？这么多指标，到底该如何跟项目关联起来呢？

我在第 19 讲中介绍了正向度量的实践，引发了一个小高潮。文章发出后，有不少同学加我好友，并跟我深入沟通和探讨了度量建设的问题。由此可见，当前，企业的研发度量应该是一个大热门。

但是，度量这个事情吧，你越做就越会发现，这是个无底洞。那么，在最最开始，有没有可以用来指导实践的参考步骤呢？当然是有的。我总结了四个步骤：找抓手、对大数、看差距、分级别。

第 1 步：找抓手。

对于度量体系建设来说，很多公司其实都大同小异。最开始的时候，核心都是需要有一个抓手来梳理整个研发过程。这个抓手，往往就是需求。因为，只有需求是贯穿研发交付过程始终的，没有之一。

当然，你也可以思考一下，除了需求，是否还有其他选项？那么，围绕需求的核心指标，首先是需要提取的内容。如果，连一个需求在交付周期内各个阶段的流转时长都没有，那么，这个度量就是不合格的。

第 2 步：对大数。

对大数，也就是说，当度量系统按照指标定义，提取和运算出来指标数据之后，最重要的就是验证数据的真实有效性，并且让团队认可这个客观数据。

很多时候，如果公司里面没有一套权威指标，各个部门、系统就都会有自己的度量口径。如果是在没有共识的前提下讨论这个事情，基本也没什么意义。所以，说白了，一定要让团队认可这些大数的合理性。

第 3 步：找差距。

抓手有了，核心大数也有了，大家也都承认这个度量数据的客观有效性了。但是，在这个阶段，肯定有些地方还是明显不合理。这个时候，就需要对这个领域进一步进行拆分。比如，测试周期在大的阶段里只是一个数字，但实际上，这里面包含了 N 多个过程；比如，功能测试、产品走查、埋点测试等等。

如果没有把表面问题，细分成各个步骤的实际情况，你就很难说清楚，到底是哪个步骤导致的问题。所以，在达成共识的前提下，识别可改进的内容，这就是一个阶段性的胜利。

第 4 步：分级别。

实际上，不是所有指标都可以关联到个人的。比如，如果要计算个人的需求前置周期，这是不是感觉有点怪呢？同样，应用的上线崩溃率这种指标，也很难关联到一个具体的部门。

所以，我们需要根据不同的视角和维度划分指标。比如，可以划分组织级指标、团队级指标和项目级指标。

划分指标的核心还是由大到小，从指标受众和试图解决的问题出发，进行层层拆解，从而直达问题的根本原因，比如用户操作原因、数据计算原因、自动化平台原因等等。当然，这是一件非常细致的工作。

我们再来回顾下，我们刚刚深入剖析了 3 个 DevOps 的典型问题。

首先，你要非常清楚地知道，DevOps 在面对未知需求时的解题方法和解题套路，那就是业务侧尽量拆解分析靠谱需求，交付侧以最快、最低的成本完成交付。它们之间就是一个命运共同体，一荣俱荣，一损俱损。

配置管理作为 DevOps 的核心基础实践，在实施的过程中，并不只局限在单一领域。实际上，要从研发流程优化的视角出发，驱动标准化、自动化和数据可视化的能力建设。

最后，关于度量指标部分，你要注意的是，向上，要支撑核心指标；向下，要层层分解，展示真实细节。

讲解完这 3 个典型问题之后，接下来进入第 2 部分，这也是我极力要求增加的部分。其实，我就是想跟你说说心里话。

如何高效学习？

跟你一样，我也是极客时间的用户，订阅了很多感兴趣的课程。在学习的过程中，我一直在思考，如何在有限的时间内高效学习。直到我自己成为了课程老师，从用户和老师两个角度思考这个问题，有了一些感悟，想要跟你分享一下。

忙，是现在大多数人的真实生活写照。我们每天从早到晚，忙于工作，忙于开会，忙于刷手机……忙得一塌糊涂。

但是，如果要问，过去的一天，自己都在忙什么，要么是大脑一片空白，要么是碎碎念式的流水账。可见，我们每天忙的很多事情，都没有什么价值。

其实，很多事情，都没有我们想象得那么重要。我们常常把目光聚焦于眼前，眼前的事情就变成了整个世界。但是，如果把时间拉长到一周，甚至一年，你会发现，这些事情，做与不做没有什么分别。

正因为时刻处于忙碌的状态，所以，抽出一整段时间学习，就变成了一件奢侈的事情。但我要祝贺你，因为至少你比大多数人有意识，有危机感，愿意拿出零碎的时间，来充实自己。

既然花了这么难得的时间，你肯定希望能有所收获，无论是在知识上，还是能力上，抑或是见识上，至少不白白浪费这段时间。

那么，我想问的是，你真的有收获吗？

史蒂芬·科维曾经说过，大多数人聆听的目的是为了“怼回去”，而不是为了真正的理解。

Most of people listen with the intent to reply, but not with the intent to understand.

这里面的“怼回去”稍微有点夸张，实际上，我发现，当我在交流的时候，脑海里总是不自觉地想象如何回复对方，而不是专心地听对方讲话，感悟他的意图和情绪。

所以你看，听这种学习方式，总是会受到固有思维模式的影响。也就是说，在很多时候，我们往往会把自己置身于一种评论者的身份。

那么，什么是评论者的身份呢？这就是说，站在一种置身事外的立场，以一种审视的角度，来看待每一件事情，并试图找到一些问题。当然，这些问题，都是在已有的认知局限中发现的。

这些反馈，对于知识的生产者而言，其实是一件好事，因为他能够时刻审视自己，反思自己，并从中找到不足之处。

但是，对学习者来说，能不能在学习的过程中，暂时放弃评论者的身份，转而做一个实践者呢？

比如，以极客时间的专栏为例，对于作者提到的内容，你有哪些不同的观点呢？面对同样的问题，你又有哪些更好的手段呢？

其实，每一个作者之所以能成为作者，都有他的独到之处。那么，能够让他的思想为你所用，让他的知识与你互补，让你自己成为交流的赢家，这才是对得起时间的更好选择。

最后，以极客时间的专栏为例，我认为：

60 分的体验，就是可以看完所有的文稿，而不是仅仅听完课程音频；

70 分的体验，就是可以仔细学习文稿中的附加资源，比如代码、流程图以及补充的学习信息等。这些都是精选的内容，可以帮助你在 15 分钟之外，扩充自己的知识面；

80 分的体验，就是可以积极参与到专栏的留言和讨论中，甚至可以就自己的问题跟作者深入交流，建立连接；

90 分的体验，就是可以结合工作中的实际场景，给出自己的思考和答案，并积累出自己的一整套知识体系，并且，可以反向输出给其他人；

100 分的体验，就是持续改进。我想，能够具备这种思想，可能要比 100 分本身更重要。

那么，你想做到多少分的体验呢？你可以自己想一想。

好了，接下来，我们即将进入“工具实践篇”，希望你可以继续保持学习的热情，坚持下去，期待美好的事情自然发生。

思考题

对于前面已经更新的内容，你还有什么疑惑点吗？或者说，你在实践的过程中，有什么问题吗？

欢迎在留言区写下你的思考和答案，我们一起讨论，共同学习进步。如果你觉得这篇文章对你有所帮助，也欢迎你把文章分享给你的朋友。

期末总结 | 在云时代，如何选择一款合适的流水线工具？

你好，我是石雪峰。今天是期末总结，我们来聊一聊，在云时代，如何选择一款合适的流水线工具。

在过去的几年里，我一直专注于软件持续交付的工程实践领域。我发现，越来越多的公司（无论规模大小）开始重视软件持续交付能力的建设了，基本上每家公司都有自己的流水线平台。

以前提到 CI/CD 工具，基本上就默认是 Jenkins，也没什么其他太好的选项。但是最近两年，随着云容器技术的快速发展，在 CI/CD 流水线领域，新工具和解决方案出现了爆发式的增长。比如不甘寂寞的 GitLab CI、轻量级的容器化解决方案 Drone。最近一段时间，GitHub 的 Actions 也火了一把。可见，作为软件交付主路径上的核心工具，流水线是每一家企业都不愿意错过的领域。

对于行业发展来说，这当然是好事情。老牌工具 Jenkins 自己都开始反省：“在云容器时代，是不是过于保守？十几年的老架构是否已经难以支撑云时代的快速发展了？”于是他们就另辟蹊径，孵化出了 Jenkins X 项目。

但是，对于用户来说，选择工具时就很为难：“这些工具看起来大同小异，要解决的也是类似的问题，到底应该选择哪个呢？”

今天，我就来给你梳理一下流行的 CI/CD 工具，并给你提供一些选择建议。我挑选了 5 个工具，分为 3 组介绍，分别是 Jenkins 系的 Jenkins 和 Jenkins X、版本控制系统系的 GitLab CI 和 GitHub Actions，以及新兴的、正在快速普及的云原生解决方案 Drone。我会从 5 个方面入手，对它们进行对比和介绍，包括工具的易用性、流水线设计、插件生态、扩展性配置以及适用场景。

Jenkins/Jenkins X

关于 Jenkins，我想已经不需要做太多介绍了。在过去的 15 年里面，Jenkins 一直都在为无数的软件开发者默默服务。从一组数字中，我们就能看出来它的影响力：官方能统计到的集群数有 26 万多个、插件将近 1700 个、执行的任务数超过 3000 万次，这还不包括大量公司自建、本地电脑运行的节点信息。另外，一年两次的 Jenkins 全球大会往往能够吸引上千人参与，这对于国外的技术大会来说，已经是超大规模的盛会了。

当然，Jenkins 的优缺点也很明显。

优点：普及率高，搞过开发的基本应该都接触过；插件生态成熟且丰富，可以适用于任何场景。

缺点：软件架构和 UI 设计风格有些过时，配置操作比较复杂；插件的安全性、通用性方面也存在很多问题，最重要的是，在云容器领域，多少有些格格不入。

我重点说说 Jenkins X。很多人都不清楚 Jenkins 和 Jenkins X 是什么关系，这就好比刚开始我们很难说清楚 Java 和 JavaScript 的关系一样。实际上，JavaScript 除了名字上带有“Java”字眼，蹭了个热度之外，本质上它们之间并没有什么关系。而对于 Jenkins 和 Jenkins X 来说，虽然并不能说二者一点关系没有，但其实它们面对的场景和要解决的问题是不同的。所以，并不能说 Jenkins X 就是下一代 Jenkins，或者是 Jenkins 迟早会迁移到 Jenkins X 上面。

Jenkins X 最开始的确是作为 Jenkins 的子项目存在的，但是发展到现在，它已经有了独立的品牌和 Logo，并且和 Jenkins 一起作为 CDF（持续交付基金会）的初始项目。Jenkins X 想要解决的核心问题是 Kubernetes 上的原生 CI/CD 解决方案。所以，Jenkins X 和 Kubernetes 是强绑定的关系，它致力于通过一系列的自动化工具和最佳实践，来降低云原生环境下的研发配置和使用 CI/CD 的成本，并尽可能地做成开箱即用的状态。

而 Jenkins 更像一个百宝箱，你可以通过插件扩展来解决各种各样的问题，并没有一定之规。

我给你举个例子，来形象地对比一下 Jenkins 和 Jenkins X 这两个项目。

Jenkins 就好比你在开车，你知道目的地，但是走哪条路，开多快，中间要不要休息一下，什么时候加油，这些都是你自己来决定的。当然，灵活性带来的就是多变性，你并不知道是不是下一秒就封路了或者是汽车突然坏了。

而 Jenkins X 更像是一辆高速列车，你只要上对了车，列车会把你安全、快速地送往目的地，而你并不需要关心这个车是怎么设计的，时速应该是多少，甚至你在哪里能够下车，它都规定好了。

Jenkins X 项目中内建了大量的开源工具和解决方案，可以说是开源工具的理想国和试验田，核心目的就是为了简单、快速、开箱即用。比如对 Tekton 的集成，就被视为对 Jenkins 自身的颠覆，因为这彻底改变了 Jenkins 流水线调度机制。因为在 Jenkins X 看来，Jenkins 只不过是 Jenkins X 中的一个应用，是一个黑盒子，编排通过 Tekton 来实现，换句话说，即便你想用其他应用来取代 Jenkins，也不是不可能的。

值得注意的是，Jenkins X 中有很多约束，比如你必须使用 GitOps 的方案来完成应用的晋级和部署，没有其他的选择。如果你没有使用 Helm 管理应用，也不想使用 GitOps，那就现阶段来说，Jenkins X 对你就不是一个可选项。

我们来总结一下 Jenkins X 项目：

工具的易用性：采用了开箱即用的设计，提供大量的模板来降低新应用上手 CI/CD 的成本。虽然安装复杂，但是目前已经提供了 JX Boot 工具，通过初始化向导帮你完成环境搭建。而且，随着云服务商的引入，环境方面应该都是可以默认提供的，就像你不需要操心如何搭建 Kubernetes 一样，因为会有人以服务的形式把 Jenkins X 提供出来。

流水线设计：Tekton 取代了 Jenkins，成为了流水线的默认引擎，作为 Kubernetes 的原生解决方案，这也是未来的发展趋势。在编排方面，它采用了 yaml 方式，继承了原有 Jenkinsfile 的语法特征，并对 Tekton 的资源进行隐藏和抽象，通过描述式的语言，以代码化的方式实现，可以说是当前的通用解决方案。不过，它目前并没有提供可视化的编排界面。

插件生态：继承了 Jenkins 丰富的插件生态，以及庞大的开发者社区。

扩展性配置：采用容器化的解决方案，对于 Tekton 来说更是如此。每个步骤都在容器中完成，可扩展性非常强。

适用场景：我认为，Jenkins X 项目现在还处于快速开发的阶段，适用于原型产品验证。对于那些没有固有模式，想要沿用 Jenkins X 的设计流程的项目来说，可以尝试使用。不过由于云服务商的接入度不足，目前应该还存在很多挑战，你可以保持学习和跟进。毕竟，这个项目中的很多工具和设计思路都是非常有价值的。

GitLab CI/GitHub Actions

除了 Jenkins，国内使用比较多的应该当属 GitLab CI 了。前些年也有过社区的讨论，到底应该使用 GitLab CI，还是 Jenkins？很显然，这样的讨论并不能达成共识，毕竟“萝卜白菜，各有所爱”。而 GitHub Actions 的推出，也是看中了流水线编排领域的“蛋糕”。曾经，GitHub 和 TravisCI 是珠联璧合，可以说是“开源双碧”。GitHub 也一再强调，自己只想把代码托管服务做到极致，其他领域都交给合作伙伴完成。但是今天的 Package 功能和 Actions 功能都体现出了 GitHub 自建生态的野心。

其实，这两个产品有很多相似之处，因为它们都是依托于一个成熟的代码托管平台衍生出来的原生流水线功能。

对于软件开发而言，最重要的无疑就是源代码。之前，我有个同事就说过，只要掌握了源代码，你就可以为所欲为了。比如，基于代码拓展代码评审工具、内建各类静态动态代码检查功能、增加包管理和依赖管理工具等，这些是代码编译之前和编译之后的必备功能。增加内建的持续集成功能，也有助于在代码评审的时候做到机器辅助。

当这些功能都集成到代码托管系统中时，你就会发现，它不再是一个简单的版本控制系统了，而是一整套 DevOps 平台。它们的设计理念是，一个平台解决所有 DevOps 的工具问题。这一点在 GitLab 的路线图规划中，也体现得淋漓尽致，GitLab 对主流工具都进行了对比，并提供了一个工具的全景图。可以说在行业对标方面，GitLab 是做到极致了。你可以参考一下下面这张全景图和他们自己写的对比文章。

图片来源：https://about.gitlab.com/devops-tools/

回到流水线方面，GitLab CI 和 GitHub Actions 都和版本控制系统进行了深度集成。我们还是从五个方面来整体看一下。

1. 工具的易用性

易于上手：由于是内建功能，GitLab CI/GitHub Actions 使用起来都非常简单，你并不需要单独构建和维护一个独立的 CI 服务器来实现这个功能。

原生体验：由于是原生功能，所以无论是在流水线状态展示方面，还是在代码评审流程的集成方面，它们都做到了原生化的体验，显示的信息和丰富程度是外部独立的 CI 工具所无法比拟的。

一体化协同平台：工具链繁多、集成配置复杂、信息分散，都是 DevOps 工具方面的痛点问题。而一体化的研发协同平台的价值就在于能够集中解决这些问题。开发者不需要在各种工具系统中跳来跳去，可以在一个地方解决所有问题，在一个地方看到所有有用的数据。

在线文档：GitLab 的文档和示例都非常丰富，GitHub 就相对薄弱一些，不过两者的文档基本都够用。

2. 流水线设计

流水线描述：GitLab CI 和 GitHub Actions 都采用了 yaml 形式的流水线过程描述文件，二者的语法规则虽然不同，但基本上大同小异。但相对来说，GitHub 的语法规则更加符合当前 Kubernetes 的资源描述风格。关于这两个产品的语法风格，你可以看下这两份资料：GitHub Actions，GitLab CI

流水线编辑：两个产品都支持在线编辑流水线文件，GitHub 在这方面更加人性化一些。当你打开 Actions 的时候，系统会给你推荐一些模板，你可以直接选择生成 Actions 配置。如果想自己编辑 Actions 文件的话，系统的右侧也提供了很多示例代码片段，让你可以通过简单的复制、粘贴完成这项工作。另外，GitHub 新版本提供了在线的可视化编辑器，毕竟 GitHub Actions 是全新设计的，集合了各方面的优势。

3. 插件生态

GitLab 生态：作为一个开源软件，GitLab 的优势也恰恰在于开源，官方对于社区 PR 和 feature 的响应也是非常及时的。但是，由于 GitLab 是基于 Ruby 语言、Rails 框架开发的，这个语言就成了比较大的瓶颈，毕竟，熟练掌握 Ruby 语言的国内开发者相对还是比较少的，所以 GitLab 的插件生态并没有做起来。

GitHub 生态：GitHub 有建设 Marketplace 的长期经验，再加上开源贡献者众多，所以，在短短一年左右的时间里，他们已经积累了 1700 多个 Actions 组件，可以帮助你快速地搭建自己的流水线。从扩展性和生态丰富性方面来说，GitHub 更胜一筹。

使用成本：必须要强调的是，GitHub 是商业软件，虽然对待开源项目采用免费策略，但是如果企业级使用的话，成本也是必须要考虑的因素之一，而自建 GitLab 如果采用社区版本，就没有这么多限制了，这也是优势之一。

4. 扩展性配置

它们都支持多种环境类型。GitLab 很早就提供了对容器和 Kubernetes 的支持，GitHub 在这方面自然也不会落后，官方提供了 Linux、Windows 和 Mac 环境的支持，你也可以自建节点并注册到 GitHub 中。不过必须强调一点，GitHub 如果是非企业版本的话，是不支持私有化部署的，这也就意味着，如果你想把企业内部的资源注册到 GitHub 上，那么就意味着这些资源必须对外可见。

5. 适用场景

由于国内 GitLab 自建服务的普及，如果你对 CI 的功能要求没有那么高，那么 GitLab CI 就足够了。但是，在功能广度方面，由于缺少庞大的插件生态，很多功能还是更多地依赖于你自己实现，所以，如果软件交付流程非常复杂，依赖于多种环境，GitLab CI 就不是那么适用了。

而 GitHub 在企业中的使用场景就更加有限了，一方面是成本问题，另一方面，SaaS 化服务依赖于内部开放性。所以，如果是开源项目，或者创业项目不希望自己维护一套很重的研发基础设施，那么我建议你考虑使用 GitHub 的方案。

在最新发布的 2019 年 Forrester 的趋势报告中，GitLab 和 Jenkisn 都入选了云原生 CI 工具的榜单，并且处于行业领先地位，你可以看一下报告的图片。虽然图中没有写明 Jenkins，但是其背后的 CloudBees 公司，以及目前在云原生项目 Jenkins X 中有深度合作的 Google 公司都处于领先地位，由此可以看出，各大公司都已经开始在云原生领域布局了。

Drone

这也是一个近来冉冉升起的 CI 工具领域的新星。在咱们专栏的留言中，有很多同学提到过这个工具，可见，好工具是会自己说话的。

Drone 主打的就是云原生 CI，整体设计非常轻量级，即便没有什么经验，一两天也能快速上手搭建。在我看来，Jenkins X 虽然也是主打云原生，但由于引入了大量组件和流程约束，整体还是略显笨重一些。相反，Drone 的实现非常优雅，无论是流水线的语法，还是环境的扩展性方面，都让人不由得赞叹。

作为一个开源软件，Drone 使用 Go 语言实现。在我看来，Go 就是为云原生而存在的，无论是 Docker、Kubernetes，还是我参与的 Jenkins X 项目，都是通过 Go 语言来实现的。所以，这个项目对于内部开发团队快速提升 Go 语言的 DevOps 平台建设能力，也是一个很好的参考学习案例。

对于 Drone 平台，我目前也在学习和探索阶段，我从下面这几个方面谈谈我个人的看法。

1. 工具的易用性

Drone 的搭建非常简单，你可以采用自建服务的形式，也可以使用 SaaS 服务。UI 风格设计体现了恰到好处的理念，整体非常清爽，同时也能跟其他工具（如 GitHub）进行集成。

2. 流水线设计

作为云原生的解决方案，流水线同样采用 yaml 形式、具备描述式表达和流水线即代码的功能。虽然没有过于复杂的语法，但是 Drone 的流水线语法风格是我个人最喜欢的，它的结构非常清晰。

3. 插件生态

Drone 也提供了插件机制，而且官方还提供了对主流版本控制系统和云服务商的集成支持。虽然数量远远比不上 Jenkins 生态，但是你能想到的基本都有了。比如常见的 Artifactory、SonarQube、Ansible 等工具，甚至还包含了对微信、钉钉这类国内流行的通讯软件的集成。由于它的开放特性，未来它也会提供更多的插件。

4. 扩展性配置

对于 Drone 来说，最大的特征就是容器优先。上面提到的这些工具虽然都支持容器，但是并没有把容器作为默认支持的第一选项。而在 Drone 中，容器则是标配，这也是典型的云原生 CI 工具的特征：一切都在容器中运行。也正因为如此，非容器化开发部署的项目如果采用 Drone 就不太合适了。另外，除了容器方式之外，Drone 也支持本地执行，这为一些特殊的场景提供了可能性（比如绑定设备的自动化测试等）。

5. 适用场景

我认为，Drone 在云原生 CI/CD 方面的设计代表了未来的趋势。对于基于容器开发交付的产品来说，如果你在寻找一个对应的云原生解决方案，那么我推荐你用 Drone。它也比较适合于中小型团队、初创公司想要快速受益于 CI/CD，又不想投入太多精力的场景。同时，作为一款 Go 语言开发的开源软件，随着业务扩展，你大可以自建插件，满足差异化的需求。

总结

最后，为了方便你理解和进行对比学习，我把这五个云原生流水线工具的特征汇总了图片里。

到此为止，这几款主流的流水线工具，我就介绍完了。在文章的最后，我还想再补充两点：

工具并非决定性的因素，不要轻易陷入“工具决定论”的思想之中，就好比真正的编程高手可能都不需要 IDE，选择好的工具，并不代表就有好的结果。

工具是“存在即合理”的，它们都有各自擅长的领域，没有绝对意义上的最好，只有最适合的场景。另外，即便是同一个工具，在不同的人手中发挥的作用也不一样，选择自己最熟悉的工具，一般都不会有错。比如你要问我选择什么工具的话，我肯定推荐 Jenkins。但这并不是因为 Jenkins 完美无缺，而仅仅是因为我用得顺手而已。

思考题

对于 Drone 这款工具在生产环境的应用，你有哪些实际的经验，又踩过哪些“坑”呢？

欢迎在留言区写下你的思考和答案，我们一起讨论，共同学习进步。如果你觉得这篇文章对你有所帮助，也欢迎你把文章分享给你的朋友。

结束语 | 持续改进，成就非凡！

不知道你是否看过或者听说过《中国好声音》这个节目？在这个节目中，导师总会发出“灵魂拷问”：“你的梦想是什么？”

和很多“80 后”的男孩子一样，我最初的梦想就是当一名飞行员，翱翔天空。但是随着视力越来越差，身体越长越高，我才发现，并非所有的梦想都能实现。好在我还留了一手，因为我还有另外一个梦想，那就是当一名老师。现在，我的这个梦想已经在极客时间上实现了。

为什么想当老师呢？说真的，我也不记得当初是怎么想的了，可能是因为在中小学生眼中，老师这个形象都是霸气侧漏的。但随着年龄的增大，我越发觉得，当老师这个事情真的没有那么容易。你应该也听说过“教学相长”这个词，但你有没有想过，“教”为什么在“学”的前面，是“教学相长”，而不是“学教相长”呢？

或许，只有当你的身份从一名学生变为一位老师的时候，你才能真的想明白这个问题。实际上，很多时候，教的人可能比学的人收获要大得多。为什么这么说呢？

任何一门课程，任何一个知识点，你在学的时候可以不懂，大不了就当没听过，等到真正用到的时候，临时再学也是可以的。但是，作为老师，你不仅要懂，还要逻辑清晰、思维缜密，甚至要尽可能地用有趣的方式把别人教会，这可就没那么简单了。

不过，任何一个知识领域都是博大精深的，你不可能对每一个细节都了如指掌，这就会逼着你不断学习、不断思考、不断精进。我想，这就是输出式学习之所以高效的奥秘所在。

对于专栏写作来说，这个道理也同样适用。几个月的持续输出，无论是对精力、体力，还是家庭和谐力都是一场漫长的试炼。在专栏完结的时间点，我看到的不仅仅是 20 万字的内容，更多的是自己身上的不足，而这些都是我成长道路上的灯塔，指引我面向未来，持续精进。

在最后，我想给你分享我在专栏写作中的三个心得，希望这些心得可以帮助你在未来的学习道路上披荆斩棘，无往而不利。

当你跨越技术领域的门槛之后，知识的体系化程度就成了决定你未来发展高度的一个重要因素。只有建立了自己的知识体系，并不断地吸收外界精华，你才能让这些知识和经验在身体内不断循环、沉淀，并最终成为你的一部分。这也是写作专栏几个月以来，我想给你分享的第一个心得：建立自己的知识体系，持续进行输出式学习。

对于一篇专栏的写作来说，你知道什么时间点最可怕吗？那就是当你打开一个空白的文档，却不知道第一个字应该写什么的时候。这跟我们平时的工作是很相似的，你知道这件事要做到什么程度，可就是不知道该如何开始。脑子里思绪万千，身体的疲劳有时还在同你作对，当你在不断地自我怀疑的时候，时间却悄悄地跑掉了，而你终究还是得自己面对这个问题。这该如何是好呢？

有句经典的话大概是这么说的：“一件事情，当你不想去做的时候，理由可以有一百个，但是当你决定做的时候，理由只有一个，那就是做。”很多事情并没有你想象的那么困难。我们不是科学家，也不是要解决人类的未解之谜，我们面对的都是身边的问题。我们之所以觉得这些事情很难，缺少的往往不是能力、经验和学识，而是“先干再说”的勇气和信心。因为只要开始做了，你就已经成功一半了。对于 DevOps 这种改进类工作来说，更是如此，你要先想尽一切办法完成它，有机会再追求完美，这可比一开始就全盘规划要实际得多。这也是我想分享给你的第二个心得：完成比完美更重要，很多事情可以先干再说。

我们家也有一句特别经典的话，那就是有日子就快。这句话的意思就是，对于一件事情，你只要确定了里程碑，时间就会带领你快速地抵达那个终点。比如，对于一个项目的推进来说，事先看见全貌和里程碑节点就是至关重要的。在专栏的写作过程中，我认为最最重要的一份素材，就是编辑同学帮我整理的《专栏发布排期计划》，里面注明了我每星期、每天需要完成的任务。

虽然计划就是为了被打破而存在的，它永远也赶不上变化，尤其是在软件的世界里，Delay 似乎是一件不可避免的事情，但是，这个计划存在的目的是帮你守住一件事情的下限。既然最差也就如此了，多做一点就多一点成功，那你又何必纠结和焦虑呢？所以，在推进项目的时候，尤其是在依赖多人协作的时候，一个清晰的项目计划至关重要。这恰恰是我想分享给你的第三个心得：让计划帮你守住底线，让行动为成功添砖加瓦。

我想，此时此刻还在坚持看下去、听下去的你内心里一定有一团火焰，激励着自己有朝一日可以脱颖而出。因此，在最后的最后，我特别想给你分享一些我个人的职业生涯发展的经验，这也是帮助我从一个默默无闻的小兵成长为极客时间作者的秘密。

1. 找到自己适合的领域

要知道，并非所有人都适合所有领域。有的人天生就是编程高手，有的人天生就爱与人沟通，与其在你不擅长的领域死磕，不如找到自己擅长的领域并不断深耕。与此同时，要以这个领域为起点，不断向外扩展，营造自己的“护城河”体系，提升自己的专业素养。这些是你将来安身立命的本事，你一定要让自己有几个拿得出手的核心技能。如果你现在还答不上来你擅长的领域和核心技能是什么，那么 2020 年，请继续努力。

2. 打造自己的专属标签

当你掌握了一门核心手艺之后，你可以在这个圈子里不断地总结和分享，建立起别人对你的初始认知。只要你用心，你就会发现，这种分享的机会其实有很多，如果你苦于没有途径，欢迎你来找我。

不过，这还并不足以让你脱颖而出，最多也只能达到平均水准。这时候，你需要的就是等待一个机会，比如一门新技术、一种新思想、一个新工具，什么都可以。然后，你要快速地抓住这个机会，让自己站在第一线，去分享，去实践，去布道，让它成为你的专属标签。

3. 不断积累成功，打造自己的良好口碑

你要知道，有一种能力，叫作“让别人相信你”的能力。企业在为某个职位寻找合适的人选时，为什么选你而不选别人呢？除了你自身过硬的技术素养之外，你能不能让别人相信你的能力，是你能否突破天花板的重要因素。那这种能力从何而来呢？我认为，这是来自于过往点滴的积累，最终由量变产生的质变。所以，请你善待每一个机会，善待每一个人。在企业中，要么提升自己的执行力，要么提升自己的创新力，要么让自己能够快速地整合资源，只有这样，你才能具备成功的资本。

4. 保持责任心、进取心和事业心

不管做什么事情，最重要的就是责任心，要把自己该做的事情做好，做正确的事情，而不仅仅是 KPI 要求的事情。另外，你要保持进取心，并且对新事物、新技术保持长久的好奇和开放的心态，而不是故步自封，局限在自己的一亩三分地上。如果可能的话，要把自己的工作视为一个事业，你要保持着“每一行代码都是你的名片，每一个产品都是你的代言人”的信念，和团队一起努力，共同成长，只要还有一丝改进空间，就不要轻言放弃。

正如这篇文章的标题所说的，只有持续改进，才能成就非凡，也必将不枉此生。

希望这个专栏能够带给你一些灵感和新知，不管怎样，感谢你陪我一起走过 2019 年的夏天、秋天和冬天。

最后，我给你准备了一份调研问卷，欢迎你点击下面的图片，去填写问卷，给我和专栏提供一些宝贵的建议，期待你的反馈。

P.S. 最最后，感谢我的夫人在这半年里给予我的无私“支持和理解”，如果不是她，这个专栏早就写完了。