• Cams2
  • Cal
  • Training
  • Five
  • Arne-04
  • Jens-02
  • Jim-banner
  • 2015
  • Shine-scrum-01
  • Jens-heart-of-scrum
光棍节不孤单——陪你聊聊技术债务(技术债务下篇)

 技术债务上篇(鬼节版)故事篇回放鬼节真故事——欠债总是要还的 

技术债务下篇(双十一版) 感悟篇


技术债的分类

对于技术债的分类,敏捷大师们有很多讨论,也有各自不同的分类方法。Ken提出技术债的三种主要形式(幼稚的技术债、不可避免的技术债和策略性技术债),并分析它们各自产生的根本原因。结合Ken发表在博客上的文章,可以看出,幼稚的技术债源于“团队成员不成熟”,不可避免的技术债源于“无法完美预测未来”,策略性技术债源于“组织有意采取的策略”。


问题分析清了,根本原因找到了,解决方案自然呈现出来。


既然幼稚的技术债源于团队成员的不成熟,那么根源在开发团队身上。开发者粗心大意、不负责任,那就给团队成员提供技术实践方面的培训,在完成的定义中给团队细化、明确在技术方面的要求,培养团队成员,帮助团队成员成熟起来,从而达到停止增加技术债的目的。


不可避免的技术债源于无法完美预测未来,根源在于开发创新型产品时,人们对业务领域的认知规律天然如此。我们无法改变这个认知规律,但可以运用这个规律。Scrum通过短期频繁迭代,快速获得对业务领域的认知,来减少负债。


既然策略性技术债是组织在权衡利弊后有意采取的策略,那么根源在组织身上。重写代码需要多少时间?相当于提高多少成本?避免或承担技术债,哪个收益更高?技术债可以作为一个工具,量化部分成本,帮助决策者认识到技术债的利弊,正确决策。


用我自己的话总结一下Ken的思路:不该欠的债,不欠;不得不欠的债,少欠;不确定要不要欠的债,先量化比较再做决策


技术债的管理力度

技术债的管理力度,弹性相当大。Ken指出,技术债像财务债一样,必须加以管理。同时他又指出,没有哪个产品能做到“无债一身轻”。对于这样一个必须要管,又不能管死的问题,如何掌握弹性空间呢?这里,我们能体会到充分且必要的管理原则。Ken以不明显影响将来产品开发为准,为技术债积累设定了上线阈值。管理要充分,技术债积累不能超过上限阈值,否则必将对产品的后继开发明显不利。但是否要努力达到零负债呢?不必。因为那样做,组织的经济效益未必是最大化的。这个道理容易懂。以买房做类比,当下房价疯涨,攒钱不买房,一年又白忙。你需要买房,是攒够钱再买呢?还是贷款负债买房呢?只要把月供控制在可承受范围内,当然贷款买房的经济效益是最大的。这个可承受范围就是合理的弹性空间。


技术债的偿还原则

Ken提出了偿还技术债的5条原则。这些原则至少基于2类基础,一类是其他人的研究成果,另一类,也是给我们读者印象最深刻的一类,是Ken自己的实践。


比如,第一条原则是“并非所有技术债都应该偿还”。Ken生动地重现了一段与某集团副总裁交涉的亲身经历。听听副总裁是怎么对Ken说的:“孩子,哪怕你花我一个子儿去清理系统,我也会亲自把你逮起来毙掉。”如果当时被喷的是你或我,这是多么尴尬的记忆。或许我们会像很多人那样,抱怨不被理解,然后不了了之。但我们看Ken是怎样反省自己的。Ken说:“从我个人的角度来看,上线一个脆弱的系统对他们来说存在巨大的风险,但从利润的角度来看,我的想法显然错了。”有了换位思考,有了多角度的观察和理解一个问题,才有了“并非所有技术债都应该偿还”这样一条重要的原则。


又比如,第三条原则“分期偿还技术债”。在这部分,Ken总结了他指导团队实施Scrum时观察到的常见错误:“技术债冲刺”,并指出该错误导致的不良后果:技术债冲刺是一个误导,它让人们以为,债务可以增长,不用刻意减少。于是本该在每个冲刺完成的工作,却堆积到不得不处理了再专门花一个冲刺来处理。Ken指出技术债冲刺最严重的后果是影响交付客户价值,进而提出“分期偿还”的原则。


