使用Spec重构
并非所有Spec都是功能。学习如何使用 LeanSpec 进行重构和架构变更,其中文档至关重要。
时间:15 分钟
结果:完成带有清晰文档的重构
前置条件
- 完成管理多个功能
- 了解您的代码库结构
立即尝试
使用准备好重构的项目快速上手:
npx lean-spec init --example api-refactor
cd api-refactor
npm install
npm start
然后向 AI 工具发送提示:
- GitHub Copilot CLI
- Claude Code
- Gemini CLI
- IDE
# 确保已安装 GitHub Copilot CLI
npm install -g @github/copilot
# 向 Copilot CLI 发送提示
copilot -p "帮我重构这个应用,提取一个可重用的 API 客户端" \
--files specs/ \
--add-dir .
# 确保已安装 Claude Code
curl -fsSL https://claude.ai/install.sh | bash
# 为系统提示 AGENTS.md 创建软链 CLAUDE.md
ln -s AGENTS.md CLAUDE.md
# 向 Claude Code 发送提示
claude prompt \
"帮我重构这个应用,提取一个可重用的 API 客户端" \
--include-files specs/ \
--include-dir .
# 确保已安装 Gemini CLI
npm install -g @google/gemini-cli
# 向 Gemini CLI 发送提示
gemini -p "帮我重构这个应用,提取一个可重用的 API 客户端" -y
在 IDE 中使用 AI 编码助手(GitHub Copilot、Claude、Cursor 等):
- 在 IDE 中打开项目
- 打开 AI 助手聊天面板
- 发送提示:"帮我重构这个应用,提取一个可重用的 API 客户端"
想了解底层发生了什么? 下面的章节将详细介绍每个步骤。
场景
您的 API 客户端分散在整个代码库中。每个组件都直接导入 Axios,这使得难以:
- 添加请求/响应拦截器
- 切换 HTTP 库
- 在测试中模拟 API 调用
- 跟踪 API 使用情况
您需要提取一个集中的 ApiClient 类。这是重构,而不是功能——没有面向用户的变化,但架构得到改善。
起点:
your-project/
├── src/
│ ├── components/
│ │ ├── UserProfile.tsx # 直接导入 axios
│ │ └── Dashboard.tsx # 直接导入 axios
│ └── services/
│ ├── auth.service.ts # 直接导入 axios
│ └── data.service.ts # 直接导入 axios
└── specs/
└── (您现有的Spec)
创建技术Spec
询问您的 AI:
创建一个用于提取集中式 API 客户端的Spec。
将所有 axios 调用移动到单个 ApiClient 类,包括:
- 请求/响应拦截器
- 错误处理
- Token管理
- 类型安全方法
标记为 "refactoring" 和 "architecture"。
设置优先级为高。
AI 创建 specs/024-centralize-api-client/README.md,包含:
---
status: planned
priority: high
tags: ['refactoring', 'architecture']
---
# 集中 API 客户端
## 概述
将分散的 Axios 调用提取到单个 ApiClient 类中。
当前痛点:整个代码库中有 47 个直接 axios 导入,没有一致的
错误处理,无法全局添加认证拦截器,测试模拟 axios
而不是我们的 API 层。
目标:具有集中错误处理和拦截器的可维护 HTTP 层。
单一导入点,易于切换 HTTP 库,更好的可测试性。
## 设计
新的 ApiClient 类,具有类型化的 get/post 方法和用于
认证Token注入和错误处理的请求/响应拦截器。
(...图表或代码片段...)
迁移策略:
1. 创建带有基本方法的 ApiClient
2. 添加认证拦截器
3. 首先替换服务层中的 axios(4 个文件)
4. 替换组件中的 axios(15 个文件)
5. 更新测试并移除 axios 依赖
非目标:不更改 API 端点或响应数据结构。
## 计划
- [ ] 创建带有类型化方法的 src/lib/api-client.ts
- [ ] 实现请求/响应拦截器
- [ ] 迁移服务层
- [ ] 迁移组件层
- [ ] 更新测试模拟
- [ ] 移除直接的 axios 导入
## 测试
- [ ] 所有现有测试通过
- [ ] ApiClient 测试覆盖错误处理
- [ ] 认证Token正确注入到请求中
这里有什么不同? 这是一个技术Spec:
- 专注于架构,而不是用户功能
- 包括迁移策略(顺序很重要)
- 明确的非目标防止范围蔓延
- 详细计划,因为重构有风险
实施
询问您的 AI:
实施Spec 024。逐步进行:
1. 首先创建 ApiClient
2. 在迁移之前向我展示实现
3. 然后迁移一个服务作为测试
4. 等待我的批准后再继续
AI 逐步进行:
步骤 1: 创建 src/lib/api-client.ts
export class ApiClient {
private client: AxiosInstance;
constructor() {
this.client = axios.create({ baseURL: process.env.API_BASE_URL });
// 认证拦截器向请求添加Token
}
async get<T>(path: string): Promise<T> { /* ... */ }
async post<T>(path: string, data: any): Promise<T> { /* ... */ }
}
步骤 2: 迁移一个服务作为证明
// src/services/auth.service.ts
- import axios from 'axios';
+ import { apiClient } from '@/lib/api-client';
- const { data } = await axios.post('/auth/login', credentials);
+ const data = await apiClient.post('/auth/login', credentials);
您审查、测试并批准:"看起来不错。继续处理其余服务和组件。"
步骤 3: AI 迁移其余文件,更新测试,移除 axios 导入
审查和完成
运行测试套件:
npm test
所有测试通过?在开发中验证:
npm run dev
# 点击查看,检查网络选项卡
一切正常。完成Spec:
lean-spec update 024 --status complete
Spec现在记录了您进行此更改的 原因 以及 如何 完成的。未来的开发人员可以阅读它以了解架构决策。
刚才发生了什么
您记录并执行了一个复杂的重构:
没有 LeanSpec:
- 重构理由在 PR 描述中丢失
- 实现细节在 git 历史中(难以找到)
- 未来的开发人员会问"我们为什么这样做?"
- 范围蔓延:"在重构时,让我们也..."
有了 LeanSpec:
- 在编码之前清楚地捕获理由
- 迁移策略已记录
- AI 逐步遵循计划
- 非目标防止功能蔓延
- 完成的Spec = 永久记录
Spec成为 架构文档,向未来的维护者解释过去的决策。
何时为重构编写Spec
编写Spec时:
- 重构影响 >5 个文件
- 架构决策需要解释
- 迁移顺序很重要
- 有破坏现有行为的风险
跳过Spec时:
- 重命名变量/文件
- 提取单个函数
- 修复代码风格
- 明显的改进
重构Spec检查清单:
- "为什么这很重要"部分解释痛点
- 设计显示前后结构
- 迁移策略是明确的
- 非目标防止范围蔓延
- 测试标准确保没有回归
关键模式
技术Spec包括:
- 理由:我们为什么这样做(痛点)
- 设计:架构变更(图表有帮助)
- 迁移:变更顺序(对重构至关重要)
- 非目标:我们不做什么(范围控制)
- 测试:如何验证没有破坏任何东西
AI 协助最适合:
- 逐步说明("做 X,等待批准")
- 清晰的迁移顺序
- 每个阶段后测试方法
- 明确的文件路径
下一步
尝试重构代码库中的某些内容:
- 选择一个分散的关注点(日志记录、错误、配置)
- 创建带有迁移策略的Spec
- 让 AI 逐步实施
- 完成并记录决策
了解更多:
高级: