重构Skill refactoring

重构技能专注于提高代码质量,通过系统性代码重构技术改善代码的可读性、可维护性和性能,而不改变外部行为。关键点包括代码清理、去除重复、应用设计模式、优化代码组织和减少技术债务,适用于软件开发中的架构设计和代码改进。关键词:代码重构、软件工程、代码质量、可维护性、性能优化、设计模式、技术债务、代码异味。

架构设计 0 次安装 0 次浏览 更新于 3/24/2026

name: 重构 description: | 在不改变外部行为的情况下,重构现有代码以提高可读性、可维护性和性能。

使用时机:在不改变行为的情况下重构代码,提取方法/类,移除重复,应用设计模式,改进代码组织,减少技术债务。 不要使用:用于修复错误(使用 /debugging),用于添加测试(使用 /testing),用于新功能(直接实现)。

触发词:重构、重组、重写、清理、简化、提取、内联、重命名、移动、拆分、合并、分解、模块化、解耦、技术债务、代码异味、DRY、SOLID、改进代码、现代化、重组。 triggers:

  • 重构
  • 重组
  • 重写
  • 清理
  • 简化
  • 提取
  • 内联
  • 重命名
  • 移动
  • 拆分
  • 合并
  • 分解
  • 模块化
  • 解耦
  • 技术债务
  • 代码异味
  • DRY
  • SOLID
  • 改进代码
  • 现代化
  • 重组 allowed-tools: 读取、查找、匹配、编辑、写入、命令行

重构

概述

此技能专注于通过系统性重构技术提高代码质量。它识别代码异味并应用已验证的重构模式,在保留功能的同时增强可维护性。

当用户请求以下内容时使用此技能:

  • 代码重构或清理
  • 减少技术债务
  • 改进代码组织
  • 应用设计模式
  • 拆分大型文件或函数
  • 移除重复
  • 现代化遗留代码
  • 改进可测试性

范围选择

何时使用此技能:

  • 局部重构(单个模块/文件)
  • 模式应用(提取方法、引入接口)
  • 测试重构和测试套件改进
  • 数据流水线重组
  • 具有测试覆盖的安全重构

何时升级到高级软件工程师:

  • 影响多个模块的架构变更
  • 需要迁移路径的API重新设计
  • 范围不清晰的跨组件重构
  • 需要性能分析的性能优化
  • 基础设施重构(使用基础设施相关技能,如 /terraform、/kubernetes)
  • 安全性敏感的重构(使用 /security-audit 和 /threat-model 技能)

指令

1. 识别重构机会

要搜索的代码异味:

  • 长方法(>50行)或大类(>300行)
  • 重复的代码块
  • 高圈复杂度
  • 魔法数字和字符串字面量
  • 深度嵌套(>3层)
  • 特性嫉妒(方法使用另一个类的数据)
  • 霰弹枪式手术(一个变更需要多次编辑)
  • 数据簇(相同的参数组)
  • 原始类型执着(使用原始类型而非对象)

使用查找/匹配来查找模式:

# 查找长函数(粗略启发式)
rg "^(\s*)(def|function|fn|func)\s+\w+" --after-context=60

# 查找重复代码
rg --multiline "pattern.*
.*pattern"

# 查找魔法数字
rg "\b\d{2,}\b" --type=py --type=js --type=rs

2. 规划重构

开始前:

  1. 验证测试覆盖 - 运行测试建立基线
  2. 列出所有变更 - 记录重构序列
  3. 识别依赖关系 - 什么代码依赖于您要更改的代码?
  4. 规划回滚点 - 哪里可以安全提交?
  5. 检查影响 - 查找对正在更改的函数/类的引用

需要升级的红色标志:

  • 不存在测试覆盖
  • 变更影响具有外部消费者的公共API
  • 所有权不清晰或涉及多个团队
  • 性能关键的热路径

3. 应用重构模式

代码组织模式

提取方法/函数:

  • 将长函数拆分为更小、专注的函数
  • 每个函数应做一件事
  • 提高可读性和可测试性

提取类:

  • 拆分具有多个职责的大类
  • 遵循单一职责原则
  • 提高内聚性并减少耦合

移动方法/字段:

  • 将方法移动到使用其数据的类中
  • 减少特性嫉妒
  • 提高封装性

内联方法/变量:

  • 移除不必要的间接
  • 简化过度抽象的代码
  • 当抽象不增加价值时使用

重命名:

  • 提高命名清晰度
  • 使用领域语言
  • 使意图明确

结构模式

用多态替换条件:

  • 用子类方法替换类型切换
  • 实现开放/封闭原则
  • 提高可扩展性

