写点什么

软件交付的演进历程

2019 年 8 月 25 日

软件交付的演进历程

经常有人会问我什么是敏捷流程。我都会给出那个让人不尽满意的答案“没有一个单独的流程。它取决于每个团队的实际情况”。为了更好的回答这个问题,我撰写该文介绍了软件交付的演进历史。我打算归纳成一个线性的发展,即使我知道它并不像我要表达的那样有序和线性。但我觉得参考它,能得到比前面那个“取决于”的答案更多的信息。希望它对你同样有用。



开始阶段

软件开发刚开始的时候,并没有很好的经验或思想来指导一个开发项目的运行。最开始,人们标识出软件开发的一些关键假设,映射到那时已有的可理解的流程上。


最初的假设如下:


  1. 软件开发需要很长的时间

  2. 软件发布不会频繁

  3. 软件构建后很难进行更改,所以确保第一次把事情做对

  4. 软件开发需要很多不同的、成本高昂的技能集


建筑行业也有着类似的假设。建筑需要很长的时间,竣工后不能简单的添加一层或把面积扩大。建筑也涉及到很多不同的专业,从设计师到开发商,到质量监理以及工人、电工和水暖工等等。从这些角色的命名可以看出,软件开发从建筑行业借鉴了很多。


建筑行业遵循的流程是,把端到端的项目分成不同的阶段,每个流程阶段由不同的专业人士来负责。这种在每个阶段赋予角色的做法有利于充分利用成本高昂的人力资源。



瀑布流程


这看起来是一个很棒的流程。瀑布模型在 20 世纪 60 年代后期开始采用,直到 80 年代中期它才成为事实上的软件交付标准。但在流程执行中出现了些问题。根据2014 问题报告,31%的瀑布项目在投入很多后被取消,更有 52%的项目预算需要翻倍。


鉴于这种很低的成功概率,很多人开始各自提出新的、更好的方式来交付项目,以克服瀑布流程中的一些缺陷。


敏捷开发

人们不希望看到自己的工作被废弃掉,因此最初的一个思想是把大型项目分解成小的部分,逐步迭代出解决方案。这种方法让人们能对产品随时间的进展有更直观的印象,让团队可以收集反馈来看产品是否已经解决用户的问题。这种早期的反馈让团队按需进行纠正。


但是从瀑布模型转型到迭代交付很难,很多组织就把迭代开发解释成随时间增量交付解决方案。敏捷这个术语很灵活,按照设计,并没有什么敏捷流程——其关注点在于小型迭代、持续学习和反应性。尽管流程很容易遵守和实现,不过这些软技能很难掌握。对流程阐述不够,会让人们绕开一些比较困难的变革,实现“对他们有效”的敏捷流程,并起一个引人注目的名字,如 Wagile 或 WaterScrumFall。



敏捷开发


更好的透明度限制了出现严重超限的风险,但是它没有解决导致瀑布项目高失败率的根本问题。仍然有项目会花费比预期长的时间来进行构建,有些项目会因为不能交付预期价值的产品被取消。


为了实现到迭代交付的飞跃,我们需要改变对软件交付的假设。我们要承认,我们前期不知道要构建的产品是什么样的,因此我们需要将预先大量设计(Big Design Up Front,BDUF)阶段替换成增量设计。


这样可以让团队有能力在项目开展过程中进行学习,并在需要的时候改变设计。这里的挑战是,设计阶段是保证项目团队内外进行协调的关键阶段,并汇总实现解决方案所需的各种时间估计。一个公司的各个流程不是孤立的,所以要改变一个流程,就会影响另外一个看起来好像没有关联的流程。比如,从 BDUF 中得到的估计,会被其他支撑流程所需要,如资金、监管、资源分配和环境分配等等。


采用这些“对我们有效的敏捷”中的问题是,没有认识到或解决我们对软件交付做出的假设和现有情况的冲突。


假设


  1. 软件开发需要很长的时间

  2. 软件发布不会频繁

  3. 软件构建后很难进行更改,所以确保第一次把事情做对

  4. 前期不可能确切知道要构建成什么样的产品,因此把大型开发分解为小部分,并在项目进行中不断学习

  5. 软件开发需要很多不同的、成本高昂的技能集


如果前期并不能确切知道要构建怎样的产品,我们怎么才能做到一次把事情做对呢?软件的大设计和最终产品经常有很大的出入——这就产生了不能预期的挑战,即要求设计根据不断出现的新需求进行调整。这说明,和建筑行业不一样,软件的变更在构建后并不困难,不需要像实体建筑那样前期做缜密的设计。我们可以简单的添加(软件)层数,改变层高或是扩大面积,而不需要推倒重来。因此,假设 2 实际是不正确的。


