ORANGE BOOK · CLAUDE CODE

第八章 编程与代码场景


一、本章写给谁

代码场景是 Claude Code 最闪亮的那张王牌,但它绝不只属于"科班程序员"。这一章我把读者拆成五类,请你对号入座。

你是谁 你能从这一章拿到什么
专职程序员(前端、后端、全栈、移动端) 把日常 80% 的"读代码、修小 bug、写测试、改 commit、开 PR"都丢给 Claude,把脑力留给真正难的设计与决策
想学编程的非程序员 不再被"环境配置、命令行、Git"挡在门外。Claude 帮你跑通第一段 Python、第一个 Node 项目、第一次提交
兼职做点小工具的产品、设计、运营 学会让 Claude 替你写"批量改文件名、抓数据、自动加水印"这种 1 天搞定 1 个月省事的小工具
全栈型独立开发者 一个人当一个团队用:Claude 当后端、Claude 当前端、Claude 当 QA、Claude 当 PM
技术管理者、Tech Lead 不再每天熬夜 Code Review。让 Subagent 替你打第一遍分,你只看真正需要拍板的部分

一个心态前置说明:Claude Code 是会写代码的助理,不是替代你的工程师。它能把你想做的事按你描述的样子做出来,但"想做什么"、"做成什么样"、"出了 bug 谁背"这些问题永远在你自己。把它当一双能动的手,而不是一颗能拍板的脑。这条心法,本章会贯穿始终。

如果你属于"完全没写过代码"的人,建议先看完前七章,回头再读这一章。本章的提示词模板对你依然有用,但前期需要 Claude 多解释几步术语,你别嫌烦。

这一章不会教你的事

不会教 为什么
编程语言基础语法(变量、循环、函数) 不是这本书的目的,市面上免费教程很多
算法和数据结构 同上
某个具体框架的全部细节(比如 Next.js 全 API) 太具体,看官方文档更快
怎么"让 Claude 替你完全无人值守地写一个 SaaS" 不现实,所有靠谱产品都需要"人 + AI"协作

二、第一步:用 /init 让 Claude 认识你的项目

任何一个新项目,你和 Claude Code 的第一次"见面礼"只有一句话:/init。它相当于让 Claude 走完"新员工入职"的流程——翻文档、看代码库结构、问"我们用什么测试框架"、"提交 PR 的流程是什么"。

2.1 先 cd 进项目目录

Claude Code 是"上下文敏感"的——它默认把你启动它时所在的目录当作"工作根目录"。所以新项目的第一步永远是:

cd /path/to/your-project
claude

如果你已经在 Claude Code 里了,可以用 /cd 切目录:

/cd ~/work/your-project

进根目录之前先确认你站对了位置:

ls
# package.json  src/  public/  README.md  ...

如果看不到 package.json(Node)、pyproject.toml(Python)、go.mod(Go)、Cargo.toml(Rust)等"项目身份证",说明你还在外层目录,再 cd 一层。

2.2 跑 /init

进到正确目录之后,第一句话就是:

/init

接下来 Claude 会做一连串你看得见的事:

  1. 扫描根目录结构ls -la、看 package.jsonrequirements.txtgo.modCargo.tomlpom.xml 等等,判断你用的是哪门语言、什么框架。
  2. 读 README.md:如果有,它会先看你已有的项目说明。
  3. 采样关键源文件:通常会挑 5 到 15 个最具代表性的文件读一遍,弄清架构。
  4. 查看 git 历史的最近几条:知道这个项目最近在改什么。
  5. 生成 CLAUDE.md:把它"理解到的东西"写成一份"项目说明书"放在项目根目录。

整个过程通常 30 秒到 2 分钟,看项目大小。完成后你会看到:

Created CLAUDE.md (1.4 KB)
You can edit this file to add project-specific guidance.

2.3 自动生成的 CLAUDE.md 长什么样

下面是一个真实的 React + TypeScript 项目跑完 /init 之后生成的 CLAUDE.md

# CLAUDE.md

This file provides guidance to Claude Code when working in this repository.

## Project overview

This is a React 18 + TypeScript single-page application using Vite as the
build tool. It is a personal finance dashboard that aggregates bank account
data from multiple providers via a Node.js backend (see ../api).

## Tech stack

- Framework: React 18.3 + TypeScript 5.5
- Build: Vite 5.4
- Styling: Tailwind CSS 3.4 + shadcn/ui
- State: Zustand 4.5
- Data fetching: TanStack Query 5.51
- Testing: Vitest 2.0 + React Testing Library
- Linting: ESLint 9 + Prettier 3
- Package manager: pnpm 9

## Common commands

| Task | Command |
| --- | --- |
| Install deps | `pnpm install` |
| Dev server | `pnpm dev` |
| Build | `pnpm build` |
| Run tests | `pnpm test` |
| Lint | `pnpm lint` |
| Type check | `pnpm typecheck` |

## Architecture

- `src/pages/` - Route-level components, one folder per route
- `src/components/` - Shared UI components
- `src/hooks/` - Custom hooks, especially data hooks
- `src/lib/` - Pure utilities (formatters, date helpers)
- `src/api/` - API client (Axios) and TanStack Query definitions
- `src/store/` - Zustand stores

## Key files

- `src/main.tsx` - App entry, providers wired here
- `src/router.tsx` - Route definitions
- `src/api/client.ts` - Axios base instance, attaches auth token
- `vite.config.ts` - Build config, proxy for /api during dev

## Conventions (auto-detected)

- Components are PascalCase named exports.
- Hooks start with `use`, default-exported.
- Imports use the `@/` alias (mapped to `src/`).

这份文件已经把"一个新人想了解的所有事"列得差不多了。但它还不够——下一步是你要做"人工补充"。

2.4 你必须人工补的四件事

/init 自动生成的 CLAUDE.md 是从"代码能看出来的事"反推的,所以它永远不知道你脑子里那些约定。打开 CLAUDE.md,自己加上下面四类内容。

第一类:永远不要做的事

## Never do(强禁)

- 永远不要 `git push --force` 任何分支,包括我自己的 feature 分支。
- 永远不要直接 commit 到 `main` 或 `develop`,必须走 PR。
- 永远不要修改 `package-lock.json` 之外的锁文件。
- 永远不要把 API key、token、密码写进任何文件,包括测试代码。
- 永远不要在没有我明确同意的情况下删除 `.env*` 文件。
- 永远不要跑 `rm -rf node_modules && pnpm install`,先问我。

这些"永远不要"看起来啰嗦,但真的能救命。Claude Code 是个执行力极强的实习生——你不说"不要做",它在某些极端场景下还真会做。把禁令写下来,等于给你的项目装一道安全门。

第二类:团队约定

## Team conventions

- 所有 React 组件文件名用 PascalCase(`UserCard.tsx`),工具函数用 camelCase(`formatDate.ts`)。
- 导出统一用 named export,不要默认导出(测试发现易拼错且重构困难)。
- 异步函数命名以动词开头:`fetchUser`、`createOrder`、`syncAccounts`。
- 注释只写"为什么",不写"做了什么"——做了什么读代码就知道。
- Commit 信息走 Conventional Commits:`feat:`、`fix:`、`refactor:`、`docs:`、`test:`、`chore:`。

第三类:测试与发布流程

## Testing & release

- 改任何 `src/api/` 下的代码,必须同步更新 `src/api/__tests__/` 的对应测试。
- PR 前本地必须跑过:`pnpm typecheck && pnpm lint && pnpm test`。
- 主分支(main)的 push 会触发 GitHub Actions 自动部署到 staging,所以 main 要永远绿。
- 生产部署由专人手动从 GitHub Releases 触发,你不要尝试直接 deploy。

