作者 | Chelsea Troy 译者 | 明明如月
责编 | 夏萌
出品 | CSDN(ID:CSDNnews)
你是否有过类似的经历?听到这样令人沮丧的话:
我们原本计划在三周前就发布这个功能。
然而,一名开发者因为用到的软件框架升级导致代码不能正常运行了,另一名开发者在重构 Feature flags (特性标识)的过程中遇到困难, 还有一名开发者需要在一份已经不再维护的代码库中寻找关键信息,才能启动数据库的更改。整个团队都陷入了困境。在解决掉这些技术债之前,每次的功能发布都会带来如此的困扰。我们甚至不知道该如何让业务部门理解并重视这个问题。
然而,我们往往陷入这样的困境。我们试图通过使用“技术债”这个词,让商业人士、设计师、产品经理和工程师达成共识。但是,这个词却让我们陷入了完全不同的立场。
如果你问科技界的人是否听说过技术债,他们可能会同情地叹息回答你。但是,再问他们这个词具体指的是什么。我敢说,你问十次,会得到多少不同的答案呢?三个?四个?七个?
他们却不能确切地知道这种情绪究竟来自哪里。于是他们随意将这个术语贴在任何让他们感到困惑或恐慌的事情上。设计师认为,这意味着设计无法按照预期实现。产品团队则担心,这意味着他们要白白浪费三个星期的时间,却无法得到任何功能。工程师呢?他们的答案变化最大,但通常会提到“糟糕的代码”。我们将在稍后解释为什么“技术债等同于糟糕的代码”是如此具有误导性,但首先我们必须解决一个问题,即许多不同的人以各种各样的方式定义同一个术语。
造成的结果是:每当我们提到“技术债”这个词时,虽然每个人都表现得很关注,但实际上没有人真正听懂。每个参与讨论的人都认为他们明白我们在讨论什么,但他们各自的理解实际上存在很大差异。这就像工程师请求获得三周的时间,以便暂时缓解发布新功能的压力。他们还记得上次申请延期那几周时间:短短一个月之内,团队又陷入了困境。当商业人士不愿批准一个“技术债周”,因为他们亲眼看到上次并没有提升团队的工作效率,我们怎么能期望他们会急切地再次给予我们这样的机会呢?
作为工程师,我们必须审视我们所使用的术语。我们可以通过剖析我们在谈论“技术债”时究竟指的是什么,来重新定义这个术语。
技术债不只关乎糟糕的代码
如果我们仅仅将技术债理解为糟糕的代码,就可能会偏离了原本的含义。这种认识可能导致我们怀疑前任开发者的工作效率,这既不公平,也可能让我们无法理解原有的约束。这些约束可以解释为什么一段代码让人头疼,而且还可能阻碍我们执行自认为高效的解决方案。
我曾在一个团队工作,团队成员一直对需要从两个不同表查询客户信息感到不满。他们认为这种情况的持续存在只是由于惯性,或者是因为改变数据库结构可能会影响向后兼容性。在花费大量时间批判数据库设计并构想如何改进之后,团队发现他们的计划却是违法的。由于隐私保护的考虑,在他们所在的行业中,将两种特定的个人识别数据存储在同一张表是非法的。幸好,产品经理在工程团队行动之前向公司的法律顾问提及了这个问题,从而避免了一个可能的合规问题。
如果我们将技术债与糟糕的代码等同看待,可能会产生一种误解,认为只要编写出足够好的代码,就不会存在技术债。因此,我们可能就不会花时间去解决它。没有必要去重新审查、记录或测试这段代码,因为它已经足够好。然而,一年后,我们又回到了原点,那就麻烦了。
再者,将技术债与糟糕的代码等同,也可能让我们将“这段代码并不符合我的个人审美”与“这段代码存在问题”两者混为一谈,这在我们的时间充裕的时候无伤大雅,但当时间紧张时,问题就暴漏了。我们可能会在“技术债周”期间,更愿意进行自己喜欢的重构,而不是真正的修复。工程师们都热衷于“技术债周”,因为他们可以去解决自己关注的问题。问题在于,这些问题往往与代码最紧迫的维护挑战无关。因此,当每位工程师完成他们的“重构狂欢”后,代码的工作难度并没有降低:它只是变得与之前不同,除了那些重构者,别人很难理解它了。结果就是,表面上看起来很好,一切都很完美,但实际上问题并未解决。
说实在的,这就是为何投入三周时间偿还技术债,短期内通常对团队效率并没有明显帮助的重要原因。
要解决这类问题,我们需要选择一个可衡量的标准来评估系统的质量。我建议使用“维护负担”作为这样的指标。开发者在进行非功能增加或减少的任务上投入了多少时间和精力?这是我们可以和工程团队之外的人一同讨论的数据。如果我们有六名开发者,但却有一半的工作都是在维护任务上,那么我们的功能开发计划只能假设有三名开发者在进行。商业人士通常认为工程师的成本高昂,因此,这样的数据能够激励他们帮助我们降低维护负担。
我们可以追踪这个指标,看看它随着时间的推移增长的速度。维护负担增长得越快,我们感受到的压力就越大。维护负担零增长意味着我们可以始终用我们工程团队的同一比例来维护系统。
挽回你的时间
那么,我们如何才能抑制维护负担的增长呢?答案就是通过良好的代码管理实践。我们往往忽视、忽略或缺乏对代码管理方式的关注,而过分关注特性开发技巧。然而,代码管理技巧,包括记录系统、从代码中恢复上下文、为未来的变化做出设计,是决定一个团队能否顺利运行十年甚至更长时间的关键因素,否则,团队可能会反复陷入代码难以维护、进行重写的恶性循环并感到绝望。
那么,最理想的情况是什么呢?就是我们能够实现维护负担的减轻:随着时间的推移,我们的代码变得更易于维护。要实现这一理想状况,团队需要付出比日常代码管理常规更大的努力。我们需要关注每个维护任务,追踪它们的源头,并在源头解决这些问题。这些任务为我们在讨论技术债的会议中提供了具体的讨论点,这些点都有实证证据的支持。
我们是否频繁进行例行的库或框架更新?如果是,我们可能需要设定明确的时间策略来完成这些更新。因为累积的更新越多,调试不同版本库间的交互就越困难。另外,若程序员长期无法进行这些操作,他们在不得不更新时会很难且痛苦。
我们是否在探索被遗弃的仓库,试图理解如何修改?这就需要我们投入精力重新理解这些仓库的运作方式。关键团队成员的离开会导致开发变得困难,因为他们可能掌握着许多未记录或整理的重要信息。成员的离开会让开发变得困难,因为他们可能掌握着许多未记录或整理的重要信息。我将此称为“上下文丢失事件”。只有经历过这样的事件,我们才能真正评估一个代码库的可维护性。在这种事件之后,开发者需要主动评估并弥补团队共享知识的损失,否则那些不熟悉的代码库部分会令人困惑和恐惧。
我们是否一直在规避过去的架构选择?这些选择基于旧有的领域假设,但现在可能已不再适用。如果是,我们可能需要制定和优化重构工单。我们可能需要制定并优化一份重构工单。弹性代码设计需要考虑团队未来预期的改变,并在代码的部分地方提供灵活性。和所有弹性代码设计需要考虑团队未来预期的改变,并在代码的某些部分提供灵活性。预测未来的任务一样,有时我们可能会犯错。在这种情况下,我们可能需要调整设计,这可能需要一番努力。
如何确定并优先处理这些琐事?关注具体琐事的维护负担,而非那些看似无法攀越的“技术债”,也能为我们解决问题提供更好的起点。
我们希望开发功能的流程更流畅而且不会耗费太多精力。然而,维护工作的延迟越长,功能开发的流畅性和效率就会越低。我们不应仅仅将这些待办任务统一归入“技术债”的概念,只在必要时作为一个整体去处理。相反,我们应该追踪那些阻碍功能开发,增加开发工作量的具体元素,以这些元素所需的开发者工作量来衡量它们。我们应将解决这些问题视为单独的任务,并把它们的完成视为提升开发者能力的标志。这样,这些问题不再是不透明且不确定的负担,而是对我们生产高效功能的明确和具体的投资。这样的对话让人们更加统一和协同。同时,它也带来了以下可能性:
工程师可以专门分配时间进行维护工作
工程师因为维护工作而得到认可
维护工作是针对导致功能开发速度放缓的真正问题,它能真正改善未来的功能开发体验。
这样,我们对技术债的对话就少了许多负面和沮丧的成分;甚至可能滋生出希望。
领取专属 10元无门槛券
私享最新 技术干货