(真正的)敏捷开发

如果设计可以随着迭代过程中的学习进行更改,那么只做每次迭代所需的设计就会有利于减少可能的返工。



这其实是最难的一步,因为它不仅要求改变项目团队中的一些职能部门的工作方式,还包括支持部门工作方式的改变。


  1. 我们没有足够的架构师,无法为每个团队都配备一个,指导他们进行持续的架构选择。架构师们需要定义好实践、原则和强制措施,确保设计符合指定的约束条件,而不是定义一个固定的架构。

  2. 开发工程师们将被赋予更多的责任。他们要完成针对问题给出最佳解决方案的任务,而不仅仅是按照需求规格说明书进行软件构建。架构师们不再面对交付的挑战,因此他们的假设经常不正确。最前线的开发人员在面临挑战时往往能提出更好的解决方案。

  3. 不进行预先的大量设计,就很难预估时间和成本。在瀑布项目里,时间和成本是基于项目启动时的估计确定的。在增量开发中,项目范围会根据实际遇到的新情况进行调整。时间和成本估计仍可以根据对交付的大致理解和团队规模进行,不过因为项目范围会有变化,投资回报率(ROI)和价值实现进度(benefits realisation schedule)无法在前期给出。


这些不是能轻松解决的任务,不过还是可以解决的。我会在后续的文章中详细谈到如何解决这些困难。


现在,我们再更新下我们的假设。


假设


  1. 软件开发需要很长的时间

  2. 软件发布不会频繁

  3. 前期不可能确切知道要构建成什么样的产品,因此把大型开发分解为小部分,并在项目进行中不断学习

  4. 软件开发需要很多不同的、成本高昂的技能集

  5. 实现团队负责在一定的边界条件下进行设计


持续集成

迭代交付的好处很大程度上是因为它可以获得关于产品的早期反馈。为了获取这些反馈,需要有一个软件的工作版本,解决了客户的问题,能够进行演示,并获得实际的反馈。为了交付这样一个软件版本,主要有两个挑战需要克服——软件开发怎样进行优先排序和怎样进行测试。


传统的瀑布项目中,最有效的方法是按组件构建产品——构建完美的轮胎、完美的底盘,最后组装到汽车上。上下文切换会耗费时间,因此,切换越少就可以越高效地利用开发时间。这种组件开发方式在开发团队中根深蒂固,即使他们采用了敏捷开发,实际的构建方式仍相同。问题是,如果客户想从 A 点到 B 地点,而我们给客户展示的是一个完成了的车轮,客户没法给出任何有价值的反馈。这解决不了他们的问题。我们需要从基于组件的开发转换到迭代开发方式,这要求有一个思想上的转换,即关注于客户问题而不是解决方案。只有不再做预先的大量设计,并承认前期我们并不很清楚需要构建的是什么,这种转变才可能实现。但即使如此,团队仍需要培训,因为它会影响到需求文档的编写和开发的进行。



价值增量 (Courtesy of Henrik Kniberg)


开发人员的时间是软件开发中一项很高的成本,产品定义改变是否值得呢?除了 31%的失败率,微软的分析指出,高达 66%的功能没有实现预定的商业价值。考虑到失败率,确保我们是否做对了事情远比开发效率更重要。我们会很快回到这一点,因为它即将影响到我们的下一个假设。


第二个挑战是关于测试的。为了得到有价值的反馈,我们需要让软件在客户面前工作起来,而不仅只作为演示。但是这需要测试,要花费很多时间和努力来完成的一项工作。过去,只在每次大的发布上执行一次测试,则自动化测试用例并不划算。但是有两件事改变了测试的这种情况。第一,现在的软件为商业的各个环节所需要,过去那种一年花很多天进行一次发布的情况已经不见了。第二,和开发人员的时间一样,项目中最大的浪费就是开发了错误的东西,而自动化测试让我们可以更频繁的测试客户的想法,它带来的益处超过了其成本。自动化测试周期让团队在整个开发过程中,可以持续开发“可发布”的代码。100%的自动化测试是个很难达到的目标,因此在软件发布前还有会小量的手动验收测试,但其质量已经足够验证解决方案。



瀑布流程中,保证不同团队高效是一个很关键的假设,这样才能降低成本。但是对于软件,因为软件发布频率增大,效率的经济性也随之发生了改变。现在的重点是保证端到端流程的有效性,而不再是保证每个职能部门的高效。这对软件来说并不新鲜——这种方法和技术是直接从精益生产运动中借鉴过来的。


