瓶颈 #01:技术债务

技术债务的累积;实验和捷径是核心组成部分

2022 年 3 月 9 日


Photo of Tim Cochran

Tim Cochran 是 Thoughtworks 美国东部市场的技术总监。Tim 拥有超过 19 年的经验,领导着从初创公司到大型企业的各种领域的工作,例如零售、金融服务和政府。他为组织提供技术战略方面的建议,并进行正确的技术投资,以实现数字化转型目标。他是一位热衷于开发者体验的倡导者,并热衷于使用数据驱动的方法来改进开发者体验。

Photo of Carl Nygard

Carl Nygard 是 Thoughtworks 的技术主管。Carl 拥有超过 20 年的经验,领导着从初创公司到大型企业的团队,为 GIS/遥感、供应链、实时控制、在线教育、零售和政府构建解决方案。他与组织合作制定技术战略,通过优化的软件交付实践实现业务成果。


在早期,初创公司会寻找合适的产品市场匹配。当找到合适的匹配后,它会寻求快速增长,这个阶段被称为规模化。在这个阶段,它在许多方面快速增长:收入、客户、员工数量。在 Thoughtworks,我们与许多这样的规模化企业合作,我们的工作重点是帮助他们克服阻碍这种增长的各种瓶颈。

在进行这项工作时,我们注意到了一些常见的瓶颈,并学习了应对这些瓶颈的方法。本文是一系列文章中的第一篇,探讨了这些瓶颈。在每篇文章中,我们将探讨初创公司是如何陷入瓶颈的,通常是通过在初创公司生命周期的早期阶段做正确的事情,但随着增长的变化,这些事情不再正确,因为工作方式的背景发生了变化。我们将重点介绍初创公司正在接近或陷入瓶颈的关键迹象。然后,我们将讨论如何突破瓶颈,描述我们所见过的让规模化企业实现其应有潜力的变化。

我们从技术债务开始这个系列:如何改变促进产品/市场匹配快速实验的工具和实践,以便在增长开始后也能适应。

你是如何陷入瓶颈的?

我们遇到的最常见的扩展瓶颈是技术债务——初创公司经常说技术债务是他们增长的主要障碍。术语“技术债务”往往被用作一个笼统的术语,通常表示技术平台和堆栈需要改进。他们发现功能开发速度变慢、质量问题或工程人员感到沮丧。初创公司团队将其归因于他们在增长阶段缺乏技术投资而产生的技术债务。需要进行分析以确定技术债务的类型和规模。可能是代码质量很差,使用了较旧的语言或框架,或者产品的部署和运行没有完全自动化。解决方案策略可能是对团队流程进行微调,或者启动一项重建应用程序部分的计划。

重要的是要说明,谨慎的技术债务是健康的,也是可取的,尤其是在初创公司旅程的初始阶段。初创公司应该用质量或健壮性等技术方面来换取产品交付速度。这将帮助初创公司实现其第一个目标——可行的商业模式、经过验证的产品以及喜欢产品的客户。但是,当公司寻求扩展时,我们必须解决所采取的捷径,否则它会很快影响业务。

让我们检查一下我们遇到的几个例子。

公司 A——一家初创公司已经构建了一个 MVP,该 MVP 已经显示出足够的证据(用户流量、用户情绪、收入)来吸引投资者,并获得了下一轮融资。与大多数 MVP 一样,它是为了生成用户反馈而构建的,而不是为了构建高质量的技术架构。在获得融资后,他们没有重建该试点,而是继续在其基础上进行构建,通过专注于功能来保持吸引力。这可能不是一个直接的问题,因为初创公司有一个小型高级团队,他们了解尖锐的边缘,并且可以提供临时解决方案来维持公司的运营。

问题开始出现时,团队继续专注于功能开发,而债务却没有得到偿还。随着时间的推移,低质量的 MVP 成为核心组件,没有明确的改进或替换它们的途径。学习、工作和支持代码存在摩擦。有效地扩展团队或功能集变得越来越困难。工程领导人也非常担心原始工程师的流失,以及他们所掌握的知识的流失。

最终,缺乏技术投资达到了顶峰。团队变得瘫痪,表现为速度降低和团队沮丧。初创公司必须进行重大重建,这意味着功能开发必须放缓,让竞争对手赶上来。

公司 B——该公司由前工程师创立,他们希望做所有事情都“正确”。它是为了扩展而构建的。他们使用了最新的库和编程语言。它具有细粒度的架构,允许应用程序的每个部分使用不同的技术实现,每种技术都经过优化以完美扩展。因此,当公司发展到那个规模时,它将能够轻松地处理超速增长。

