金句:遗留代码是一个没有测试的代码库。AI 是第一个不会因为它的复杂性而感到恐惧的"工程师"。
一、遗留代码的噩梦
每个工程师都有这样的经历:
- 接手一个 5 年前的老项目,没有文档,注释残缺
- 想改一个 Bug,却发现牵一发动全身
- 明知道代码需要重构,但不敢动,因为"不知道会影响什么"
遗留代码的核心问题是不可见性:你不知道它的边界,不知道它的副作用,不知道改动它的后果。
AI 正在改变这个现状。
二、AI 重构的四步法
第一步:读懂代码(AI 翻译遗留代码)
# 一段典型的遗留代码
def proc_data(d, t, f=None, x=True):
r = []
for i in d:
if i['s'] != 'D' and (not f or i['c'] in f):
tmp = {'id': i['id'], 'val': i['v'] * t}
if x and 'tax' in i:
tmp['val'] = tmp['val'] * (1 + i['tax'])
if i.get('disc'):
tmp['val'] = tmp['val'] * (1 - i['disc']/100)
r.append(tmp)
return r
提示词:
请分析这段代码:
1. 用自然语言解释这个函数的业务逻辑
2. 解释所有参数和变量的含义
3. 找出潜在的 Bug 或设计问题
4. 给出重命名建议(所有参数和变量)
AI 解析输出:
这个函数的业务逻辑是:处理商品价格计算
参数含义:
- d: 商品数据列表(data)
- t: 汇率或价格倍率(tax_rate 或 multiplier)
- f: 允许的商品类别过滤器(filter_categories)
- x: 是否计算含税价格(include_tax)
潜在问题:
1. 参数 t 的含义不明确,可能是汇率或税率
2. 未处理 i['v'] 不存在的情况(KeyError 风险)
3. disc 字段的折扣计算顺序可能有问题(先乘税再乘折扣 vs 先折扣再乘税)
重命名建议:
- d → products
- t → price_multiplier
- f → category_filter
- x → include_tax
- r → result
- i → product
- tmp → processed_item
第二步:生成测试(锁定当前行为)
重构的黄金原则:在重构之前,先为现有代码生成测试,锁定当前行为。
基于以上分析,请为这个函数生成完整的测试用例。
要求覆盖所有参数组合和边界情况。
我的目标是:先确保重构后函数行为不变,再优化代码。
生成的测试:
import pytest
# 测试基础功能
def test_basic_price_calculation():
products = [{'id': 1, 'v': 100, 's': 'A', 'c': 'electronics'}]
result = proc_data(products, 2)
assert result[0]['val'] == 200
# 测试过滤删除状态的商品
def test_filters_deleted_products():
products = [
{'id': 1, 'v': 100, 's': 'D', 'c': 'electronics'}, # 已删除
{'id': 2, 'v': 200, 's': 'A', 'c': 'electronics'}, # 正常
]
result = proc_data(products, 1)
assert len(result) == 1
assert result[0]['id'] == 2
# 测试类别过滤
def test_category_filter():
products = [
{'id': 1, 'v': 100, 's': 'A', 'c': 'electronics'},
{'id': 2, 'v': 100, 's': 'A', 'c': 'clothing'},
]
result = proc_data(products, 1, f=['electronics'])
assert len(result) == 1
# 测试含税计算
def test_tax_calculation():
products = [{'id': 1, 'v': 100, 's': 'A', 'c': 'x', 'tax': 0.1}]
result = proc_data(products, 2, x=True)
assert result[0]['val'] == 220 # 100 * 2 * 1.1
# 测试折扣计算
def test_discount_calculation():
products = [{'id': 1, 'v': 100, 's': 'A', 'c': 'x', 'disc': 20}]
result = proc_data(products, 1, x=False)
assert result[0]['val'] == 80 # 100 * (1 - 20/100)
第三步:逐步重构
原则:每次只做一种类型的重构,运行测试,通过后再进行下一种。
重构顺序:
1. 重命名(变量/参数/函数名)— 风险最低
2. 提取函数(长函数拆分)
3. 提取类(相关逻辑封装)
4. 改变数据结构(如果有必要)
提示词:
请对以下函数进行第一步重构:只做重命名,不改变逻辑。
基于你之前的分析,将所有缩写和无意义的名称替换为语义化名称。
保证重构前后行为完全一致。
[粘贴原函数]
第一步重构结果:
def calculate_product_prices(
products: list,
price_multiplier: float,
category_filter: list = None,
include_tax: bool = True
) -> list:
result = []
for product in products:
if product['s'] != 'D' and (
not category_filter or product['c'] in category_filter
):
processed_item = {
'id': product['id'],
'val': product['v'] * price_multiplier
}
if include_tax and 'tax' in product:
processed_item['val'] *= (1 + product['tax'])
if product.get('disc'):
processed_item['val'] *= (1 - product['disc'] / 100)
result.append(processed_item)
return result
第四步:架构级重构
当单个函数重构完成后,进行更大范围的架构优化:
基于以上代码,请进行架构级重构:
1. 应用单一职责原则,将价格计算逻辑拆分为独立的类
2. 使用策略模式处理不同的价格计算规则
3. 添加完整的类型注解
4. 优化错误处理
目标:使代码满足开放-封闭原则,
新增价格规则时不需要修改现有代码。
三、AI 重构大型代码库的策略
策略一:从"热点"文件开始
# 找出改动最频繁的文件(往往是问题最多的)
git log --name-only --pretty=format: | sort | uniq -c | sort -rn | head 20
这些文件是重构的高优先级目标。
策略二:绞杀者模式(Strangler Fig Pattern)
传统重构(危险):
修改旧代码 → 部署 → 希望没破坏什么
绞杀者模式(安全):
旧代码继续运行
新代码并行实现
流量逐步切换
旧代码退役
AI 辅助绞杀者模式:
我有一个遗留的 OrderService 类,包含 2000 行代码,无测试。
我想用绞杀者模式逐步替换它。
请帮我:
1. 分析 OrderService 的职责(可能有几个独立的子职责)
2. 建议拆分方案(新的类/模块划分)
3. 生成新旧接口的适配层代码
4. 生成测试用例,用于验证新旧实现行为一致
@src/services/OrderService.legacy.ts
四、重构成果量化
建立重构前后的量化对比:
# 代码质量指标统计脚本
metrics_before = {
"函数平均行数": 45,
"最长函数行数": 312,
"循环复杂度": 18,
"重复代码率": "23%",
"测试覆盖率": "0%",
"TypeScript 类型覆盖率": "34%"
}
metrics_after = {
"函数平均行数": 12,
"最长函数行数": 38,
"循环复杂度": 4,
"重复代码率": "3%",
"测试覆盖率": "87%",
"TypeScript 类型覆盖率": "100%"
}
章节小结:AI 重构遗留代码的核心价值在于"减少认知负担"。理解一段谜一样的代码、生成保护测试、逐步安全重构——这三步原本耗时数天,AI 可以压缩到数小时。记住:重构不是重写,是在保持行为不变的前提下改善代码结构。