<!-- title: Claude Code遗留代码现代化六步实战法 -->

# Claude Code遗留代码现代化：六步安全重构法

## 概述

本教程面向需要在生产环境中改造遗留系统的中高级开发者。你将学会如何利用 Claude Code 的 Agent 能力，对零文档、零测试的老旧代码库执行**安全的增量现代化**——从依赖图谱绘制、特征测试生成，到逐模块迁移与持续回归验证。全文以一个真实的 Java EE 单体应用改造为微服务架构为主线，提供可直接复用的 Prompt 模板和 CLAUDE.md 配置。

**适用人群**：维护遗留系统的后端开发者、技术负责人、SRE 工程师  
**预计学习时长**：60-90 分钟（含实操）

## 前置条件

| 条件 | 说明 |
|------|------|
| Claude Code CLI | 已安装并完成 API Key 配置（`claude` 命令可用） |
| 遗留代码仓库 | 一个你熟悉的旧项目（Git 管理） |
| 基础测试工具 | 项目对应语言的测试框架（JUnit、pytest 等） |
| Git 操作意识 | 会创建分支、查看 diff、回滚 commit |

## 为什么遗留代码需要特殊策略

直接对遗留代码说"帮我重构"是 Claude Code 使用中最危险的操作之一。遗留系统的三大特征决定了必须采用分步策略：

1. **无测试覆盖**：无法验证重构后行为是否一致
2. **高耦合度**：一处改动引发连锁编译错误
3. **隐式依赖**：配置文件、环境变量、数据库 Schema 散落各处

Claude Code 的 Agent 模式天然适合这种场景——它能自动读取多文件上下文、生成分步计划、逐个文件修改并验证。但前提是你必须给它正确的约束。

```
我的项目是一个2015年的Java EE单体应用，约12万行代码。
项目目录: /home/dev/legacy-monolith
技术栈: Java 8, Spring 4, MyBatis, Oracle DB, Maven
目标: 将订单模块拆分为独立微服务
```

## 第一步：项目画像与依赖图谱

### 操作说明

在项目根目录创建专用的 CLAUDE.md，定义项目上下文和约束规则：

```markdown
# /home/dev/legacy-monolith/CLAUDE.md

## 项目概况
- 12万行Java EE单体应用，2015年开发至今
- 技术栈: Java 8, Spring 4.2, MyBatis 3.3, Oracle 11g
- 构建工具: Maven 3.x
- 无单元测试，仅有少量手动集成测试

## 现代化目标
- 将订单模块(order)拆分为独立Spring Boot微服务
- 保持与主系统的API兼容
- 使用PostgreSQL替代Oracle（仅限新服务）

## 安全约束（CRITICAL）
- 每次修改前必须先创建特征测试(Characterization Test)
- 单次修改不超过3个文件
- 每次修改后必须通过编译和现有测试
- 不修改数据库Schema，除非有明确的migration脚本
- 所有新代码必须包含错误处理和日志

## 代码规范
- 遵循现有命名约定（Service以Impl结尾）
- 新模块使用Spring Boot 3.x标准结构
- 配置使用application.yml而非properties
```

然后用 Claude Code 生成依赖图谱：

```bash
claude -p "分析项目结构，生成订单模块的依赖关系图谱。需要识别：
1. 订单模块涉及的所有Java包和类
2. 这些类被其他模块引用的情况（入向依赖）
3. 订单模块引用的外部模块（出向依赖）
4. 共享数据库表的访问情况
输出格式：每个依赖标注强度（强/中/弱）和风险等级（高/中/低）"
```

### 预期结果

Claude Code 会输出类似这样的分析：

```
=== 订单模块依赖图谱 ===

入向依赖（被其他模块引用）:
  [强|高] PaymentService → OrderService.createOrder()
  [强|高] ShippingService → OrderService.getOrderById()
  [中|中] ReportService → OrderRepository.queryOrders()
  [弱|低] NotificationService → OrderStatusListener.onStatusChange()

出向依赖（订单模块引用的外部）:
  [强|高] → UserRepository (用户模块)
  [强|高] → ProductRepository (商品模块)
  [中|中] → InventoryService (库存模块)
  [弱|低] → LogUtil (公共工具)

共享数据库表:
  [高] T_ORDER, T_ORDER_ITEM, T_ORDER_STATUS
  [中] T_PAYMENT (与支付模块共享)
```

