技术债务的类别
技术债务是软件开发中用于比喻短期决定促使长期成本增加的现象,其中成本的增加类似于随时间增长的应计利息。更确切地说,团队当前为某个决定付出的工作越多,后期就越可能需要更高的工作量来纠正这个决定。
这一术语在软件行业内获得了不少的关注,但技术债务不是百害无一利的,它有时也能快速解决产品上市的问题。这个概念最早是由 Ward Cunningham 提出的:
第一次交付的代码如同欠债一样,只要能通过重写还清,一点债务就能加速进程……但如果债务没有即时还清,那么就危险了。在问题代码上花费的每一分钟都会算作是债务的利息。地基不牢的实现所带来的债务负担甚至会让全部工程团队停滞不前,无论这种实现是否是面向对象的。【注 1】
有两个重要的点需要注意。首先,技术债务往往是软件交付过程中很有帮助的权宜之计。没有任何产品时完美的,无数软件项目都曾过于沉迷“打磨”短期内完全够用的代码而就此消失。第二点则是,在长期可支持性面前,这些权宜之计可能会需要重新考量。
不过,我们还需要对“技术债务”这一词有明确定义才能避免引起混淆。Kruchten、Nord 及 Ozkaya 在他们的《管理技术债务》一书中,对技术债务的概念及相应管理方法做了很好的概述,这是他们给出的定义:
在软件密集型的系统中,技术债务由设计和实现结构组成,这些短期内的权宜之计构建的技术环境,可能让未来的变动更加昂贵或不可能。技术债务是一种或有负债,主要影响内部系统质量,但不限于可维护性和可进化性。【注 2】
这种定义深得我们喜爱,因为它更侧重于技术债务的影响,而非是其在金融债务方面的比喻,后者仅仅涵盖了部分问题所在。正如《实践中的持续架构》所言:
对可维护性和可进化性的关注对技术债务的
对可维护性和可进化性的关注度是影响技术债务看法的关键。这就意味着,如果系统没有对进化的期望,那么对技术债务的关注也应当是最小化的。以旅行者号航天器为例,其软件的技术债务是非常有限的,因为它没有进化的需求,维护的机会也有限。
感兴趣的读者可以参阅注 2 中的《管理技术债务》,以获取关于该主题的更多内容。也可以在《管理技术债务》、《技术债务》,《技术债务和利息的实证模型》的参考文献部分,以及雷曼法,找到更多关于技术债务的实证研究。
什么是技术债务?
依据 Kruchten、Nord 及 Ozkaya 的定义,技术债务可以分为以下三大类。
-
架构:由软件开发过程中的架构决策造成的债务。
-
代码:难以维护或发展的临时代码。
-
生产基础设施:为构建、测试和部署软件系统的基础设施和代码的决策。
此外,技术债务可以是无意为之,也可以是特意为之。许多业界人士认为潜在的缺陷是技术债务的一部分,而架构决策则几乎永远是在两个相互冲突的 QAR 之间权衡,因此后者是属于“有意为之”的分类。
技术债务一词的不足
每个术语都有不足,“技术债务”也不例外。
-
假设性。一个“技术债务”问题可能永远都不需要解决。或许代码很丑,但如果能正常运行且没什么副作用或依赖性,那团队完全可以专注于其他事,比如为客户提供价值。认为其需要修复则是夸大了问题本身。如果可以将问题影响局部化,那这个问题大概就不需要修复。
-
与拥有贷款人的债务不同,团队的技术债务没有限制。贷款人会评估债务人的还款可能性,并为债务人违约时造成的后果寻求保障。习惯性滥用债务的人最终将再也无法拿到信贷的机会。
相比之下,软件团队的限制较少。自动或手动的架构、设计,以及代码审查之类都可以防止技术债务意外发生。但在复杂的系统中,审计无法找到的很多错误只会在运行的系统中出现。错误预算或许能让团队在解决缺陷之前不再新增更多功能,但它的前提条件是要能识别出错误,而技术债务就像是水下冰山,大部分都是看不见的。
但是在多数情况下,开发团队可以随便“发布”任何包含有意为之的技术债务,而不会有人要他们为自己不可持续的决定负责。事实上,如果他们在面向项目的资金模型组织中工作,那么他们要做的就是把项目发布到生产中去,让 IT 运维去头疼因此产生的问题,成功让自己甩锅。
-
决策推迟的成本会随着时间的推移迅速增长。但决策推迟实际不存在。决定在未来采取不同方法不过是额外的工作成本,而如果需要返工的代码有大量依赖,重写代码的成本将会叠加式增长(见《寻找管理架构性技术债务的指标》)。技术债务所暗含的复利意味着返工的成本增加,但却掩盖了造成成本增加的依赖原因。通过封装和模块化等设计策略,团队可以减少甚至完全消除变化所带来的成本。
-
只要没出大事,多数组织都会无视技术债务。这就又让我们回到了第一个问题上,这些问题或许并不需要解决。而即使这些问题真的需要解决,商业利益相关者也大概不会重视。真正的问题在于“技术债务”这个词将重点仅仅放在了成本上,没有传达商业利益相关者会因为忽视技术债务而损失的东西。对于眼里只看得到一季度或一年的人来说,长远的可支持行没什么讨论的必要,也就可扩展性和防御破坏性安全漏洞有些许的说服力。
-
技术债务很难用财务术语来量化。就像 Kevlin Henney 在 2022 年 QCon Plus 的演讲中所述(可参见 Ben Linders 的 InfoQ 文章《技术债务可量化为金融负债:开发者眼中的不可能》),管理者对团队无法衡量其技术债务的金融价值感到迷惑,对于耳濡目染“你无法衡量的东西,你也无法管理”【注 4】的人来说,无法表达技术债务的财务影响让团队看起来很不明智。
架构决策和技术债务
正如我们在前一篇文章中所述,软件架构是 QAR 驱动的决策,而这些决策可能对技术债务有积极或消极的影响,如图一所示。决策发生的时间决定了团队架构设计所要采取的方式。在项目之初,通常也是在确切定义 QAR 之前,便做出多数的架构决定,可能会导致前期架构不易发展,且随着对 QAR 更准确的定义,也需要大规模重构。与之相反,如果在敏捷架构中的每个阶段,逐步做出架构决策,可以更好地适应 QAR 的变化。
几乎所有的架构决策都是至少两个 QAR 之间的权衡。如安全性与可用性之间的抉择,无论怎么选都有可能增加技术债务,无论是优先考虑可用性但使系统更加脆弱,还是优先安全性但牺牲系统可用性。说到底,随着用户数量的增加,或者需要调整 QAR 的优先级才能让技术债务更可控,将来的某天我们总要面对这些问题。其他例子还有可扩展性和可修改性、可扩展性和上市时间。
这些决定通常被描述为“满足”,也就是“足够好”。虽然你还可以做得更好,但你选择在结果足够好时就停下来。正如《实践中的持续架构》中所言,“架构决策可以增加或削减技术债务”【注 5】。然而,具体增加或削减了多少,这是很难用财务甚至技术术语来量化的。
除非团队成员非常幸运或者知识极其渊博,否则无论是通过什么方法,他们所做的部分技术决策可能都需要根据反馈回路所带来的信息(见图一)在未来进行调整甚至彻底重做。对现有的架构决策进行调整或重做会产生额外工作量,并与其他积压的任务相竞争,后者常被期望能向利益相关者提供有用功能而被认为拥有更高优先级。因此,调整或重做架构决策相关的工作可能会被推迟,从而进一步增加系统的“技术债务”。
质量属性、架构决策、技术债务与反馈循环
每当团队做出决策时,都要做好所有这个决策相关工作在未来都可能要返工的准备。因此,团队需要将决策视作是需要在相当短的时间内验证或需要的假设,以确保所作的工作在未来的某一时刻不会被删除。
因为所有工作至少在验证之前,都有可能产生额外的返工工作量,所以,团队可以尝试以下几点:
-
推迟决策到万不得已时再决定;
-
尽快验证必须做出的决策,以限制潜在的成本风险;
-
通过封装和抽象等设计技巧减少依赖关系的增长。
了解并接收决策对技术债务的影响有助于团队更好地做出决策。但由于其很难通过财务术语量化,技术债务对评估决策成本没有帮助,且很难被用作是评估至少两个 QAR 之间权衡的精确评估工具。
让我们再回到安全性与可用性的例子。要想在短时间内部署一个 MVP,我们很难估算最小可用架构(MVA)在优先可用性而非安全性时所带来的财务影响。更好的方案是做出一系列最小化决策后,随着时间的推移,借助经验对其进行测试和发展。这些决策应当搭配一套最小架构实践加以补充,以帮助团队在发展产品的同时保持架构的可行性。
当然,架构工作中最重要的一部分就是沟通,即使我们无法将与决策相关的技术债务数量进行准确量化,还是可以利用这一比喻可以帮助团队沟通决策的长期影响。
延迟维护:或许是更合适的用词?
技术债务在工程界有另一个说法:延迟维护。延迟维护是设计优秀的大桥断裂、设计优秀的大楼坍塌、设计优秀的飞机从空中坠落的原因。在物理学中,熵的增加是有代价的,而如果无法领先熵的增长将会产生灾难性后果。
分析物理学延迟维护成本的优势在于,我们能更清晰地看到维护被推迟时,成本是如何快速累加的:如果底层钢板没什么问题,那么密封图层就足够了。而一旦钢板开始锈蚀,在重新喷漆之前就必须先清理干净旧涂层和铁锈。如果钢板已经出现裂痕,那么就还需要加固,裂痕过于严重甚至还可能需要更换全部的结构。
对于软件来说,事情远没这么简单。错误不易被检查发现,再加上组件之间交互导致返工可能影响到全部代码库。即使是“简单”的组件替换也会非常困难,因为新组件可能有副作用,或者需要不同的参数数据,而调用它的代码可能无法访问这些数据。如果变动的是如调整算法等更深层次代码,那么成本将会是指数级地增加。
但就如“维护”一词也是有限制的。“维护”通常是指对磨损部件的简单维护,但软件不会随着使用而磨损。软件的变化可能由外部事件引起,如操作系统或框架的变化、供应商倒闭,或者基础设施软件的新版本,以及更具破坏性的,由客户行为、商业运作或组织战略变化等造成的影响。
每一种用词都有其局限性,有时我们必须抛弃这些术语,才能找到更好的模型来帮助我们做出决策。
结论
多数团队并不认为目前的决策在未来可能会被撤销或返工,但现实中事情总会发生变化,而我们需要不同的方式以面对这些变化。虽然团队无法预测未来,但他们可以通过实验,在变更所带来的影响变得无法接收之前检测出这种可能性。
技术债务是对未来变更工作量已知的一个例子,常发生于团队决定推迟必须要完成的工作量。债务一词意味着,处理这类变化所需的成本将会随着时间的推移呈指数上升,与复利类似。但矛盾的是,正如我们在本文中所述,技术债务很难用财务术语进行量化,这也限制了它在决策评估成本模型中的作用。
虽然技术债务有助于向利益相关者传达团队决策的技术影响,但更合适的方法是通过质量属性要求重塑讨论,让利益相关者将其看作是软件系统必备的能力,而非是需要完成的工作量。
最后,感谢 Thomas Betts、Murat Erder、John Klein、Philippe Kruchten 以及 Eoin Woods 为本文的初版审阅。
尾注
-
Ward Cunningham,《WyCash 投资组合管理系统》,ACM SIGPLAN OOPS Messenger4, no.2 (1992)
-
Philippe Kruchten, Rod Nord, and Ipek Ozkaya, 《管理技术债务:减少软件开发中的摩擦》(Addison-Wesley, 2019).
-
Murat Erder, Pierre Pureur, and Eoin Woods, 《实践中的持续架构》 (Addison-Wesley, 2021)
-
这句话经常被认为是 Peter Drucker 和 W.Edwards Deming 说的。
-
Murat Erder, Pierre Pureur, and Eoin Woods, 《实践中的持续架构》 (Addison-Wesley, 2021)
原文链接:https://www.infoq.com/articles/technical-debt-tells-you/