今年二月开始正经用 Claude Code,到现在三个月。用法和刚开始完全不一样:最早我只在卡住的时候让它写个小函数,现在会把整块重构任务丢给它,但会要求自己每一条 diff 都看过。这个转变不是因为更信任它,而是因为吃了一次亏。
一、第一阶段的用法:当补全用
刚开始我把它当"更聪明的补全"。比如一个解析查询串的小方法,我不会写,就直接在编辑器里说"给我写个把 a=1&b=2 拆成字典的函数",它给出来,我贴进去,跑通就完事。这个阶段它确实省时间,但用的频率不高,因为真正难的地方不在这种小函数。
那时候我有个错觉:它写得都对。后来证明只是因为小函数出错一眼就能看出来。
二、那次把命名规范搞乱的事故
转机是一次我让它重构一段老查询。原来的 LINQ 是这么写的,嵌套了好几层:
var list = db.Orders
.Where(o => o.Status == 1)
.Select(o => new { o.Id, o.Amount })
.ToList();
我让它"把这段改成更清晰的分步写法,并加上按 CreateTime 倒序"。它改出来的 LINQ 逻辑确实对了,查询出来的数据和之前一致。但问题出在命名:它把局部变量从 list 改成了 orderDtos,又把方法里的 o 换成了 x,还顺手把旁边两个完全不相干的方法里的同名变量也一起改了。
我们团队的规范是查询结果的集合用复数名词、lambda 参数统一用 o。它这一改,和我司的 .editorconfig 对不上,CI 的命名检查直接红了。我 review 时只盯着 LINQ 逻辑,没注意命名,合进去之后另一个同事提了一句我才发现。
这件事让我明白:它"看起来在帮你整理代码"的时候,最容易在你没盯着的角落动手。逻辑对不等于可以放心。
三、现在的用法:限定文件 + 盯 diff
从那以后我定了个规矩,每次调用都明确告诉它范围。我的常用写法是这样的,先给白名单再给任务:
# 只改这两个文件,不要碰其它任何文件
claude "只修改 src/Reports/OrderQuery.cs 和 src/Reports/OrderQueryTests.cs,
把 OrderQuery 里的嵌套 LINQ 改成分步写法,加 CreateTime 倒序,
其余文件一律不要动,命名保持 o / list 不变"
配置上我也在项目根目录放了个 CLAUDE.md,把这些约定写死:命名规则、禁止修改的文件、跑测试的命令。这样它每次启动都能读到,比我在对话里反复说一遍省事。
# CLAUDE.md 节选
- 命名:集合用复数,lambda 参数统一用 o
- 禁止修改:appsettings*.json、*.config、Migrations/
- 改完必须本地跑 dotnet test 再告诉我结果
这一步我其实晚了一个月才做,早做的话前面那次命名事故大概率不会发生。现在想有点后悔,但当时觉得"写个说明文件"很麻烦。
四、什么任务我交给它,什么不交
三个月下来,我交出去的多半是"范围清楚、能跑测试验证"的活:抽方法、补单元测试、把一段重复代码改成循环。不交的是"要先理解业务历史"的活,比如一个字段为什么有特例值,这种它不知道背景,编出来的理由很危险。
另外我养成一个习惯:凡是它改过的文件,我一定用 git diff 过一遍再提交,平均每次能挑出一两处"逻辑没问题但我不想要"的改动。这个动作现在花的时间,比我当初省下的还多,但我觉得值。
五、一次让我放心交出去的任务
也不能只说它闯祸。上个月有个活我挺放心地交给了它:把一个报表导出从同步改成后台任务,涉及把原来的 ExportService 拆成"入队—执行—轮询状态"三步,还要补单元测试。我给了它三个文件作为参考,明确说"只动 Export 这一块,命名沿用现有风格",然后就去开了个会。
回来一看,它产出的代码结构基本可用:入队接口、一个继承 BackgroundService 的执行器、再加状态表。我 diff 下来,逻辑是对的,只有两处要调——一处它把轮询间隔写死成了五秒,我改成读配置;另一处它漏了"导出中"状态的并发保护,我补了把锁。总共改了不到二十行,骨架全是它搭的。
这次之所以顺利,回头看是因为任务边界清楚、又有现成文件当范本。换句话说,它擅长的是"在已知套路里填空",不擅长的是"在没有先例的地方开路"。把活拆成前者,我俩配合就顺;塞成后者,就回到第二节能乱改命名的状态。
六、给后来想用的同事的建议
组里有人问我值不值得用,我的回答是:先把"只动指定文件"和"改完必 diff"这两件事刻进习惯,再谈效率。否则省的那点打字时间,会在某次它悄悄改错一个地方时一次性赔回去。我现在甚至会在重要的任务前先让它复述一遍"你打算改哪些文件、不动哪些",它说不清的时候,我就知道这任务还不能交。