引入参数对象:

  • 将相关参数分组到对象中
  • 减少参数列表
  • 使数据关系明确

用常量替换魔法数字:

  • 为字面量定义命名常量
  • 提高可读性和可维护性
  • 集中配置

分解条件:

  • 将复杂条件提取到命名函数中
  • 用防护子句替换嵌套if
  • 提高可读性

测试重构模式

提取测试固件:

  • 将通用设置移动到固件/工厂中
  • 减少测试文件中的重复
  • 提高测试可维护性

引入测试数据构建器:

  • 用构建器替换复杂的对象构建
  • 使测试意图更清晰
  • 简化测试设置

替换断言轮盘:

  • 使用描述性断言消息
  • 每个测试一个逻辑断言
  • 清晰的失败消息

提取测试助手:

  • 将重复的测试逻辑移动到助手中
  • 保持测试专注于行为
  • 提高测试可读性

数据流水线模式

提取转换:

  • 隔离数据转换逻辑
  • 使转换可组合
  • 提高可测试性

引入流水线接口:

  • 定义标准输入/输出契约
  • 启用阶段组合
  • 简化测试和调试

用阶段替换内联处理:

  • 将整体处理拆分为阶段
  • 每个阶段具有单一职责
  • 启用并行化和监控

4. 安全重构工作流

对于每个重构步骤:

  1. 进行变更 - 一次一个重构
  2. 运行测试 - 验证行为被保留
  3. 提交 - 使用清晰消息创建检查点
  4. 重复 - 移动到下一个重构

如果测试失败:

  • 立即恢复(git checkout)
  • 分析失败 - 是测试问题还是行为变更?
  • 修复或调整方法

提交消息格式:

重构:从process_order中提取calculate_discount

通过隔离折扣逻辑提高可测试性。
行为无变更。

5. 验证变更

验证检查表:

  • 所有测试通过(现有 + 任何新测试)
  • 功能无回归
  • 性能未降级(对于热路径)
  • 代码覆盖保持或提高
  • 代码检查通过
  • 构建成功

对于大型重构:

  • 运行额外的冒烟测试
  • 检查内存使用(如适用)
  • 审查错误处理保留情况

最佳实践

  1. 小步前进:进行增量变更,而不是大爆炸重写
  2. 测试先行:确保在重构前有测试 - 如果缺失则编写
  3. 一次一件事:每个提交专注于单个重构
  4. 保留行为:外部行为必须保持不变
  5. 保持工作状态:每个步骤后代码应通过测试
  6. 记录意图:在提交中解释为什么需要重构
  7. 重构测试:保持测试清洁和可维护
  8. 使用类型安全:利用类型系统早期捕获错误
  9. 测量而非猜测:在优化性能前进行性能分析
  10. 知道何时停止:不要过度设计或添加不必要的抽象

常见模式示例

模式 1:提取方法

# 之前:具有多个职责的长方法
def process_order(order):
    # 验证订单
    if not order.items:
        raise ValueError("订单为空")
    if order.total < 0:
        raise ValueError("无效总额")

    # 计算折扣
    discount = 0
    if order.customer.is_premium:
        discount = order.total * 0.1
    if order.total > 1000:
        discount += order.total * 0.05

    # 应用折扣并保存
    order.final_total = order.total - discount
    order.save()

# 之后:提取的方法,具有单一职责
def process_order(order):
    validate_order(order)
    discount = calculate_discount(order)
    finalize_order(order, discount)

def validate_order(order):
    if not order.items:
        raise ValueError("订单为空")
    if order.total < 0:
        raise ValueError("无效总额")

def calculate_discount(order) -> float:
    discount = 0
    if order.customer.is_premium:
        discount = order.total * 0.1
    if order.total > 1000:
        discount += order.total * 0.05
    return discount

def finalize_order(order, discount: float):
    order.final_total = order.total - discount
    order.save()

模式 2:用常量替换魔法数字

// 之前
if (response.status === 200) {
  setTimeout(retry, 3000);
  if (attempts > 5) {
    throw new Error("超过最大重试次数");
  }
}

// 之后
const HTTP_OK = 200;
const RETRY_DELAY_MS = 3000;
const MAX_RETRY_ATTEMPTS = 5;

if (response.status === HTTP_OK) {
  setTimeout(retry, RETRY_DELAY_MS);
  if (attempts > MAX_RETRY_ATTEMPTS) {
    throw new Error("超过最大重试次数");
  }
}

模式 3:用防护子句替换嵌套条件

