DevOps是软件研发的洗碗机
原创:BrianKelly(2019年8月12日发表的一篇博客文章)。本文授权转载自公众号老丛讲桌,特此感谢。
最近一篇博客文章突然爆火,许多敏捷、精益、DevOps大咖都在转发这篇文章。Brain Kelly通过洗碗这件事,通俗的解释了两个重要概念:Donald Reinertsen提出的U曲线和DevOps。正是这个通俗的例子,让大咖们拍案叫绝。虽然最近忙的团团转,还是决定花几个小时时间,把这篇文章翻译出来,介绍给大家。
这是一篇关于洗碗的故事,也是一篇关于DevOps的文章,但主要是洗碗。
在聊洗碗和DevOps之前,先介绍一个十分重要但大家知之甚少的概念:U曲线。
如果你读过Donald G. Reinertsen那本具有里程碑意义的书:The Principles of Product Development Flow(老丛讲桌多次推荐过).你已经知道U曲线是什么东东了,估计你也能猜到它和洗碗比喻的关联在那了。如果你是干软件的,还没读过这本书,那还等什么呢?
那么究竟什么是U曲线呢?想象下你要处理一些事情,你可以选择不处理,把它们放在那(形成等待队列),这样会产生储备成本(holding cost)。当你处理这些事时,会产生处理成本(Transaction Cost)。如上图所示,U曲线就是二者之和的形状。
这个曲线的精妙之处是可以帮助我们找到要处理任务的最佳批量规模(batch size)。
如果你已经有点晕了,那就正常了!所以需要用一个日常生活的例子和更多的图像把它解释清楚。
用手洗碗的U曲线
咱们来看看用手洗碗的成本(放心,很快你会看到它和软件的关系!)。
把一个脏碗完全洗干净,我们需要干下面几件事:
- 放下手头的事去洗碗
- 准备好热水、洗碗液、刷碗布
- 用热水和洗碗液洗刷脏碗
- 用水将碗清理干净
- 用布把碗擦干净
这一系列活动代表用手洗碗的处理成本。不论你是洗一只碗,还是把厨房里的所有脏碗都洗完,这些活都跑不掉。差异是你一次选择清理几个碗,这就是所谓的批量规模。
一般刷个碗需要几分钟时间,显然用完就洗就不那么高效了。通常我们会先把脏碗放在水池里,等积攒一些后,再一起清洗。
上图中的红线代表洗碗的处理成本,灰色代表储备成本,紫色则代表二者之和的总成本,它形成了一个U形状。用手洗碗的最佳批量规模就是“U”图的最低点。
优化用手洗碗流程
如果一次仅洗一个碗,那么处理成本会非常高,因为洗每个碗都需要许多准备工作。
如果一周洗一次,处理成本会大大下降,但储备成本会变得很高:没有足够的干净碗用,厨房脏乱不堪,可以用来准备食物的空间会减少。(这让我想起了当年学生时代的宿舍。)
其实咱们人类在不经意中常常能够找到优化总成本的点,平衡储备成本和让一堆脏碗坐在水池中造成的后果是我们与生俱来的能力。
对一个一手拿洗碗液,一手拿洗碗布的人来说,找到U曲线的最低点就够了。换句话说,不对系统做根本的变更,很难大幅度降低洗碗的总成本。
用手洗碗,嗯,软件
我答应过要把这个例子和软件以及DevOps串起来,这就说给你听听:
脏碗:已经完成编码但尚未发布的新功能和修复。
干净碗:已经发布而且用户在用的新功能和修复。
处理成本:用来构建软件发布版本并部署到生产的过程。
储备成本:这就多了,如没能获取用户对新功能的反馈,维护未发布的代码,不知道这些新功能能否在生产环境下真正发挥作用等。
在软件世界里,用手洗碗就像缺乏自动化手段的产品发布。人工构建,通过进入服务器中,手敲指令部署变更;手工编译ChangeLog entries,等。这就等同于“用手洗碗”的软件世界。
等待队列真的是很糟
一堆脏碗代表不断增加的队列。在任何系统里–无论是电子化的还是人的系统–队列都是健康流动(FLOW)的天敌。队列增长可以增加交付延迟,也是未来问题的征兆,它让反馈不能闭环。
不幸的是,长长的队列让人变得低效。想象下测试人员被要求去测试一个花了几年时间开发出来的软件,听到这样的哭诉应该不奇怪“测试这么大的版本,实在无法记住所有的变更啊!”
从人的天性来讲,长长的队列让人头皮发麻,下决心去处理这些事情变得更难,结果是队列越来越长。在洗碗的例子里,看到水池中满满的脏碗,想象下至少1-2个小时的洗碗工作量,更会让人望而却步。(同样有拖延症的朋友,咱们真需要注意了!)
长长的队列(或者一堆脏碗)会让处理工作变成关注的重心,对处理工作量增加的恐惧,让我们围绕着它们(transaction)形成习惯和常规,而对增长的队列却视而不见。我们仅关注做好处理工作的要求,而忽略了用户的需求。
回到咱们洗碗的例子,多少人习惯性的堆积用过的碗,把周末早上定为每周法定洗碗时间。一个靠手工发布的团队,一定最终会形成一套复杂的流程、指南、手册,但发布一定极不频繁,这也会变成团队文化的一部分。
缺少自动化的过程,天性会让我们滑向U曲线的右边,减少处理频率,导致批量规模越来越大。如果你听到这样的对话,“先别测试,再等一天吧,我们还有一个Bug要修复…”恭喜你,你在目睹这样一个现象。
引入自动化:传统的洗碗机
洗碗机算是一个有价值的发明,但它还是不能完全解决我们洗碗优化的问题。它能做的是更加容易帮助人们找到U曲线的最佳点。
它是怎么做到的呢?
首先我们不再惧怕处理(洗碗)工作了,洗满负荷的碗,洗一个碗,工作量对人而言没有什么区别了。这就导致我们会经常洗碗,批量规模变低,总成本变低。
用洗碗机时,一般不会只放一只碗,也不会把它塞得满满的,最常见的是差不多快满了就用一次。
虽然处理成本不低(洗一次需要几个小时),但这是机器在跑,人可以同时做其他事情,用手洗碗所带的机会成本完全不见了。
现在批量规模有了上限,洗碗机的容量是固定的,满了你就必须洗。
用洗碗机也大大降低了手洗摔碗的风险。
但是洗碗的仪式依然存在,个人活动还是要围绕洗碗机转。“晚饭后用洗碗机洗碗”成了多少人的日常习惯。
洗碗机和软件
引入洗碗机,对软件来讲,就像是将发布过程中容易出错的一些步骤自动化,但基本流程没变。
它的好处是增加了发布频率,让批量规模变得更优,但线条和曲线并没改变。换句话说,自动化让发布变得不那么可怕了,但没有从根本上改变可优化的空间。
是讲DevOps的时候了。
隆重推出DevOps洗碗机
咱们发挥下想象力,设计一台具备下列功能的乌邦托洗碗机:
- 脏碗从不积压
- 碗用完就被清洗
- 我们完全不需要担心洗碗的投入
- 我们不需要优化每次洗碗的个数
- 洗碗机变得完全自动化并且不可见,我们无需再关注它,可以安心做其他事情
通过智慧的运用新技术,这样的智能厨房能实现这样一个我们关注的目标:总有源源不断的干净碗等着我们用。
具体来讲,我们需要构建这样一个机器人洗碗机,它有无穷无尽的热水和洗碗液,可以自动在第一时间把放在水池子里的碗拿过来,快速洗干净并擦干,然后把它放到碗柜里该放的地方。
如果一堆脏碗同时出现在水池里,(这里我需要发挥下想象…),一群机器人洗碗机会神奇的出现,同时并行清洗它们。用过的碗永远不会积压,洗干净的碗会立即出现在碗柜上。
注意这个发明改变了洗碗的方式,处理曲线大大下降,它也大大改变了U曲线,让最低点变得更低了,批量规模的减少让这些成本节省变成了可能。
建造一台DevOps洗碗机
把这台奇妙的洗碗机放到软件世界里的话,它会包含这些部件:DevOps, CI/CD, pipelines, trunk-based development, value stream mapping, infrastructure-as-code, and more.这些是让你产品代码库的变更能在第一时间被送达用户手中所需要的东西:
- 团队不断交付小规模的功能包(trunk),避免大的branches
- 有一个靠谱、可扩张的持续集成系统(Continuous Integration (CI) system),做到自动测试并构建新提交的代码
- 快速、可靠、高覆盖的自动化测试
- 一个可以自动将新代码纳入生产环境中运行的持续交付系统(A Continuous Delivery (CD) system)
- 有一个灵活、可编程、可靠的基础设施
- 开发和运维通力合作,对如何保证整个系统的健康和响应能力达成共识
不论你有什么语言描述上面提的这些东西(放在一起姑且称之为DevOps),他们就是神奇机器人洗碗机在软件中的等价物。如果使用得当,它们可以把批量规模变得微小,让等待队列消失,大大节省总的成本。
不断部署小的变更也可以减少生产环节的问题、风险。有多少个bugs会隐藏在10行代码中呢?如果是1万行呢?出问题的概率随着批量规模的增加会极速提升,所以高频率小规模的部署比将几个月开发出来的代码一次部署要安全得多。
行动起来去构建这样的洗碗机吧
现在你理解了U曲线,以及批量规模,处理成本,储备成本,风险之间的经济关系,也许你可以举一反三,将其应用在生活和工作的其他领域。
也许下一次,当你参加团队会议,讨论何时手工发布一堆积累了数周的新功能时,在你的脑海里会出现堆积一水池的脏碗,同时你也开始想象该用什么样神奇的方式去清洗它们。
DevOps图书推荐:
《发布!设计与部署稳定的分布式系统(第2版)》
《凤凰项目(修订版)》
《DevOps实践指南》