第四类:这个项目的"潜规则"

## Gotchas(踩过的坑)

- `useAccounts` hook 在 SSR 环境下会报错,只能在客户端组件用。
- 时间字段全部按 UTC 存,前端展示时用 `formatLocalDate` 转换。
- `react-pdf` 在 Vite dev server 下需要单独配 `optimizeDeps.include`。
- 后端的分页参数是 1-indexed(`page=1` 是第一页),不是 0-indexed。

把这四类补完之后,你的 CLAUDE.md 就从 1.4 KB 涨到 3 到 5 KB。这 3 到 5 KB 的投资,接下来三个月每一次和 Claude Code 对话都能省你 2 分钟解释

2.5 多个 CLAUDE.md 的层级

CLAUDE.md 可以多层叠加,Claude Code 会自动按下面的顺序读:

~/.claude/CLAUDE.md            ← 全局,你所有项目都生效
└─ /path/to/project/CLAUDE.md  ← 项目级,这个项目生效
   └─ src/api/CLAUDE.md        ← 子目录级,只对 src/api/ 下的工作生效

举个例子,你可以在 src/api/CLAUDE.md 里写:

# src/api/CLAUDE.md

这个目录下的所有改动,必须遵守:

1. 任何新接口都要在 `__tests__/` 下加对应测试,覆盖成功 + 至少 1 个错误路径。
2. 不要直接用 `axios.get`,必须用 `apiClient` 实例(已自动加鉴权)。
3. 接口返回的时间字段全部用 ISO 8601 字符串,不要传 timestamp。

之后 Claude Code 在 src/api/ 下工作时,会自动叠加这些规则,不用你每次手动提


三、第二步:让 Claude 读懂你的代码库

/init 让 Claude 知道项目大概是什么。下一步是让它理解项目细节。这一节给你三类提问技巧。

3.1 提问技巧:从"宏观"到"微观"问

宏观:理解一个模块

解释 src/auth 这个模块做什么。
要求:
- 一句话定位它的职责
- 列出它对外暴露的关键 API(函数、组件、类)
- 列出它依赖的外部模块
- 指出它的状态在哪里管理(全局 store 还是局部)
- 如果有不合理的设计,顺便指出来

Claude 会去读 src/auth/ 下的文件,跨文件 join 信息,给你一份这样的报告:

src/auth 负责用户的认证状态管理与登录、登出流程。

对外暴露

  • useAuth() hook:返回当前用户、loading、login()、logout()
  • <AuthProvider>:在 src/main.tsx 包裹整个 App
  • requireAuth():Route Guard 的高阶函数

依赖

  • @/api/auth 提供 loginRequestrefreshToken
  • @/store/userStore:Zustand store 持久化当前用户
  • react-router-dom 用于在 401 时跳转

状态管理: Token 存在 localStorage,内存里挂在 userStore.user.token

不合理的地方

  1. useAuth 内部有 5 个 useEffect,其中两个在做相同的事(都在监听 user 变化做 redirect),会造成重复跳转。
  2. requireAuth 在 SSR 下会报错(读 localStorage),建议加 typeof window 判断。

这种回答的价值在于:它不仅告诉你"是什么",还顺手给你指出"哪里有坑"

中观:理解一个流程

用户登录的完整流程是怎样的?画一个序列图,
从用户点"登录"按钮开始,到首页加载完成结束。
覆盖前端、后端 API、token 持久化、路由跳转这四层。

Claude 会输出一份 Mermaid 序列图:

```mermaid
sequenceDiagram
    participant U as 用户
    participant L as LoginPage
    participant A as authApi.login
    participant S as userStore
    participant R as Router
    participant H as HomePage

    U->>L: 输入账号密码点登录
    L->>A: POST /api/auth/login
    A->>A: 验证 + 生成 JWT
    A-->>L: { token, user }
    L->>S: setUser({ token, user })
    S->>S: 持久化到 localStorage
    L->>R: navigate("/")
    R->>H: render HomePage
    H->>S: useAuth() 拿到 user
    H->>A: GET /api/dashboard
    A-->>H: dashboard data
```

这种图你贴到 Notion 或飞书文档里,直接可以当架构文档用,比让你自己手画快 100 倍。

微观:剖析一个文件

@src/api/user.ts 这个文件有什么坑?
重点看:
- 异步错误处理是否完整
- 有没有重复代码可以抽
- 类型定义是否准确
- 有没有 N+1 查询风险
- 单元测试覆盖了多少分支

@src/api/user.ts 是 Claude Code 的文件引用语法,等于把这个文件的内容塞进上下文。Claude 会逐行扫一遍,给你输出形如:

src/api/user.ts 共 184 行,我发现 6 个值得注意的点:

行号 严重 问题
23 到 31 getUser 在 401 时只 console.error,没把错误抛上去,调用方不知道失败
47 到 62 updateUserpatchUser 90% 重复,可以抽成内部 _putUser
89 User.tags 类型是 any[],实际后端返回 {id, name}[],改成强类型
110 到 145 loadFriends 串行调了 N 次 getUser(id),标准 N+1,改 getUsersByIds 批量接口
全局 没有任何 JSDoc 注释,IDE 提示能力弱
测试 __tests__/user.test.ts 只测了 happy path,完全没测错误路径

你想我先修哪一条?

这就是 Claude Code 真正的价值——它能在 30 秒内做你做半小时的事

3.2 用 Plan Mode 探索复杂代码

读懂大型项目时,你会担心一件事:Claude 一不留神改了某个文件。Plan Mode 就是为这件事设计的。

怎么进入 Plan Mode

两种方法,任选一种:

按键:Shift + Tab(在普通模式下连按一次)
命令:/plan

进入后,你会看到提示符变成:

[Plan Mode] >

Plan Mode 的核心特性

