---
source: ../../../core/refactoring-standards.md
source_version: 2.1.0
translation_version: 2.1.0
last_synced: 2026-02-10
status: current
---

# 重构标准

> **语言**: [English](../../../core/refactoring-standards.md) | 简体中文

**版本**: 2.0.0
**最后更新**: 2026-01-21
**适用范围**: 所有进行代码改善的软件项目

---

## 目的

本标准定義程序码重構的完整指引，涵蓋從日常 TDD 重構循環到大型遺留系统現代化的所有場景。确保重構工作安全、可衡量，并与业务目標一致。

**主要優点**：
- 系统化的程序码品质改善方法
- 降低重構過程中引入错误的風險
- 清晰的重構 vs 重写决策框架
- 可衡量的成果与投資报酬率追蹤

---

## 目录

1. [重構 vs 重写决策矩陣](#重構-vs-重写决策矩陣)
2. [依規模的重構策略](#依規模的重構策略)
3. [遺留程序码策略](#遺留程序码策略)
4. [大型重構模式](#大型重構模式)
5. [数据庫重構](#数据庫重構)
6. [安全重構工作流程](#安全重構工作流程)
7. [重構度量指標](#重構度量指標)
8. [团队协作](#团队协作)
9. [技術債管理](#技術債管理)
10. [相关标准](#相关标准)
11. [參考数据](#參考数据)
12. [版本歷程](#版本歷程)

---

## 重構 vs 重写决策矩陣

在開始任何大型重構工作之前，评估重構或重写哪个更合適。

### 决策流程图

```
┌─────────────────────────────────────────────────────────────────┐
│                     重構 vs 重写决策樹                           │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  程序码目前在生产環境运行嗎？                                     │
│  ├─ 否 → 考慮重写（風險較低）                                    │
│  └─ 是 ↓                                                        │
│                                                                 │
│  你了解程序码在做什麼嗎？                                         │
│  ├─ 否 → 先写特徵测试，再决定                                    │
│  └─ 是 ↓                                                        │
│                                                                 │
│  测试覆蓋率足夠嗎（>60%）？                                       │
│  ├─ 否 → 先補测试，再决定                                        │
│  └─ 是 ↓                                                        │
│                                                                 │
│  核心架構可以保留嗎？                                             │
│  ├─ 否 → Strangler Fig（漸进替换）                               │
│  └─ 是 → 漸进式重構 ✓                                            │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘
```

### 比較矩陣

| 因素 | 傾向重構 | 傾向重写 |
|------|---------|---------|
| **程序码規模** | 大型、複雜 | 小型、獨立 |
| **测试覆蓋率** | 良好（>60%）| 差或没有 |
| **业务連續性** | 关鍵 | 可容忍停机 |
| **团队知識** | 团队理解程序码 | 無組織知識 |
| **核心架構** | 健全，只是混亂 | 根本性缺陷 |
| **时间壓力** | 緊迫期限 | 彈性时间 |
| **風險容忍度** | 低 | 較高 |

### 警告：第二系统效应

> 「第二个系统是一个人设计過最危險的系统。」— Fred Brooks

重写时，团队常常過度工程化。避免：
- 新增原本没有的功能
- 「为了未來彈性」過度抽象
- 忽视現有系统的教訓

---

## 依規模的重構策略

### 小規模：TDD 重構阶段（分鐘级）

紅-綠-重構循環的一部分。詳見[测试驅动开发](test-driven-development.md)。

**特点**：
- 时長：5-15 分鐘
- 範圍：单一方法或类别
- 测试：必須保持綠色

**常用技術**：
- 提取方法（Extract Method）
- 重新命名（Rename）
- 內联变數（Inline Variable）
- 以常數取代魔術數字（Replace Magic Number with Constant）

### 中規模：功能级重構（小时到天）

改善特定功能或模組，不改变其外部行为。

**特点**：
- 时長：數小时到數天
- 範圍：单一功能或模組
- 测试：若缺少則補充特徵测试

**規划检查清单**：

```
□ 定義範圍邊界（包含什麼、排除什麼）
□ 識别模組的所有进入点
□ 确保受影響程序码的测试覆蓋率 > 80%
□ 規划增量提交（每个都应可部署）
□ 与团队溝通（避免合併衝突）
```

### 大規模：架構级重構（周到月）

重大架構变更，如從单体迁移到微服务。

**特点**：
- 时長：數周到數月
- 範圍：多个模組或整个系统
- 测试：需要完整的集成测试

**模式**：見[大型重構模式](#大型重構模式)

---

## 遺留程序码策略

基於 Michael Feathers 的《Working Effectively with Legacy Code》。

### 遺留程序码困境

**定義**：遺留程序码 = 没有测试的程序码（無关年齡）

**困境**：
- 要安全地修改程序码，我們需要测试
- 要加测试，我們常常需要修改程序码
- 没有测试就修改程序码是有風險的

**解决方案**：使用安全技術在修改前加入测试。

### 特徵测试（Characterization Tests）

**目的**：捕獲現有行为（不是验证正确性）

**流程**：

```
1. 呼叫你想了解的程序码
2. 写一个你预期会失败的斷言
3. 执行测试看实际發生什麼
4. 更新斷言以符合实际行为
5. 重複直到覆蓋你需要修改的行为
```

**範例**：

```javascript
// 步骤 1：初始（预期会失败）
test('calculateDiscount 回传... 某个值', () => {
  const result = calculateDiscount(100, 'GOLD');
  expect(result).toBe(0); // 猜测 - 可能会失败
});

// 步骤 2：执行後，更新为实际值
test('calculateDiscount 对 GOLD 客戶回传 15', () => {
  const result = calculateDiscount(100, 'GOLD');
  expect(result).toBe(15); // 实际行为
});
```

### 尋找接縫（Finding Seams）

**定義**：接縫是可以在不编辑程序码的情况下改变行为的地方。

| 接縫类型 | 运作方式 | 範例 |
|---------|---------|------|
| **物件接縫** | 透過多型覆写 | 透過界面注入测试替身 |
| **预处理接縫** | 编譯时替换 | 条件编譯、巨集 |
| **連結接縫** | 連結时替换 | 依賴注入、模組替换 |

### Sprout 与 Wrap 技術

| 技術 | 使用时机 | 做法 |
|-----|---------|-----|
| **Sprout Method** | 在現有方法中加入新邏辑 | 建立新方法，從舊方法呼叫 |
| **Sprout Class** | 新邏辑需要獨立演进 | 建立新类别，從舊程序码參照 |
| **Wrap Method** | 需要在前後加入行为 | 重命名原方法，建立包裝器 |
| **Wrap Class** | 裝飾現有类别 | 裝飾者模式 |

**原則**：新程序码使用 TDD；遺留程序码在测试前保持不动。

### 程序码考古

理解無文件程序码的技術：

```
1. 草稿重構（Scratch Refactoring）
   ├─ 重構以理解，不是保留
   ├─ 使用 git stash 或分支
   └─ 完成後捨棄（git reset --hard）

2. 追蹤变數流动
   ├─ 從输入追蹤到输出
   ├─ 標记关鍵转换点
   └─ 邊發現邊记录

3. 执行时觀察
   ├─ 加入暫时性日誌
   ├─ 使用除錯器逐步执行
   └─ 建立心智模型

4. Git 考古
   ├─ git log -p <file>（查看所有变更）
   ├─ git blame（找到原作者）
   └─ 搜尋提交消息找脈络
```

---

## 大型重構模式

### Strangler Fig 模式

**使用时机**：漸进替换遺留系统

```
┌─────────────────────────────────────────────────────────────────┐
│                    Strangler Fig 模式                            │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  阶段 1: 攔截（INTERCEPT）                                       │
│  ┌─────────┐     ┌─────────┐     ┌─────────────┐               │
│  │  请求   │────▶│  門面   │────▶│ 舊系统(100%)│               │
│  └─────────┘     └─────────┘     └─────────────┘               │
│                                                                 │
│  阶段 2: 迁移（MIGRATE）                                         │
│  ┌─────────┐     ┌─────────┐     ┌─────────────┐               │
│  │  请求   │────▶│  門面   │──┬─▶│ 新系统(功能A)│               │
│  └─────────┘     └─────────┘  │  └─────────────┘               │
│                               └─▶│ 舊系统(其餘) │               │
│                                  └─────────────┘               │
│                                                                 │
│  阶段 3: 完成（COMPLETE）                                        │
│  ┌─────────┐     ┌─────────────┐                               │
│  │  请求   │────▶│ 新系统(100%)│  [舊系统已下线]                │
│  └─────────┘     └─────────────┘                               │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘
```

**检查清单**：
- [ ] 識别攔截点（API 閘道、門面、代理）
- [ ] 建立事件捕獲层
- [ ] 在新系统中实作第一个功能
- [ ] 漸进式路由流量
- [ ] 監控并比較結果
- [ ] 下线舊元件

### Branch by Abstraction

**使用时机**：在不用長期分支的情况下重構共享程序码

```
步骤 1：引入抽象
        客户端 → 抽象（界面）→ 舊实作

步骤 2：新增新实作
        客户端 → 抽象 → 舊实作
                     └─→ 新实作（功能開关控制）

步骤 3：切换并移除
        客户端 → 新实作
        [舊实作已移除]
```

**关鍵原則**：
- 所有变更在主幹（trunk）上（没有長期分支）
- 功能開关控制哪个实作是活躍的
- 兩个实作可以在過渡期共存

### 平行变更（Expand-Migrate-Contract）

**使用时机**：变更多个客户端使用的界面

```
阶段 1: 擴展（EXPAND）
├─ 在舊的旁邊新增新欄位/方法
├─ 新程序码使用新界面
└─ 舊程序码仍然运作

阶段 2: 迁移（MIGRATE）
├─ 更新所有客户端使用新界面
├─ 验证所有客户端已迁移
└─ 数据迁移（如需要）

阶段 3: 收縮（CONTRACT）
├─ 移除舊欄位/方法
├─ 清理迁移程序码
└─ 更新文件
```

---

## 数据庫重構

### Schema 变更的 Expand-Contract 模式

```
┌─────────────────────────────────────────────────────────────────┐
│              数据庫重構（Expand-Contract）                        │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  阶段 1: 擴展（新增新的，保留舊的）                                │
│  ├─ 新增新欄位/表                                               │
│  ├─ 应用程序同时写入新舊                                         │
│  └─ 此时可安全回滾                                              │
│                                                                 │
│  阶段 2: 迁移（搬移数据）                                         │
│  ├─ 從舊複制数据到新                                            │
│  ├─ 验证数据一致性                                              │
│  └─ 应用程序開始從新读取                                         │
│                                                                 │
│  阶段 3: 收縮（移除舊的）                                         │
│  ├─ 确认舊欄位/表不再被读取                                      │
│  ├─ 移除舊欄位/表                                               │
│  └─ 清理雙写程序码                                              │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘
```

### 常見 Schema 重構場景

| 場景 | 策略 | 風險等级 |
|-----|------|---------|
| **重命名欄位** | 新增新的 → 迁移 → 刪除舊的 | 中 |
| **拆分表格** | 新表 + 外鍵 → 迁移 → 調整应用程序 | 高 |
| **合併表格** | 新表 → 合併数据 → 切换应用程序 | 高 |
| **变更数据型别** | 新欄位 → 转换 → 切换应用程序 | 中 |
| **新增 NOT NULL** | 填入预设值 → 新增約束 | 低 |

### 数据庫迁移安全检查清单

```
迁移前：
□ 完整备份已完成
□ 迁移脚本已在测试環境验证
□ 回滾脚本已准备
□ 迁移时间已估算（考慮数据量）
□ 維護窗口已通知

迁移中：
□ 監控数据庫效能
□ 增量验证数据完整性
□ 应用程序健康检查通過

迁移後：
□ 数据一致性验证
□ 应用程序功能验证
□ 效能基线比較
□ 备份保留一段时间以供回滾
```

### 零停机迁移技術

| 技術 | 说明 | 使用場景 |
|-----|------|---------|
| **Online Schema Change** | pt-osc, gh-ost | MySQL 大表变更 |
| **Blue-Green Database** | 雙数据庫切换 | 高可用需求 |
| **Shadow Write** | 同时写入兩个数据庫并比較 | 验证迁移正确性 |
| **Feature Flag** | 控制读取來源 | 漸进式切换 |

---

## 安全重構工作流程

### 重構前

```
□ 定義成功标准（可衡量的）
□ 确保足夠的测试覆蓋率（建议 >80%）
□ 提交/暫存當前工作（乾淨的工作目录）
□ 建立功能分支（或在主幹上使用功能開关）
□ 与团队溝通以避免衝突
```

### 重構中

```
□ 一次只做一个小变更
□ 每次变更後执行测试
□ 如果测试失败，立即復原
□ 頻繁提交（每次测试通過都是一个存檔点）
□ 重構时絕不加入新功能
```

### 重構後

```
□ 所有测试通過（与之前相同）
□ 程序码可衡量地更好（複雜度、重複等）
□ 如需要則更新文件
□ 团队审查完成
□ 没有新增功能
```

---

## 重構度量指標

### 程序码品质指標

| 指標 | 测量方式 | 目標 |
|-----|---------|-----|
| **循環複雜度** | 静态分析工具 | 每函式 < 10 |
| **认知複雜度** | SonarQube 等 | 越低越好 |
| **耦合度** | 模組间依賴數 | 降低 |
| **內聚性** | LCOM 指標 | 提高 |
| **程序码重複** | 重複程序码百分比 | < 3% |
| **程序码行數** | 僅供參考 | 較少 ≠ 一定更好 |

### 测试品质指標

| 指標 | 目標 | 备註 |
|-----|-----|------|
| **测试覆蓋率** | ≥ 80% | 重構期间不要降低 |
| **测试速度** | 更快 | 重構应改善可测试性 |
| **不穩定测试數** | 降低 | 穩定性改善 |

### 运維指標（DORA 指標）

| 指標 | 测量方式 | 预期改善 |
|-----|---------|---------|
| **部署頻率** | CI/CD 记录 | 提高（可維護性改善）|
| **变更失败率** | 回滾次數 | 降低 |
| **平均恢復时间** | 事故记录 | 縮短 |
| **前置时间** | 從提交到部署 | 縮短 |

### 团队效率指標

| 指標 | 测量方式 | 备註 |
|-----|---------|------|
| **新人上手时间** | 新員工熟悉时间 | 縮短 = 更好的可读性 |
| **PR 审查时间** | Git 记录 | 縮短 = 更好的可理解性 |
| **Bug 修復时间** | Issue 追蹤 | 縮短 = 更好的可維護性 |

### 重構 ROI 框架

```
成本：
├─ 开发时间 × 时薪
├─ 测试时间
├─ 部署風險成本
└─ 机会成本（未建置的功能）

收益：
├─ 減少的維護时间 × 未來年數
├─ 減少的 Bug × 修復成本
├─ 更快的功能开发
└─ 更低的人員流动成本
```

---

## 团队协作

### 重構项目啟动

```
啟动会議議程：
1. 範圍定義
   ├─ 哪些模組/文件在範圍內
   └─ 明确排除什麼

2. 成功标准对齊
   ├─ 量化目標（複雜度降低 X%）
   └─ 功能目標（行为不变）

3. 工作分配
   ├─ 按模組（垂直切分）
   └─ 按层级（水平切分）

4. 風險评估
   ├─ 最高風險區域
   └─ 回滾策略
```

### 分工策略

| 策略 | 使用时机 | 注意事项 |
|-----|---------|---------|
| **垂直切分** | 獨立模組 | 确保界面不变 |
| **水平切分** | 跨模組重構（如命名规范）| 需嚴格同步 |
| **Strangler 分工** | 大型系统替换 | 一人一个 Strangler 切片 |
| **Mob Programming** | 核心/高風險區域 | 全团队一起，降低風險 |

### 溝通机制

```
日常溝通：
├─ 站立会議同步重構进度
├─ 共享的重構看板（Kanban）
└─ 專用頻道（#refactoring-xxx）

PR 规范：
├─ 標題加 [Refactor] 前綴
├─ 说明改了什麼以及为什麼
├─ 包含前後複雜度比較
└─ 遺留程序码需要特徵测试

衝突处理：
├─ 小範圍：立即解决
├─ 中範圍：每日同步会議
└─ 大範圍：考慮 Branch by Abstraction
```

### PR 大小指引

| 大小 | 变更行數 | 审查时间 |
|-----|---------|---------|
| 小 | < 200 | < 30 分鐘 |
| 中 | 200-500 | < 1 小时 |
| 大 | > 500 | **应該拆分** |

**原則**：多个小 PR > 一个大 PR

---

## 技術債管理

### 技術債象限

基於 Martin Fowler 的技術債象限：

```
                       刻意的
                         │
        ┌────────────────┼────────────────┐
        │                │                │
        │    审慎的      │     魯莽的     │
        │   「我們知道   │   「我們没时间  │
        │    这是債务」  │    做设计」    │
        │                │                │
审慎的  ├────────────────┼────────────────┤ 魯莽的
        │                │                │
        │    审慎的      │     魯莽的     │
        │   「現在我們   │   「什麼是     │
        │    知道該怎麼  │    分层？」    │
        │    做了」      │                │
        │                │                │
        └────────────────┼────────────────┘
                         │
                      無意的
```

### 債务優先順序

| 優先级 | 标准 | 行动 |
|-------|------|-----|
| **高** | 阻擋开发、導致頻繁 Bug | 立即处理 |
| **中** | 拖慢开发、增加複雜度 | 排入下个 Sprint |
| **低** | 小煩惱、影響隔離 | 隨机处理 |

### 追蹤技術債

```
每个債务项目记录：
├─ 描述：問題是什麼？
├─ 影響：如何影響开发？
├─ 估计工作量：修復需要多久？
├─ 忽视的風險：不处理会怎样？
└─ 相关程序码：受影響的文件/模組連結
```

---

## 相关标准

- [测试驅动开发](test-driven-development.md) - TDD 循環包含重構阶段
- [程序码审查清单](code-review-checklist.md) - 重構 PR 审查指引
- [提交消息指南](commit-message-guide.md) - `refactor` 提交类型
- [程序码簽入标准](checkin-standards.md) - 提交前要求

---

## 參考数据

### 書籍

- Martin Fowler -《重構：改善既有程序的设计》第二版（2018）
- Michael Feathers -《Working Effectively with Legacy Code》（2004）
- Joshua Kerievsky -《Refactoring to Patterns》（2004）

### 文章

- Martin Fowler - [Strangler Fig Application](https://martinfowler.com/bliki/StranglerFigApplication.html)
- Martin Fowler - [Branch by Abstraction](https://martinfowler.com/bliki/BranchByAbstraction.html)
- Pete Hodgson - [Feature Toggles](https://martinfowler.com/articles/feature-toggles.html)
- Martin Fowler - [Technical Debt Quadrant](https://martinfowler.com/bliki/TechnicalDebtQuadrant.html)

### 工具

- [Refactoring Guru](https://refactoring.guru/) - 重構技術目录
- [SonarQube](https://www.sonarqube.org/) - 程序码品质与複雜度分析
- [ApprovalTests](https://approvaltests.com/) - Golden Master 测试

---

## 版本历程

| 版本 | 日期 | 变更 |
|-----|------|------|
| 2.0.0 | 2026-01-21 | 重大重组：新增战术性策略（预备性重构、童子军规则）、防腐层、决策矩阵摘要。重组为战术性/战略性/安全防护三类。 |
| 1.0.0 | 2026-01-12 | 初始重构标准定义 |

---

## 授权

本标准以 [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/) 授权釋出。
