当团队建设工作告一段落,要求公司给团队提供了一个相对来说安全的环境。那么,我们要有产出,交付出一个高质量的产品。所以,当时我们就引入敏捷开发,形成定期迭代,每两周发布一定的产品增量,让客户也好、业务部门也好,有一个预期。问题也来了,在产品最初的几次迭代中,交付的新功能非常少且零碎,经常会因为要修复一些紧急的缺陷打乱节奏。并且因为之前遗留的一些历史问题,研发人员经常需要返工,偿还技术债及技术债带来的利息,这往往占用了他们大量的时间,还将整个迭代计划完全打乱。
还有一个很重要的问题暴露出来,团队一直缺少测试人员,真的很难想象一个软件开发团队居然没有一位测试人员。团队里的每个开发人员互相不沟通交流,闷声只做自己的工作,然后直接提交代码,不但提交的时候经常互相覆盖代码,很多时候做出来的东西和业务部门实际的需求是两个东西。 所以,当时产品虽然定期迭代,但质量特别差。差到什么程度?很多代码都是那种硬代码,直接写“死”了。比如我给A客户的某个值写成“123”,当B客户的这个值变成“234”的时候就不行了,就要把代码重新拿出来改成“234”后,再重新发布一次。
还有最常见的就是功能的核心流程操作经常被打断,业务闭环走不通。还有很多体验方面的,比如点了一些按钮没有反应,跳出一堆乱七八糟字符等,甚至很多客户都在不停地吐槽我们的系统界面太难看了,杂乱无章,风格不一。虽然质量问题不是由SM操刀负责的,但我既然作为领导者,有能力也有义务来解决频繁返工,交付质量低下的难题。我当时是怎么解决的呢?
12.2.1 提升质量意识
首先,从研发人员的思想入手,让他们充分认识到外部失败成本对于组织、对于团队所造成的严重后果。研发人员在开发阶段,就要达到高质量水平。这涉及怎么建立、提升开发人员的质量意识。我还引入了精益开发的一个核心概念—— “质量内建”,要求软件生命周期之间,参与的各个角色都需要实时的对软件的质量负责。也就是说,从产品经理开始,从产品到UI到开发再到测试,每个职能都要对产品负责,确保软件在交付到下一环节前已经有了基础的质量保证,这样才能减少因为质量问题导致的返工,避免浪费大量人力成本。
其次,灌输“我即团队,团队即我”的思想。之前面对产品的质量问题,尤其是被客户投诉,被业务人员嘲讽时,团队成员的第一反应就是“这个功能不是我开发的”“跟我有什么关系,当时是领导叫我这么做的”。
有一次,这个产品的人脸识别功能出现故障,用户使用时一直提示错误。这只是小问题,很快就能修复好。但是为了避免以后出现类似的问题,我把团队成员聚在一起开会讨论为什么会出现这个问题,以后也避免犯这种低级错误。但是大家都是一副“这个‘锅’是某人的,你直接跟他说就行了,我不需要听你讲这些”的态度。我气得厉害,从思想层面来说,要让研发团队的成员在工作中深刻贯彻“我即团队,团队即我”。团队要为质量负责,也就是每一个人都要为质量负责,而不是说这个功能不是我开发的就不关我的事。
12.2.2 增加测试岗并配备人员
通过迭代计划会保证PO、开发人员和测试人员对用户故事和验收标准的认知是一致的,并且让测试同学提前介入测试,及早发现缺陷并及时修复,或者在合适的时候采用测试驱动开发(TDD)的方法,将缺陷扼杀在摇篮里。需要特别说明的是,TDD会增加大量的工作量,我们需要在合适的时机恰当使用。
随着大家对于质量意识的提升,我继续在产品的更新迭代中引入单元测试、集成测试和回归测试。我当时设想得很完美,单元测试、集成测试不仅可以提升代码质量,还能提升开发人员的代码设计能力、质量主人翁意识,让开发阶段的交付质量有所提高。但我没有料到,如果在一个没有测试文化的团队里引入这些,阻力会这么大,团队的成员都提出异议:
“单元测试仅仅是证明这些代码做了什么,我觉得太浪费时间了。”
“我是很棒的程序员,技术能力这么强,我是不是可以不进行单元测试?”
“后面的集成测试将会抓住所有的BUG,单元测试的成本效率不高,我把测试都写了,那么测试人员做什么呢?”
“公司请我来是写代码,而不是写测试。测试代码的正确性,不是我的工作。”
……
对此,我只能不厌其烦地跟大伙解释,单元测试虽然是所有测试中最底层的一类测试,是第一个环节,也是最重要的环节,也是唯一一次有保证能够代码覆盖率达到100%的测试。我拿出数据说明,之前产品大部分的错误是在软件设计阶段引入的,我们为了修正一个错误所需的费用,将随着产品生命期的进展而上升。错误发现得越晚,修复它的费用就越高。
编码人员是唯一能够做到生产出无缺陷程序这一点的人,其他人都无法做到这一点。最后我吓唬了他们,“如果你能百分百确定在开发后期,不会因为BUG过多而失控,你就可以不做,后果自己负责。”好在团队成员都明白我讲的有道理,也都认真执行了。
如果说单元测试、集成测试是开发人员来做,那么回归测试通常由团队一起来完成。因为回归测试重复枯燥,通常都是借助一些工具自动完成。如果是带页面的项目,也会要求测试人员进行UI测试,帮助团队提高回归测试的效率。
当然,我们也会设立持续集成(continuous integration,简称CI)服务器,将以上测试定期运行,并且生成可视化报告,让所有团队成员看到,并且要求团队第一时间修复CI中出现的问题。
我们使用分布式控制系统(git)管理代码,并建立Git的规范和分支策略,并且充分利用Git的一些高级功能和规范流程帮助我们提升代码质量,同时解决一些“疑难杂症”。我们也鼓励开发人员设计更好地部署架构和技术架构,帮助团队做更好的决策。
12.2.3 代码回顾
除了以上测试工作,还有一个我认为也是非常重要的工作,那就是代码回顾。对于代码回顾的重要性,想来也不需要再做过多的说明,代码回顾的好处几乎不存在争议。代码回顾既是质量的一道门槛,也是知识分享的一个很好途径。如何保证代码回顾本身的质量呢?
首先,我们要在团队的技术能力的不同阶段,采用不同的代码回顾策略。比如团队稳定,编码规范掌握得比较好,使用的语言也是熟悉的语言,可能代码回顾的重点就会放到业务逻辑方面;如果团队新成立,还在磨合,可能编码规范就需要多注意;如果是团队新换了一门编程语言,那么语法本身可能也会是代码回顾的重点。
其次,在公司业务发展的不同阶段,需要采用不同的回顾策略。比如对公的业务在稳步推进,那么代码回顾可能需要更加仔细严格,保证质量和代码的可读性、可维护性。如果是在互联网行业,业务发展初期,在快速试错阶段,那么代码回顾需要领导去平衡回顾力度和业务交付的要求。
这些做到了,代码回顾就没问题了吗?当然不是。当时团队在开始代码回顾时也出现了问题。一开始进行代码回顾时,做代码回顾的成员交付出来的东西很差。有一次,我终于忍不住指出他的问题,没想到他直接说:“我的能力不够,做不了,你换人吧。”我没想到他这么排斥这项工作,我立刻缓和态度,真诚地问他遇到什么困难,稳住他的情绪。他才说平时工作量不少,现在做代码回顾,很难挤出很多时间来做,而且还经常是一次性提交大量的代码回顾,很难抓住重点。
我没想到,我认为理所当然的操作,也很好操作的代码回顾,竟然给他带来这么大的困扰。作为领导,我首先控制了每次需要回顾的代码量,避免对大量、无意义的代码进行回顾的现象存在。同时,要求提交代码的人在代码提交说明(commit note)中应该写清楚提交代码的目的。例如这个实现的是什么功能?做的是什么优化?修改的是什么BUG?这样才方便负责代码回顾的人有的放矢,清楚代码改动的上下文。
解决了这个问题,你以为代码回顾就可以高枕无忧了吗?当然不是,我们团队还陷入了成员互相挑错的陷阱。例如,当时我们在回顾一个页面设置的代码,有人指出了小张的代码写得太啰唆,还犯了低级错误。小张不舒服了,“你居然当面这样说我,我不要面子吗?你等着,我现在就挑你的错处”。
这样的事情再多发生几次就会造成恶性循环,面对代码回顾,大家都会将内心封闭起来,抗拒那些针对自己的批评意见,团队气氛越来越紧张。一说到开展代码回顾,大家都情绪低落,特别排斥。最后,不仅代码回顾工作没有做好,还严重地影响正常的开发工作。我意识到不能放任大家有这样的情绪。我开始遏制挑错现象,改变用代码评审、代码走查等“审、查、评字眼”,跟成员强调代码回顾重点是在共同学习和建设性上面,而不是批评。让大家以开放的心态面对代码回顾,它不是设置障碍,或者挑毛病,而是一个必不可少的质量保证过程,也是一个互相学习的过程,只是需要对于编程规范有一个共识,避免因为编程习惯发生不必要的异议。
还要提醒一点,一定要让成员将代码回顾养成习惯,让它成为工作中的一部分。当然,对代码回顾者的时间要有所保证,每个人在一个迭代中有自己承诺的任务,只有在预留了代码回顾的时间的情况下,代码回顾才能作为一个日常任务被执行。可以把代码回顾作为完成标准(DoD)的一部分。
这部分的信息量有点大,我们再简单地回顾一遍。之前研发团队交付的新功能非常的少且零碎,研发人员常常因为返工被占用了大量时间,迭代节奏、迭代计划经常被打乱。而且产品的质量常常被诟病,也成了业务部门攻击我们的重点。面对这些困局,我们可以分为三步走。
第一步,要求团队各个角色都要实时对软件的质量负责,给他们传递“我即团队,团队即我”的思想,也就是提升大家的质量意识。
第二步,引入单元测试、集成测试和回归测试,提升开发人员的代码设计能力、提升代码质量,让开发阶段的交付质量有所提高。
第三步,开发人员要做好每日代码回顾,提高质量和团队整体效率。
这样操作下来,我不仅获得了团队内外的肯定、还获得负责人的赞赏,看到了我如何发挥自己的敏捷领导力,用行动推动和促进了团队变革。为什么这么说呢?因为我通过行动,提升了研发成员的质量意识,从而提升了开发阶段的质量水平,尤其在经历了几个迭代后,效果非常明显。不仅减少了之前返工带来的对迭代节奏的破坏,让迭代顺畅又有质量。产品的BUG率有了明显的降低,使得我们团队有更多的精力投入到新功能中,还能帮助开发人员写出更好的代码,培养他们开发处理复杂和疑难问题的能力,大伙也不再因为产品质量被人诟病,相互甩“锅”,而是想着如何一起处理缺陷,避免类似问题再次发生。
同时,间接开阔了团队的视野,让团队成员了解更多的技术,学习如何利用新技术提升效率,甚至大家面对代码回顾这种枯燥又烦琐的工作,也不会抗拒,能明白其中起到的重要作用。正因为研发团队对产品控制度上升了,公司内外部成本明显降低,业务部门的抱怨也少了,并且关系更加融洽,客户好评率也上升了。