【51CTO.com快译】通常而言,债务是一个能够让人产生消极感觉的词汇。大家往往会联想到学生贷、医疗费、以及抵押付款等景象。不过,一些金融上的债务还是多少对人有益的。而技术债也是如此。

作为一个隐喻,技术债(也称为代码债务)是指开发团队为了加快项目或功能的交付速度,在后期需要重构时会发生的情况。显然,优先事项是更快的开发过程,而不是更高质量的代码。

和金融债务类似,技术债对于组织来说是一把双刃剑。为了合理地使用它,工程师和团队负责人必须监控他们手头有多少技术债,并学习如何对其进行良好的管理。而对于组织而言,这将是一项艰巨的任务,尤其是当他们对技术债的优缺点尚不清楚时。

技术债的基本特征

Scrum已经成为了软件开发人员在寻求以更高效的方式交付产品时,使用到的流行框架。众所周知,客户经常会有新的需求出现,并且会改变主意。因此,开放性的Scrum以事情的不可预测性为重要原则,并让用户在使用该框架时产生技术债。

在此,我们借用Scrum培训师Stefan Wolpers(请参见--https://www.scrum.org/resources/blog/technical-debt-scrum-who-responsible#:~:text=%E2%80%9CTechnical%20debt%20(also%20known%20as,approach%20that%20would%20take%20longer.%E2%80%9D)曾经提到过的,如下两种不同类型的Scrum技术债:

  • 首先创建一个由性能欠佳的代码所组成的短期解决方案,以便开发团队可以更快地交付产品。同时,团队期望在初次发布之后,回过头来改善代码的质量。

  • 随着开发团队发现有关待解决问题信息的增多,另一类技术债也会被动地产生。即:随着新需求的出现,往日起作用的解决方案可能在将来就失效了。因此,这些需要调整和重构的代码,会包含一定数量的债务。

Wolper同时认为:Scrum团队应该重视如下方面:

  • 为了简便管理,应优先考虑技术债的透明度。团队需要将技术债的可视化突显效果放在首位,并在每次Sprint(冲刺)会议期间审查技术债的各项需求。

  • 跟踪技术债。团队通过尽可能地使用诸如圈复杂度(cyclomatic complexity)、代码覆盖率、SQALE评级、以及违反规则等深入的代码度量标准,对各类错误进行记录和计数。

  • 快速定期偿还债务。Scrum团队应该考虑在每个Sprint周期中,将其15-20%的资源分配给重构代码并修复错误。

  • 调整产品的积压,将其与偿还的技术债任务关联。您可以将债务整理成要解决的Sprint状态,以有助于防止债务被遗忘。

  • 调整对“完成”的定义,即:在满足了那些可管理的技术债的既定标准之前,请不要将其状态设置为完成。

  • 规范程序。为团队如何处理添加新的功能(包括引入技术债),制定可重复的公式。

技术债有哪些不同类型?

目前,大多数专家普遍认为技术债有故意和无意的两种类型。其中:

  • 当组织为了缩短上市时间而选择留出改进代码的空间时,就会产生故意的(也称为主动)技术债。

  • 当在发布了一段时间create后需要提高代码的质量时,就会产生无意的(也称为偶然的、过时的、被动的)技术债。这些既可能是由于第一次发布不佳所致,也可能是由于代码过时而自然产生的更新需求。

另一种观点则根据技术的具体类别,以及组织预期的更好服务,提出了如下13种不同类型的技术债,每一种债务都包含了标题中的特定问题:

  • 建筑债务

  • 构建债务

  • 代码债务

  • 缺陷债务

  • 设计债务

  • 文件债务

  • 基础设施债务

  • 人员债务

  • 处理债务

  • 需求债务

  • 服务债务

  • 测试自动化债务

  • 测试债务

Martin Fowler在故意和无意的分类基础上增加了鲁莽和谨慎两个维度,提出了技术债的四象限。其中谨慎的技术债来自一个知道如何做的团队,而当人们太草率时,鲁莽的债务就会产生。两者的区别在于:审慎的团队是在了解其行为的基础上,故意地去使用技术债。而鲁莽的团队则像是刚刚经历了双十一剁手节一样,碰到债务的不断增加。

可见,对于所有的软件工程团队而言,无论他们的专业知识或经验如何,适当承担一定程度的债务是可以接受的。也就是说,在谨慎的情况下,一些可以预期的债务会促进团队知晓应当对手头的项目做些什么,以及哪些是稍后要进行的一些新工作。他们不但会尽力减少鲁莽的债务,还能减少不良代码,以提高软件的质量。

应当始终避免哪种类型的技术债?

审慎的技术债虽然对软件组织来说有一定的好处,但是如果累积得多了,从量变发生了质变,也可能会成为鲁莽的技术债。也就是说,当软件随着时间的流逝,恶化到产生错误、甚至影响其功能和可用性时,就会成为Bit rot(也称为“软件熵”)。例如:当开发人员需要对其不甚了解的历史遗留代码进行较小的增量更改时,软件本身的复杂性和潜在问题会随即增加。一些工程师甚至可能违反NFR(Non-functional requirement,非功能要求),完全破坏代码,进而对软件的整体功能产生影响。解决此类技术债的唯一方法便是重构整个过程。

而且,在大多数情况下,团队并不会察觉到自己的一些微小变化,实际上会导致债务总额的增加。虽然我们也可以使用Wolper的透明化概念,协助避免此类灾难的发生,但是从根本上说,团队还是应当对目标软件具有充分的了解,从而避免在无意中添加可能阻碍系统的代码。

技术债的指标有哪些?

和任何良好的管理计划类似,组织需要通过了解各项指标,才能获得对于技术债的控制权。下面是一些值得参考与衡量的指标:

软件缺陷

软件开发者应当持续记录和跟踪发现到的缺陷,其中包括未修复的缺陷和已修复的缺陷。对于未修复的缺陷,开发团队可以在敏捷迭代中持续专注和修复它们。而通过跟踪已修复的缺陷,团队则能够衡量其技术债的管理流程与效率。

代码质量

如果说软件缺陷直接影响的是软件的最终用户,那么代码的复杂性则会阻碍团队的开发与维护。下面是有关代码复杂度的指标:

  • 圈复杂度

  • 类的耦合

  • 代码行数

  • 继承的深度

当然,这些指标应该越低越好。通过密切关注这些指标,团队还能够准确地获悉有待重写或重构的代码,以降低复杂性,并改善软件的后端。

代码的内聚

与代码质量类似,专注代码的内聚性,将有助于简化代码的复杂性。较高的代码内聚性通常意味着目标代码更具有可维护性、可重用性和鲁棒性。同时,该指标还可以最大程度地减少需要开发人员的数量,以及大幅降低复杂性,减少Bit rot。

代码所有权

“人多手杂”在此可以被用来形容更多的开发人员,产生更多的工作量,导致更大的问题,以及更多的无意技术债。因此,我们需要祭出“代码所有权”的指标,来解答“谁在关注哪块代码?”,以及“如果出现问题该找谁?”等问题。

此类指标将向项目管理人员展示从事某项代码工作的人员数量,以及花费在控制上的时间。据此,我们可以避免由于完整的代码部分被掌握在某个成员手里,而他可能因为被堵在路上,而耽误了项目进度等单点故障。因此,我们可以将代码库分割成不同的域,然后授权给团队中不同的开发人员角色。

代码变化(Churn)

代码段被重写或替换等活动都可以被视为发生了代码变化。如果开发人员不得不围绕着某段代码持续解决相似的错误,那么就意味着此处的技术债非常严重。据此,团队也可以识别并确定代码的哪些部分需要重构。因此,团队需要特别注意那些经常发生变化的代码,以便快速发现问题,进而避免问题的加剧和技术债的累积。

值得一提的是,简单地跟踪上述技术债的各项指标,并不能自动消除所有的债务,我们仍然需要更为有效的管理实践。

有关技术债的调查

根据卡内基梅隆大学软件工程学院的一项行业调查(请参见--https://insights.sei.cmu.edu/sei_blog/2015/07/a-field-study-of-technical-debt.html)发现:糟糕的架构往往是技术债的首要来源,其次是过于复杂的代码,第三则是缺少文档和测试之间的紧密联系。而更糟糕的是,有65%的受访者表示他们没有适当的技术债管理应用。这就意味着由于缺乏策略来应对技术债,因此他们选择不去实施任何解决方案!

一位拥有与多家公司(从《财富》500强到初创公司)合作超过20年经验的软件开发人员建议:开发团队应当像投资信用卡业务那样去投资技术债,而且投资的重点应放在如下两个地方:

  • 公司的文化,将人员对应到复杂的系统上,各司其职。

  • 代码库的构建,执行更深入和更频繁的质量保障测试。在组织已经积累了大量技术债的情况下,您可以将此类测试自动化。投资的内容至少涉及到通过某种形式的代码审查,以确保问题能够被尽早地解决。当然,这也意味着需要更加频繁地进行重构。

不过,上述两方面的投资只是一个起点,我们仍然强调需要管理自己的技术债。如果没有一个明确的策略,技术债会继续增加,并在线上和线下制造更多的问题,正如上述调查中所提到的那样。

如何管理技术债?

就像金融债务一样,只有通过制定计划,实施管理,才能减少技术债。当然,正所谓“知易行难”,我们真正管理起来并不容易。它需要持续的监控和投入,并将其纳入软件开发的必要组成部分。而且,由于技术债很容易脱离业务目标,因此对其管理有助于让开发与业务目标保持一致。

据预测,到2024年,技术债务将给全球科技公司带来4万亿美元的损失。而实施了技术债管理与补救的公司将会缩短50%客户产品交付时间。

目前,市场上已有一些新的技术应用捕捉到了此类软件需求,并提出了相应的解决方案。例如,Stepsize之类的软件,便可以使开发团队轻松地获取债务报告,对它们进行分类,并确定有待解决的最重要债务。通过监控并管理积累的所有技术债,它们可以协助软件工程团队在无需大幅改变常规工作流程的前提下,及时交付出色的软件产品。

原文标题:The Engineer’s Complete Guide to Technical Debt,作者:Alex Omeyer

【51CTO译稿,合作站点转载请注明原文译者和出处为51CTO.com】