持续交付/部署(DevOps)

持续集成的好处在于代码在任何阶段都是可供部署的。这样即使项目即将被叫停,我们也有可部署的代码。不过和前面提到的测试一样,部署代码成本高而且耗时多。


即使软件已经就绪,人们仍然需要一些时间在环境间移动代码并完成部署步骤。而且软件还可能遇到新的问题,比如负载性能差。所以你以为软件已经可以发布了,但实际不是。


越早发现软件问题,解决的成本就越低。所以理想情况下,团队应该在每次迭代结束后,发现是否有非功能性需求的问题需要解决。手动部署占用时间很长,因此部署也应该自动化。



持续交付缩减了代码发布的时间,但有时可能不需要发布。比如,你可能只完成了某个特性的一半,那么在第二个迭代完成后发布也是合理的。


了解整个部署阶段有助于我们发现问题,所以应该更频繁的进行部署。这样就引入了功能发布控制(feature toggles / feature flags)。在标识后面开发新功能,这样我们可以部分发布已完成的功能,但让它们处于关闭状态。用户甚至都不会意识到这些新功能,但我们可以测试到,这些代码不会对其它部分造成破坏。


功能发布控制还有其它的好处。将功能置于一个动态的转换中,我们可以开始在测试环境下进行 A/B 测试和多元测试,进而更精确的量化出变更的效果,这可以让我们更精准的验证我们对于客户的假设,必要时进行修正。我们可以动态打开或关闭某个功能,因此可以在生产环境进行用户验收测试,从而节省时间和成本。



经过这些变化后,我们再来回顾下我们的假设。


团队将交付时间从几个月缩减到几天,到一天几次。我们真的不能说软件开发花费很长的时间。如果它花的时间不长,我们是否能让专业人员分布到不同的阶段呢——每天怎样对多个阶段进行管理?我们没有减少所需的技能集,因此我们仍然需要架构师、业务分析师、手动测试工程师、自动化测试工程师、开发人员、运营人员、安全、管道开发人员等等。每个人只贡献一小部分,因此我们不需要让这些人员一直在一个团队,这样成本太高了。但同样的,我们不能让他们独立于团队之外,因为这样响应会太慢。如之前描述的架构师一样,确定边界和限制后,部分角色不再需要很深地介入到项目。然而,项目其他人员将要承担更多的责任。这类人员被称为 T 型人才。他们在某个领域有很深的专业知识(“|”),同时对其它领域有广博的了解,(“–”)。广博的知识面让他们在没有全职人员参与的领域内,也可以解决相关的问题。


假设

  1. 软件发布可以很快很频繁

  2. 前期不可能知道确切知道要构建成什么样的产品,因此把大型开发分解为小部分,并在项目进行中不断学习

  3. 持续交付中,T 型人才是最有效的

  4. 实现团队需要在已定义的边界下负责设计、开发和发布


持续价值(Continuous Value)

如果我们快速迭代地进行发布,那么如何进行完工定义?如果我们有既定的范围和时间,这个问题很简单。现在,我们要随时部署代码,什么东西会妨碍我们这样做?我们怎么才知道什么时候产品已经足够好呢?


如果软件交付不再需要很长时间,它就给我们打开了一个实验和验证的世界。


相应的,这也允许我们确认每次小的迭代的效果是否能达到用户的需求和我们的业务底线。


业务流程被相互协调的团队所代替,这些团队必须交付业务所需的产品。该团队实验并迭代需要开发的产品理念,从而确保可以达成既定的目标。



该结构确保持续的交付来验证我们的尝试,但是仍存在一些效率低下的情况,因为在产品/用户体验/设计和实现团队之间,可能缺乏一致性。这种隔离通常被归类为“业务”(定义需开发产品的范围)和“IT”(做实际的交付工作)。这意味着只有一半的团队真正负责完成目标,另一半则作为交付的工具。我们仍需进行从交付物到交付业务成果的思想转变。


假设


  1. 软件发布可以很快很频繁

  2. 前期不可能知道确切知道要构建成什么样的产品,因此把大型开发分解为小部分,并在项目进行中不断学习

  3. 持续交付中,跨团队的 T 型人才是最有效的

  4. 实现团队为交付的产品成果负责


产品团队


我们将有一个真正的跨职能产品团队,挖掘需求,交付产品,为客户和业务创造成果。让开发工程师在概念阶段就介入进来,可以集思广益,还能对交付它们的复杂度提供输入信息。设计人员自始至终参与到开发团队中,可以更好地了解设计对于客户的影响。