这个例子的问题是,它花费了很长时间来创建,功能开发速度很慢,许多工程师花费时间在平台上工作,而不是在产品上工作。它也很难进行实验——细粒度的架构意味着不适合现有服务架构的想法很难实现。该公司没有意识到高度可扩展架构的价值,因为它无法找到产品市场匹配来达到那个规模的客户群。

这两个例子都是极端的例子,基于 Thoughtworks 初创公司团队与各种客户合作的经验。公司 A 陷入技术债务瓶颈,使公司瘫痪。公司 B 过度设计了一个解决方案,减缓了开发速度,并削弱了它在学习更多知识时快速转向的能力。

这两个例子都体现了无法找到技术投资与产品交付之间的正确平衡。理想情况下,我们希望利用谨慎的技术债务来推动快速的功能开发和实验。当发现这些想法有价值时,我们应该偿还技术债务。虽然这很容易说出来,但要付诸实践却很困难。

为了探索如何创造正确的平衡,我们将研究不同类型的技术债务

典型的债务类型

技术债务是一个含糊不清的术语,通常被认为纯粹与代码相关。在本讨论中,我们将使用技术债务来表示任何技术捷径,即我们用对技术平台的长期投资来换取短期功能开发。

代码质量
脆弱、难以测试、难以理解或文档不足的代码将使所有开发和维护任务变慢,并降低编写代码的“乐趣”,从而使工程师失去动力。另一个例子是领域模型和相关数据模型不适合当前的业务模型,导致出现变通方法。
测试
缺乏单元测试、集成测试或 E2E 测试,或者分布不当(参见测试金字塔)。开发人员无法快速确信他们的代码不会破坏现有功能和依赖关系。这会导致开发人员批量更改,并降低部署频率。较大的增量更难测试,通常会导致更多错误。
耦合
模块之间(通常发生在单体应用中),团队可能会互相阻塞,从而降低部署频率,并增加更改的交付时间。一种解决方案是将服务提取到微服务中,这会带来自身的复杂性——在单体应用中设置明确的边界可能会有更直接的方法。
未使用的或价值较低的功能
通常不被认为是技术债务,但技术债务的症状之一是难以使用的代码。更多功能会创建更多条件,更多开发人员必须设计绕过的边缘情况。这会降低交付速度。初创公司正在进行实验。我们应该始终确保回头重新评估实验(功能)是否有效,如果无效,就删除它。从情感上讲,团队很难做出判断,但当你拥有量化功能价值的客观数据时,它会变得容易得多。
过时的库或框架
团队将无法利用新的改进,并且容易受到安全问题的攻击。这会导致技能问题,减缓新员工的入职速度,并让被迫使用旧版本的现有开发人员感到沮丧。此外,这些遗留框架往往会限制进一步的升级和创新。
工具
需要大量维护的次优第三方产品或工具。市场不断变化,可能出现了更高效的工具。开发人员自然也希望使用最有效的工具。购买与构建之间的平衡很复杂,需要在考虑剩余债务的情况下重新评估。
可靠性和性能工程问题
这会影响客户体验和扩展能力。我们必须小心,因为我们已经看到在为假设的未来情况进行扩展时,过早优化浪费了精力。拥有一个经过验证的用户价值的产品,比一个未经验证但可以扩展的产品要好。我们将在“扩展瓶颈:没有考虑到可靠性和可观察性而构建”一文中详细介绍这一点。
手动流程
产品交付工作流程的一部分没有自动化。这可能是开发人员工作流程中的步骤,也可能是与管理生产系统相关的步骤。警告:当你在自动化一个使用频率不足以值得投资的事情上花费大量时间时,也会出现这种情况。
自动化部署
早期阶段的初创公司可以使用简单的设置,但这应该尽快解决——小的增量部署推动了实验性软件交付。使用四个关键指标作为你的指导。你应该能够随时部署,通常每天至少部署一次。
知识共享
缺乏有用的信息是一种技术债务。它使新员工和依赖团队难以快速上手。作为标准做法,开发团队应该编写简洁的技术文档、API 规范和架构决策记录。它还应该通过开发者门户或搜索引擎进行查找。一种反模式是没有审核和弃用流程来确保质量。

这真的是技术债务还是功能性?

初创公司经常告诉我们他们被技术债务淹没了,但在仔细检查后,他们实际上指的是技术平台的功能有限,这需要通过规划、需求收集和专门的资源来进行适当的处理。

例如,Thoughtworks 的创业团队经常与客户合作,自动化客户入职流程。他们可能拥有一个单租户解决方案,自动化程度很低。这在一开始还不错——开发人员可以手动设置帐户并跟踪安装之间的差异。但是,随着添加更多客户,这对开发人员来说变得过于耗时。因此,创业公司可能会雇用专门的操作人员来设置客户帐户。随着用户群和功能的增长,管理不同的安装变得越来越困难——客户入职时间增加,质量问题也随之增加。此时,自动化部署和配置或迁移到多租户设置将直接影响 KPI——这就是功能。

