精益生产原本是来自于制造业的一个理念,为丰田汽车首创。之后随着一代代丰田人的丰富和完善,逐渐成为丰田汽车商场制胜的一大法宝。之后随着精益生产的理念传到美国,逐渐的发展为一套完整的价值体系。
与此同时,在软件工程领域,敏捷也逐渐发展成为一套完整的价值观和方法论的体系。直到有一天,这两者被同时摆在桌子上的时候,我们才发现,这两者虽然行业背景不同,关注点也不尽相同,给出的解决方法也不一致,但是在最基本的价值观上却可以做到相互融合。由此,精益生产的理念也被引入了软件工程领域,并逐渐形成Lean-Agile的项目管理理念。现在如果你去搜索“精益 敏捷”,你能看到的往往是这样的:
这样的:
还有这样的:
所以我们可以看到,这两种思想正在软件工程领域发生着深度的融合。正所谓他山之石,可以攻玉。作为一个长期浸淫在敏捷开发领域的开发者,精益生产又能带给我们哪些启发呢?
我们知道,精益生产的主要目的是为了减少生产过程中的浪费,从而提升企业的整体盈利能力,按照精益生产的理论,生产制造过程中的浪费主要有以下7种:
1.过量生产
2.纠正缺陷
3.多余工序
4.过度库存
5.物料运输
6.多余动作
7.等待
投射到软件开发过程中,这些浪费又分别有着哪些隐喻呢?相应的,我们又能做些什么来减少我们软件开发过程中的“浪费”,从而提升软件开发团队的“整体盈利能力”呢?
过量生产 — 需求镀金或优先级颠倒
作为一个“有追求”的BA或者Dev,我们总是希望能给用户提供一个眼前一亮的功能,但是这种强大的“自驱力”反映到软件开发中的结果却往往是画蛇添足。我们花了20%的时间去完成了80%的核心功能,然后再花80%的时间去完成剩下那20%的无用功能(蛇足)。试想一下,如果我们在用20%的时间完成那80%的核心功能之后,及时的与用户确认,获取用户的改进意见或更进一步的需求,反馈回路会比之前短得多,也会避免画蛇添足给团队带来的挫败感,而这一切恰恰是精益生产中所说的“不多不早刚刚好”。所以我们在聊Product Backlog的时候,如果出现一些产品特性是来自于我们的“Product Vision”,而并没有与用户进行任何的确认的时候,我们都应该警惕,我们是不是又在开始“画蛇添足”了。
还有一种情况就是产品特性开发顺序的混乱。我相信很少会有团队会在订单管理功能还没开始做之前,先花上3个月的时间实现一套完整的报表功能,因为谁都知道,用户需要的是能够用来支持每天运营的功能,能够让他们的客户能够正常的下单,能够让他们真正的挣到钱。但是在实际的工作过程中,我们往往对于某几个产品特性的优先级无法迅速的达成一致,这个时候体现出来的正是我们对于用户核心需求和痛点的理解模糊不清。那么这个时候我们应该怎么办?很简单,找用户确认。“嘿,老板,我们现在有这么两个产品特性,你最想要哪一个?” 是的,就这么简单。
纠正缺陷 — 产品特性在验收之后才发现bug
我们在说敏捷三角的时候,会提到价值-质量-约束,质量的重要性可见一斑。质量对于我们的用户的重要性不言而喻,毕竟谁也不希望花了大价钱开发出来的产品动不动就崩溃,动不动就丢失订单,因为这一切对于我们的用户来说意味着客户流失和财务损失。
那么质量对于软件开发团队而言意味着什么呢?软件质量低下,bug频发对于开发团队而言就意味着成本的激增。因为这些bug的修复都属于计划外的工作,计划外工作的增加就意味着计划内工作(新的产品特性)会受到影响。
同时我们经常会说,开发人员同一时间应该只工作在一件事情上,因为工作上下文的切换是会带来切换成本的。这种上下文的切换越频繁,这种成本就会越高。我们花45分钟完成一份数学试卷,再用45分钟完成一份语文试卷,这不是一件难事。但是如果让你做5分钟的数学,再做5分钟的语文,如此循环下去,我相信在同样的90分钟时间内完成这两份试卷的难度会明显的提升很多。
同样的道理,在开发人员正沉浸于一个产品特性的开发的时候,持续的用他3个月前开发的一些特性的bug来打断他,于是他被迫在多个他自己都不记得如何实现的产品特性的上下文之间来回切换,我想谁也不会指望他手头新的产品特性的开发能如期完工。而且这些bug修复完了之后,还有一个抓狂的QA需要在这些bug修复后的功能测试之间来回的切换上下文。
我们要做的就是在团队内部养成测试的意识。我们可以制定团队的单元测试覆盖率标准,并将功能测试和产品的CI/CD流程进行整合,让所有不符合测试覆盖率要求的新特性都无法进入下一个环节。测试人员通过一系列自动化测试的手段提高测试效率,保证每一个新特性的集成都不会破坏已有的功能。通过一些成熟的第三方工具分析代码的坏味道,并保证每一个新特性的集成不会引入新的坏味道,毕竟今天的坏味道明天可能就是一个bug,谁也无法保证在开发新功能的时候不会触发别人(很大概率就是他自己)几个月之前埋下的一个臭弹。
多余工序 — 不必要的流程环节或无意义的会议
产品生产过程中的工序分为三种,一种是产生实际价值的工序,比如汽车焊接,软件功能的开发,界面的设计等;第二种是不产生实际价值但是却不得不做的工序,比如汽车出厂前的质检,软件上线前的测试等;还有第三种是不产生实际价值,并且通过流程优化之后可以避免的工序,比如说通过优化汽车生产线的布局,可以避免半成品在不同加工车间的搬运和转移。
而在我们软件开发的过程当中类似的这种可以避免的工序往往也存在。比如说我们的BA在迭代期间会准备下个迭代要开发的故事卡,有时他会在全部的10张或15张卡全部准备好之后去跟QA做一次kickoff,而这些原本可以通过小批量移交的方式来进行。
有时我们的QA会为一个页面上一个小小的布局错误专门创建一个task,用一套完善的文字描述和截图来记录这个“bug”的复现步骤,然后把这个task移交给开发人员。
有时候我们会临时召开一些会议,叫上所有团队成员,在没有给他们留出充分的时间做准备的前提下,去讨论某一个问题的解决方案。而所有的这一切,其实都可以通过更加轻量化更加优雅的方式去处理。
过度库存 — 片面的优化某一环节的工作效率
每一个产品特性的交付都会经历需求-设计-开发-测试-部署等环节,当我们在说提升团队的工作效率的时候,其实应该从团队整体的角度来思考。比如说如果我们花了大力气提升需求分析环节的效率,将需求分析的产出从之前的每个迭代分析10张卡提升到了每个迭代能分析100张卡,然而设计环节的产出仍旧是每个迭代只能设计10张卡,那么结果显而易见,大量分析完成的卡成为“半成品”进入“需求仓库”成为“库存”。当我们某一天做到一张半年前分析的卡时,这张卡还能否符合此时此刻的业务需求,可能就无从得知了。
同样的情形可以发生在这条“产品流水线”上的任何一个环节。所以我们要做的是,评估整条“生产线”上的产出效率,找出制约整条“生产线”效率提升的痛点,进行有针对性的优化,最终使得需求-设计-开发-测试-部署所有环节的产出效率一致,减少这些库存半成品的产生。
而且我们还要认识到,随着人员熟练度的提升以及新成员的加入,各个环节的生产效率是一个持续波动的过程,因此这个“生产线调优”的工作将是一个长期持续的过程。
物料运输 — 分散无序的项目文档和开发材料
试想一下,如果一个团队的代码库放在GitHub,应用服务器在AWS,数据库放在自家的数据中心,项目文档放在项目自己搭建的SVN里,公司的管理文档放在Google Drive里,团队的账号密码信息用LastPass存储和分享,系统日志存在SumoLogic,用Jira管理迭代任务......
请问开发人员在开发一个新的产品特性时,一共需要访问多少个外部系统才能完成他的工作?当一个新入职的同事加入团队时,他需要多久才能将这些信息汇总到能开始日常的工作?所以我们应当将项目的开发工作所需要使用到的文档和材料通过wiki等工具有机的管理起来,减少团队成员在完成日常工作的过程中需要跑好几个“仓库”才能备齐所需的全部“原材料”。
多余动作 — 交接清单,百科全书式的故事卡
在devops这个概念兴起之前,开发人员与运维人员从属于两个团队,在项目开发工作完成之后,代码会被打包移交给运维团队去部署和运维,在此过程中,一个大型的项目会有一个交接清单,代码包,安装说明,运维手册林林总总一大堆东西。而现在我们强调要打造全功能团队,当我们的开发人员能够完成全部的部署和运维工作之后,我们会发现,所有的这些交接清单都省了,我们再也不用花大把的时间去写这些文档了。
同样的,BA在写故事卡的的AC过程中,有时也会尝试将AC写得如同百科全书一般的尽善尽美,结果后面开发和测试的同事看到这些长篇小说一般的AC时,都不由得会皱一下眉头。敏捷团队必须借助迭代评审会议和迭代回顾会议之类的活动,及时的将类似的“不适感”反馈给对应的同事,以便于团队成员工作方式的持续改进。
等待 — 各个环节之间节奏不统一,团队成员之间界限过于清晰
生产线上出现等待的原因无非就是各个环节之间节奏不统一,需求和设计的速度跟不上开发的速度,开发的环节必然出现等待。这个问题在过度库存那个部分有提及。
还有一种情形就是团队成员之间职责边界过于清晰,BA只负责分析需求,对测试的工作一无所知,开发只专注于提升前端的开发技能,对后端开发提不起兴趣,对于业务需求和测试漠不关心,测试人员只关心测试,对ops的工作一窍不通。于是我们只能祈求这些关键角色不要生病,不要休假,否则一旦QA跟女朋友去新马泰了,ops就只能看着一堆没有测试的功能干瞪眼了。而如果有一天ops不舒服需要休息两天,成吨的新特性就无法被部署到生产环境中去了。
对于这种情况,我们需要鼓励团队成员的融合发展,建立一个全功能的团队,避免某一项关键技能,或某一块业务的上下文只掌握在某一个团队成员的手中,此时pair工作会是一个比较好的方式,在分享上下文的同时解决技能单一化的问题。