07 代码模式提炼:从实现中抽象通用模式
这是《Git 仓库蒸馏术:从代码仓库到 OpenClaw 虚拟人》系列的第 7 篇。前几篇我们蒸馏了"文档"和"知识",这一篇蒸馏"智慧"——从重复的代码实现里,抽象出可复用的模式。如果说知识摘要是"知道什么",那模式库就是"知道怎么做"。
一、为什么代码模式值得提炼
写代码的人都知道一个现象:同一个问题,会在代码里出现很多次。可能是同一个 API 的调用方式,可能是同一个校验逻辑,可能是同一个状态处理流程。
这些重复不是偶然——它们背后是团队反复验证过的解决方案。但问题是:
- 这些方案散落在代码各处,没有名字、没有文档
- 新成员只能靠"翻代码"才能发现"原来大家都是这么写的"
- 方案背后的"为什么"(为什么这么写)完全丢失
模式提炼的价值:把"散落的重复"变成"有名字、有文档、有理由"的模式库。让团队从"每次重新发明"变成"查库复用"。
二、重复代码与相似实现识别
2.1 用 jscpd 检测重复代码
jscpd(JavaScript Copy/Paste Detector)是检测重复代码的利器:
# 安装
npm install -g jscpd
# 检测重复代码
jscpd src/ --min-lines 5 --min-tokens 50
# 输出 HTML 报告
jscpd src/ --output report.html --format html
输出示例:
Found 23 clones in 12 files.
Total tokens: 45600
Clones tokens: 8900 (19.5%)
Clones:
src/api/model-api.ts:10-35
src/api/export-api.ts:15-40
(similarity: 92%)
重复率解读:
- < 5%:健康,无需处理
- 5% ~ 15%:有重复,值得关注
-
15%:重复严重,是模式提炼的富矿
2.2 用 grep 找"相似实现"
有些重复不是逐字复制,而是"结构相似"。用 grep 找相似模式:
# 找重复的 try-catch 结构
grep -rn "try {" src/ --include="*.ts" | wc -l
# 找重复的 loading 状态处理
grep -rn "isLoading\|loading.value" src/ --include="*.ts" --include="*.vue" | wc -l
# 找重复的 API 调用模式
grep -rn "axios.get\|http.get" src/ --include="*.ts" | head -20
2.3 用 git log 找"反复修改"的代码
# 找出被反复修改的函数(可能是"问题模式")
git log --oneline -S "handleError" -- src/
# 找出反复出现的"临时修复"
git log --oneline --grep="hotfix\|临时\|workaround" -- src/
反复修改的代码往往是"半成品模式"——团队一直在用,但一直没把它做好。这类代码提炼成模式后,价值最大。
三、模式抽象:从具体实现到通用模式
3.1 模式抽象四步法
把重复实现抽象成模式,分四步:
- 收集:找出所有相似实现
- 对比:找出共同点和差异点
- 抽象:提取共同结构,参数化差异点
- 命名:给模式起一个有意义的名字
3.2 示例:从重复代码到模式
第一步:收集(发现 3 处相似实现)
// src/api/model-api.ts
export async function fetchModels() {
const res = await http.get('/models');
if (res.code !== 0) {
throw new Error(res.message);
}
return res.data;
}
// src/api/export-api.ts
export async function fetchExports() {
const res = await http.get('/exports');
if (res.code !== 0) {
throw new Error(res.message);
}
return res.data;
}
// src/api/user-api.ts
export async function fetchUsers() {
const res = await http.get('/users');
if (res.code !== 0) {
throw new Error(res.message);
}
return res.data;
}
第二步:对比(共同点 vs 差异点)
| 维度 | 共同点 | 差异点 |
|---|---|---|
| 请求方式 | 都是 GET | 无 |
| 响应处理 | 都检查 code,非 0 抛错 | 无 |
| 返回数据 | 都返回 res.data | 无 |
| 接口路径 | 无 | /models、/exports、/users |
第三步:抽象(提取通用结构,参数化差异点)
// src/utils/request.ts
export async function fetchList<T>(path: string): Promise<T> {
const res = await http.get(path);
if (res.code !== 0) {
throw new Error(res.message);
}
return res.data as T;
}
// 使用
const models = await fetchList<Model[]>('/models');
const exports = await fetchList<ExportItem[]>('/exports');
const users = await fetchList<User[]>('/users');
第四步:命名(给模式起名)
模式名:统一请求封装(Unified Request Wrapper)
适用场景:所有"GET 请求 + 统一响应格式"的接口调用
做法:封装fetchList<T>(path),统一处理响应码和错误
理由:避免重复的错误处理逻辑,保证错误处理一致
3.3 模式文档模板
每个模式都应该有标准文档:
# 模式:统一请求封装(Unified Request Wrapper)
## 适用场景
所有"GET 请求 + 统一响应格式"的接口调用
## 问题
每个 API 函数都重复写"检查 code、抛错、返回 data"的逻辑
## 解决方案
封装通用函数,参数化接口路径
## 代码示例
(见上文 fetchList 实现)
## 使用方式
const models = await fetchList<Model[]>('/models');
## 注意事项
- 仅适用于统一响应格式的接口
- 非标准响应需单独处理
## 来源
- src/api/model-api.ts、export-api.ts、user-api.ts(2022-03 提炼)
四、模式库建设
4.1 模式库目录结构
patterns/
├── README.md # 模式库索引
├── 01-请求封装/
│ ├── unified-request.md # 模式文档
│ └── example.ts # 示例代码
├── 02-状态管理/
│ └── store-factory.md
├── 03-表单处理/
│ └── form-validation.md
└── 04-错误处理/
└── error-boundary.md
4.2 模式库索引
# 模式库索引
## 请求层
- [统一请求封装](01-请求封装/unified-request.md) — GET + 统一响应
- [分页请求](01-请求封装/pagination.md) — 列表分页加载
## 状态层
- [Store 工厂](02-状态管理/store-factory.md) — 统一创建 Pinia store
- [缓存模式](02-状态管理/cache.md) — 请求结果缓存
## 交互层
- [表单校验](03-表单处理/form-validation.md) — 统一表单校验
- [空态处理](03-表单处理/empty-state.md) — 列表空数据展示
## 异常层
- [错误边界](04-错误处理/error-boundary.md) — 组件级错误兜底
- [重试模式](04-错误处理/retry.md) — 请求失败自动重试
4.3 模式库的维护
模式库不是"写完就完",需要持续维护:
# 定期重新检测重复代码,发现新模式
jscpd src/ --min-lines 5 --min-tokens 50
# 检查模式是否被实际使用
grep -rn "fetchList" src/ --include="*.ts" | wc -l
维护原则:
- 新模式出现 → 提炼并入库
- 模式不再使用 → 标记废弃
- 模式被大量使用 → 考虑提升为公共库
五、输出模式库
5.1 模式库汇总表
# 模式库汇总
| 模式 | 分类 | 使用次数 | 提炼时间 | 状态 |
|------|------|---------|---------|------|
| 统一请求封装 | 请求层 | 12 | 2022-03 | 活跃 |
| 分页请求 | 请求层 | 8 | 2022-05 | 活跃 |
| Store 工厂 | 状态层 | 6 | 2022-08 | 活跃 |
| 表单校验 | 交互层 | 9 | 2022-11 | 活跃 |
| 错误边界 | 异常层 | 4 | 2023-02 | 活跃 |
| 重试模式 | 异常层 | 2 | 2023-06 | 实验 |
5.2 模式库的用途
模式库是蒸馏流程的方法论沉淀:
- 给 08 决策记录:模式的选择/放弃是决策的素材
- 给 09 知识图谱:模式是图谱的"方法"节点
- 给 10 工具链:高频模式可固化为代码生成模板
- 给 12 虚拟人化:模式库是虚拟人 skills 的核心来源
六、小结
这一篇的核心收获:
- 识别重复:用
jscpd检测重复代码,用grep找相似实现,用git log找反复修改的代码。 - 模式抽象四步法:收集 → 对比 → 抽象 → 命名,从具体实现到通用模式。
- 模式文档:每个模式有标准文档(适用场景、问题、方案、示例、注意事项、来源)。
- 模式库建设:分类归档 + 索引 + 持续维护。
- 输出模式库:一份可复用的方法论沉淀,是虚拟人 skills 的核心来源。
下一篇,我们记录决策:[08 决策记录:用 ADR 固化架构决策](08-Git 仓库蒸馏术:从代码仓库到 OpenClaw 虚拟人-决策记录.md)——把"为什么这么设计"用 ADR 固化下来,防止知识流失。
上一篇:[06 文档蒸馏:从 issue、PR、README 提炼知识](06-Git 仓库蒸馏术:从代码仓库到 OpenClaw 虚拟人-文档蒸馏.md)
下一篇:[08 决策记录:用 ADR 固化架构决策](08-Git 仓库蒸馏术:从代码仓库到 OpenClaw 虚拟人-决策记录.md)

351

被折叠的 条评论
为什么被折叠?