### 常见问题

**Q: Claude Code 报"context too large"怎么办？**

使用 `--max-turns` 限制交互轮次，并分模块分析：

```bash
claude -p "只分析 src/main/java/com/company/order 目录下的类依赖关系" \
  --max-turns 5
```

对于超大项目（>50万行），先用 `find` 和 `grep` 缩小范围，再让 Claude Code 分析子目录。

## 第二步：生成特征测试安全网

### 操作说明

特征测试（Characterization Test）是 Michael Feathers 在《修改代码的艺术》中提出的核心概念——不是测试代码"应该"做什么，而是记录代码"当前实际"做什么。这是安全重构的前提。

```bash
claude -p "为 OrderService.createOrder() 方法生成特征测试。

要求：
1. 读取 OrderService.java 的完整实现
2. 读取其所有依赖的接口定义
3. 使用 Mockito 模拟所有外部依赖
4. 测试用例覆盖方法的所有分支路径
5. 每个测试用例的assert必须精确记录当前行为（包括看似bug的行为）
6. 不要修正任何现有行为，即使看起来是bug

测试文件放在 src/test/java/com/company/order/ 目录下"
```

### 预期结果

Claude Code 会生成类似这样的测试：

```java
// Characterization Test - 记录当前行为，不判断对错
class OrderServiceCharacterizationTest {

    @InjectMocks
    private OrderServiceImpl orderService;

    @Mock
    private OrderRepository orderRepository;
    @Mock
    private ProductRepository productRepository;
    @Mock
    private InventoryService inventoryService;

    @Test
    void createOrder_normalCase_savesOrderWithCorrectTotal() {
        // 当前行为：计算总价时包含折扣但不包含税费
        when(productRepository.findById(1L))
            .thenReturn(new Product(1L, "Widget", new BigDecimal("99.00")));
        when(inventoryService.checkStock(1L, 2))
            .thenReturn(true);

        OrderRequest request = new OrderRequest(1L, 2, "DISCOUNT10");
        Order result = orderService.createOrder(request);

        // 特征记录：当前实现的总价 = 99 * 2 * 0.9 = 178.20
        // 注意：这里没有加税，这是一个已知的行为特征
        assertEquals(new BigDecimal("178.20"), result.getTotalAmount());
        verify(orderRepository).save(any(Order.class));
    }

    @Test
    void createOrder_outOfStock_throwsRuntimeException() {
        // 当前行为：库存不足时抛出RuntimeException（非业务异常）
        when(productRepository.findById(1L))
            .thenReturn(new Product(1L, "Widget", new BigDecimal("50.00")));
        when(inventoryService.checkStock(1L, 100))
            .thenReturn(false);

        OrderRequest request = new OrderRequest(1L, 100, null);

        assertThrows(RuntimeException.class,
            () -> orderService.createOrder(request));
    }
}
```

### 批量生成脚本

对于大量需要特征测试的类，使用 `-p` 模式批处理：

```bash
#!/bin/bash
# gen_characterization_tests.sh
# 为订单模块下所有Service类生成特征测试

CLASSES=$(find src/main/java/com/company/order -name "*ServiceImpl.java")

for class in $CLASSES; do
    classname=$(basename "$class" .java)
    echo "Generating tests for $classname..."

    claude -p "为 $class 生成完整的特征测试(Characterization Test)。
    使用JUnit5和Mockito。记录所有当前行为，不修正任何bug。
    测试文件放在 src/test/java/ 对应路径下。" \
    --max-turns 3 \
    --output-format text > "test_report_${classname}.txt"
done
```

### 常见问题

**Q: 生成的测试编译不过怎么办？**

让 Claude Code 自行修复：

```bash
claude -p "运行 mvn test-compile，修复所有编译错误。
不要修改测试的assert内容，只修复import和类型问题。"
```