再比如,最后一条原则“一边做有客户价值的工作,一边偿还相应部分的技术债”。意思是,比如在开发某个有客户价值特性的时候,涉及到几个C++文件的修改。那么,对于这几个C++文件而言,首先保证不添加幼稚的技术债,其次清除偶然发现的技术债,最后,也是最核心的,专门偿还出现在这几个文件中的技术债。这个办法简单、自然,又能兼顾多方面需求,如PO关注交付客户价值,团队成员关注偿还责任等。如此巧妙的方法,出自人民群众的智慧,即Scrum团队的智慧。Ken观察到这些优秀的实践,再把它总结提炼成为原则。


Ken善于在实施Scrum的实践中总结,既有成功经验,又有失败的教训。于是关于偿还技术债,我们应该怎样做,避免怎样做的原则被提炼出来,而这些原则进而不断丰富着、发展着Scrum理论。这些原则于读者来说,如醍醐灌顶,让人受益匪浅。


解决自己工作中的问题

我在敏捷教练的实践中,遇到过技术债管理的两类典型错误。


不了解不可避免的技术债

某组织有独立的测试团队执行系统测试,把缺陷登录在缺陷管理系统中。在管理者看来,修复这些缺陷需要花费开发团队大量时间,在质量保证部门看来,这些缺陷意味着软件质量差。于是组织提出“预防缺陷”的口号,试图通过更频繁地监控缺陷密度(关闭的缺陷个数/代码行数),强化代码审查、单元测试等活动,显著减少测试部门发现的缺陷,最终达到节约时间,提高质量的目的。但事实证明,在强化对开发团队监督以后,缺陷个数并未显著减少。原因何在?


分析发现,大量缺陷无法预防。例如,UX规格书在频繁迭代过程中根据反馈意见不断修改,测试团队根据最新版UX测试旧版软件,登录缺陷,促进开发团队根据UX规格书更新软件,这就是不可避免的技术债。又例如,一个开发团队开发的组件A依赖于第三方开发的组件B。当组件B变更接口时,测试团队测试包含新版A和旧版B的现有软件系统,登录缺陷,促进开发团队更新组件A,这也是不可避免的技术债。迭代次数越多,得到的反馈信息越多,变更就越多,不可避免的技术债就越多。多次迭代的缺陷累计总数与迭代次数有正比例关系,随迭代次数的增长近似线性增长。经过多个迭代周期,缺陷管理系统上登记的缺陷中,由不可避免的技术债导致的缺陷数量几乎淹没了幼稚的技术债导致的缺陷数量。所以,无论怎样强化监督,缺陷数目也无法显著减少。也就是说,对于使用迭代开发的创新型产品来说,技术开发团队百分之百地认真开发,不出任何粗心大意的错误,缺陷密度这个KPI也不会有明显下降。


认识到不可避免的技术债天然无法“预防”这个道理后,管理思路也需要相应改变。不可避免的技术债,管理重点在于及时偿还。缺陷密度这个KPI以关闭的缺陷作分子,只能提示多少技术债已经得到偿还,但更应关注的是,等待偿还的技术债是否超过了上限阈值。依据一个团队的开发能力,合理设定其上限阈值,然后监督尚未偿还的技术债的累计情况,低于阈值是正常情况,高于阈值才需要提高关注。以房贷类比,已还多少贷款不重要,重要的是还有多少贷款没还,更重要的是,这个月的贷款是否高到还不起的地步了。每个月需要还房贷不是问题,及时还贷是正常情况,这个月没钱还贷才是需要警惕的异常情况。


忽视幼稚的技术债

幼稚的技术债是可以避免的,但不成熟的开发团队常常任由其积累,不注意偿还。


实际开发工作中,不成熟的开发团队和团队中不成熟的开发人员并不少见,他们写完代码就提交,单元测试敷衍了事。只是给开发团队提供培训,告诉他们要运用测试驱动开发、要注意重构代码,要制定并执行“strong definition of done”,提醒他们定期检查,甚至定期审计他们的技术实践活动,这些工作往往花费人力不少,但收效甚微。


经过长期实践,我们摸索出一套自动化触发模式。原理是依托于一套自动化构建系统,以代码提交作为触发条件,触发若干项活动自动进行,如单元测试、全局变量统计分析、圈复杂度统计分析,内存碎片分析等。每项活动进行完毕,构建系统自动在缺陷管理系统中登录相应问题,并用特殊标记标识,促进开发团队解决。以代码提交作为触发条件,把开发团队编写代码的活动与检查代码的活动自然地结合在一起,不成熟的开发者再也不会忘记,也无法敷衍这些活动,从而使技术实践落到实处。


本文作者 书山有伴  ,由ShineScrum审核