查看原文
其他

“所有代码,都是技术债务!”

CSDN 2024-01-17

多开发团队在推进项目时,都会不断强调“尽量减少技术债务”,对此,本文作者 Paul McMahon 表示:别费劲了,你写的每一行代码,最终都是技术债务。

原文链接:https://www.tokyodev.com/articles/all-code-is-technical-debt

者 | Paul McMahon,TokyoDev 创始人
译者 | ChatGPT      责编 | 郑丽媛
出品 | CSDN(ID:CSDNnews)

术债务,这个概念最初由沃德·坎宁安(Ward Cunningham)提出,指的是通过紧急的软件开发来获得暂时的速度提升,但代价是放慢未来的开发速度。 

这好像一笔贷款:通过贷款,你可以借到钱更快地完成某件事——对于技术债务而言,这就好比你获得了最初的开发动力;一旦贷款,你就需要支付利息——在技术债务中,利息就是未来开发速度会减缓;当你还清贷款本金时,利息就会减少——放到技术债务中,这就类似于重构,你需要花大把时间改进代码以加快未来的开发速度。

与金融债务一样,技术债务也可以是一种有用的工具,有时短期收益会大于长期后果。然而,就像背负过多的金融债务会导致破产一样,技术债务积累过多也会导致产品开发陷入停滞。

如果你曾从零开始创建一个新应用程序,那么你一定体验过在没有任何技术债务的情况下开展项目的美妙感觉。在初次创建应用程序时,你可以以惊人的速度开发新功能,无需担心对现有用户的影响,只需专注于实现新功能即可。

然而随着应用程序的成熟,开发速度将不可避免地减慢,尤其是发展不佳的产品更是如此。而即使是一个实现得很好的产品,随着你向应用程序添加的代码越多,开发速度仍然会随时间减慢——因此,我将所有的代码视为技术债务。

只要增加新设定,就会增加技术债务

随着应用程序的成熟,它会积累一系列基本设定。当你开始一个新项目时,由于此前没有任何功能,代码库中没有内置任何设定,因此添加新功能时只需关注如何实现功能即可。然而,一旦项目有了第一个功能,你就永远需要考虑迄今为止开发的所有功能对未来开发的影响。

我将根据自己创建社区活动平台 Doorkeeper(一个社区活动平台,帮助网络活动、研讨会的组织者吸引参与者并管理注册)的经验,举例说明核心设定导致的技术债务是如何积累的。

刚开始我们创建 Doorkeeper 的初衷,是为了帮助当地网络活动 Mobile Monday Tokyo 更顺利地完成注册和签到过程。对于这个活动,当时组织者只需要一个简单的注册流程:注册参加活动以及取消注册。

在扩展 Doorkeeper 以满足其他组织者需求的过程中,我们发现许多组织者对出席人数有硬性限制。为了满足新组织者的需求,我们决定添加一个限制参与人数的选项。

在现有的“人们可以注册参与活动”的设定基础上,我们对活动的参与人数进行了限制,但还需要考虑当有人试图注册一个人数已满的活动时会发生什么。最简单的解决方案是在人数已满时阻止用户注册,但我们认为这会给潜在参与者带来不好的体验,同时也无法向组织者反馈活动的受欢迎程度。因此,我们采用了候补名单功能,如果有人想注册但活动人数已满,他们将加入候补名单。如果有参加活动的人取消了注册,那么候补名单上的第一个人就可以替补上去。

在这之后,我们为 Doorkeeper 添加的下一个功能是预购门票。如果我们唯一的设定是“人们可以注册参与活动”,那么这个功能直接就能实现,因为它是建立在这个设定之上的——但实际情况是,我们还需要考虑其他可能性。

根据不同活动,有的组织者可能不太希望预购门票的参与者取消活动。此外,他们可能还想要制定某种取消政策,即根据参与者取消的时间,他们可获得部分退款。考虑到取消预购门票涉及到各种边缘案例,且大多数组织者都不想让参与者轻易取消,所以我们在设计这项功能时,不允许参与者自行取消存在预购门票的活动。相反,他们需要联系组织者,然后由组织者决定如何处理这种情况。

此外,由于活动的注册人数有限,我们还需要一些机制来确保预购门票的人能够得到活动名额。为此,我们将注册流程分为两步:首先是输入注册信息,然后是付款。如果在开始填写初始表单和提交之间活动名额已满,那这些人将加入候补名单。

接着,考虑到存在已提交注册表单但未完成付款的情况,我们增加了在一定时间后自动取消未付款订单的功能;除此之外,对于需要预购门票的活动,我们也不能给从候补名单中移出的替补人员立即出票,因为他们需要返回网站完成付款…… 

正如你所看到的,随着我们需要考虑迄今为止添加的所有设定的影响,添加新功能这件事变得越来越复杂。

有时候,功能会带来负面价值

要让一个功能为产品增值,它就必须对用户有用。可是当功能给产品带来的技术债务大于其为产品增加的价值时,这些功能就会产生负面价值。

我见过的一个经常产生负面价值的功能是应用本地化。简单来说,本地化就是将应用程序翻译成多种语言。除了翻译之外,其中涉及到的挑战还有很多,但现在让我们简单地考虑本地化:拥有一组特定语言字符串的词典。

首先,这意味着你不能在应用程序中硬编码字符串,从而增加一个额外的抽象层。虽然这并不会增加太多开销,但开发人员仍需时刻牢记。接着,你需要在开发过程中引入一个翻译步骤。假设你手下开发人员的母语与应用支持的语言并不相通,那他们很难自己编写字符串,而需要依赖翻译人员。当然你也可以自己解决这个问题,但这仍会使所有未来的开发工作都变得缓慢。