维度 普通模式 Plan Mode
能读文件
能改文件
能跑命令 是(高危的会问) 只能跑只读命令(如 lscatgit log
能搜索
能给计划 是,而且是它的本职
适用场景 真正动手干活 探索、规划、理解、画图

简单说:Plan Mode 是 Claude 的"图书馆模式"——它只读不写。在这个模式下,你可以放心大胆地让它"逛"你的代码库,完全不用担心它手滑。

Plan Mode 三大典型场景

场景 A:理解你接手的烂摊子

[Plan Mode]
我刚接手这个项目,前任工程师离职了文档不全。
帮我:
1. 先列出整个项目最重要的 10 个文件,按重要性排序
2. 给每个文件一句话说明它的作用
3. 指出 3 个最容易让新人踩坑的"潜规则"
4. 给我一份"上手路径":如果我要从零开始读懂这个项目,应该按什么顺序?

场景 B:规划一次大重构

[Plan Mode]
我准备把现在的 Redux 全部换成 Zustand。
请你:
1. 列出所有用到 Redux 的文件
2. 估算改造工作量(以"小时·人"为单位)
3. 给我一个分阶段执行计划,每阶段最大 3 小时,可以独立提交 PR
4. 标出"风险最高"的 3 个点
5. 不要写一行代码,先给我计划

场景 C:做架构评审

[Plan Mode]
我们准备给用户中心加"双因子认证"功能。
当前架构图:见 @docs/architecture.md
新需求:用户除了密码外,还要短信或 TOTP。

帮我评估:
1. 现有 auth 模块需要改哪些地方
2. 数据库需要新增什么表、字段
3. 前端需要新增哪些组件
4. 需要新增哪些后端接口
5. 需要新增哪些环境变量、配置
6. 给一个推荐实施顺序

只出方案,不动代码。

Plan Mode 出的方案我建议先复制到 Notion、飞书、钉钉文档里,让真正会拍板的人(可能是你自己,可能是技术 Leader)审一遍。计划过审之后,再切回普通模式,逐项执行。这是真正"工程化"用 Claude 的关键习惯。

3.3 配合"模型切换"做更深的探索

复杂代码探索,你可能想用更聪明的模型。Claude Code 内置三档模型,切换非常简单:

/model opus       ← 切到最聪明的 Opus,适合规划、架构、深度推理
/model sonnet     ← 切到默认的 Sonnet 4.5,日常使用平衡之选
/model haiku      ← 切到最便宜的 Haiku,适合写脚手架、简单任务

实战技巧

1. 用 /model opus + /plan 让 Opus 出方案(算贵的脑子,出主意)
2. 把方案 review 一遍
3. /model sonnet 切回 Sonnet 4.5
4. 退出 /plan 模式,让 Sonnet 干活(算便宜的手,真执行)

这一招本书后面会反复用到,记住它:Opus 出谋,Sonnet 实施


四、第三步:让 Claude 帮你修 Bug

读懂代码之后,我们干第一件真正生产力的事:修 Bug

4.1 一个真实案例:用户报告"上传图片失败"

我们用一个完整案例走一遍。客服群里突然出现这条消息:

用户 @张三 反馈:在"上传头像"页面,选择文件后大概 80% 的概率会失败, 错误提示是"上传失败,请重试"。我自己试了好几次,有时成功有时失败, 没有明显规律。麻烦排查一下。

4.2 提示词:把"故事"完整告诉 Claude

我有一个 bug 需要你排查,过程要让我看见每一步,不要直接改代码,先定位。

【背景】
- 项目:本仓库(已有 CLAUDE.md)
- 报障人:用户 @张三
- 现象:"上传头像"页面,选文件后约 80% 概率失败,提示"上传失败,请重试"
- 频率:间歇性,无明显规律
- 复现:本机暂时没复现成功

【相关文件(已知)】
- 前端入口:@src/pages/profile/AvatarUpload.tsx
- 上传工具:@src/lib/upload.ts
- 后端日志:@logs/error.log(最近 24 小时的)

【你的任务】
1. 把可能的原因列出来,按可能性从高到低排序
2. 对最可能的 1 到 2 个,给出"我该跑哪条命令、看哪段日志"的具体定位步骤
3. 不要直接改代码,先告诉我你怀疑的根因

完成第 3 步停下来等我回复,确认根因后再动手。

4.3 Claude 的反应

它会做下面这一连串动作,你看着就行

1. read_file: src/pages/profile/AvatarUpload.tsx
2. read_file: src/lib/upload.ts
3. read_file: logs/error.log(最近 200 行)
4. grep: "upload" 在 logs/error.log 中
5. grep: "timeout" 在 logs/error.log 中
6. read_file: vite.config.ts(看看 dev proxy 设置)
7. read_file: src/api/client.ts(看 axios 全局 timeout)

然后给你输出:

我大致定位到三个可能根因,按可能性排序:

概率 根因 证据
70% 超时配置过低src/api/client.ts 第 12 行设了全局 timeout: 5000,但日志里 17 条上传失败记录全部是 5.0 到 5.1s 触发的 ECONNABORTED,显然图片大就超时
20% 后端 multipart 解析限制:nginx 默认 client_max_body_size = 1M,日志里 3 条 413 Request Entity Too Large 印证了这个
10% 前端没正确处理重试upload.ts 47 行的 retryCount = 0,实际从来没启用,失败就直接 throw

我最怀疑根因 1。你可以做两件事确认:

  1. 让用户截一张失败时浏览器 Network 面板的截图,看具体是哪种错误(net::ERR_TIMED_OUT413502
  2. 我可以先把 client.ts 的全局 timeout 从 5s 调到 60s,但这是治标——根因可能要根据上一步确认调整

要我接着改吗?如果改,我建议先只改 timeout这一条,提一个最小 PR,观察 24 小时效果。

4.4 你怎么 review、怎么放行

你看了这个分析,觉得逻辑通,回它:

确认根因 1 是主要原因。我也刚问了运维,nginx 已经早就把 client_max_body_size 调到 50M 了,所以根因 2 排除。

请你:
1. 把全局 timeout 从 5000 改到 60000
2. 同时把 src/lib/upload.ts 改成"图片上传专用"的接口,带进度条,允许 120s 超时
3. 不要影响其他接口的 5s 超时(只对上传接口单独调长)
4. 加一个简单测试,模拟"上传超过 5s 但小于 60s"的场景,确保不再失败
5. 改完跑一遍 pnpm typecheck && pnpm test,确认通过
6. 给我一份 PR 描述草案,说明改了什么、为什么、怎么验证

按上面步骤来,完成后告诉我。

Claude 会严格按你说的步骤做完,期间任何一步如果遇到不确定(比如发现你没说清楚的边界),会停下来问你。

4.5 修 Bug 的三条铁律

铁律 解释
1. 把堆栈完整贴进去 不要只贴错误信息,把完整 stack trace 贴进去——Claude 能从堆栈里读出大量隐含信息
2. 用 @ 引用相关文件 比起让它自己 grep,你直接用 @ 引用又快又准
3. 先复现,再修 复现不了的 bug 不要急着改。让 Claude 先写一个能稳定复现的测试,再针对测试改代码

第 3 条特别重要。下面这段话就是"先复现,再修"的标准提示词:

这个 bug 我现在还无法稳定复现。请你:
1. 根据日志和代码,推断出能稳定触发 bug 的最小输入条件
2. 用现有测试框架写一个测试,这个测试在 bug 修复前必须失败、修复后必须通过
3. 让我先看测试,确认能复现
4. 我确认后,再开始改源码

这套流程下来,你修的 bug 不会"修完三天又来一遍",因为有测试守门


五、第四步:让 Claude 帮你写测试

很多人写代码不写测试,因为写测试又烦又花时间。但让 Claude 写测试,是它最擅长的事之一——它读完源码就能精准列出该测的边界条件。

5.1 一个完整的"写测试"提示词

为 @src/utils/dateFormat.ts 写完整的单元测试。

【要求】
- 框架:Vitest
- 覆盖率目标:行覆盖 > 95%
- 必须覆盖的边界情况:
  * 空字符串、null、undefined 输入
  * 非法日期字符串(如 "2026-13-45")
  * 极端日期(1970-01-01、2099-12-31)
  * 跨时区(UTC、Asia/Shanghai、America/New_York)
  * 闰年的 2 月 29 日
  * 浮点 timestamp(带小数位)
- 测试名用中文描述,例:`it("应在输入为空字符串时返回空字符串", ...)`
- 写完后跑一遍 `pnpm test src/utils/dateFormat.test.ts`,确认全部通过
- 如果发现源码本身有 bug,先告诉我,不要私自改源码

5.2 Claude 输出的测试长这样

import { describe, it, expect, beforeEach, afterEach, vi } from "vitest";
import { formatDate } from "./dateFormat";

describe("formatDate", () => {
  describe("基础格式化", () => {
    it("应将合法 Date 对象格式化为 YYYY-MM-DD", () => {
      const d = new Date("2026-04-19T10:00:00Z");
      expect(formatDate(d)).toBe("2026-04-19");
    });

    it("应在输入为空字符串时返回空字符串", () => {
      expect(formatDate("")).toBe("");
    });

    it("应在输入为 null 时返回空字符串", () => {
      expect(formatDate(null)).toBe("");
    });

    it("应在输入为 undefined 时返回空字符串", () => {
      expect(formatDate(undefined)).toBe("");
    });
  });

  describe("非法输入", () => {
    it("应在输入非法日期字符串时返回空字符串", () => {
      expect(formatDate("2026-13-45")).toBe("");
    });

    it("应在输入纯数字字符串时返回空字符串", () => {
      expect(formatDate("not-a-date")).toBe("");
    });
  });

  describe("跨时区", () => {
    beforeEach(() => {
      vi.useFakeTimers();
    });
    afterEach(() => {
      vi.useRealTimers();
    });

    it("应按 Asia/Shanghai 时区返回当地日期", () => {
      vi.setSystemTime(new Date("2026-04-19T16:00:00Z"));
      expect(formatDate(new Date(), "Asia/Shanghai")).toBe("2026-04-20");
    });

    it("应按 America/New_York 时区返回当地日期", () => {
      vi.setSystemTime(new Date("2026-04-19T03:00:00Z"));
      expect(formatDate(new Date(), "America/New_York")).toBe("2026-04-18");
    });
  });
});

跑完之后,Claude 会把覆盖率报告贴给你:

 PASS  src/utils/dateFormat.test.ts (24 tests) 187ms

 % Coverage report from v8
-----------|---------|----------|---------|---------|-------------------
File       | % Stmts | % Branch | % Funcs | % Lines | Uncovered Lines
-----------|---------|----------|---------|---------|-------------------
All files  |   97.3  |   95.0   |   100   |   97.3  |
 dateFmt.ts|   97.3  |   95.0   |   100   |   97.3  | 89-91
-----------|---------|----------|---------|---------|-------------------

差 89-91 行没覆盖,那是一段处理自定义 locale 的死代码,
当前接口未暴露。我已经在测试文件顶部加了 // TODO: 解锁 locale 时补充。

这就是高质量的工程产出——不是"我把测试写了",而是"我把测试写了、覆盖率给你了、没覆盖的地方解释了原因"。

5.3 TDD 工作流:让 Claude 帮你"先写测试再写代码"

TDD(测试驱动开发)三步循环:红 → 绿 → 重构。Claude Code 配合 TDD 极其顺手。

第一步:红(写一个失败的测试)

我要新增一个 `mergeAccounts(a, b)` 函数,作用是合并两个银行账户对象。
合并规则:
- id 取 a.id
- balance 取 a + b
- transactions 数组合并并按时间倒序去重
- 任意一方为 null 直接返回另一方
- 两个都 null 抛异常

请你:
1. 先在 @src/lib/accounts.test.ts 里写一组覆盖上述规则的测试
2. 跑一遍,所有测试都应该红(因为函数还不存在)
3. 不要写实现,只写测试

第二步:绿(让测试通过)

测试写完确认你看过没问题之后:

好,实现 mergeAccounts 函数,目标是让所有测试变绿,
不要改测试代码。

第三步:重构(让代码漂亮)

所有测试都绿了。现在请你 refactor:
- 抽出公用的"按时间去重"逻辑
- 给函数加 JSDoc 注释
- 保持所有测试依然绿

这一套流程的妙处在于:你只描述"行为",Claude 写代码;测试是"行为"的具象化。代码改了 100 次,只要测试还绿,行为就没变。这是工程师最舒服的睡眠方式


六、第五步:Git 操作

Claude Code 默认就懂 git——不光懂,它已经被训练成"按工程界主流最佳实践来"

6.1 它默认会做的 git 动作

动作 它会自动 绝不会自动
git status 查状态 ——
git add 加你刚改的文件 .env*.key*.pem 等敏感文件
git commit 写好 commit message 提交 ——
git push 推到当前分支 origin git push --force(除非你明确说)
git pull 拉远端最新 ——
git reset --soft 撤销 commit --hard(除非你明确确认)
git rebase 简单 rebase 复杂的会先列计划等你 review
.gitignore —— 主动改(除非你明确要求)
改 git config —— 永远不会

这些"绝不会"的清单,本质上是 Anthropic 在系统提示里硬编码的安全护栏。Claude Code 把"代码丢失"看作和"删用户文件"同等严重的事故。

6.2 自动生成 Commit Message

最常用的一句话:

请按 Conventional Commits 提交本次修改。

Claude 会:

  1. git status 看哪些文件改了
  2. git diff --staged(或 git diff)看具体改动
  3. 根据改动归类(feat、fix、refactor、test、docs、chore 等)
  4. 写一段 1 到 2 句的简短 message,可能再加一段 body 说明"为什么"
  5. 用 here-doc 提交,避免引号转义问题

输出大概长这样:

git add src/api/client.ts src/lib/upload.ts src/lib/upload.test.ts
git commit -m "$(cat <<'EOF'
fix(upload): 上传超时从 5s 调到 60s, 避免大图片失败

用户报告头像上传约 80% 概率失败, 经排查根因为 axios 全局
timeout=5s, 而后端处理大图片普遍需要 10-30s。

本次修改:
- 全局 timeout 维持 5s 不变, 避免影响其他接口
- 新增 uploadClient, timeout=60s, 专门用于上传场景
- 补 1 条单测覆盖 5s-60s 之间的成功场景
EOF
)"

注意几个细节:

  • 类型加 scopefix(upload) 比裸 fix: 更易归类
  • 第一行不超过 72 字符,严格遵守 Conventional Commits 规范
  • body 写"为什么",不写"做了什么"——做了什么 git diff 自带

6.3 复杂 Git 场景

场景 A:解决 merge conflict

我刚 git pull,出现 3 个文件冲突,你帮我解一下。
原则:
- 我的本地是 feature 分支,远端是 main 合并过来
- 任何业务逻辑冲突,优先保留我的本地版本(理由:我的更新)
- 任何依赖版本号冲突,选两边的更高版本
- 解完跑一遍 pnpm typecheck,确认能编译
- 不要直接 commit,解完让我看一眼

Claude 会:

  1. git status 列出冲突文件
  2. 逐个 read_file 看冲突标记 <<<<<<<=======>>>>>>>
  3. 按你给的原则做选择
  4. 删冲突标记,生成最终版本
  5. pnpm typecheck 跑一遍
  6. 把改动列表给你 review

场景 B:开 feature branch 干活

开一个新 feature branch, 叫 `feat/two-factor-auth`,
基于最新的 main。开完直接 checkout 过去。

Claude 自动跑:

git fetch origin
git checkout main
git pull origin main
git checkout -b feat/two-factor-auth

然后告诉你"已切到新分支,可以开干"。

场景 C:rebase 复杂历史

这种事永远要 Plan Mode 先看计划,再动手:

[Plan Mode]
我在 feature 分支上有 5 个 commit, 其中前 4 个是探索,
有大量 console.log 调试残留。我想:
- 把前 4 个 commit 合并(squash) 成 1 个干净的 commit
- 保留最后 1 个 commit 不动
- 合并后的 commit message 我来写, 你先草拟一份

帮我先列出 rebase 的具体步骤、可能的风险点, 不要动手。

Claude 会给你一份执行计划,包括 git rebase -i HEAD~5 后该怎么改 pick 为 squash、可能的冲突点等。你看完没问题再退出 Plan Mode 让它执行

6.4 一句话救命操作

如果你不小心让 Claude 做了什么破坏性 git 操作,第一时间

ctrl+c 中止当前操作, 然后告诉我刚才 Claude 跑了什么命令、HEAD 现在指向哪。

99% 的 git 操作都能用 git reflog 找回来。Claude 也会主动帮你恢复——你只要别在它修复之前继续乱跑命令。


七、第六步:Code Review

Code Review 是工程师最累的事之一。Claude Code 用 Subagent(子代理)能把一大半 review 工作替你做掉。

7.1 用 Subagent 定义专属 Reviewer

在你的项目根目录下创建 .claude/agents/code-reviewer.md

---
name: code-reviewer
description: 严格的资深 Code Reviewer, 擅长找出安全、性能、可读性问题
model: opus
---

你是一位有 10 年经验的资深 Code Reviewer。
你的任务是评审用户给你的 diff 或代码片段, 严格、专业、不客气。

# 评审标准

## 1. 安全 (Security)
- SQL 注入、XSS、CSRF
- 密钥、token 泄露
- 权限漏洞、越权访问
- 不安全的反序列化
- 文件上传漏洞 (类型校验、路径穿越)

## 2. 性能 (Performance)
- N+1 查询
- 不必要的循环嵌套
- 内存泄漏 (未释放的监听器、定时器)
- 不必要的重渲染 (React 场景)
- 大对象的深拷贝

## 3. 可读性 (Readability)
- 命名是否清晰、一致
- 函数、方法是否太长 (> 50 行警告)
- 嵌套层级是否过深 (> 3 层警告)
- 注释是否解释"为什么"而非"做了什么"

## 4. 测试 (Testing)
- 是否有测试覆盖
- 测试是否覆盖了关键边界
- mock 是否合理 (没有 mock 自己要测的逻辑)

## 5. 风格 (Style)
- 是否符合项目根目录 CLAUDE.md 中定义的约定
- 是否符合语言常规风格

# 输出格式

按"严重程度"分三档:

## Block (必须改的)
> 这条不改我不会同意 merge

## Warn (强烈建议改的)
> 不改也能 merge, 但下次不希望再看到

## Nit (可选优化)
> 看你心情, 改不改都行

每一条必须给:
- **位置**: 文件路径:行号
- **问题**: 一句话说明
- **建议**: 具体改成什么样, 带代码示例

# 风格

- 不夸赞, 只挑刺。表扬留给作者爹妈。
- 不模糊。"建议优化"不算建议, "建议把 useState 改成 useReducer 因为状态超过 5 个"才算建议。
- 不啰嗦。一条 issue 三句话讲完。

7.2 调用这个 Reviewer

写完代码之后,你只需要说:

review 一下我刚写的这部分代码。
分支:feat/two-factor-auth(对比 main)

Claude Code 会自动派出 code-reviewer 这个 subagent,带着上面的 prompt 跑一遍 diff,然后输出形如:

## Block (必须改的)

### 1. SQL 注入风险
- 位置: `src/api/users.ts:47`
- 问题: 直接拼接 `where username = '${name}'`, 未做参数化
- 建议:

```ts
const users = await db.query(
  "SELECT * FROM users WHERE username = ?",
  [name],
);
```

### 2. 密钥写死在源码
- 位置: `src/lib/totp.ts:12`
- 问题: `const SECRET = "abc123def456"` 硬编码, 会随仓库泄露
- 建议: 改成读取 `process.env.TOTP_SECRET`, 并在 `.env.example` 加占位

## Warn (强烈建议)

### 3. 多余的 useEffect
- 位置: `src/pages/profile/TwoFactor.tsx:34-41`
- 问题: useEffect 里只是同步 props, 可以直接计算
- 建议: 删掉这个 useEffect, 在 render 阶段直接派生

### 4. 缺少错误边界
- 位置: `src/pages/profile/TwoFactor.tsx`
- 问题: 整个组件没有 error boundary, 一个抛错就白屏
- 建议: 用 `<ErrorBoundary fallback={...}>` 包一层

## Nit (可选)

### 5. 命名建议
- 位置: `src/lib/totp.ts:5`
- 问题: 函数 `gen` 不够具体
- 建议: 改成 `generateTotpCode`

7.3 把 Code Review 接到 PR 流程

如果你的项目用 GitHub,可以更进一步——让 Claude 自动 review 每个 PR

  1. .github/workflows/ 下加一个 workflow,PR 触发时调 Claude API
  2. 把上面的 reviewer prompt 作为系统提示
  3. 把 PR diff 作为输入
  4. 把 review 结果以评论形式回贴到 PR 上

这套自动化第十四章会专门讲。这里你只要知道它能落地、能省你 80% 的 review 时间就行。

Code Review 用 Claude 的核心心法:让它打一遍分,你再决定要不要改。它不会直接改你的代码——它的角色是"挑刺的甲方",改不改你说了算。


八、第七步:重构与架构

重构是"大事",大事就要走 Plan Mode + Opus 这个组合拳。

8.1 流程模板

1. /model opus           ← 切到最聪明的脑子
2. /plan                 ← 进入只读规划模式
3. 描述目标 + 约束        ← 让 Opus 出方案
4. 你 review,反复打磨    ← 来回 2-3 轮
5. /model sonnet         ← 切回平价的手
6. 退出 /plan            ← 让 Sonnet 干活
7. 分阶段执行,每阶段一个 PR

8.2 案例:把单体应用拆成多个微服务

第一步:让 Opus 出方案

/model opus
/plan

【目标】
当前是一个 Node.js + Express 单体应用, 所有业务都在一个进程里:
- 用户 (auth)
- 订单 (orders)
- 支付 (payments)
- 通知 (notifications)

随着业务变重, 部署一次要 8 分钟, 任何小改动都要重启整个服务。
我想把它拆成 4 个独立服务: auth-svc、orders-svc、payments-svc、notif-svc。

【约束】
- 现有数据库不能拆 (短期内还是一个 PostgreSQL)
- 服务间通信优先 HTTP (暂不引入 message queue)
- 必须保留一份"聚合 BFF"层给前端用, 前端无感
- 团队只有 3 个后端, 每周可投入 30 人时

【你的任务】
1. 给我一份 6 到 8 周的拆分路线图
2. 每周列出"做什么、做完的验收标准、风险"
3. 列出"必须先解决的技术债" (比如: 数据库的跨服务查询怎么办?)
4. 给一份"该买、该装"的工具清单 (API gateway、监控、CI/CD 改造)
5. 标出 3 个"如果不解决会让整个迁移失败"的关键点

只出方案, 不动代码。可以画 Mermaid 图。

Opus 会给你一份 3000 字以上的详细方案,带图、带表、带阶段拆分。这种方案如果让你自己琢磨,大概要花 2 个工作日

第二步:你和团队一起 review

把 Opus 出的方案打印出来(或贴到 Notion),拉个会:

  • 哪些假设不对?(可能 Opus 不知道你们公司的某些限制)
  • 哪些步骤太激进?(可能 6 周拆 4 个服务对你们团队太狠)
  • 哪些技术选择有更适合你们的替代?(可能你们公司禁用某些工具)

把 review 结果再喂回 Opus:

团队 review 后给的反馈:
1. 数据库短期不能拆, 这个保留
2. 6 周太紧, 改成 12 周, 每两周做一个服务
3. 公司禁用 Kong, 要换成 nginx + 自研路由
4. ……

请按这些反馈更新一版方案。

来回 2 到 3 轮,你会得到一份既专业又落地的执行方案。

第三步:切回 Sonnet 分阶段执行

/model sonnet
(退出 /plan, 正常模式)

按方案 v2 的 Week 1-2 执行: 把 auth 模块抽出去成独立服务。
具体步骤:

1. 在仓库根新建 services/auth-svc 目录
2. 把现有 src/auth/ 下的代码移到 services/auth-svc/src/
3. 在 services/auth-svc 加独立的 package.json、tsconfig、Dockerfile
4. 改造原 monolith, 通过 HTTP 调 auth-svc (走内网)
5. 加端到端测试, 确保用户登录流程不变
6. 改完跑全套测试, 确认绿
7. 提一个 PR

这就是 Opus 谋,Sonnet 行的完整流程。Claude Code 把"工程师最贵的那部分大脑"用便宜的方式给了你。

8.3 重构的两条铁律

铁律 解释
1. 永远先有测试再重构 重构的定义是"行为不变,结构变化"。没有测试你怎么证明行为不变?让 Claude 先补测试,再重构
2. 永远小步快跑 一次重构 200 个文件 = 灾难。让 Claude 拆成"每次 5 到 20 个文件、可以独立提交、可以独立回滚"的小步

九、第八步:完整 PR 工作流

我们把上面所有步骤串起来,走一个真实的 PR——从需求到合并

9.1 需求来了

产品经理在企微群:"这周给用户中心加一个'修改密码'功能,要 OWASP 推荐的密码强度检测,要旧密码二次确认,要支持邮箱通知用户'你的密码被修改了'。"

9.2 第 1 步:让 Claude 出 Plan

/plan

【需求】
给用户中心加"修改密码"功能。

【约束】
- 必须验证旧密码
- 新密码必须通过 OWASP 推荐的强度检测 (长度 ≥ 12, 大小写、数字、符号至少各 1)
- 修改成功后, 后端必须发邮件通知用户 (用现有的 emailService)
- 必须有"密码可见、隐藏"的小眼睛切换
- 不能影响现有的登录会话 (改完密码不要把用户踢出去)

【约束 2】
- 前端用现有的 React + shadcn/ui
- 后端 Express, 数据库 PostgreSQL
- 必须有 e2e 测试

请给我:
1. 涉及到改动的文件清单
2. 数据库改动 (如果有)
3. 新增 API 接口的设计 (method、path、req、res)
4. 前端组件结构
5. 测试覆盖范围
6. 估算工时

Claude 输出方案,你看完觉得对,放行:

方案没问题, 开始执行。先做后端, 做完做前端, 最后 e2e。
退出 /plan。

9.3 第 2 步:Claude 写代码 + 测试

它会:

  1. 先开 feature branch:feat/change-password
  2. 写后端:新增 PUT /api/users/me/password 接口、校验旧密码、强度检测、邮件通知
  3. 同步写后端测试(单元 + 集成)
  4. 写前端:新增 ChangePasswordDialog 组件,接到用户中心
  5. 同步写前端测试(组件级 + 集成级)
  6. 写 e2e 测试:Playwright 模拟"打开用户中心 → 改密码 → 验证邮件 → 重新登录"

整个过程你坐在屏幕前看,重要决策它会停下来问你(比如"邮件模板放哪个文件?")。

9.4 第 3 步:Hook 自动跑 lint + 测试

如果你配置了 PreCommit Hook(第九章会详细讲),每次 Claude 想 commit,Hook 会自动跑:

pnpm lint
pnpm typecheck
pnpm test

任何一项失败,commit 被拦截,Claude 自动看错误信息再修。它不会绕过 Hook——除非你明确说"跳过 hook"。

9.5 第 4 步:Claude 提交 + push 分支

git add .
git commit -m "$(cat <<'EOF'
feat(profile): 新增"修改密码"功能

- 新增 PUT /api/users/me/password 接口, 校验旧密码 + 强度检测
- 新增 ChangePasswordDialog 组件, 集成到用户中心
- 修改成功后通过 emailService 发送通知
- 不影响现有登录会话 (只更新密码 hash, 不轮换 token)
- 补 12 条单测、4 条集成测试、2 条 e2e
EOF
)"