# 之前
def get_payment_amount(employee):
    if employee.is_active:
        if employee.is_full_time:
            if employee.tenure > 5:
                return employee.salary * 1.1
            else:
                return employee.salary
        else:
            return employee.hourly_rate * employee.hours
    else:
        return 0

# 之后
def get_payment_amount(employee):
    if not employee.is_active:
        return 0

    if not employee.is_full_time:
        return employee.hourly_rate * employee.hours

    if employee.tenure > 5:
        return employee.salary * 1.1

    return employee.salary

模式 4:引入参数对象

// 之前
function createUser(
  firstName: string,
  lastName: string,
  email: string,
  phone: string,
  street: string,
  city: string,
  state: string,
  zip: string,
) {
  // ...
}

// 之后
interface UserDetails {
  name: PersonName;
  contact: ContactInfo;
  address: Address;
}

interface PersonName {
  first: string;
  last: string;
}

interface ContactInfo {
  email: string;
  phone: string;
}

interface Address {
  street: string;
  city: string;
  state: string;
  zip: string;
}

function createUser(details: UserDetails) {
  // ...
}

模式 5:用多态替换类型代码

// 之前
enum ShapeType { Circle, Rectangle, Triangle }

struct Shape {
    shape_type: ShapeType,
    radius: f64,
    width: f64,
    height: f64,
    base: f64,
}

impl Shape {
    fn area(&self) -> f64 {
        match self.shape_type {
            ShapeType::Circle => 3.14159 * self.radius * self.radius,
            ShapeType::Rectangle => self.width * self.height,
            ShapeType::Triangle => 0.5 * self.base * self.height,
        }
    }
}

// 之后
trait Shape {
    fn area(&self) -> f64;
}

struct Circle { radius: f64 }
struct Rectangle { width: f64, height: f64 }
struct Triangle { base: f64, height: f64 }

impl Shape for Circle {
    fn area(&self) -> f64 {
        3.14159 * self.radius * self.radius
    }
}

impl Shape for Rectangle {
    fn area(&self) -> f64 {
        self.width * self.height
    }
}

impl Shape for Triangle {
    fn area(&self) -> f64 {
        0.5 * self.base * self.height
    }
}

模式 6:提取数据流水线阶段

# 之前:整体处理
def process_data(raw_data):
    # 验证
    if not raw_data:
        raise ValueError("数据为空")

    # 清理
    cleaned = []
    for item in raw_data:
        if item.get('status') == 'valid':
            cleaned.append(item)

    # 转换
    transformed = []
    for item in cleaned:
        transformed.append({
            'id': item['id'],
            'value': item['raw_value'] * 100,
            'timestamp': item['ts']
        })

    # 聚合
    total = sum(item['value'] for item in transformed)
    return {'items': transformed, 'total': total}

# 之后:可组合阶段的流水线
def validate_input(raw_data):
    if not raw_data:
        raise ValueError("数据为空")
    return raw_data

def filter_valid(data):
    return [item for item in data if item.get('status') == 'valid']

def transform_items(data):
    return [
        {
            'id': item['id'],
            'value': item['raw_value'] * 100,
            'timestamp': item['ts']
        }
        for item in data
    ]

def aggregate_results(transformed):
    total = sum(item['value'] for item in transformed)
    return {'items': transformed, 'total': total}

def process_data(raw_data):
    return (raw_data
            |> validate_input
            |> filter_valid
            |> transform_items
            |> aggregate_results)

模式 7:使用构建器简化测试

// 之前
func TestUserRegistration(t *testing.T) {
    user := &User{
        FirstName: "John",
        LastName: "Doe",
        Email: "john@example.com",
        Phone: "555-0100",
        Address: Address{
            Street: "123 Main St",
            City: "Springfield",
            State: "IL",
            Zip: "62701",
        },
        Preferences: Preferences{
            NewsletterEnabled: true,
            Theme: "dark",
        },
        CreatedAt: time.Now(),
    }

    err := RegisterUser(user)
    assert.NoError(t, err)
}

// 之后
func TestUserRegistration(t *testing.T) {
    user := NewUserBuilder().
        WithName("John", "Doe").
        WithEmail("john@example.com").
        Build()

    err := RegisterUser(user)
    assert.NoError(t, err)
}

// 测试构建器专注于每个测试重要的部分
func TestUserWithNewsletter(t *testing.T) {
    user := NewUserBuilder().WithNewsletter(true).Build()
    // ...
}

何时停止重构

停止如果:

  • 测试开始意外失败
  • 范围超出初始计划
  • 不确定架构影响
  • 出现性能担忧
  • 安全性影响不清晰

在这些情况下:

  • 提交当前进展
  • 记录剩余工作
  • 升级到高级软件工程师或相关专家