其他形式的技术债务更难发现,也更难指出其直接影响,例如难以处理的代码或重复的简短手动流程。识别它们的最佳方法是征求每天都遇到这些问题的团队的反馈。团队的持续改进流程可以处理它,不需要专门的计划来修复它。

你正在接近扩展瓶颈的迹象

价值交付时间

查看为用户提供价值的端到端流程及其随时间的趋势,将突出显示技术债务与其他问题之间的摩擦。

对最终用户的影响

系统中的延迟、客户入职时间和质量问题会影响客户——技术捷径可能是根本原因。

工程满意度

您的系统中有多个产品:一个是用户体验的,另一个是员工和开发人员体验的。倾听开发人员的抱怨会揭示技术平台中的根本问题,从而优先考虑对他们影响最大的问题。

吸纳新开发人员的能力

查看入职流程和新开发人员的满意度,可以发现长期员工已经养成习惯避免的问题。

非功能性指标的下降

运行时基础设施成本、性能和可用性都可能是过度技术债务影响业务成果的间接指标。

如果您已经看到这些迹象中的任何一个,您的产品路线图可以揭示在哪里针对改进进行投资。技术债务最大的负面影响将由您未来产品所需的平台部分造成。

如何摆脱瓶颈?

团队处理技术债务的方法应该来自其技术策略,由其领导者制定。它应该是故意的、清晰的,并且随着时间的推移而重新评估。不幸的是,我们经常看到团队根据历史方向工作,在没有意识到的情况下制造未来的问题。对于处于这种状况的公司来说,一些机会通常会触发何时重新评估其当前策略。

  • 新的资金意味着更多功能和更多资源——这将加剧当前问题。解决当前的技术债务应该是资金计划的一部分。
  • 新的产品方向可能会使之前的假设失效,并给系统的新的部分带来压力。
  • 良好的治理流程包括定期重新评估技术状况。
  • 新的观点可以帮助避免“温水煮青蛙”问题。外部帮助、团队轮换和新员工将带来新的视角。

滑坡

您是如何积累大量技术债务的?这可能很难确定。通常这不是由于单一事件或决策,而是由于在压力下做出的系列决策和权衡。

具有讽刺意味的是,事后看来,如果考虑到每个决策在做出时的时机,以及当时已知的信息,它不太可能被认为是错误的。但是,一个让步会导致另一个让步,以此类推,直到您遇到严重的质量问题。通常有一个临界点,在该临界点上,解决技术债务所需的时间比开发增量价值所需的时间更长。

很难恢复,情况往往会雪球般越滚越大。开发人员自然会使用当前状态作为可接受状态的指标。在这种情况下,开发新功能会导致更多债务。这就是滑坡,一个恶性循环,不幸的是会导致悬崖,因为实现下一个功能的努力呈非线性增长。

设定质量标准

许多组织发现,拥有公司承诺的一套标准和实践来指导技术发展是有益的。请记住,一些技术实践很难实现,例如持续交付;定期部署而不会影响用户在技术上具有挑战性。团队通常会遇到最初的问题,作为回应,领导层可能会降低该实践的优先级。相反,我们建议这样做,更频繁地这样做,您的团队将掌握这些实践并形成牢固的习惯。当困难时期到来时,不要放弃实践,而是利用反馈来指导未来对团队能力的投资。

爆炸半径

我们接受走捷径是扩展业务的必要部分。我们如何限制爆炸半径,因为我们知道这些捷径需要解决,甚至需要完全重建?显然,我们需要一个限制对业务影响的策略。一种方法是解耦团队和系统,这允许团队引入隔离的技术债务,并且不会像上面描述的那样雪球般越滚越大。

关于解耦的高质量文献很多,所以我们不会在这里尝试解释。我们建议将注意力集中在微服务和领域驱动设计技术上。但是,要小心不要过早地做太多事情,解耦会增加系统延迟和复杂性,并且在团队之间选择不良的领域边界会增加沟通摩擦。我们将在以后的文章中讨论与过度复杂的分布式架构相关的反模式。

产品和工程协作

如果权衡讨论没有在业务策略、产品和工程之间取得平衡,技术质量最常首先下降,因此产品质量最终也会下降。当您寻找此瓶颈的根本原因时,它几乎总是归结为公司内部业务、产品和工程目标之间的平衡。缺乏协作通常会导致在真空中做出的短视决策。这可能双向进行,在关键领域偷工减料或过度镀金一些没有价值的东西同样有可能。

  • 任何时候的业务策略都应该清晰透明。
  • 我们赋予团队领导者做出有利于业务的决策的权力。
  • 产品和工程应该平等地位,相互信任,并愿意根据对业务的长期和短期影响做出权衡决策。
  • 决策是根据数据做出的——例如,技术平台的当前状态、估计、对预期价值和 KPI 改进的分析、用户研究、A/B 测试结果。
  • 当数据得到细化或发现新的学习内容时,会重新审视决策。