git push -u origin feat/change-password

9.6 第 5 步:Claude 自动开 PR(GitHub MCP)

如果你装了 GitHub MCP(第十一章会讲),Claude 自动调用 gh pr create,生成的 PR body 长这样:

## 这个 PR 做了什么

为用户中心加"修改密码"功能, 完整覆盖前端组件 + 后端接口 + 邮件通知 + 测试。

## 改动清单

### 后端
- 新增 `PUT /api/users/me/password` (`src/api/users.ts`)
- 抽出 `passwordStrengthCheck` (`src/lib/security/password.ts`)
- 集成 `emailService.sendPasswordChangedNotice`

### 前端
- 新增 `ChangePasswordDialog` (`src/pages/profile/ChangePasswordDialog.tsx`)
- 在 `ProfilePage` 增加入口按钮
- 复用现有的 `PasswordInput` (支持小眼睛切换)

### 测试
- 后端: `src/api/__tests__/users.password.test.ts` 12 条
- 组件: `src/pages/profile/__tests__/ChangePasswordDialog.test.tsx` 6 条
- e2e: `e2e/change-password.spec.ts` 2 条

## 怎么验证

1. 跑 `pnpm test` 全绿
2. 跑 `pnpm e2e` 全绿
3. 本地 `pnpm dev` 后, 登录任意账号, 在用户中心点"修改密码"
   - 用错的旧密码 → 提示错误
   - 用强度不够的新密码 → 提示强度不足
   - 修改成功 → 收到邮件 + 当前会话保持登录

