是什么让我们慢下来?通常,这是因为让某个功能能够运行并不等于让它在长期内具备良好的可维护性(参考 Google 软件工程实践)。第一个可运行版本通常是快速而粗糙的,而让其具备可修改性则需要额外的努力。这引出了“技术债务”的隐喻(参考 Ward 的解释)。开发人员选择暂时不投资于代码的可变更性,而是承受技术债务,以便更快完成任务。之后,每次修改代码都需要支付额外的“利息”,直到技术债务彻底清偿。
另一方面,如果我们的系统已经因为技术债务濒临崩溃,那就需要采取更激进的“清理”措施——在为时已晚之前。在这种情况下,建议建立多个改进指标,并使用它们来跟踪这些措施的进展。
一个广泛认可的观点是,代码质量的唯一有效衡量指标是每分钟 WTF 次数(参考 Martin 的《代码整洁之道》)。或许可以开发一款设备,专门用来统计 WTF 次数,这或许会成为一个不错的创业点子?当然,这个指标既主观又依赖于开发者的技术水平及团队的工程文化。根据破窗理论,糟糕的代码越多,就越会鼓励开发人员继续制造技术债务。
Martin Fowler 和 Kent Beck 引入了“代码异味”这一概念,帮助开发者识别代码中可能存在问题的地方。Fowler 的《重构》一书列举了 24 个代码异味示例。Uncle Bob 的《代码整洁之道》中也包含了许多代码异味和启发式规则(参考《[代码整洁之道》第17章]。一些代码异味,如重复代码和过长函数,可以通过静态分析工具(如 [SonarQube]轻松检测。然而,许多代码异味无法通过静态工具轻松发现。这也是为什么需要像“每分钟 WTF 次数”这样的另一个指标。
当测试自动化覆盖率较低成为限制团队进步的因素时,这一指标尤为有效。例如,我的团队曾发现某个遗留组件的测试自动化覆盖率非常低(仅约50%)。因此,我们将提高该覆盖率作为优先事项。通过持续监控指标、在团队回顾会议上讨论进展,我们在一年内将单元测试覆盖率提升至80%,并且不再视其为限制因素。现在,我们将其作为代码库健康的一个重要指标。
如何使用这个指标?在文档不足被视为制约因素的团队中,可以优先改善这一问题。我们列出所有组件,并评估每个组件当前的文档覆盖情况。每周更新指标,并监控改进进展。
如何使用这些指标?例如,我的团队负责一个覆盖 200 多个国家的住宿合作伙伴门户中与发票相关的财务内容。去年,我们开发了一个新的发票展示页面,并在几乎所有国家推出。然而,由于一些国家有特定逻辑,我们决定暂时保留旧页面以便后续迁移。这一决定让我们可以更快地获得新页面的反馈。然而,这也导致我们在几个月内需要支持多个版本的页面。尽管旧页面的支持工作量不大,但累积效应可能会显著增加负担。在这种情况下,我们将这一指标作为改进和健康监控的重要工具。
我们可以使用工具 Dependency-Check 来检查项目中的依赖项。将该工具集成到 CI/CD 流水线中是广泛认可的最佳实践。这种方法可以帮助我们尽早发现并修复漏洞或过时组件,从而减少技术债务带来的潜在影响。
最简单的衡量方式可能是估算清偿技术债务所需的工作量。然而,这种估算需要团队具备足够的技能和经验,例如掌握设计模式、重构技巧、自测试代码的编写,甚至是架构最佳实践(如松耦合架构)等。通过结合这些能力,我们可以更准确地评估并应对技术债务。
技术债务是指当前软件状态与最适合轻松实现更改的目标状态之间的差距。在几乎所有情况下,保持技术债务处于较低水平是非常重要的。如果忽视它,每次修改代码时都会付出额外的努力。技术债务的来源包括:
(i) 团队对其危害缺乏认识;
(ii) 在权衡利弊后有意选择积累技术债务;
(iii) 由于信息不完整,随着开发过程中的学习和需求变化不可避免地产生的债务。
技术债务往往通过无数次小的妥协逐渐积累,最终可能导致严重后果。最好的实践是从一开始就让技术债务变得可见,并通过设置健康指标进行监控,在早期采取纠正措施。如果发现技术债务已经威胁到系统的正常运行,则需要采取更加激进的清理措施。在这种情况下,可以通过设立改进指标并定期跟踪进展来评估和调整清理策略。