## 第三步：绘制组件边界与接口契约

### 操作说明

有了依赖图谱和特征测试后，下一步是定义微服务的边界。这一步不需要写代码，而是用 Claude Code 生成结构化的接口文档。

```bash
claude -p "基于已有的依赖分析，为订单微服务定义API接口契约。

要求：
1. 分析 OrderService 和 OrderRepository 的所有public方法
2. 区分内部方法（仅限新微服务使用）和外部API（其他模块需要调用）
3. 外部API设计为RESTful接口，使用Spring Boot 3.x的@RestController
4. 生成OpenAPI 3.0规范的YAML文档
5. 列出需要保留的跨模块调用点（暂时通过HTTP客户端桥接）"
```

### 预期结果

生成的 OpenAPI 文档片段：

```yaml
# order-service-api.yaml
openapi: 3.0.3
info:
  title: Order Microservice API
  version: 1.0.0

paths:
  /api/v1/orders:
    post:
      summary: 创建订单
      operationId: createOrder
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateOrderRequest'
      responses:
        '201':
          description: 订单创建成功
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/OrderResponse'
        '400':
          description: 参数校验失败
        '409':
          description: 库存不足

  /api/v1/orders/{orderId}:
    get:
      summary: 查询订单详情
      operationId: getOrderById
      parameters:
        - name: orderId
          in: path
          required: true
          schema:
            type: integer
            format: int64
      responses:
        '200':
          description: 成功返回订单信息
```

### 架构决策记录

让 Claude Code 帮你维护架构决策记录（ADR）：

```bash
claude -p "创建一个ADR(Architecture Decision Record)文件：
ADR-001-订单服务拆分策略.md

记录以下决策：
1. 为什么选择先拆订单模块（而非支付或库存）
2. API兼容策略：采用BFF模式还是直接REST
3. 数据库迁移策略：双写还是CDC
4. 跨模块通信：同步HTTP还是异步MQ"
```

## 第四步：Strangler Fig 渐进式迁移

### 操作说明

Strangler Fig（绞杀者无花果）模式是 Martin Fowler 推荐的遗留系统迁移策略——逐步用新系统替换旧系统，而非一次性重写。Claude Code 的 worktree 功能天然支持这种并行开发模式。

```bash
# 创建隔离的worktree进行新服务开发
claude worktree create order-service-migration
```

在新 worktree 中初始化 Spring Boot 项目：

```bash
claude -p "在当前目录创建一个Spring Boot 3.2微服务项目：
1. 使用Spring Initializr结构
2. 依赖: spring-boot-starter-web, spring-boot-starter-data-jpa,
   spring-boot-starter-validation, postgresql driver, flyway
3. 配置文件使用application.yml
4. 创建标准的controller/service/repository/package结构
5. 添加健康检查端点
6. 端口设为8081"
```

### 核心迁移步骤：逐步搬运业务逻辑

这是最关键的一步。不要让 Claude Code 一次性迁移所有代码，而是按照以下顺序逐个方法迁移：

```bash
claude -p "迁移 OrderService.getOrderById() 方法到新的微服务。

严格按照以下步骤：
1. 在新服务中创建 OrderController.getOrderById()
2. 从旧代码复制核心业务逻辑到新的 OrderService
3. 使用JPA实体替代MyBatis映射（保持字段名不变）
4. 编写对应的Repository方法
5. 确保特征测试在新环境中通过
6. 暂时不删除旧代码，只添加@Deprecated注解"
```

### 路由切换：API Gateway 桥接

在旧单体应用中添加路由转发，将对已迁移接口的请求转发到新微服务：

```bash
claude -p "在旧单体应用中添加一个OrderServiceProxy。

当订单API调用到达旧系统时：
1. 如果对应的 getOrderById 已迁移到新服务，转发到 http://order-service:8081
2. 如果未迁移，继续走旧的 OrderServiceImpl
3. 使用RestTemplate实现转发
4. 添加降级逻辑：如果新服务不可用，fallback到旧实现
5. 添加请求耗时的metrics日志，用于对比新旧服务的性能

在 src/main/java/com/company/proxy/ 目录下创建。"
```