限制技术债务影响的技术策略

在思考创业公司的策略及其如何扩展时,我们喜欢使用一个四阶段模型来了解创业公司发展的不同阶段。

第一阶段

实验

原型——半功能软件来演示产品,随着兴趣的增加而转向功能性

第二阶段

获得牵引力

生态系统决策——云供应商、语言选择、服务集成风格

用核心系统的原型软件替换

建立初始基础——实验、CI/CD、API、可观察性、分析

建立广泛的领域,设置初始的软边界(在代码中)

第三阶段

(超)增长

创建解耦的产品团队,管理他们自己的服务

建立与产品客户体验信号相关的 SLA 和质量标准

建立专注于产品团队有效性的平台团队

第四阶段

优化

重新评估专注于长期生产力和维护的 SLA 和质量标准

审计技术平台的状态,赞助产品团队的计划并创建临时老虎团队来修复最大的技术债务

重建或购买功能以提高效率

培训团队了解良好的技术质量实践

如何解决技术债务

它始于透明的信息共享业务状况、当前产品方向、当前扩展能力的指标、客户对产品的评价以及客户支持和运营部门的见解。这些信息将使技术人员能够做出明智的决策。共享当前挑战的数据有助于技术人员了解为什么解决问题以及衡量他们的成功。

应该对所有产品及其相关系统拥有明确的端到端所有权。随着团队的成长并承担其各自领域的责任,端到端旅程通常没有明确的所有权,这会导致技术差距,这些差距通常会用技术债务来填补。随着团队的成长并承担新的职责,越来越难找到旧代码的所有者。此外,如果没有所有权,团队修复问题的积极性就会降低。

我们必须赋予团队解决问题的权力——解决技术债务应该是产品开发的自然流程的一部分。工程师和产品经理需要以正确的务实心态协商技术债务与功能之间的健康平衡。维护和维持技术上健康的產品是產品團隊工作的一部分,而不是事后才做的事情。应该有一个商定的流程来持续解决和监控技术债务。这需要工程和产品领导者之间进行艰难的权衡,以保持稳定的平衡。

以正确的方式设计您的团队拓扑结构也可能是一个因素。例如,假设我们不断看到某些领域产生的技术债务。在这种情况下,它可能表明团队设计是错误的,并且可能存在需要强大所有权和关注的平台或业务能力。

一些指标非常强大——例如,扫描常见错误或衡量构建和部署时间。工程组织应该提供自助服务工具,团队可以快速将其系统集成到其中。指标应该用作团队做出有关技术债务决策的指南,而不是用作经理监控或激励的指标。经验丰富的开发人员通过解释可用数据并将他们的直觉建立在基于事实的定性信息的基础上,提供了价值。

虽然我们相信自治团队,但过度的自治可能是一个问题,会导致混乱的技术环境。应该有一些轻量级的检查和平衡,例如自动检查或架构同行评审,这可以帮助执行策略并帮助开发人员。

您的组织选择如何解决其技术债务取决于您的环境。我们在许多组织中看到的一个共同主题是希望“做点什么”,这通常会导致一个很快就会产生自身摩擦的权宜之计。相反,我们发现采用迭代方法,让指标与当前开发活动相结合来指导解决技术债务的投资,可以带来更好的结果。

总结

  • 承担谨慎的技术债务对于早期创业公司来说是必要的和健康的。
  • 寻找预警信号(价值交付时间或工程满意度),表明您的技术债务将限制您的业务
  • 拥有明确的技术质量标准,并使团队能够坚持下去。
  • 创建一个技术债务流程,明确的所有权和有权的团队,他们可以访问透明的信息以做出明智的决策。
  • 必要的技术平台改进可能伪装成技术债务,尤其是如果它们可以直接与 KPI 相关联。
  • 不断重新评估您的技术债务策略,尤其是在创业公司成长旅程的关键时刻(新资金、新产品方向、新员工)。

致谢

这篇文章从我们许多同事的评论和建议中得到了极大的改进。感谢 Martin Fowler、Tom Marsh、Andrew Buchanan、Ryan Puskas、Ahmet Sakar、Ryan Sawson、Kennedy Collins、Shea Clark-Tieche、Thomas Donahue、Christopher Hastings 和 Yue Liang。


重大修订

2022 年 3 月 9 日:发布文章的剩余部分

2022 年 3 月 8 日:发布“您是如何陷入瓶颈的?”和“您正在接近扩展瓶颈的迹象”