什么是合适的重构流程
本文介绍渐进式重构流程,以大文件拆分为例说明如何分析依赖、迁移代码并验证每一步。
核心原则
分步迁移,逐步验证。
每次只移动一小部分代码,立即验证,然后继续。这种方法将风险降到最低,并确保每个步骤都是可控的。
大文件拆分的标准流程
第一步:创建专属分支
在开始任何重构工作之前,必须创建一个独立的 git 分支:
git checkout -b refactor/split-large-file为什么需要独立分支?
- 保护主分支的稳定性
- 可以随时回退到重构前的状态
- 便于代码审查和追踪变更
- 如果重构失败,不影响主分支和其他开发工作
第二步:分析拆分目标
不要急于动手,先搞清楚”拆什么”:
- 阅读完整文件:理解文件的整体结构和职责
- 识别功能模块:找出逻辑上独立的代码块
- 绘制依赖关系:标注模块之间的引用关系
- 确定拆分粒度:每个新文件应该职责单一、内聚性高
原始大文件分析示例:
┌─────────────────────────────┐
│ utils-large-file.ts │
├─────────────────────────────┤
│ • 字符串处理函数 (15个) │ ← 可拆分为 string-utils.ts
│ • 日期处理函数 (8个) │ ← 可拆分为 date-utils.ts
│ • 数组工具函数 (12个) │ ← 可拆分为 array-utils.ts
│ • 格式化函数 (10个) │ ← 可拆分为 formatters.ts
└─────────────────────────────┘
第三步:从最简单的模块开始
什么是最简单的模块?
- 没有外部依赖或依赖最少的模块
- 函数数量少、逻辑清晰的模块
- 不涉及复杂类型定义的模块
从简单到复杂的好处:
- 快速建立信心
- 积累拆分经验
- 早期发现潜在问题
- 为后续复杂拆分建立模板
第四步:渐进式迁移
这是最关键的步骤,遵循”拆一个、改引用、删原代码”的循环:
循环执行以下步骤:
1. 将目标模块复制到新文件
↓
2. 更新原文件中对该模块的引用,指向新文件
↓
3. 从原文件中删除已迁移的代码
↓
4. 运行测试/构建,验证没有破坏功能
↓
5. 提交变更(可选,但推荐)
↓
6. 重复以上步骤,直到全部拆分完成
具体示例
假设我们要拆分 utils-large-file.ts:
# 1. 创建新文件 string-utils.ts,包含字符串处理函数
touch src/utils/string-utils.ts// src/utils/string-utils.ts
export function capitalize(str: string): string {
return str.charAt(0).toUpperCase() + str.slice(1)
}
export function camelCase(str: string): string {
// ... 实现
}// 原文件 utils-large-file.ts 中,更新引用
// 修改前:
// import { capitalize, camelCase } from './utils-large-file'
// 修改后:
import { capitalize, camelCase } from './string-utils'// 然后从 utils-large-file.ts 中删除 capitalize 和 camelCase 的函数定义# 验证没有破坏功能
npm run build
npm test渐进式重构的关键步骤
| 特征 | 说明 |
|---|---|
| 小步前进 | 每次只迁移一个模块 |
| 即时验证 | 每步都运行测试/构建 |
| 引用同步 | 拆完立即修改引用 |
| 原代码清理 | 迁移后删除原文件中的对应部分 |
| 分支保护 | 始终在独立分支进行 |
重构后的收尾工作
- 运行完整的测试套件:确保没有破坏任何功能
- 检查代码风格:运行 linter 和 formatter
- 审查新文件结构:确保拆分后的文件组织合理
- 更新文档:如果文件结构变化影响文档,及时更新
- 提交并合并:
git add .
git commit -m "refactor: 拆分大文件为多个职责单一的模块"
git checkout main
git merge refactor/split-large-file其他重构场景的通用策略
虽然本文档以大文件拆分为例,但同样的原则适用于:
- 函数提取:将长函数拆分为多个小函数
- 模块重组:重新组织目录结构
- 接口优化:简化复杂的 API 或函数签名
- 依赖解耦:减少模块间的耦合
核心思想不变:小步、验证、清理、循环。
总结
渐进式重构按分析目标、迁移模块、更新引用和验证结果的顺序推进;具体粒度和检查范围应与项目风险相匹配。
“重构的两条法则:
- 任何情况下,重构前必须有能运行的代码
- 每次只做一个小改动,然后测试” — Martin Fowler, 《重构:改善既有代码的设计》