### 预期结果

代理类代码片段：

```java
@Component
@Primary
public class OrderServiceProxy implements OrderService {

    private final OrderServiceImpl legacyService;
    private final RestTemplate restTemplate;
    private final MigrationConfig migrationConfig;

    @Override
    public Order getOrderById(Long id) {
        if (migrationConfig.isMigrated("getOrderById")) {
            // 已迁移：转发到新微服务
            return restTemplate.getForObject(
                "http://order-service:8081/api/v1/orders/" + id,
                Order.class);
        }
        // 未迁移：使用旧实现
        return legacyService.getOrderById(id);
    }

    // ... 其他方法类似
}
```

### 常见问题

**Q: 两个系统的数据不一致怎么办？**

使用双写 + CDC（Change Data Capture）策略：

```bash
claude -p "设计数据库同步方案：
1. 旧系统写Oracle的同时，通过Debezium CDC同步到PostgreSQL
2. 新服务的写操作同时写入PostgreSQL和发送MQ消息
3. 旧系统消费MQ消息更新Oracle
4. 添加数据一致性校验的定时任务"
```

## 第五步：持续回归验证

### 操作说明

每完成一批方法迁移，都需要运行全量验证。Claude Code 可以自动化这个过程：

```bash
claude -p "执行回归验证：

1. 运行所有特征测试: mvn test
2. 对比新旧服务的API响应（从测试报告读取）
3. 检查是否有测试失败
4. 如果有失败，分析失败原因：
   - 是预期行为变化？→ 更新特征测试
   - 是真正的回归bug？→ 修复新服务代码
5. 生成验证报告保存到 migration/reports/ 目录"
```

### 自动化回归脚本

将验证过程写成可重复执行的脚本：

```bash
#!/bin/bash
# regression_check.sh
# 每次迁移一批方法后执行

echo "=== Step 1: 编译检查 ==="
mvn compile -q || { echo "编译失败！"; exit 1; }

echo "=== Step 2: 运行特征测试 ==="
mvn test -pl order-module -Dtest="*CharacterizationTest" -q
TEST_RESULT=$?

echo "=== Step 3: API兼容性检查 ==="
claude -p "对比以下两组API响应是否一致：
旧系统: $(curl -s http://localhost:8080/order/1)
新系统: $(curl -s http://localhost:8081/api/v1/orders/1)
忽略响应中的timestamp和traceId字段。"

echo "=== Step 4: 生成迁移进度报告 ==="
claude -p "读取 migration/ 目录下的所有ADR和测试报告，
生成当前迁移进度摘要：
- 已迁移的方法列表
- 待迁移的方法列表
- 已知风险项
- 建议的下一步操作"

if [ $TEST_RESULT -ne 0 ]; then
    echo "⚠️  特征测试失败，请检查！"
    exit 1
fi
echo "✅ 回归验证通过"
```

### 使用 Hooks 自动触发验证

在 `.claude/settings.json` 中配置 hooks，让 Claude Code 在每次文件修改后自动触发测试：

```json
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "command": "cd /home/dev/legacy-monolith && mvn test-compile -q 2>&1 | tail -5",
        "description": "每次文件修改后编译检查"
      }
    ]
  }
}
```

## 第六步：旧代码退役与文档沉淀

### 操作说明

当所有方法都迁移完毕且稳定运行后，清理旧代码：

```bash
claude -p "执行订单模块旧代码退役：

1. 检查迁移清单，确认所有方法已在新服务中实现
2. 运行全量特征测试，确认新旧服务行为完全一致
3. 移除旧单体中的OrderServiceImpl（保留接口定义作为文档）
4. 移除OrderServiceProxy的降级逻辑
5. 更新README和架构文档
6. 在git中创建 tagged release: order-service-v1.0.0

注意：每一步操作前先确认，不要自动执行。"
```

### 知识沉淀：生成迁移文档

