老项目增量开发策略
版本说明:本文基于 Michael Feathers《Working Effectively with Legacy Code》的核心理念,结合 AI 辅助开发的实践撰写。
适用技术版本:Java 17+、Spring Boot 3.x、JUnit 5、Claude Code v1.x、Maven 3.9+。
内容时效:本文内容基于 2026 年 4 月验证。AI 工具能力可能随版本迭代变化,文中提到的具体 AI 能力(如代码理解、Seam 识别、特征测试生成等)以实际使用时的模型版本为准。建议读者关注 Claude Code 更新日志以获取最新能力信息。
适用对象:技术负责人、高级开发者、维护老项目的团队。
前置知识:第12篇项目接入AI、第16篇代码考古、第20篇测试编写。
一、老项目增量开发的核心挑战
第12篇讲的是"让 AI 认识项目"——配置 CLAUDE.md / AGENTS.md,让 AI 理解项目结构。本篇讲的是"在老项目上安全开发"——拿到一个新需求,如何在已有代码上安全地完成修改。
Michael Feathers 在《Working Effectively with Legacy Code》中给出了一个经典定义:遗留代码就是没有测试的代码 。这个定义直指核心问题——没有测试保护的代码,每次修改都像在雷区行走。
老项目增量开发的三个核心挑战:
| 挑战 | 说明 | 后果 |
|---|---|---|
| 不理解现有设计 | 老代码缺乏文档,设计决策散落在 Git 历史中 | 修改破坏了隐式约定 |
| 隐式依赖多 | 老项目的模块间耦合严重,牵一发动全身 | 小改动引发连锁故障 |
| 缺少测试保护 | 老项目通常测试覆盖率低 | 改了不知道有没有改坏 |
Martin Fowler 指出,GenAI 在遗留代码现代化中的核心价值不是"生成新代码",而是"理解现有代码"——帮助开发者快速建立对大型、复杂、长期迭代的遗留系统的认知 。
二、安全开发的四个策略
策略 1:精准定位修改区域
在老项目中,最大的风险不是"不知道怎么改",而是"改错了地方"或"改了不该改的代码"。
定位修改区域的方法:
步骤 1:从需求出发,找到业务入口
- 用户触发的 API 接口
- 定时任务的调度入口
- 消息队列的消费入口
步骤 2:从入口追踪调用链
- Controller → Service → DAO → DB
- 标注调用链上涉及的所有文件和类
步骤 3:圈定最小修改范围
- 只修改直接相关的文件
- 不动间接依赖的代码
- 记录"为什么不动这些代码"
Anthony Bordonaro 提出了"代码考古"的系统化技术——使用 AI 从入口点向内构建分层心智模型,逐步建立对代码库架构、约定、数据流和隐式决策的理解 。
策略 2:确保不破坏现有功能
在不破坏现有功能的前提下做修改,这是老项目开发的铁律。
Michael Feathers 提出了"特征测试"(Characterization Test)的概念 :在不理解代码逻辑的情况下,先写测试记录代码的当前行为,然后才能安全修改。
特征测试 vs 单元测试:
特征测试:记录代码"现在做什么"(可能是 bug,也可能不是)
单元测试:验证代码"应该做什么"(基于需求定义)
在老项目中,先写特征测试锁定当前行为,
然后再写单元测试验证新逻辑。
特征测试完整操作示例:
以一个老项目的 CouponValidator.validate() 方法为例,展示从发现老方法到写出特征测试的全流程:
# 第1步:定位需要修改的老方法
# 假设老项目没有测试,先通过 AI 分析代码结构
claude -p "分析 src/main/java/com/example/coupon/CouponValidator.java 中的 validate() 方法,列出所有输入参数和可能的返回值"
# AI 输出:
# validate() 方法接收 Coupon 对象,返回 ValidationResult
# 输入组合:有效券/已过期/已使用/金额不满足/券不存在 → 5种场景
# 当前没有单元测试覆盖
扫码添加企业微信,找大熊掌门开通会员

添加后说明想开通的会员类型即可