1Working Effectively with Legacy Code

遗留代码基础

什么是遗留代码

遗留代码定义修改困境测试安全网变更策略

🎯 AI 时代的学习建议:不要只读理论。理解这一章的设计动机(为什么需要这个概念?)和边界条件(什么情况下会失效?)。当 AI 生成的代码涉及这些概念时,你能判断它是否用对了场景。AI 能帮你总结内容,但无法替代你亲手阅读、思考、建立直觉的过程。

第1章:遗留代码基础(Legacy Code Fundamentals)

一、导读

1.1 本章学习目标

第1章定义了什么是遗留代码,以及面对遗留代码时的基本策略。Michael Feathers 给出了一个颠覆性的定义:遗留代码就是没有测试的代码。

本章的核心学习目标包括:

  • 理解遗留代码的真正含义:没有测试 = 遗留代码
  • 掌握修改遗留代码的基本策略
  • 理解"修改困境"
  • 学会建立测试安全网

1.2 为什么本章如此重要

大多数开发者大部分时间都在与遗留代码打交道。Feathers 的定义改变了我们看待遗留代码的方式——问题不在于代码有多旧,而在于我们能否安全地修改它。

1.3 核心问题引导

为什么"没有测试"是遗留代码的核心问题?

修改遗留代码的困境是什么?

如何在不理解代码的情况下安全地修改它?

特征测试和回归测试有什么区别?


二、核心概念详解

2.1 遗留代码的定义

传统定义:遗留代码 = 旧的、过时的代码
Feathers 定义:遗留代码 = 没有测试的代码

关键洞察:
- 有测试的旧代码不是遗留代码(可以安全修改)
- 没有测试的新代码是遗留代码(无法安全修改)
- 测试是修改的安全网

2.2 修改困境

修改困境(Change Dilemma):
1. 要修改代码,你需要理解它
2. 要理解它,你需要修改它
3. 修改它可能导致 bug
4. 没有测试,你不知道是否引入了 bug

解决方案:先添加测试,再修改代码

2.3 安全修改的步骤

遗留代码修改算法:
1. 识别变更点(在哪里需要修改?)
2. 找到测试点(在哪里可以插入测试?)
3. 分解依赖(如何让代码可以被测试?)
4. 编写测试(建立安全网)
5. 修改代码(在测试保护下修改)
6. 运行测试(确认没有破坏)

2.4 特征测试

java
// 特征测试:记录系统的实际行为
// 即使行为看起来是"错误的",也要先记录下来
@Test
void testCurrentBehavior() {
    // 不关心是否正确,只关心当前行为是什么
    String result = legacySystem.process("input");
    assertEquals("actual_output", result);    // 记录实际输出
}

// 有了特征测试后,你可以安全地重构
// 如果重构后测试仍然通过,说明行为没有改变

三、实战案例

3.1 案例一:为遗留代码添加第一个测试

java
// 遗留代码
public class Payroll {
    public int calculatePay(Employee employee) {
        int base = employee.getBaseSalary();
        int bonus = 0;
        if (employee.getYears() > 5) bonus = base / 10;
        if (employee.getDepartment().equals("Sales")) bonus += 1000;
        // 200 行复杂的计算逻辑...
        return base + bonus;
    }
}

// 第一步:写特征测试
@Test
void testCalculatePayKnownCase() {
    Employee emp = new Employee("Engineering", 3, 50000);
    Payroll payroll = new Payroll();
    int pay = payroll.calculatePay(emp);
    assertEquals(50000, pay);    // 记录实际行为
}

// 第二步:在测试保护下重构
// 现在可以安全地提取方法、重命名变量、简化逻辑

四、本章小结

遗留代码 = 没有测试的代码。

修改困境:要修改需要理解,要理解需要修改。

特征测试:记录系统实际行为,作为安全网。

安全修改:先添加测试,再修改代码。


五、思考与练习

为什么 Feathers 将遗留代码定义为"没有测试的代码"?

特征测试和单元测试有什么区别?

为一个你熟悉的遗留系统制定修改策略。


1/7遗留代码
0%