为了全面从瀑布项目已经定义好的阶段迁移到产品团队的持续流中,需要不断的尝试和创新,从而消除可能遇到的阻碍。但是万事都在变化中。团队随着产品需求不断成长,包括市场、客服和运维。流程的演进从不停止。我会增加最后一个假设:最好的流程来源于持续的反馈和尝试


这些会把我们带向何方?

流程是很神奇的。当做一些重复性工作时,清晰的流程可以帮助我们明确需要做什么,需要避免那些已知的错误。在大型公司里,流程制度化是更有效的做事方式。


但有时候这也会有问题。Jeff Bezos 在其第一天理论中指出了这点:


“好的流程为我们服务,进而为客户服务。但是,如果我们不保持警惕,流程就会成为问题。流程成了你希望获得的结果的替代品。”


所有流程的通病是它们包含了流程建立之初的假设和限制。随着时间迁移,那些已经嵌入流程之中的最初假设被遗忘了。问题在于,假设和限制不再有意义时,流程会阻碍我们的工作。


我们来看看下面的假设,看看哪一种描述对我们现在的工作状态描述更准确。


项目产品
时间软件开发需要很长时间 软件发布不频繁软件交付快速且频繁
设计软件在构建后很难变更,因此确保第一次把事情做对前期不可能知道确切知道要构建成什么样的产品,因此把大型开发分解为小部分,并在项目进行中不断学习
团队定义不同的角色,有效利用成本高昂的技术人员持续交付中,跨团队的T型人才是最有效的
目标实现团队对输出负责实现团队对结果负责
流程流程变更集中化,并在组间同步推进根据持续的反馈和实践,流程可以在团队进行变更


做这种转变并不容易,我在接下来的文章中会深入探讨,为了支持产品团队的转变,整个组织需要做那些相应改变,包括:


  • 管理层 / 组织架构变化

  • 监管层变化

  • 财务制度变化

  • 用户体验和设计变化

  • 开发变化

  • 测试变化



原文链接:


The Evolution of Software Delivery


2019 年 8 月 25 日 11:3525994

评论

发布
暂无评论
发现更多内容

单向链表合并节点

chenzt

架构师第8周练习

小蚂蚁

教培行业工程师面临着什么挑战?研发面板全栈式解决工程师的痛点

Deepexi

DevOps 运维 敏捷开发 研发管理 单元测试

Hadoop 中的 Namenode 和 Datanode

dongge

第八周·总结·数据结构预算法

刘璐

架构师训练营 - 第八周 - 作业

韩挺

六大自动化测试技巧

禅道项目管理

自动化 测试

第八周课后作业

晨光

缓存思想在算法设计中的应用梳理

che-ri-sh

缓存

躬履艰难,其节乃见:华为陈黎芳眼中的全球责任

脑极体

第八周课后总结

晨光

CompletableFuture运行流程源码详解

编号94530

Java 并发编程 多线程 CompletableFuture

架构师课程第八周总结

dongge

如何让你的Nginx 提升10倍性能?

老大哥

Java

Java十大常用框架介绍(spring系+dubbo+RabbitMQ+Ehcache+redis)

BUZHIDAO

套娃成功!在《我的世界》里运行Win95、玩游戏,软件和教程现已公开!

程序员生活志

游戏 我的世界

各类SQL中日期时间那些事

大唐小生

sql 大数据 SQL语法

TNFE-Weekly[第六十六周已更新]

莹姐🙈

小程序 前端 周报

链表查找算法,HDFS数据节点宕机处理

dony.zhang

架构师训练营 - 第八周 - 学习总结

韩挺

网络通讯

陈皮

华青融天战略拓展总监王旭详解IT运维的九阳神功

DT极客

37岁程序员被裁,想用6月工资跪舔领导划掉被裁名额,结果蒙了!

程序员生活志

程序员 职场 程序员生活

架构师第8周学习总结

小蚂蚁

第8周

李朋

最新硬件虚拟化检测技术,让攻击者逃不出“楚门的世界”

百度安全

云计算 安全 虚拟化

PC人脸识别登录,出乎意料的简单

程序员内点事

Java 人脸识别

总结

李朋

查找两个单向链表合并元素

张磊

架构师培训 -08 数据结构算法,网络通信协议,非阻塞网络I/O,数据库原理

刘敏

信创舆情一线--工信部开展APP侵害用户权益专项整治行动

统小信uos

演讲经验交流会|ArchSummit 上海站

演讲经验交流会|ArchSummit 上海站

软件交付的演进历程-InfoQ