如何摆脱烂代码陷阱:从重构到最佳实践的实战经验
烂代码是一个有趣而值得深思的话题。在 Martin Fowler 的经典著作《重构:改善既有代码的设计》中,他专门提到了代码异味(code smells),并指出:“代码异味是一种表象,通常对应系统中更深层次的问题。”对此我深有体会。
如果你的系统充斥着烂代码,就要反思其中的深层次原因:需求过于频繁变动?项目进度压力大?团队技能不过关?缺乏设计?或许这些因素都有所贡献。Martin Fowler 给出的解决方案是重构,这无疑是很好的建议,但执行起来却充满挑战:
- 我想重构,但没有工期怎么办?
- 重构完成后,会不会没多久又回到老样子?
- 我个人没有足够的能力去重构!
这些问题不仅仅是技术层面,还涉及软件工程和项目管理。我刚开始写代码时,也写过很多烂代码。后来见识过好的代码风格,逐渐提升了自己代码的质量,直到带团队时才真正意识到如何解决烂代码问题。我现在带领的团队代码质量非常出色,即便有新手程序员,也能确保烂代码不混入,产出效率显著高于其他团队,一个功能实现速度往往是其他团队的 1.5 到 2 倍,甚至更快。
代码审查:严格执行与自动化工具的结合
最初,我尝试通过严格的代码审查来提升团队代码质量。所有更新必须经过代码审查才能合并到主干。要注意的是,审查应在合并前,而不是事后,这样才能避免修改的优先级被降低,影响质量。
严格的代码审查确实有效,但也面临不少挑战:
1. 代码命名和格式不符合规范,靠肉眼很难完全审查到。
2. PR(Pull Request)太大,审查压力很大。
3. 工期紧急时,质量不高的代码如何处理?
4. 自动化测试覆盖不足,合并时心里没底。
5. 代码结构混乱,但功能实现没问题,该不该批准?
6. 原本的项目就是“屎山”代码,新代码难以彻底改善。
为此,我逐步引入了工具化和自动化手段来辅助代码审查:
- 源代码管理和代码审查工具,清楚展示代码改动。
- CI(持续集成),每次提交代码都通过 CI 运行自动化测试。
- Lint 工具,自动检查命名、格式等问题。
- 自动化测试,包括单元测试和集成测试,确保每次更新不会破坏现有功能。
此外,**拆小 PR** 也是关键,越小的 PR 越容易审查,质量越有保障。而对于那些急着上线的低质量 PR,我要求必须创建 Ticket 跟踪后续改进,这些改进任务的优先级等同于其他正式功能,以确保问题尽快被解决。
系统设计:先磨刀再砍柴
我还遇到过这样的情况:开发很快实现了某个功能,代码质量也不算太差,但由于没有遵循最佳实践,导致整体可读性和可维护性差。推翻重写往往会让开发者产生强烈抵触情绪,简单修改也意义不大。
后来,我找到了一个更好的方法:在写代码前,先做系统设计。通过简单的设计文档和结构图,在设计评审会议中对齐团队思路,这样在代码实现时就不会出现大偏差,也避免了重写的困境。这种做法不仅是“磨刀不误砍柴工”,还让团队成员在设计评审中学习如何做好设计和遵循最佳实践。
技术债务与老项目的重构
对于那些需要长期维护的老项目,我的策略是逐步重构而非一刀切推翻重写。首先补充自动化测试,尤其是集成测试,以确保后续的任何修改都不会引入严重问题。然后逐个模块替换,降低整体迁移的风险。例如,我最近用 NextJS 重构一个重要的前端项目,不是先写完新项目再整体替换,而是先建立组件库,让新旧项目共用组件,一步步逐渐替换和测试,最终实现平滑过渡。
技术债务也需定期偿还
技术债务并不完全是坏事,但必须有计划地偿还。我的策略是将技术债务任务创建成 Ticket,并在每个 Sprint 中分配约 20% 的时间去处理。这样可以有效地避免技术债务积累到必须大规模“清仓”的地步。
我们最近还探索了一种新的开发模式:在两周的 Sprint 中,第一周专注于产品需求开发并部署到测试环境,第二周主要修复新功能 Bug,并有足够的时间进行技术任务,例如偿还技术债务、测试新技术栈和开发公共组件。这种模式既能持续交付产品功能,也能保证技术任务的推进,得到了产品经理的认可。
最佳实践:为新手提供清晰指引
新项目或已有项目要有明确的最佳实践供新手参考,并确保团队成员共同遵守。如果是我自己设计的架构,我会在架构设计后先实现一些基础模块,形成良好的开发实践,这样其他开发者可以“照葫芦画瓢”。对于不符合最佳实践的代码,必须在代码审查阶段果断拒绝。
总结
- 代码审查:一定要先审查再合并。
- 系统设计:坚持先做系统设计再进行评审。
- 自动化测试:代码必须有自动化测试覆盖。
- 技术债务:定期偿还,保持在良性水平。
- 老项目重构:逐步替换,降低风险。
- 最佳实践:为团队提供清晰的开发标准,共同遵守。
这些方法帮助我的团队有效摆脱了烂代码的困扰,提升了整体开发效率和代码质量。
注:本文是2年多前在微博 https://www.weibo.com/1727858283/OAlQiEHhr 首发的,用 Canvas 帮忙润色了一下重发的,效果挺不错的。