Files
test-repo/docs/zh-cn/appendix/9-engineering-excellence/code-quality-refactoring.md
T
sanbuphy f35cddeb8b feat(appendix): 重构工程实践章节,添加交互式演示组件
## 新增组件 (14个)
- CodeSmellDemo.vue: 代码异味识别演示
- DecisionMatrixDemo.vue: 决策矩阵工具
- DesignPatternCatalogDemo.vue: 设计模式目录
- DocStructureDemo.vue: 文档结构示例
- LicenseComparisonDemo.vue: 开源许可证对比
- OpenSourceWorkflowDemo.vue: 开源协作流程
- PatternPlaygroundDemo.vue: 设计模式演练场
- RefactoringDemo.vue: 重构实战演示
- SecurityChecklistDemo.vue: 安全检查清单
- TDDCycleDemo.vue: TDD 循环演示
- TechRadarDemo.vue: 技术雷达图
- TechWritingPracticeDemo.vue: 技术写作实践
- TestPyramidDemo.vue: 测试金字塔
- WebSecurityDemo.vue: Web 安全演示

## 文档更新 (7篇)
- code-quality-refactoring.md: 代码质量与重构
- design-patterns.md: 设计模式
- open-source-collaboration.md: 开源协作
- security-thinking.md: 安全思维
- technical-writing.md: 技术写作
- technology-selection.md: 技术选型
- testing-strategies.md: 测试策略

## 其他变更
- 将 browser-as-os.md 内容合并到 computer-networks.md
- 更新 .gitignore 和 theme/index.js
2026-02-24 13:03:21 +08:00