## 风险与回滚

- 邮件发送失败时不应阻塞密码修改成功 (已用 try-catch + 异步队列)
- 如有问题, revert 此 PR 即可, 数据库无 schema 变更

9.7 第 6 步:你 review → merge

PR 进来,你打开:

  • 看 description 一眼,知道这个 PR 干什么
  • 看测试是否通过(CI 会跑一遍)
  • 重点看"安全相关的代码"(密码、token、权限)
  • code-reviewer subagent 再扫一遍 diff
review 一下 #142 这个 PR, 重点看安全相关代码。

确认没问题:

merge 这个 PR, 用 squash 模式, 删除 source branch。

Claude 自动跑 gh pr merge 142 --squash --delete-branch,然后告诉你:

PR #142 已 merge 到 main, 远端 feature 分支已删除。 CI 触发了 staging 自动部署, 5 分钟内生效。 你的本地分支也已清理 + 切回 main + pull 最新。

整个 PR 从需求到合并,你的"实际敲键盘时间"可能不超过 10 分钟。剩下的 90% 时间是在 review、决策、确认。这就是 Claude Code 当队友的样子。


十、第九步:调试技巧

修 Bug 不是只能"读代码 + 猜"。Claude 能"亲自跑一遍"、"加日志再跑一次",这是它远胜传统 IDE 的关键能力。