如果应用本地化能带来大量价值,那么这种额外的开销就不是问题。但我经常看到一些应用程序在本地化方面敷衍了事,就希望其他国家的人开始使用它——然而,事实并非如此。除非你愿意在应用支持的语言中,进行出色的本地化工作并大力推广你的应用程序,否则本地化将不会创造大量价值。于是最终,你会得到一个产生技术债务比其价值更大的功能。 

代码的价值,并非与生俱来

作为开发者,我们很容易认为编写代码就是在创造价值。然而,软件的真正价值来自于它对用户的实用性,而不是我们的代码质量:写得不好却能执行实用任务的代码,比写得很好却做了无用功的代码更有价值。

正因如此,我们需要确保我们正在开发有价值的功能。传统开发过程中,会假定存在一个无所不能的产品负责人,他会以某种方式了解功能的相对价值,但实际情况并非如此。

我希望你能与这种厉害的产品负责人合作,并对你正在从事的工作为何具有价值有了清晰的了解。但如果没有,你就应该主动反击,试着找出他们认为该功能有价值的原因,并对其进行验证。确保我们实现的功能是有足够价值的,以此减少未来其造成的技术债务过重的可能性。

功能一旦添加,就会永久存在

我们之所以要对那些不能产生足够价值的功能保持高度警惕,部分原因在于:一旦添加了某项功能,它几乎就会一直存在下去。

即使事后发现该功能的性能不如预期中好,通常的做法也是什么也不做,因为人们往往有沉没成本谬误:即使这个功能今天看来没什么用,保不齐将来可能会有用。 

除此之外,不采取任何行动也有其他合理原因,毕竟移除一项功能也是有成本的,既要耗费大量的开发精力来清理删除,还可能会让客户不高兴。因此,一旦在产品中添加了某项功能,它几乎就会一直存在。

为了避免技术债务,不要编写代码

避免技术债务的唯一可靠方法,就是先不写代码。作为开发者,我们的第一反应总是通过编码来解决问题,但这并不总是最佳策略。很多时候,我们需要抛开这种本能。

举一个我个人的例子,我曾经营过一个职位信息平台,帮助国际开发者在日本找工作。一开始,我只是简单发布我发现的职位,但后来我听到了太多类似的成功故事,我觉得公司会愿意为此付费。作为其中一部分,我想在公司收到申请之前,对其进行一些基本的垃圾邮件筛选。

为此,我开始使用 Ruby on Rails 构建一个筛选系统。然而,经过大约一天的开发后,我意识到建立一个比让应聘者直接发送电子邮件更好的系统相当复杂。我需要复制电子邮件中的所有功能:附件、应聘者与公司之间的沟通等等。此外,我还需要确保系统正常运行,监控日志等。

然而,我真正需要的只是一种在邮件发送到公司之前对其进行审核的方法。因此,我没有继续实施自己的方案,而是用 Google 应用程序的“群组”功能为每家公司建立了一个邮件列表。虽然这不是最佳的技术解决方案,但最终我创造的价值本身就与技术无关,后来我的时间也更多花在了帮助公司和求职者找到最佳人选/雇主。

在现有设定的限制下进行开发

在添加新功能时,减少技术债务的方法之一就是在现有设定的限制下进行开发,而不再添加新的设定。下面,我将举例说明我们是如何在 Doorkeeper 中做到这一点的。

活动的组织者可以向参与者发送消息,我们也鼓励组织者使用此功能向参与者发送提醒信息。但有些组织者从未发送过提醒信息,可能是因为他们忘记了或太忙了;另一方面,其他组织者则会发送定制提醒,以提供活动当天的详细说明。

作为一项新功能,我们希望确保参与者能始终收到提醒,而不依赖于组织者手动发送消息。

  • 最直接的方法是添加一个提醒功能,即在活动前一天自动向参与者发送提醒电子邮件——这很容易实现,但无法很好地处理组织者想要发送临时说明的情况。

  • 要么让这些组织者可以在提醒之外再发送一条信息——可这样一来,参与者就会收到多封关于同一内容的邮件,导致体验不佳。

为了解决这个问题,我们可以让组织者定制提醒内容。而我们也由此意识到,提醒和消息实际上没有太大区别。如果我们自动安排在特定时间发送消息,组织者就可以自定义这条信息,甚至可以将其禁用它。

当时,我们还没有能力在特定时间发送消息,而让组织者发送消息已经是一个非常有用的功能。更重要的是,让提醒信息仅仅是信息,我们就可以向组织者提供所有常规报告,比如有多少人打开和点击了信息。

通过在现有功能的基础上构建,而非创建一个全新的独立功能,我们就能得到一个既有更好的用户体验、又能减少技术债务的解决方案。 

总结

最后,简单总结一下:由于向产品添加更多代码会减缓开发速度,我们应将所有代码视为技术债务。为了确保开发不会逐渐停滞,我们需要确保代码创造的实用价值大于技术债务。

作为开发者,我们应该是产品的捍卫者,避免其遭受一些考虑不周的功能的影响。我知道这可能很难做到,但只要确保我们正在创造有价值的产品,而不仅仅只是编写大量代码,我们就可以做更多有益的事情。

推荐阅读:
“这是疯狂的一年!” Sam Altman 交出 2023 年终总结,公开他曾渴望听见的 17 条建议

小米汽车技术发布会官宣;苹果发布开源多模态大语言模型Ferret;Windows 10停服时间确定|极客头条

腾讯工作13年之所思所想,那些优秀程序员的共性特征

继续滑动看下一个

“所有代码,都是技术债务!”

向上滑动看下一个

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存