238 lines
8.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 代码质量与重构
::: tip 前言
**代码写出来能跑就行了吗?** 你可能写过这样的代码:功能是实现了,但过了两周自己都看不懂了。或者团队里有人离职,留下一堆"只有上帝和他才能看懂"的代码。
本章带你理解什么是好代码,如何识别坏代码,以及如何安全地改进它。
:::
**这篇文章会带你学什么?**
| 章节 | 内容 | 核心概念 |
|-----|------|---------|
| **第 1 章** | 代码坏味道 | 识别常见问题 |
| **第 2 章** | 重构手法 | 安全地改进代码 |
| **第 3 章** | 代码审查 | 团队协作中的质量保障 |
| **第 4 章** | 质量度量 | 用数据衡量代码健康度 |
学完本章,你将掌握识别代码问题、安全重构、以及通过团队协作持续提升代码质量的方法。
---
## 0. 全景图:代码的生命周期
在软件开发中,有一个常被忽视的事实:**代码被阅读的次数远远多于被编写的次数**。
一段代码从诞生到退役,大致会经历这样的旅程:
::: tip 代码的一生
- **编写阶段**:开发者写下第一版实现,功能跑通了,测试通过了。
- **审查阶段**:团队成员阅读代码,提出改进建议。
- **维护阶段**:修 Bug、加功能、适配新需求——这个阶段占据了代码生命周期的 80% 以上。
- **重构阶段**:当代码变得难以维护时,需要在不改变外部行为的前提下改善内部结构。
- **退役阶段**:技术迭代,旧代码被新方案替代。
:::
Martin Fowler 在《重构》一书中说过:**"任何一个傻瓜都能写出计算机能理解的代码,唯有好的程序员才能写出人类能理解的代码。"**
---
## 1. 代码坏味道:识别常见问题
### 1.1 什么是代码坏味道?
"代码坏味道"Code Smell)这个概念由 Kent Beck 提出,指的是代码中那些**虽然不是 Bug,但暗示着更深层设计问题**的特征。就像房间里有股怪味——不会立刻让你生病,但说明某个地方需要清理了。
通过下面的交互组件,识别几种最常见的代码坏味道:
<CodeSmellDemo />
### 1.2 常见坏味道清单
| 坏味道 | 症状 | 危害 |
|-------|------|------|
| **过长函数** | 函数超过 50 行 | 难以理解、测试和复用 |
| **魔法数字** | 代码中直接写 `86400000` | 含义不明,修改时容易遗漏 |
| **重复代码** | 相似逻辑出现在多处 | 修改时必须同步多处,容易遗漏 |
| **过深嵌套** | 超过 3 层的 if/for | 逻辑像迷宫,难以追踪 |
| **过长参数列表** | 函数参数超过 4 个 | 调用困难,容易传错顺序 |
| **上帝类** | 一个类/模块做了太多事 | 职责不清,牵一发动全身 |
::: tip 核心洞察
坏味道不是"错误",而是"信号"。它告诉你:这里的设计可能需要改进。不是所有坏味道都需要立刻修复,但你需要有能力识别它们。
:::
---
## 2. 重构手法:安全地改进代码
### 2.1 什么是重构?
重构(Refactoring)的定义非常精确:**在不改变代码外部行为的前提下,改善其内部结构。**
关键词是"不改变外部行为"。重构不是重写,不是加功能,不是修 Bug。它是对代码内部的"整理收纳"。
通过下面的组件,对比几种常见重构手法的前后变化:
<RefactoringDemo />
### 2.2 常用重构手法
**提炼函数(Extract Function**
这是最常用的重构手法。当一段代码可以用一个有意义的名字来概括时,就应该把它提炼成函数。
```javascript
// 重构前
function printReport(data) {
// 计算总价
let total = 0
for (const item of data.items) {
total += item.price * item.qty
}
// 打印...
}
// 重构后
function calculateTotal(items) {
return items.reduce((sum, item) => sum + item.price * item.qty, 0)
}
function printReport(data) {
const total = calculateTotal(data.items)
// 打印...
}
```
**重命名(Rename**
好的命名是最廉价也最有效的文档。当你需要写注释来解释一个变量/函数的含义时,说明它的名字不够好。
```javascript
// 重构前
const d = new Date() - startTime // 经过的时间
const arr = users.filter(u => u.a) // 活跃用户
// 重构后
const elapsedMs = new Date() - startTime
const activeUsers = users.filter(user => user.isActive)
```
**用卫语句替代嵌套(Replace Nested Conditional with Guard Clauses**
```javascript
// 重构前
function getPayAmount(employee) {
if (employee.isSeparated) {
return { amount: 0 }
} else {
if (employee.isRetired) {
return { amount: employee.pension }
} else {
return { amount: employee.salary }
}
}
}
// 重构后
function getPayAmount(employee) {
if (employee.isSeparated) return { amount: 0 }
if (employee.isRetired) return { amount: employee.pension }
return { amount: employee.salary }
}
```
::: tip 重构的安全网
重构最大的风险是"改着改着就改出 Bug 了"。所以重构的前提是**有测试覆盖**。每次小步重构后运行测试,确保行为没变。没有测试的代码,先补测试再重构。
:::
---
## 3. 代码审查:团队协作中的质量保障
### 3.1 为什么需要代码审查?
代码审查(Code Review)是团队中最有效的质量保障手段之一。它的价值不仅在于发现 Bug,更在于:
- **知识共享**:团队成员了解彼此的代码,降低"巴士因子"(如果某人被巴士撞了,项目还能继续吗?)
- **统一风格**:通过审查逐步形成团队的编码规范
- **提前发现设计问题**:比 Bug 更难修的是糟糕的架构决策
- **互相学习**:看别人的代码是提升编程能力的捷径
### 3.2 审查什么?
| 维度 | 关注点 |
|------|--------|
| **正确性** | 逻辑是否正确?边界条件是否处理? |
| **可读性** | 命名是否清晰?结构是否易懂? |
| **安全性** | 是否有注入风险?敏感数据是否暴露? |
| **性能** | 是否有明显的性能问题?N+1 查询? |
| **测试** | 是否有对应的测试?覆盖了关键路径吗? |
### 3.3 审查的礼仪
好的代码审查是**对代码的讨论,而不是对人的批评**:
- 用"我们"而不是"你"~~"你这里写错了"~~ → "这里我们可以考虑用 guard clause"
- 提问而不是命令:~~"改成 const"~~ → "这个变量后面会被重新赋值吗?如果不会,用 const 更安全"
- 给出理由:不只说"不好",要说"为什么不好"以及"怎样更好"
---
## 4. 代码质量度量
### 4.1 圈复杂度
圈复杂度(Cyclomatic Complexity)衡量代码中独立路径的数量。每个 `if``for``case``&&``||` 都会增加复杂度。
| 复杂度 | 评价 | 建议 |
|--------|------|------|
| 1-10 | 简单 | 容易理解和测试 |
| 11-20 | 中等 | 考虑拆分 |
| 21-50 | 复杂 | 必须重构 |
| 50+ | 不可维护 | 紧急重构 |
### 4.2 代码覆盖率
代码覆盖率衡量测试执行了多少比例的代码。常见指标:
- **行覆盖率**:被执行的代码行占总行数的比例
- **分支覆盖率**:被执行的条件分支占总分支的比例
::: tip 覆盖率的陷阱
80% 的覆盖率不代表代码质量好。覆盖率只能告诉你"哪些代码没被测试到",不能告诉你"测试是否有意义"。一个只断言 `expect(true).toBe(true)` 的测试可以提高覆盖率,但毫无价值。
:::
### 4.3 实用工具
| 工具 | 用途 |
|------|------|
| **ESLint** | JavaScript/TypeScript 静态分析 |
| **Prettier** | 代码格式化,统一风格 |
| **SonarQube** | 综合代码质量平台 |
| **Husky** | Git hooks,提交前自动检查 |
---
## 5. 总结
回顾这一路,我们从识别问题到解决问题,建立了一套完整的代码质量改进体系:
1. **识别**:学会闻到代码坏味道,知道哪里需要改进
2. **重构**:掌握安全的重构手法,在测试保护下小步改进
3. **协作**:通过代码审查,让团队共同守护代码质量
4. **度量**:用客观指标追踪代码健康度
::: tip 终极思考
代码质量不是一次性的工作,而是持续的习惯。就像保持房间整洁一样——不是等到乱得不行了才大扫除,而是每天随手整理。**童子军法则**说得好:离开时让代码比你来时更干净一点。
:::
---
## 延伸阅读
- **经典书籍**Martin Fowler《重构:改善既有代码的设计》是这个领域的圣经。
- **代码整洁之道**Robert C. Martin《Clean Code》提供了大量实用的编码原则。
- **实践工具**:尝试在项目中配置 ESLint + Prettier + Husky,体验自动化代码质量保障。
- **代码审查**Google 的 Code Review 指南是业界标杆,值得学习。