10.1 让 Claude 亲自跑代码

我刚写的 src/lib/exchange.ts, 执行后输出和预期不符。
请你:
1. 跑 `pnpm tsx src/lib/exchange.ts` 看实际输出
2. 跟预期对比, 找出哪一步开始偏差
3. 加 debug log 再跑一遍, 定位精确出错位置
4. 给修复方案, 但不要立即改, 先告诉我

预期输出: `{ from: "USD", to: "CNY", rate: 7.25 }`

Claude 会真的去跑,看到实际输出,自己分析:

实际跑出来:{ from: "USD", to: "CNY", rate: 7.25, fee: NaN }

多了一个 fee: NaN。我看了源码,第 47 行 fee = amount * feeRate, 但 feeRategetRate("USD", "CNY") 没传入,所以是 undefined。 这个字段你接口设计上应该有还是不应该有?

10.2 让 Claude 配合 Playwright 自验

前端改动尤其有用:

我刚改了 src/pages/login/LoginPage.tsx 的"忘记密码"按钮位置。
请你:
1. 启动 dev server (pnpm dev)
2. 用 Playwright 打开 http://localhost:5173/login
3. 截图保存到 /tmp/login.png
4. 描述截图里"忘记密码"按钮在哪里、看起来对不对

Claude 调用 playwright 工具,真的开浏览器、真的点页面、真的截图、真的看图(多模态),然后给你输出:

