大概在去年这个时候就想着认真讨论一下技术债务的问题,源自于一次工作安排。
这一个运行了三年多的系统,随着业务的发展,该系统接入了越来越多的业务方和业务,陆陆续续变得更为重要,从而业务方也对系统提出更高的要求,随即安排一位部门资深同学接手这个系统,但受到这位同学的强烈吐槽,当时就想是什么原因让一向任劳任怨的服从安排引起了如此强烈的情绪呢? 毕竟在我们手里比这历史更悠久的系统比比皆是,于是决定深入了解情况。
当时分析出来有几大问题如技术栈陈旧,接口不统一,代码冗余,代码风格前后不一致,设计不合理和核心功能性能差等,这些都是老生常谈的问题,只是在这个系统表现程度较为严重。分析问题后便决定拉起该系统的现任开发,前任开发,前前任开发和我一起成立突出队利用晚上加班一起解决几个当时看来的主要问题,历时将近三个星期,过程曲折,效果却不甚明显,有 一些隐患问题导致今年该系统又再一次发生质量问题,导致产品运维量徒增。
巨大的技术债务影响了软件开发团队的生产效率,并降低他们的士气和积极性。技术债务不断累积导致了恶性循环:巨大的技术债务降低了生产效率和团队的士气 ; 同时低生产效率使得管理者推出更多的功能并导致技术债务问题的延期,而这又进一步增加了技术债务。
随着信息化和互联网的发展,管理好旧系统和技术债务是我们这些老兵们面对的一个问题。
著名的计算机程序员沃德·坎宁安,在1992年首次将一些软件系统内部混乱的问题比喻成一种负债。
交付第一次代码就像陷入债务。 债务是可以加快开发速度,只有通过重写代码,及时偿还债务。如果不偿还债务,就会发生危险。 把时间花在写一些不正确的代码上的每一分钟都算作该债务的利息。 整个软件项目可能在未合并代码的部署,面向对象设计或其他方面的债务问题而陷入停顿。—— Ward Cunningham(沃德·坎宁安)
它跟金融债务非常的相似,一个人或者组织为了快速 发展向金融机构贷款, 代价就是除还本还得加上利息。 如果他有能力定期还款,那么他欠下的债务是可以接受,不会产生进一步的问题,如果不还款或者逾期还款,就会以利息作为惩罚,随着不还款次数增加,罚息也随之增加,那么就可能由于债务累积造成破产。
卡内基-梅隆大学软件工程研究所(SEI)的Robert Nord在《The Future of Managing Technical Debt》提出了“技术债务全景图”(Tech Debt Landscape)的概念.
(图1:来自 Robert Nord 的《The Future of Managing Technical Debt》)
技术债务全景图主要从两个方向来分析技术债对于软件系统的影响:可维护性(Maintainability)、可演进性(Evolvability),同时结合问题的可见性(Visibility)分析技术债务对于软件开发过程的影响。
技术债务全景图从可见性角度分析技术债务的范围,比如说缺陷和未实现的功能特性均不能称为技术债务,因为它们显性影响软件产品价值,一般均能得到快速的解决;技术债务是不可见的部分,比如说不合理的架构设计,代码质量不佳和缺少测试或者文档。缺陷往往是技术债务的症状。
另外,为了更好的理解技术债务,SEI 的研究人员用了一周多的时间讨论出一个技术债务的工作定义和核心概念,描述了系统,功能,缺陷,症状,原来,推论,软件交付物以及上下文的关系。
(图2: 技术债务的概念模型 来自 Robert Nord 的《The Future of Managing Technical Debt》)
许多人听到技术债务就色变,与金融债务一样,技术债务并不总是坏事。债务让我们在赚到钱之前有投资的资本。在将产品推向市场时走走捷径,可以让我们以较低的成本测试业务模型,并在发现代码不好时直接丢弃代码。
通常引入技术债务是为在更短的时间交付软件产品,从而在架构,代码,测试和文档上做出妥协,从而让软件产品尽早的接触用户,获取反馈。这样做最大好处就是让软件产品快速跑起来,而不是更完美的设计和文档。毕竟用户要看到的可使用的软件产品,他们对里面的设计或者质量毫不关心,这一点对于面对C端用户开发的产品更是如此,时间就是生命,早一点面世就可能在市场上活下来,活下来才能有下一步的空间。
软件开发教父,《重构》和《企业应用架构模式》一书的作者Martin Fowler认为技术债务产生的利息是指由于草率的设计决策导致需要在未来的研发中付出更多。面对技术债务,可以持续付利,也可以通过重构一次付清。代码中的坏味道也是技术债务,是一种不计后果的债务,会让问题变得更加严重,进而将技术债务划分为个象限:
(图3: 技术债务四象限 来自 Martin Fowler 的《Technical Debt Quadrant》)
引入技术债务的原因,SEI的研究发现大部分的开发人员认为架构选择。架构选择和它们的设计影响往往持续多年,并且很难计划和改造,改造的成本极高。
(图4: Coding Frequency for Open-Ended Questions 来自 Neil Ernst 的《A Field Study of Technical Debt》)
对于技术债务的类型五花八门,1000个开发人员有一个1000个哈姆雷特。为此SEI 的研究人员进行了研究调查发现,不良的架构选择,过度复杂的代码和缺少代码文档是三个最常见的技术债务类型。
(图5: Ranking Sources Of Technical Debt 来自 Neil Ernst 的《A Field Study of Technical Debt》)
在我们大多数的业务开发场景中,软件开发团队有责任迅速提供价值给客户, 技术债务不可避免,那么管理好技术债务是每一位从业者都要面对的问题,采取勤奋和务实的态度处理技术债务问题是很重要的。
《代码大全》和《快速软件开发》一书的作者 Steve McConnell将技术债务分为两类均跟团队有关:无意的和有意的。
1)无意产生的技术债务:由于缺乏经验而编写了低质量的代码。
2)有意产生的技术债务:根据当前情况进行设计选型,可能很快就能解决当前的问题,有时会变得拙劣。
人们了解开发团队存在的技术债务。开发团队必须了解技术债务,它的各种方面和类型,以及债务对他们的项目的影响。要想让所有人了解技术债务,就让技术债务可见,养成习惯,定期沟通协商。
Mathias Verraes 在《技术债务墙:让技术债务无所遁形》一文中 建议在团队工作的地方选一面墙,确保它是公开可见的,给它贴上“技术债务墙”的标签。画一个漂亮生动的 logo,确保周围有便利贴和记号笔。
(图6: 技术债务墙 来自 Mathias Verraes 的《The Wall of Technical Debt》)
用人相关的流程可以帮助开发团队避免技术债务积累。这样的方法的典型例子是审查过程(如代码、设计、架构和测试审查)和架构管理(例如:以确保该代码符合预期的体系结构和设计)。然而,所采用的流程必须是务实的:顽固和艰难地遵循流程会阻止团队从完全遵循它们,并在坚持的过程带领他们寻求捷径。
仅从流程上是无法避免技术债务的积累, Ryan D在《You don’t need to stop shipping features to fix technical debt》一文中提出将所有的工作进行分类,至少要分为功能改进,计划工作,交付能力和计划外工作,通过将工作归类到这四个方面中,沟通工作的价值应该会变得更容易,并且腾出时间处理技术债务问题也会变得更容易。并在以上四个分类合理的分配时间,并跟利益相关者一起确定正确的时间分配比例; 如果没有利益相关者的参与,就无法成功确定分配比例。
BMC 专栏作者Stephen Watts 和 Joe Hertvik 在《Technical Debt: The Ultimate Guide》一文中提出六个步骤消除技术债务:
(图7: 6 Steps: Removing Cruft & Technical Debt 来自 Stephen Watts 和 Joe Hertvik 的《TTechnical Debt: The Ultimate Guide》)
通常情况下,团队在已经积累了大量的技术债务的项目中工作。在这种情况下,忽视债务前进是不明智的,因为它可能会导致该项目技术破产。在另一方面,停止数个月不开发新功能转而只专注于偿还技术债务也是不可行和不实用的。在这些情况下,需要均衡的发展模式,稳步偿还债务,并尽可能地保持功能和软件的实用性的进度。决定偿还技术债务必须具备以下因素:
一支有文化,有思想,有原则团队,无论战斗力还是颜值爆表的队伍。
作者:王云 - 中年微胖不称职码农