从广义上讲,技术债务是在软件开发过程中的一系列决策,这些决策会导致团队通过构建特性以创造价值的能力受损。
大家应该对下面的交流十分熟悉:产品经理描述了他们想要添加到产品中的下一个功能。开发人员要求给很长的时间才能实现该功能,而一般管理者会认为这个时间太长。开发人员则会谈到需要解决修改大量难以理解的代码时出现的相关问题,或者要应对旧的代码库或框架中的各种缺陷。因此,开发人员要求更多的时间来解决这些问题。产品经理会拒绝他们的要求,并指出眼下还有一大堆等待实现的期望功能。
如果情况长期无法解决,这种恶性循环可能导致失去市场竞争力,甚至复杂软件系统的整体崩溃。
我们有两种方式暂时应对这种情况,其中一种是选择简单或快速但并非最佳的解决方案,另一种则会导致技术栈落伍或能力的欠缺。这两种情况都需要花费工程团队的时间来处理偶发的复杂问题,进而影响创造价值或修复缺陷。
在保持快速交付功能的同时偿还技术债务会很困难,而且系统架构越大越难。管理数十或数百个微服务的技术债务要比单个服务复杂得多,并且不偿还债务所带来的风险会增长得更快。
每个软件公司都会遇到必须处理技术债务的时候。
在 Optum Digital,一个产品集(也被称为软件产品线)是一系列满足特定需求的产品的组合。每个产品都会有多个团队,通常会与软件客户端或后端服务保持一致。还有一些团队负责面向平台的、横跨多个项目集的功能。每个团队很可能负责各种软件库。我们有 700 多名工程师在开发数以百计的微服务。他们非常重视技术债务,因为失控的风险是非常大的。
2018 年,我们的首席技术官(CTO)最初发表了一篇关于工程投资重要性的博文,在这两年多的时间里,他们将自己的整体业务拆分为了微服务。
公司的工程师们提出了技术能力计划(Technology Capability Plan,TCP)来解决技术债务问题。
TCP 是一种基于社区的用于制定偿还技术债务计划的方法。 在工程中,它通过收集、组织和传达技术领域中不断变化的需求向工程端和产品端传递信息,以保证架构的长久性和适应性。 换句话说,它可以用来指出公司如果不及时采取具体措施,将会在何时陷入困境。
该计划鼓励社区按照特定的格式制定偿还技术债务的计划。在记录每个领域技术债务的风险分数后,根据该风险分数设定要进行处理的优先级。通过优先级计划,可以与产品经理积极而有效地协商技术债务偿还的工程时间。
在组织内,工程社区是横向形成的,换句话说,它们与特定的团队或产品无关。工程师们通常因为他们热衷于使用相同的技术而加入到这些社区来,因此社区是开放的,并有机地发展。
但是,如果某些社区具有战略价值,它们可以将其设为邀请制。 如果成员是经过筛选确定下来的,那么社区重点应该放在文化补充(culture add)上而不是文化契合(culture fit)上,而且还应该具备代表性和多样性。
他们通常有专门的交流方式(例如,wiki 话题、聊天频道和电子邮件列表),以便于持续交流和资源共享。
这些工程社区的政策都是自下向上制定的,这是保持 TCP 有效性和真实性的关键。
每月的社区会议会记录下来并进行共享,会议纪要会发送给所有工程师。每个社区的会议活动都保持更新记录,每个季度这些文件会收集起来,并在内部作为 TCP 发布。
每个社区的计划都包含约一页左右的说明以及一张记录随着时间推移所需的技术演进的表格。
表格中的每一行对应某种编程语言、框架、库或平台即服务的“首选”、“可接受”、“不主张”或“不可接受”(PADU)版本,这是与组织的技术栈息息相关的。
每一列代表一个时间段(例如一季度或一年)。整个表格可以展示未来三年的数据。
表格中每个单元格都包含该时间范围内该技术的生命周期状态:计划(plan)、弃用(deprecate)、迁移(migrate)、使用(use)或移除(remove)。
其中“计划”状态表明需要制定计划进行升级。 “弃用”意味着团队不能再采用该技术版本。“迁移”表明每个团队都应该主动迁移到适当的版本。 “使用”表示该技术版本是应该使用的。“移除”意味着该技术可能在该时间段内随时失效。
说明页用以描述每种技术的应用背景以及不遵循计划可能带来的影响或后果。这些社区驱动下的计划能够帮助组织管理因使用过时的、不安全的或不受支持的技术版本所带来的技术债务。
每个产品集也提交 TCP 计划。产品集驱动下的计划可用于指导偿还其他形式的技术债务,例如重构大型代码库或者将单体服务拆分为多个较小的服务。
TCP 中除了社区和产品贡献的部分之外,还会介绍计划的愿景,另外有一个章节会介绍目前风险最大的产品领域。
工程社区和主要产品集工程师们制定了偿还技术债务的计划之后,就需要进行一系列的工程投资。 在资源有限的情况下,应如何确定处理的优先级呢?产品管理人员并不知道该怎么做,因为工程投资不是从他们那里来的。要回答这个问题,需要了解如果不遵循计划会带来什么样的风险。
这种风险可以通过风险分值进行量化。得分越高,风险越大,优先级则越高。“使用”状态下的技术分值始终为零,随着技术版本变为“迁移”、“弃用”或“移除”状态时,风险分数会逐渐增加。
计划制定都是自下而上的,而风险评分则是自上而下的。技术债务偿还计划由社区工程师们制定,而计划清单的优先次序则由工程管理人员制定。
Optum Digital 的指标都收集到所谓的平衡计分卡中,这是一种哈佛商学院研发出来的战略绩效管理工具。
各种计划中技术债务都以产品为单位进行汇总。每个产品的风险评分是该产品所有技术风险评分的总和。 即便产品中只有一项技术仍在使用或依赖已经处于“弃用”、“迁移”或“移除”状态的技术,该产品的风险评分也会受到负面影响。如果产品中有多个代码库都不合规,风险评分只会计算一次。每种产品风险评分汇总结果的中位数要记录在平衡计分卡中。
在存储库上使用自动化的静态代码分析以确定技术依赖关系很有价值的。另外还需要支持 CI/CD、DevOps 和 GitOps,以便于快速、可靠地计算这个指标。
为帮助团队专注于产品,我们还要以不同的方式计算 TCP 风险分数。这种情况下,计划中的每一项技术都以代码库为单位进行汇总,每个代码库的风险分数是该代码库所有技术风险分数的总和。
产品代码库的总风险评分汇总为产品本身的总风险评分。通过这种方式,我们可以跟踪每个产品的风险消除情况,或者基于 TCP 风险进行产品比较。
现在,我们已经有了一个优先计划来偿还技术债务,这个计划是由工程师团队制定的,并得到了领导层的支持,那么我们该如何为这个计划提供资金,并将其置于路线图中呢?
首先,让我们回顾一下,在没有 TCP 的情况下,当工程经理和产品经理坐下来为下一个 sprint 制定开发计划时,通常会发生什么:在无 TCP 环境中,只有工程经理和产品经理,产品经理总是能以销售作为理由来达到他们的目的。
让我们在有 TCP 的情况下重新看待这种情况。产品经理刚刚与主管们开完会,讨论了 TCP 的重要性以及如何在平衡计分卡中降低 TCP 风险分数,然后与工程经理坐下来为下一个 sprint 制定计划。产品经理要求提供三个新功能。工程经理说:“如果由我决定,我会把这三个功能都做出来给你。不幸的是,我们所有的工程师和他们的主管们都已经意识到,这个风险极高的技术债务需要在本季度偿还。如果你在过去的一年里一直关注 TCP 就应该已经意识到了这一点。”
你看到这种变化了吗?因为 TCP 是企业范围内对技术债务及其风险的权威共识,工程经理就不用通过吵架或者威胁,而是使用这种集体讨价还价的能力获得应有的工程投资。
在少数的情况下产品经理依然在批准工程投资方面不够灵活,那么问题最终会提升到管理层进行解决。还记得风险分数是平衡计分卡的一部分吗?对于管理层来说,平衡计分卡就是他们的仪表盘,可以观察公司发展方向。仪表盘上显示的这些指标可以让他们更真实地感受到技术债务,使得他们更可能选择偿还结束债务的工程投资。
我所知道的仅有的另一种管理技术债务的系统性方法记载在 Google Site Reliability Engineering 一书中。
下面我们快速介绍一下这种方法,并说明我为什么认为 TCP 更好。
首先,基于 SLO 或服务水平目标目标达成共识。每次系统超出这些 SLO 之一时就将其视为错误。每个时间窗口有一个商定的可接受错误数量,称之为错误预算。如果系统在下一个时间窗口之前已超出其错误预算,将不可发布任何功能。
为了避免这种情况,产品经理应该更愿意转移工程资源来偿还技术债务。
接下来解释一下 Google SRE 方法非常不稳定的原因。对于大多数产品经理来说,功能和销售之间的因果关系似乎比技术债务和系统中断之间的因果关系更真实。有一种假设是,消除技术债务总是使系统更加稳定。 虽然长期来看这是正确的,但不能保证在短期内有效。
错误预算会倡导短期思维,因此不利于产品经理批准此类工程投资。由于很难预测何时超出错误预算,因此很难计划何时安排工程投资。
这种方法容易使产品经理与工程经理产生某种对立关系,这种僵持方式会使接受的风险变大,因此获得管理层批准的难度更大。最后,这种方法容易将支付技术债务政治化,产品经理试图通过说服高管不要将某些中断计入他们的错误预算,或通过重新协商 SLO 或错误预算来推迟工程投资匮乏所产生的后果,从而与系统博弈。
而 TCP 方法侧重于在产品和工程之间达成真正的共识。TCP 驱动下的开发在路线图方面更具可预测性,因此所有相关方都不容易出问题。
技术能力计划能否解决所有的工程问题么? 当然不能。
你还会有技术债务吗? 绝对会有。
在客户驱动下是否仍需要走捷径以交付功能? 我相信你会的。
TCP 无意阻碍或限制工程师和产品经理做他们最擅长的软件开发和发布。TCP 向工程师和产品经理发出信号,表明走捷径会产生额外的成本,并且他们不能无限期地忽略这些成本。
使用 TCP,您不必等到中断严重时才开始偿还技术债务。没有任何流程、政策、技术或工具可以作为质量工程的有效替代品。
TCP 记录了工程师们关于什么是风险最高的技术债务以及偿还它的合理时机的共识。 要使 TCP 得到尊重,它的计划必须是相关的、准确的、有说服力的和可信的。只有当它的贡献者是经验丰富且成熟的专业人士,具有强大的工程技能以及诚信品质时,这一切才能实现。
我认为我们 TCP 文档中的这句话是最好的总结:
设计持久和具有适应性的产品需要对今天的现实和明天的可能性有深刻的理解。它需要了解驱动它的技术和市场力量,需要长期致力于集中和持续的进步。
最近面试的小伙伴很多,对此我整理了一份Java面试题手册:基础知识、JavaOOP、Java集合/泛型面试题、
Java异常面试题、Java中的IO与NIO面试题、Java反射、Java序列化、Java注解、多线程&并发、JVM、Mysql、Redis、
Memcached、MongoDB、Spring、SpringBoot、SpringCloud、RabbitMQ、Dubbo、MyBatis、ZooKeeper、数据结构、算法、
Elasticsearch、Kafka、微服务、Linux等等。可以分享给大家学习。【持续更新中】