截图已保存。我看到登录框右下角有"忘记密码?"链接, 离"登录"按钮约 4px 间距,字号比按钮文本小 2px。 视觉上偏挤,建议把链接和按钮之间的间距调到 12px。

10.3 让 Claude 解释错误堆栈

收到一个 stack trace,直接贴给它:

跑测试时出现:

TypeError: Cannot read properties of undefined (reading 'toLowerCase')
    at normalizeEmail (src/lib/email.ts:23:18)
    at validateInput (src/api/auth.ts:47:23)
    at handler (src/api/auth.ts:89:15)
    at processTicksAndRejections (node:internal/process/task_queues:95:5)

请你:
1. 解释每一帧栈意味着什么 (给完全不懂的同事看)
2. 定位最可能的根因
3. 给修复方案

Claude 会逐帧拆解、给中文解释、定位根因(往往是某个上游没传值或值为 null)、给修复代码。这一招对"想学编程的非程序员"价值极大——你看不懂栈,Claude 一帧一帧给你翻译。

10.4 调试三件套小提示词

收藏下面这三段,直接当"调试急救包"。

急救一:没头绪

代码不知道为什么不工作, 我也描述不清楚。
请你接管:
1. 跑一遍代码, 看实际输出
2. 对比预期 (预期是: xxx)
3. 加 console.log 二分定位
4. 找到根因后, 告诉我怎么修

急救二:间歇性 bug

这个 bug 偶尔出现 (约 30% 概率)。请你:
1. 重复跑 50 次, 统计出错率
2. 对比成功、失败时的输入差异
3. 提出"什么情况下必现"的假设
4. 写一个稳定复现的测试

急救三:性能问题

@src/api/dashboard.ts 这个接口慢得让人发疯。
请你:
1. 加性能日志 (每个数据库查询、每个外部调用)
2. 跑一次完整请求, 统计每段耗时
3. 找出 top 3 最慢的环节
4. 给优化建议 (不要立刻改)

十一、第十步:写"小工具"

到这里,我们把"读懂 → 修 → 测 → 改 → review → 重构 → PR"全跑了一遍。但 Claude Code 还有一个非常被低估的用法——让普通人也能 5 分钟写出有用的小工具。下面给 6 个完整提示词,你可以直接复制改改用。

11.1 批量改文件名

我有一个文件夹 ~/Pictures/iphone-export/, 里面有 800 张从 iPhone 导出的照片,
文件名乱七八糟 (IMG_E1234.jpg、PXL_20231203_xxxx.jpg、image (5).png 等)。

请你:
1. 写一段 Python 脚本, 递归读取这个文件夹
2. 按"拍摄时间"重命名为 YYYYMMDD-HHMMSS-原后缀.jpg 格式
3. 拍摄时间从 EXIF 读; 读不到 EXIF 的退化用文件修改时间
4. 不要直接改原文件, 先输出"将要改成什么"的预览
5. 我确认无误后, 你再真正执行
6. 改完输出统计: 成功 N 张、EXIF 失败 N 张、跳过 (已经是规范名) N 张

11.2 抓某个网页的数据

帮我抓取 https://example.com/products 这个页面的所有商品数据。
页面里每个商品是一个 div.product-card, 每个卡片包含:
- 商品名 (.product-name)
- 价格 (.product-price)
- 库存状态 (.product-stock)
- 商品详情页链接 (a.product-link 的 href)

要求:
1. 用 Python + playwright (因为是 SPA 需要执行 JS)
2. 自动翻页, 抓完所有页 (看页码 div.pagination)
3. 输出成 CSV (列: name, price, stock, url)
4. 加 1 秒间隔, 礼貌爬取
5. 失败的页记录到 errors.log

11.3 自动给图片加水印

帮我写一个 Python 脚本, 给一个文件夹下所有图片加水印。
要求:
1. 输入: 文件夹路径 (命令行参数 1)、水印文字 (命令行参数 2)
2. 在每张图右下角加文字水印
3. 字体半透明白色 + 黑色描边, 在任何背景上都看得见
4. 字号是图片宽度的 3%, 自动适配
5. 不覆盖原文件, 输出到同目录的 watermarked/ 子文件夹
6. 给一个使用示例: `python watermark.py ./photos "©我的相册 2026"`

11.4 把 CSV 导入数据库

我有一个 sales.csv 文件, 30 万行, 需要导入 PostgreSQL。
列: order_id, customer_email, product_sku, amount, created_at

要求:
1. 写 Python 脚本, 用 psycopg + COPY 命令 (快)
2. 在导入前先建表 (给我 CREATE TABLE 语句, 索引建在 customer_email 和 created_at)
3. 数据清洗:
   - amount 列可能有 "$" 和 "," 符号, 去掉再转 numeric
   - created_at 可能是 "MM/DD/YYYY" 或 ISO, 统一转成 timestamptz
   - email 全部转小写
4. 用事务, 失败回滚
5. 进度条显示 (每 1 万行打一次)
6. 完成后报告: 总行数、成功、失败、耗时

11.5 监控某个文件夹有变化就推送

我希望写一个后台服务, 监控 ~/Downloads/ 文件夹:
- 一旦有 .pdf 文件新增, 就发一条飞书通知到我的群里
- 通知内容: 文件名、大小、首页缩略图
- 多个文件 5 秒内合并发 (避免刷屏)

要求:
1. Python + watchdog 库
2. 飞书 webhook 地址我已经有 (URL 我会贴给你)
3. PDF 缩略图用 pdf2image
4. 后台运行, 挂到 launchctl (我用 macOS)
5. 给一个简单的"启动、停止、状态"脚本

11.6 简单 GUI 工具(让普通人能用)

我妈想要一个"批量重命名照片"的工具, 但她不会用命令行。
请你:
1. 用 Python tkinter 写一个 GUI
2. 界面只有 3 个东西:
   - "选择文件夹"按钮
   - 一个文本框, 显示选了哪个文件夹
   - "开始重命名"按钮
3. 重命名规则: 按拍摄时间排序, 改成"我妈的照片-001.jpg、002.jpg ..."
4. 进度条 + 完成后弹窗"已重命名 N 张"
5. 打包成 macOS 的 .app (用 py2app 或 pyinstaller)
6. 给我一份"教我妈怎么用"的简单图文说明

这 6 个例子的共同点:普通人可能完全不知道用什么库、怎么下手,但描述清楚要做什么、给清楚约束,Claude Code 能 5 到 15 分钟内交付一个能跑的版本。这就是这本书反复强调的:会写代码 ≠ 必须会代码,会描述需求才是新时代的核心能力


十二、避坑:编程场景 8 大坑

最后一节,我把"编程场景下最常翻车的 8 个坑"给你一次性列清,每个都附"怎么避"。

坑 1:让 Claude 直接改 node_modules

症状:为了快速验证某个第三方库的 bug,你说"改一下 axios 的 dispatchRequest 函数"。Claude 真去改了 node_modules/axios/...。下次 pnpm install 改动全没了,你以为修好的 bug 又复活。

避坑

  • CLAUDE.md 里硬性禁止:永远不要修改 node_modules/ 下的任何文件
  • 真要改第三方库,用 pnpm patch <pkg> 生成持久化补丁

坑 2:让 Claude 操作生产数据库

症状:你跑了 claude 在生产服务器上,想让它"统计一下今天的订单数"。它顺手跑了 DELETE FROM orders WHERE created_at < ... 试图清理"老数据"。生产几个月数据没了。

避坑

  • 永远不要在生产服务器上跑 Claude Code,改用一台跳板机连只读副本
  • ~/.claude/CLAUDE.md 全局设:永远不要执行 DELETE、TRUNCATE、DROP、UPDATE,即使是模拟。除非用户明确说"在生产执行"
  • 数据库密码用只读账号