```bash
claude -p "基于整个迁移过程，生成最终的迁移文档：

包含：
1. 架构变更概览（Before/After对比）
2. 迁移的时间线和关键决策点
3. 遇到的问题和解决方案
4. 新服务的运维指南（部署、监控、排错）
5. 遗留系统的其他模块迁移建议

文档保存到 migration/FINAL_MIGRATION_REPORT.md"
```

## 完整工作流程图

```mermaid
flowchart TB
    A[遗留系统现状评估] --> B[CLAUDE.md 项目画像]
    B --> C[依赖图谱绘制]
    C --> D[特征测试生成]
    D --> E[组件边界定义]
    E --> F[API契约设计]
    F --> G[新微服务脚手架]
    G --> H{逐方法迁移}
    H --> I[复制业务逻辑]
    I --> J[适配新框架]
    J --> K[路由切换]
    K --> L[回归验证]
    L --> M{验证通过?}
    M -->|是| N{还有待迁移方法?}
    M -->|否| O[分析失败原因]
    O --> P[修复或更新测试]
    P --> H
    N -->|是| H
    N -->|否| Q[旧代码退役]
    Q --> R[文档沉淀]
    R --> S[迁移完成]

    style A fill:#f9f,stroke:#333
    style D fill:#ff9,stroke:#333
    style L fill:#9ff,stroke:#333
    style S fill:#9f9,stroke:#333
```

## 实战案例：订单模块完整迁移日志

以下是一个真实的迁移会话记录（已脱敏），展示每个步骤的实际耗时和关键决策：

```
Day 1: 项目画像（2小时）
├── 生成CLAUDE.md配置
├── 运行依赖分析 → 识别23个类、47个依赖关系
├── 标记高风险依赖: PaymentService(强), InventoryService(强)
└── 输出: dependency-graph.md

Day 2-3: 特征测试（6小时）
├── 为OrderServiceImpl生成12个特征测试
├── 为OrderRepository生成8个特征测试
├── 编译修复: 3处泛型类型不匹配
├── 特征发现: createOrder()存在隐藏的null指针风险
└── 输出: 20个测试用例, 全部GREEN

Day 4: 接口契约（3小时）
├── 生成OpenAPI 3.0规范
├── ADR-001: 选择同步HTTP而非MQ（降低复杂度）
├── ADR-002: 选择双写而非CDC（数据量小，性价比更高）
└── 输出: order-service-api.yaml

Day 5-8: 逐步迁移（12小时）
├── getOrderById() → 1小时（只读，最简单）
├── queryOrders() → 2小时（复杂查询，需JPA Specification）
├── createOrder() → 4小时（核心逻辑，涉及3个外部调用）
├── updateOrderStatus() → 2小时（状态机逻辑）
├── cancelOrder() → 3小时（涉及退款逻辑，需要补偿事务）
└── 每个方法迁移后立即运行回归验证

Day 9-10: 路由切换与灰度（4小时）
├── 实现OrderServiceProxy
├── 配置化路由开关（按方法粒度）
├── 10%流量灰度 → 50% → 100%
└── 监控: P99延迟从120ms降至45ms

Day 11: 旧代码退役（2小时）
├── 确认新服务稳定运行48小时
├── 移除旧代码
├── 生成迁移报告
└── 创建 release tag
```

## Prompt 模板速查表

以下是本教程中所有关键 Prompt 的精简模板，可直接复制使用：

### 依赖分析模板

```
分析 [模块名] 的依赖关系：
1. 涉及的包和类
2. 入向依赖（被谁引用）
3. 出向依赖（引用了谁）
4. 共享资源（数据库表、配置、文件）
输出格式：每项标注强度和风险等级
```

### 特征测试模板

```
为 [类名.方法名] 生成特征测试：
- 使用JUnit5 + Mockito
- 模拟所有外部依赖
- 覆盖所有分支路径
- 精确记录当前行为（包括bug）
- 不修正任何现有行为
```

### 迁移执行模板

```
迁移 [方法名] 到新微服务：
1. 从 [旧路径] 复制核心逻辑
2. 适配 [新框架/新依赖]
3. 确保特征测试通过
4. 旧代码添加 @Deprecated
```

### 回归验证模板

```
执行回归验证：
1. 运行所有特征测试
2. 对比新旧API响应
3. 分析失败原因（行为变化 vs 回归bug）
4. 生成验证报告
```

## 关键原则总结

```mermaid
mindmap
  root((遗留代码现代化))
    安全第一
      特征测试先行
      单次修改≤3文件
      每次改完必编译
      Git分支保护
    渐进式迁移
      Strangler Fig模式
      方法级粒度迁移
      路由切换而非重写
      灰度发布验证
    上下文管理
      CLAUDE.md项目画像
      ADR决策记录
      分模块限制上下文
      Worktree隔离开发
    自动化验证
      Hooks编译检查
      特征测试回归
      API兼容性对比
      生成验证报告
```

## 延伸阅读

- [Anthropic 官方 Code Modernization Playbook](https://resources.anthropic.com/code-modernization-playbook) — Anthropic 官方遗留代码现代化手册，涵盖从评估到执行的完整方法论
- [Michael Feathers《修改代码的艺术》](https://www.oreilly.com/library/view/working-effectively-with/0131177052/) — 特征测试和遗留代码安全重构的经典著作
- [Martin Fowler: Strangler Fig Pattern](https://martinfowler.com/bliki/StranglerFigApplication.html) — 绞杀者模式的原始定义和应用指南

## 训练营适用性评估

| 维度 | 评估 |
|------|------|
| 适合训练营类型 | 企业内训（遗留系统改造专项）、高级开发者训练营 |
| 学员基础要求 | Java/Spring 经验 2 年以上，理解微服务架构概念 |
| 预计教学时长 | 4-6 小时（含实操演练） |
| 实操依赖 | 需要准备一个可编译的遗留 Java 项目作为练习素材 |
| 难度评级 | ★★★★☆（中高级） |

---

## 参考来源

1. [Anthropic Code Modernization Playbook](https://resources.anthropic.com/code-modernization-playbook) — Anthropic 官方发布的遗留代码现代化方法论手册
2. [Claude Code for Legacy Codebases: A Practitioner's Guide](https://richardporter.dev/blog/claude-code-legacy-codebase-practitioners-guide) — 生产环境 CLAUDE.md 配置和增量工作流实践指南
3. [Claude Code for Refactoring: Modernizing Legacy Codebases at Scale](https://callsphere.ai/blog/claude-code-refactoring-legacy-codebases) — 从定向函数重写到大规模架构迁移的策略对比
4. [Legacy Code Modernization with Claude Code: Breaking Through Context Window Barriers](https://www.tribe.ai/applied-ai/legacy-code-modernization-with-claude-code-breaking-through-context-window-barriers) — 多步 Agent 工作流突破上下文窗口限制的实践方案
5. [Modernization with Claude Code: from COBOL to Cloud Migrations](https://codingscape.com/blog/modernization-with-claude-code-from-cobol-to-cloud-migrations) — COBOL 到云端迁移的企业级案例研究

> [!tip] 51学通信知识星球
> **星主：爱卫生**（微信：gprshome201101）——公众号「51学通信」创办者，19 年通信行业运维与讲师经验，著有《GPRS网络信令实例详解》《EPC原理与实践》《5G核心网原理与实践》三本纸质书（各大电商平台有售）。
> **星球定位**：深耕 5G 核心网、IMS、NFV/AI、云原生等 ICT 领域，主打运维岗位与信令分析。
> **当前规模**：5200 篇主题 / 990 个回答，198 元/年。
> **加入福利**：加入星球后请加爱卫生微信，拉您进知识星球年度陪伴与答疑群——不限量回复您的各种问题，另有群内分享。
> **AI 加持**：51学通信知识星球已作为 skill 接入 WorkBuddy，使用 deepseek-4-flash 在海量星球帖子中精准找贴、找视频、找 FAQ 和案例，做总结、找文档和 PPT 等场景全覆盖。

![51学通信知识星球海报-扫码加入](https://wiki.500nian.com/images/zhixingqiu_qrcode.png)
