2017.09.15 丨 msup
【万字长文】徐磊:DevOps实施落地的2大法宝——粒度x26解耦(线上分享实录)
2017.09.15 丨 msup
本文为徐磊老师线上分享《 DevOps实施落地的2大法宝——粒度&解耦》实录,后附与学员的互动问答。
编辑:Cynthia
一句话概括我所做的事情就是:帮助研发团队改进研发流程,包括使用工具、使用方法、借鉴他人经验等方式,让大家的软件开发效率变得更高。
——徐磊
微软MVP & Regional Director
Certified ScrumMaster & DevOps Master
《凤凰项目》沙盘认证讲师
我的DevOps之路
DevOps这个词从一出现就受到很多关注,尤其是近一两年来变得非常热,以致大家对DevOps有很多的误解,这种热度确实有一定的炒作的成分,但个人觉得任何事情的出现和流行都有其内在的原因,DevOps也不例外。
本篇简单总结过去十年我所做的相关的事情,通过我的经历来看过去十年DevOps在国内的发展历程。希望这个过程可以帮助大家了解:DevOps到底是什么、是做什么的、能帮到我们什么。由于是结合我个人经验来谈DevOps,所以很多说法会带有个人的主观判断,分享给大家,旨在一起探讨。
之所以把第一个时间点放在2005年,是因为这一年我从澳洲回到北京,组建了一家外企研发中心。在这之前我就是一个纯粹的开发人员,写code、做项目、做产品、做发布,从2005年起我的角色开始转变,开始要去带一个团队,并从团队的角度考虑问题。
当我在国内找到了几名开发人员和我一起做一些项目的时候,我发现了第一个问题:当时我们的源代码管理服务器处于澳大利亚悉尼,在北京如果想要把代码提交过去非常痛苦。这种痛苦到什么程度呢?我们切入一个文件大概需要十分钟的时间,这是非常让人无法容忍的事情,会严重造成工作效率的低下。
我们找各种办法希望能解决这个问题,包括提高网络连接,但遗憾的是没有找到更好的办法。老板和微软的关系特别好,他看到了微软一个还没有发布的产品——TFS(当时还处于beta版本),我们注意到这个产品是因为它的source control是基于HTTP的,所以我们决定把现在基于VSS的source control迁移到基于HTTP的TFS的source control上。从2005年开始大概持续了两年的时间,我把公司所有的项目从VSS迁移到了HTTP。
其实VSS也是一个很不错的source control,但当出现这种跨地域访问的时候它的性能就会有很大的问题。这是我接触专业的软件工程工具或开始去想如何提高团队效率的一个起点。
第二个关键时间节点是2008年,当时我和微软组织了一个叫VSTS Real World的活动,这场活动实际上就是:我们找到了很多国内有影响力的独立软件开发商,把其中比较资深的软件开发人员集中到一起,让他们去体验如何在一个完整的软件工程管理平台上,完成一个软件从需求到分析到开发到测试到打包到发布的过程。
从微软的角度来说,是希望推广他们的工具;从我的角度来说,是第一次完整地把自己之前在软件交付整个端到端的流程方面的经验分享到自己团队之外去。
活动开发的项目是以汶川地震这个背景为假设场景,要求开发一个叫“孤儿领养”的系统。
这个项目对我个人来说非常重要,它是我作为软件工程顾问所完成的第一个完整的项目。虽然是一种培训的交付形式,但其实在制作这场活动的相应的资料时,我是把自己和团队的经验通过文档、PPT、示例代码的方式,整理成一整套的资料分享给其他开发团队,并且在这5天的时间内,和大家一起完成一个真实的项目开发。在这个过程中,我们也采用了一定程度上的敏捷开发的概念,比如迭代、用户故事等。
上图中有一个关键时间点,标注着DevOpsDays,DevOps这个词的出现大概是在2008-2009年这个时间段内,这期间开始有越来越多的人关注到底怎样提升软件研发的效率,DevOpsDays的活动是Patrick Debois 在这个时间点第一次帮助社区开始组织这样的活动时发起的。在那个时间我对DevOps完全没有任何理解,对于我来说,我的理解就是软件工程,就是帮助团队提高效率,把工具用好。
在2008年-2012年这段时间里,我所带领的外企研发团队在业务上有一个非常大的转型:2008年以前基本上是对外做外包,为澳洲总部做软件外包;2008年以后开始接触一些国内的软件工程项目,以及研发平台解决方案的工具落地项目,(现在我们叫做DevOps咨询项目)。之所以从2008年开始转型,有非常重要的外因和内因,这也是我希望通过这个过程和大家分享的。
从一个企业来说,为什么会转变自己的业务模式,为什么会改变自己的研发模式,其实很大程度上是因为有非常强的外因逼迫你不得不这样做,另外还有非常强的内因,让你自己也意识到“我可以这样做”或者说“我这样做会比以前做得更好”。
从2008年起,我就开始在国内承接一些软件工程类似的项目,比如研发过程改进、效率提升。我们所接触的第一家比较大型的客户是京东商城。之所以重点提起这个客户,是因为对于我个人来说,这个客户让我对软件工程有比较深的了解。
首先,京东为什么要做这个事情?我们在2012年开始和京东做这个项目的时候,京东整个研发团队的规模是大概1500人,在2013年项目结束我们离开京东这个团队的时候,它的研发规模基本翻了一倍。
以此可以看到为什么它会在这个时间点去做这样一个项目,因为这时候如果还没有人通过专业的角度去帮助他们梳理研发流程、考虑在这么大的规模下怎么保持研发交付的效率,可能他们在业务上会受到非常大的挑战。
当时我们做了什么呢?我们只做了一件事情:帮助它重新梳理软件需求上线的过程,并且通过一个工具把它相关的系统和信息收集起来,让他们的开发团队、项目经理、业务人员能很快做出决策,并且将一部分功能自动化。
这里一个大的背景是:我相信现在很多互联网公司的需求上线可能仍然是采取这种模式——上线窗口,典型的是,当时京东的上线窗口是每周二和周四,它会在每周二上线一些大版本或一些比较大的改动。
为什么选择在周二呢?周一刚进入公司可能还没进入状态,周二开始比较快速地工作,把精力放到工作上,这个时间点对于一个在线商城来说流量比较低,所以这时候上一些大版本是相对安全的;而另一个时间点——周四很容易理解,过了周五就是周末了,这个时间大家会考虑是不是要买点东西周末拿回家。
在京东内部,他们在每个上线时间点之前都会开一个上线协调会,这个协调会上就会出现:一个团队说“我作为一个产品线,我想要去发布我的需求”,而另外一个产品线的团队会站起来说“你不能发,因为我还没有准备好”,这时候就会出现这种有意见分歧的问题,这样的问题只有到马上要到上线时间点的时候才会暴露出来,所以造成很多需求延迟,没办法按照希望的状态被发布出去。
我们所做的系统是把这个信息尽早地收集起来,比如三周以后要上这样一个需求,在三周之前提到系统里,系统会链接到需求规划、测试、自动化打包、上线系统,这个过程中还会有一些审批的流程,把相关的一些关联方依赖方聚合起来,帮助判断这个需求是否能上。
其实从现在DevOps或者敏捷的角度去看这件事情,会叫测试提前,或者运维规划提前等这种概念。在那个时候京东做的就是这么一件事情,它就是把风险尽量早地暴露出来,让团队能够有更多的时间去解决这些问题,这样的话,在真正需要上线的时候可以非常顺利地完成上线操作。
通过这个项目我开始意识到:软件开发,几个人做的时候是比较简单的,当团队发展到一定规模的时候,做起来会越来越困难。这个困难的来源在于软件开发本身是件个人英雄主义的事情,它必须要依赖于每一个开发人员的智慧,去探索创造性地解决问题,这是造成所有软件项目管理问题的根源,也是其本质。对于软件开发来说,没有办法认清其本质就没有办法很好地去管理它,就没有办法让你的管理思路选择适应软件开发过程的思路而去管理这个过程,这样效率肯定上不去。
到2016年,我以咨询顾问的身份参与到中国农业银行的互联网金融这个项目,去支撑和帮助他们解决在项目开发中遇到的一些问题。到现在为止,我的客户群体在向金融行业倾斜。
过去10年间,中国大陆的微软DevOps工具相关的所有大型实施项目都与我有关,通过服务过的企业和十年的实践我总结出:现在最需要软件工程过程改进,或者说需要DevOps的团队定位是:严重依赖IT的非IT行业的团队。
什么是严重依赖IT的非IT行业的团队?
比如金融行业是一个非常典型的例子。首先任何一个金融企业如果没有IT的支撑,它是根本就转不起来的,但它自己本身的业务又是和IT完全不相关的。这就造成这些企业的客户以及这些企业真正的业务从业人员对于IT的理解有非常大的误差,IT人员想要在这些企业里发挥作用,就需要和完全不理解IT的人进行沟通,同时要能够对他们进行交付,导致两方面的沟通存在很大问题,IT人员还需要对业务进行了解,沟通成本的增加对软件交付效率造成非常大的影响。
银行有非常典型的沟通问题,还有一些历史遗留问题,涉及到粒度和解耦,为什么说这两个是DevOps实施的两大法宝,这是我在给客户建议或帮助他们进行过程改进的时候所摸索出来的心得。本文将重点分享这两大法宝。
DevOps实施落地的2大法宝
不管是敏捷、精益、持续集成、持续交付或DevOps等概念,目的都是提高效率,即提高单位资源的产出。其关键原因在于,中国的经济发展迅速,很多企业已经度过了那个靠增加投资来增加产出的阶段,现在IT从业人员薪资在增长,所使用的各种工具和环境,包括市场都非常成熟,很难找到一种短时间内获得爆发性收益的方式,企业之间到了拼内在实力的阶段,在这个阶段效率非常重要。
管理粒度。有两层含义:1动词,管理这个粒度,2名词,管理的粒度。在进行研发效率优化的时候,我们要关注的就是各种粒度,需求大小、团队大小、交付的代码量的多少,原则是越小越好。因为软件研发本身是一个复杂的过程,对于复杂过程的管理永远没办法适应其复杂度,最有效的方式是将复杂问题简单化,然后去管理简单问题。所以,从管理的角度如果想优化效率就要尽量减小管理单元。
工程解耦。软件工程涉及两个领域:管理领域——怎么去管理过程和团队;工程领域——实现要实现的内容,从软件角度来说就是怎么编码,怎么把大家脑子里的东西变成可运行的应用和服务,这个过程就是工程领域。在工程领域上想提升效率要做的就是解耦,不停地解耦,让你的程序、服务、所有部分都可以相对独立地被开发、测试、部署、运行,这样整体效率才能提升上去。
建立正确的认知才能有正确的办法。
什么是软件的生产制造过程?
如果把软件的开发过程和汽车的制造过程拿来比较。要制造一辆汽车,首先得有一辆原型车,这辆原型车被确认以后,汽车的生产工厂就会不停地重复生产同样的汽车。也就是说汽车的生产过程其实就是重复生产同样的产品。
来看软件的开发过程,软件每次交付的内容都不一样。如果映射这两个过程的话,会发现软件开发的整个过程,包括需求、设计、开发、测试、构建、交付的所有过程都是在进行设计,而不是在进行制造。制造的过程是制造一个同样的产品,软件开发过程是每次产生不一样的产品。
回到刚才那个问题,到底什么是软件的生产制造过程?其实很简单,就是把软件编译打包好,右键点击zip包,选择复制、粘贴,这就是软件的生产制造过程。
汽车最大的人员和资源投入是在工厂里,需要大量的工人和技师让工厂能运转起来,制造汽车的资源投入是在重复的过程中投入比例最大,而做软件的过程资源投入的比例99.99%是在设计过程,因为那个复制&粘贴的过程不需要这么专业的人来做。
理解了这两者之间的区别,但有没有想过,传统的软件研发/软件工程里所定义的管理方法,都是在用管理一个汽车生产线上的流程的方法来管理一个完全不同的设计过程。
这就是为什么传统的软件工程方法真正用到软件开发过程中会非常难用、还会出现各种问题的原因。如果采用传统项目管理方式来管理软件开发过程,就相当于看到一条笔直的路,要开车从这头到那头,打着火、挂上档、踩油门、松开方向盘、闭上眼睛,希望自己能够顺利地到底终点。
而事实上,结果完全不是这样,会有软件变更、用户变卦、中间出现bug、开发测试理解不一致、上线过程中环境不一样……这些问题都是无法在开发之前预见的,整个软件开发过程是一个设计过程,是无法被预计、被计划,和通过计划来控制的。
这就是我说的软件开发本身是一件个人英雄主义的事情,要靠每一个开发人员自己的创造性来解决问题,是不能通过一个看似严谨的环环相扣的过程来进行控制的。在软件研发里要强调的一点:所谓计划不是为了限制变化而是适应变化的。
这就必须提到敏捷。敏捷是什么,敏捷到底帮助我们认清了什么。其实敏捷真正做的事情是帮我们认清了到底什么是软件开发,软件开发的管理过程到底在管理什么。
传统的项目管理,管理的是时间、成本和范围,它认为我们的目标是一致的,在一个固定目标的情况下,我们所要管理的就只有成本、时间和范围。这就好像我们盖一栋大楼,肯定是有一个蓝图的,有了这个蓝图以后这栋大楼到底需要多久盖一层、盖一层需要多少资源、需要多少人力投入、可能会遇到什么问题,这些基本都是可预知的。
软件开发不是这样,软件开发从来没有定义清楚我现在要盖一栋大楼,也就是说你从用户那里拿到的所谓的需求,永远都是一个假设。为什么说是假设?需求和假设到底有什么区别?区别就在于:假设的价值和质量是可变的。当你的价值和质量是可变的时候,其实你拿到的就是一个假设而不是一个需求。
实际的体现点是:当你把楼盖到第十几层的时候,用户过来说我要加个地下室,你肯定觉得用户疯了,但是从用户的角度来说他觉得这个很正常,他认为你不就是一堆代码吗?为什么不能在这儿加入一行呢?他完全意识不到,他所加入的位置其实是地下室。
原因在于我们所做的软件是虚拟的,没有办法被实例化,在软件造出来之前没有任何人能看到它长什么样,没有任何人能体验到这个软件最终会给他什么。作为一个软件来说,只有当软件已经被做出来给到用户之后,用户才真正知道这个软件到底是不是符合他当初的所谓需求。也就是说,大家看到的需求文档、开发计划其实都是假设,在做出来、代码写出来给到用户之前都通通有可能是错误的。
当我们管理这样一个不确定的过程的时候,如果还用传统的项目管理方式来管理它的话,必然会遇到很多问题。敏捷重新定义了软件开发管理的思路。它定义的方式就是:把惯常的项目管理认为不变的价值和质量定义为可变的变量,传统的项目管理领域里的变量——时间、范围和成本,仍然是变量,所以软件开发管理领域中的变量要比传统项目管理中的变量要多得多、复杂得多。
这其实就是软件研发的本质。软件研发的项目管理和传统的项目管理不是同一个概念,如果用传统的方式来管理软件研发的过程必然会遇到问题。
上图是在比较传统开发和敏捷开发,从过程上来其实是瀑布式和迭代式的比较。瀑布式和迭代式到底有什么区别?图的上半部分是瀑布式的过程,下半部分是迭代式的过程。从图中可以看到两者最大的区别就是:迭代式的过程每一个管理单元会变得更小,交付的时间点会更加提前,实际上这就是我所说的第一个法宝——粒度。为什么敏捷开发能更加适应软件开发过程,原因就在于它缩小了管理粒度。
当你定一个三个月的开发计划,并且一次开始执行,如果中间出现问题,可能需要把很多东西从头来过。敏捷开发要求我们把开发过程变成一段一段的,每一段都是一个完整的交付过程。这样就算犯错误,所犯错误的机会成本也会低很多。
也就是说,当你的团队规模到达一定程度,当你所开发的软件体量到达一定程度,软件开发必然会变成一个非常复杂的,并且你没有办法去把它管理好的过程。当到达这样的量级时怎么处理?千万不要试图以一个非常严谨的管理流程来适应它,这是不可能做到的。你所要做的就是尽量减少你所管理的单元。简单来说就是:把你的需求从Word挪到Excel里,把你的需求从一大堆的描述变成一条一条的描述,把你的团队从几百人的大团队变成一个个几个人十来个人的小团队,把你所交付的软件从一个单体的软件变成一个个小的服务,这都是在控制粒度。
当你降低了粒度以后,并不是说你变得有多聪明了,而是在你同样的聪明程度下你所处理的问题的复杂度降低了,你就能把它处理好。
总结:计划不是用来限制变化的,而是用来适应变化的。软件开发的计划本身也是“管理单元”,计划对变化的适应能力来源于计划本身“粒度”的缩小。计划越大越有可能没办法被顺利执行,计划越小就越容易被成功地执行。
软件研发是一个复杂过程,不要试图用复杂方法处理复杂过程,尝试将复杂过程简化成简单过程,再用简单方法处理简单过程。
经常有人问我:我的团队适不适合做DevOps?我的产品适不适合做DevOps?这就是个伪命题,这个问题在于你怎么看待你所管理的过程,如果愿意并能够把管理的过程简单化,就肯定可以做DevOps,且做DevOps的过程就是在不断简单化管理过程的过程。
软件研发管理过程全景
到底软件研发管理过程是什么样的?如图所示,我们要管理的就是图上的点和线。图上最下面比较粗的线上列出来的简写其实就是CMMI定义的管理过程。
用CMMI模型可视化地展示一个软件研发的管理过程,从最左边的需求提起,可以看到包括两大部分的内容:
技术架构——从技术的角度怎样来描述产品长成什么样子,这里看到的就是一个大的产品,下面分成很多子系统,每个子系统里包含很多模块,这就是所能看到的软件的技术架构。
条目化需求,条目化需求就是用户提出的一个一个的他希望软件帮助他做到的不同的场景。
往右一点是设计过程,软件的架构设计就是将用户所希望实现的场景和技术架构进行映射,需要识别的是通过哪些技术可以实现用户所希望实现的场景,并且还要在用户场景不断影响技术架构的过程中保持架构的稳定性、可扩展性、性能等。所以它所做的就是把底下的框框和上面的框框联系起来。
再往右有一个项目计划,这里我列出来了一些项目,项目里会有开发任务、测试用例、可能还会有bug等,项目是从左边的条目化需求引过来的,这是敏捷的做法。
传统的软件开发的做法是:用户想做这个事,先做分析,需要实现哪些技术模块,然后要求把技术模块的技术点梳理成所谓的开发计划,它所传递的项目来源是来自于产品的模块,这是一种瀑布的做法。就是在软件开发过程中,将业务需求打散形成整个产品的完整设计,针对完整设计进行完整开发和完整交付。
它和直接使用条目化需求组织开发过程的区别在于:在你进行完整设计、完整开发的过程中,会发现到了最后收敛的时候,当真正实现了这些软件需求,需要通过一些软件的版本进行交付的时候,你必须要让这些模块的功能收敛到用户希望的场景上。实际上你交付的还是用户场景,只是在开发的过程中把它变成了技术语言,在最后交付的时候再把技术语言转化为业务语言。
这两次转化就意味着我们必须要整体开发整体交付,也就造成了管理粒度非常大,随之而来的就是各种问题。
敏捷开发从过程管理上要把握一个非常重要的原则:中间的开发过程必须围绕一个一个条目化的业务需求来组织,而不是围绕技术功能点。用户要什么我们就开发什么,就怎样去组织开发过程,最后交给他什么。因为就算是你把它打散成技术需求,最后交付的还是业务场景,这是没有变化的。技术与业务之间转化的过程,会造成非常多的问题,包括之前说的依赖问题,都是和过程的组织方式有关系的。
就这一点在我过去所服务过的客户里一些传统的开发团队都非常难做到,因为这和他们现在的管理方法、组织过程以及他们对软件开发的认知都是不一样的。他们可能都会提我们要做敏捷,可能也会说我们要用用户故事来进行需求梳理,但他们没有意识到用用户故事的时候,更深层次的要求是:整个开发过程都要围绕单个用户故事作为管理粒度,来推进整个管理过程并且最后进行交付。
再往右可以看到编码、版本、运维的各种环节,代码的变更会从开发任务产生出来,也可能会从测试用例产生出来,但最后都会被收敛到某一个版本上,而这个版本会按照顺序进入到我们的开发环境、测试环境、准生产环境和生产环境,最后在环境里产生出一些反馈,再回到需求,这就形成了完整的软件研发过程的闭环。
结合前面介绍的内容来看,如果从管理过程来理解软件研发,管理的就是这里面的点和线;如果从工程角度来理解软件研发,更多的倾向是:从开发测试这个环节开始,怎样能够让做出来的东西更快地进入到最后的环境,并且在这个过程中保持其跟踪性以及我们对质量的控制。
总结:研发过程改进,就是对上图中的点和线建立对应的管理单元的过程;并将这些管理单元形成能够快速交付需求的管理体系。
软件研发过程具有管理属性和工程属性。管理属性定义了用户要我们做什么;工程属性定义了我们的团队真正做出来了什么,就是我们交付的东西,这两个是软件开发里非常重要的转换,而这个转换靠统一的版本管理来衔接。就是要建立一个统一的版本号的规范,在任何时候都可以通过一个编码快速识别出现在软件开发处于什么样的状态、现在的需求处于什么状态、现在需要交付的东西是哪个。
至此,如果再次反思这个过程就会对第一大法宝——粒度有一个深入的理解了。软件开发过程要管理的其实就是这个粒度,目标是尽量缩小管理粒度。在整个软件研发体系里流动的是被管理的内容,需求、任务、测试用例、编写的代码、交付的模块都是被管理的单元,管理单元越小意味着越容易管理,交付的效率越高。
持续交付就是持续解耦
前文讨论得更多的是管理属性,现在来看工程属性。从工程属性上我们要做的就是持续交付。持续交付到底是什么,持续交付意味着软件一直处于可交付状态。
持续交付本身并不完全等同于CI/CD,不完全等于持续集成和持续部署,因为持续集成和持续部署只能保证有一个可交付的产品,或者有一个可交付的代码集并可以很快把它转化成交付件,且在交付的过程中可以自动进行,CI/CD主要做的是这件事,而本身代码是否处于交付状态靠管理过程控制粒度进行保证。
上图展示的是持续交付实施框架,把持续交付分成了7大领域,并且把当前的实践状态分成了每100天交付1次和1天交付100次。实际上在任何一个团队里,当你希望把自己的交付速度提升到每天交付一百次,那你需要从这7个领域进行规划、设计、实施,在这7个领域里我们到底在做什么,归结到底就是:解耦。
想要把解耦说清楚,可以从一个简单的场景——取钱来看。站到ATM机面前,把卡插进去、输入密码、输入金额、拿走现金,对于用户来说是再简单不过的事情,但其实这里面的技术非常复杂,在ATM机里需要处理很多的事情:机器系统控制、智能卡识别、接收用户输入、连接银行系统、监控等;还要把信息和数据传输给银行,这个过程中又涉及到数据加密、数据完整性、监控等;到了核心银行系统后需要查找账户、账务信息、进行审计和风险控制等。
这十几二十个系统意味着数十个团队和上百人的团队规模,也就是当你把一个简单的用户场景从技术架构角度去看的时候,打散成技术点都会变得非常复杂,这在金融业银行业尤为严重。
这样复杂的系统造成的结果我称之为“涟漪效应”。在一个平静的水面扔下一颗小石子,会在水面荡开一圈圈的涟漪,如果水中有几颗树,涟漪会撞到树。如果把石子理解成需求,树就是受到影响的系统,一个石子的场景相对简单,尝试一下同时扔下两