坑 3:把 .env 给 Claude

症状:Claude 帮你看 bug,顺手 cat .env 把数据库密码、API Key、JWT Secret 全读进上下文。这些内容会被发到 Anthropic 服务器(你订阅 Pro/Max 时同意过)。下次会话还可能被拼回到提示词里。

避坑

在项目根加 .claudeignore 文件:

# Secrets
.env
.env.*
!.env.example

# Keys & certs
*.pem
*.key
*.p12
secrets/

# Personal
.DS_Store
.idea/
.vscode/

# Build
dist/
build/
node_modules/

这份文件的语法和 .gitignore 一样。被它匹配到的文件,Claude Code 完全不会读——即使你用 @ 显式引用,它也会拒绝。

坑 4:复杂改动不走 Plan Mode

症状:你说"重构一下整个 auth 模块",Claude 直接动手改了 30 个文件,你后悔已经晚了。

避坑

  • 任何"涉及 ≥ 5 个文件"的改动,先 /plan 看计划再放行
  • 大改动一定先开 feature branch,出问题 git reset --hard origin/main 还能回得来

坑 5:用最新 Beta 模型做生产代码

症状:Anthropic 出了 Opus 4.7 Beta,你 /model opus-beta 立刻换上。结果某些 API 调用响应格式微变,生产代码里的兼容代码崩了。

避坑

  • 生产代码永远用 GA 版本sonnetopushaiku),不要用带 -beta 后缀的
  • 要尝试新模型,在分支里玩,别合 main
  • ~/.claude/CLAUDE.md 写:永远不主动切换到 beta 或 preview 模型,除非我明确要求

坑 6:长会话不 /compact

症状:一个会话开了 4 小时,聊了 200 条。后面 Claude 突然忘了开头说的"永远用 named export"这条规则,开始默认导出。

原因:Claude 的上下文窗口有上限(Sonnet 4.5 是 200k token,Opus 是 200k),超过会"丢前面"。

避坑

  • 长会话每隔 1 到 2 小时跑一次 /compact(压缩历史保留要点)
  • 或者直接 /clear 开新会话,把"必须保留的规则"放到 CLAUDE.md 里(永远不会丢)

坑 7:多 Subagent 并行没设上限

症状:你写了一个"自动跑测试 + 自动 review + 自动写文档"的 workflow,每个步骤派一个 subagent。结果一次任务跑了 12 个 subagent,每个 subagent 自己又派 subagent,最后 50 个进程并发,API 账单当月翻 5 倍。

避坑

  • ~/.claude/CLAUDE.md 设:并发 subagent 最多 3 个,深度最多 2 层
  • 每个 subagent 的提示词里明确:你不能再派出更多 subagent
  • Anthropic 控制台开"账单告警",超过 X 美元自动报警

坑 8:PR 自动化提交前没人 review

症状:你做了一套全自动 workflow:Claude 改完代码 → 跑测试 → 通过就 push → 自动开 PR → 自动 merge。某天 Claude 把测试也"修改"通过了(把失败的 assertion 改成 expect(true).toBe(true)),自动合到 main 了。生产挂了。

避坑

  • 永远在"merge"这一步留人审。可以全自动到"PR 创建",但 merge 必须人工点
  • 在仓库里设 GitHub Branch Protection:main 必须至少 1 个 review approval 才能 merge
  • CLAUDE.md 加:永远不要修改测试文件来让测试通过,除非用户明确说"测试本身写错了"

8 大坑速查

# 一句话避坑
1 改 node_modules .claudeignore + pnpm patch
2 操作生产 DB 永远别在生产跑 Claude
3 泄漏 .env .claudeignore 必装
4 大改不 plan ≥5 文件就 /plan
5 用 Beta 模型 生产用 GA,beta 留分支玩
6 长会话忘记 /compact/clear
7 Subagent 失控 限并发 3、限深度 2
8 自动 merge merge 一定人工

本章一图回顾

   ┌─────────────────────────────────────────────────────────────┐
   │              Claude Code 编程场景全工作流                    │
   └─────────────────────────────────────────────────────────────┘

         /init                  Plan Mode + @file
   ┌────────────┐           ┌──────────────────┐
   │ 认识项目   │ ────────▶ │  读懂代码库       │
   │ CLAUDE.md  │           │  理解架构         │
   └────────────┘           └──────────────────┘
                                       │
                                       ▼
                          ┌──────────────────┐
                          │  修 Bug           │
                          │  ① 复现           │
                          │  ② 定位根因       │
                          │  ③ 改代码 + 测试  │
                          └──────────────────┘
                                       │
                                       ▼
                          ┌──────────────────┐
                          │  写测试           │
                          │  TDD: 红→绿→重构  │
                          │  覆盖率 ≥ 95%     │
                          └──────────────────┘
                                       │
                                       ▼
                          ┌──────────────────┐
                          │  Git              │
                          │  Conventional    │
                          │  Commit + Push   │
                          └──────────────────┘
                                       │
                                       ▼
                          ┌──────────────────┐
                          │  Code Review     │
                          │  Subagent 打分   │
                          │  Block / Warn /  │
                          │  Nit 三档        │
                          └──────────────────┘
                                       │
                                       ▼
                          ┌──────────────────┐
                          │  重构与架构      │
                          │  Opus 谋        │
                          │  Sonnet 行      │
                          └──────────────────┘
                                       │
                                       ▼
                          ┌──────────────────┐
                          │  开 PR           │
                          │  GitHub MCP     │
                          │  自动生成描述    │
                          └──────────────────┘
                                       │
                                       ▼
                          ┌──────────────────┐
                          │  人工 review     │
                          │  → squash merge  │
                          └──────────────────┘

   ┌─────────────────────────────────────────────────────────────┐
   │  关键指令速查                                                │
   │  ────────────────────────────────────────────────            │
   │  /init           生成 CLAUDE.md                              │
   │  /plan           进入只读规划模式                            │
   │  /model opus     切到最强模型(规划用)                      │
   │  /model sonnet   切到平衡模型(执行用)                      │
   │  /compact        压缩长会话历史                              │
   │  /clear          清空会话(保留 CLAUDE.md)                  │
   │  @path/to/file   引用文件到上下文                            │
   │  Shift+Tab       快捷切 Plan Mode                            │
   │  .claudeignore   排除文件不让 Claude 读                      │
   └─────────────────────────────────────────────────────────────┘

   一句话心法
   ──────────────────────────────────────────────────────────────
   Claude Code 是会写代码的助理,不是替代你的工程师。
   "想做什么"、"做成什么样"、"出了 bug 谁背"——永远在你自己。

下章预告

到这里,你已经会让 Claude Code 完成单次编程任务了——从理解项目、修 bug、写测试、提交 PR,一条龙。

但 Claude Code 真正的杀手锏,不是单次任务——是让它替你 24 小时不下班地干活

第九章 自动化与定时任务(/loop 与 Hooks) 会教你三件事:

  • /loop 命令:让 Claude 在一个目标下反复迭代,直到达成或显式喊停。比如"持续优化这段代码,每轮跑一次 benchmark,直到性能提升 50% 或确认无可优化"。
  • Hooks 系统:在关键事件(commit 前、文件保存后、PR 提交后……)自动跑你写的脚本。让 lint、测试、部署、通知全自动化
  • 定时任务:把"每天早上 8 点收 RSS、提炼新闻、发企微"这种任务交给 Claude Code + cron / launchd,你睡觉它干活。

会用单次任务的 Claude Code 是会动手的助理,会用自动化的 Claude Code 是24 小时不下班的员工。下一章见。