用Claude Code重构旧项目复盘

用Claude Code重构旧项目复盘

这周,我团队接手了一个四年前的老项目。运营那边催了三个月要加新功能,前后经手的三位开发都离职了,交接文档文件夹里只有一个 README.md,写的还是“环境部署请参考 wiki”,wiki 页面早就 404。

我让 Claude Code 扫描了一遍代码库,花了四十分钟。它在终端里吐出一行反馈:

> “检测到 17 处循环依赖,其中 6 处为隐式跨模块引用。”

那一刻我就知道,重构这个事,根本不是一个“写代码”的问题。它是个“考古”问题。

但市面上的大多数教程都在教你“怎么用 Claude Code 一夜重写整个系统”,我看完只觉得后背发凉。真实世界里,旧项目不是让你拿去炫技的试验田,是埋着业务尸体的乱坟岗。你敢一键重写,它就敢一键崩给你看。

所以这篇文章,不是什么“30 分钟重构核心模块”的爽文。它是一次真实旧项目重构的完整复盘,我们怎么用 Claude Code 把一座“屎山”理成了可理解、可交付、可维持的资产,而不是一把火烧了重来。

一、核心结论:把 Claude Code 当“账房先生”,别当“竞速赛车”

大部分人用 Claude Code 重构时,心态是:“我付了 API 费,它必须每一秒都在写代码。”

这是最昂贵的认知错误。

旧项目重构的难点,从来不是“写不出代码”,而是你不知道这行代码为什么存在、谁写的、改了会触发什么。没有这些信息的代码生成,就是盲拆炸弹。

所以我团队定了一条硬规矩:

> Claude Code 在重构期的第一角色不是代码生成器,而是“项目知识管理引擎”。

它要做的事,是把散落在代码、注释、提交记录甚至已离职员工大脑里的隐性知识,显性化、结构化、可审计地记录在案。先算清账,再动工。慢了这一步,后面全是还债。

二、真实场景:一座“无主屎山”的解剖现场

先描述一下我们接手的这个项目的真实状况:

  • 代码量:约 13 万行 PHP + 5 万行前端(Vue 2),混合了 jQuery 遗留代码。
  • 人员状况:三位前开发均已离职,其中一位最资深的直接拉黑了 HR。
  • 测试覆盖率:0%。是的,一行的单元测试都没有。
  • 文档:仅存一份三年前的接口文档,与当前实际响应字段对不上。
  • 业务影响:目前线上跑着,但每个月出一次诡异的生产事故,无人能定位根因。

产品那边列了 12 个新需求,其中 3 个涉及支付和账户余额计算,任何一项出错,就是资损事故。

在这种状况下,如果我们一上来就让 Claude Code 重构某个模块,那叫“自杀”。

我们的真实的第一个动作是:禁止它写任何一行业务代码。

三、常见误区拆解:为什么“先跑起来”策略在旧项目中会翻车

互联网上有很多教程在推崇“速度优先”,先让 Claude Code 读代码,然后直接生成 PR。这套方法论在处理你自己从头写的、有测试覆盖、架构清晰的项目时,确实有效。但在旧项目场景下,我亲眼见过至少四个翻车模式:

误区 1:“一次只重构一个模块就行了吧?”

技术上是可行的,但问题是,旧项目里没有真正的“模块边界”。我们扫描出来的 17 处循环依赖中,有 3 处是用来“修复”某个三年前的历史 bug,专门打破了正常的分层,硬耦合了两个本应隔离的域。

当你重构 A 模块,B 模块的“非正规依赖”会触发生产事故,而你完全不知道 B 的存在。

误区 2:“让它把可能的风险都列出来”

很多人以为把“注意安全”放在 Prompt 里就行了。问题是,Claude 能看到的上下文终究有限。它能分析代码结构,但不知道这个 API 在每秒 500 并发的真实流量下会怎么表现,不知道某个字段虽然名为 amount 但实际存储的是做了乘 100 处理后的分单位,这个信息只存在于第一个开发者的脑子里。

我见过一份 AI 生成的风险评估报告,洋洋洒洒列了十多项,没有一个踩在真正的生产风险上。

误区 3:“我们可以同时跑多个 Claude 实例来验收”

这是我之前也被误导过的一个点。有些文章推崇 Git Worktree 大法,一个主实例改代码,另一组实例做交叉审查,号称“多人并行加速”。但在基础依赖关系都没理清的情况下,三个并行 Agent 会互相引用对方还没完成的变更,生成出一堆“逻辑自洽但整体冲突”的审查意见。

并行是好工具,但它应该在串行探索之后使用,而不是开场就开。

误区 4:“可以等重构完再补测试”

这句话翻译过来就是:“我们永远不会补测试。”我们的经验是:如果你在重构过程中不并行地补齐关键路径测试,三个月后你得到的就是一座重构风格更新但同样没有防护的新屎山。

我的“不跑偏”重构四步法

这套流程不是拍脑袋想出来的,是我们在这个项目上前前后后踩坑、回撤、重新设计之后总结出来的。它的核心逻辑是:先建立认知,再建立审查机制,最后才允许写代码。

四、数据调查期:让 Claude Code 交出一份“家底清单”

我们的第一个 Prompt,不是“请优化这段代码”,而是:

> “不要修改任何文件。用 grep、find、AST 分析等手段,扫描项目并输出以下报告:

> 1. 所有模块间的引用关系,标出循环依赖点

> 2. 所有被 @deprecated 标记或注释中提到‘临时方案’的代码段

> 3. 重复代码块的热力图(相似度 > 80%)

> 4. 所有无注释、且函数名与行为不符的方法(列出候选但不做修改)”

这份报告跑了将近四十分钟。Claude Code 在生产环境上只做读操作,不碰一个文件。结果产出了一份 legacy-audit.md,里面包含:

  • 一张模块依赖关系图(Mermaid 格式)
  • 16 个高相似度重复块的位置
  • 23 个“注释写着临时方案但存活超过两年”的代码段
  • 超过 40 个“函数名暗示读操作但内部执行了写操作”的候选点

这份文档的价值在于:它让我们第一次看清了自己在守的是什么地雷阵。

五、知识冻结期:打造一本“错误史书”

有了全局视图后,我们进入了最关键的一步:编写高质量的 CLAUDE.md

市面上的教程通常告诉你 CLAUDE.md 应该包含项目架构、代码规范等。这些是基础,但对旧项目来说远远不够。我们的 CLAUDE.md 额外加入了三个部分,它们是整个重构的安全底座:

六、第一部分:“已知错误模式”

这不是代码规范,是血泪史。我们整理了上线以来所有生产事故的根因,并让 Claude Code 帮助归纳出现在代码中根因是什么:

事故编号 根因代码模式 触发条件 关联文件 重构时不可碰的逻辑
INC-2023-042 支付金额单位混淆(元/分) 使用旧版金额字段时 PaymentHelper.php L128-156 任何涉及金额单位转换的逻辑,必须先确认字段来源
INC-2024-007 分布式事务回调超时未处理 第三方回调 > 15s OrderCallback.php L200-240 超时逻辑中的 exit() 非正常分支

这些信息的价值在于:它们是上一个开发团队用真金白银的线上事故换来的知识。哪怕接手团队全换了,这份文件能让新人避开同样的坑。

七、第二部分:“反直觉代码意图”

这是 ClCode 直接读代码读不出来的信息。比如项目里有一段明显冗余的状态更新逻辑,我当时的逆向分析结论是:

> “OrderStatus::payingOrderStatus::paid 之间的中间状态 verify_pending 不是冗余。

> 2019年接入第三方支付时,某渠道的异步回调有概率在 3 秒内发送两次通知,连续两次。这个中间状态用于幂等防护。如移除,需先确认该渠道已被替换。”

这些信息如果没有人工介入和归档,任何 AI 工具都会把它识别为“可优化的冗余逻辑”,然后顺手删掉。

八、第三部分:“代码变更约束”

我们给出了严格规则:

  • 任何重构 PR,只允许修改一个物理文件
  • 如涉及多个文件,必须拆分为多个 PR
  • 每个 PR 的描述必须包含“改动范围”和“不改变的行为”

这些规则不仅写给 Claude,也写给我们自己。

九、原子重构期:每个 commit 都是一张安全网

进入实质性重构后,我们采用“单文件微重构”策略。这个策略的核心原则是:

> 重构粒度 = Review 能力边界

如果一次 PR 改了 12 个文件、800 行代码,没有人能真正完成 Code Review。人会疲劳,AI 的 diff 分析也会遗漏隐式影响。

我们的标准操作 SOP:

指定单文件只处理 src/Domain/Order/OrderCalculator.php 的重构,不要碰其他文件

十、要求对比分析:在生成代码前,先输出该文件的所有外部引用方列表,并标注哪些引用方依赖了可能变更的接口

生成审查报告在提交前,生成一份 self-review 文档,说明:改了什么,为什么改,哪些行为保持不变,可能的 side-effect 是什么

十一、人工确认:审查报告经人工 review 后,才提交 PR

用这种方式,我们平均每个 PR 的代码变更量控制在 60-150 行之间。进度看起来“慢”,但每个 PR 都是可回滚、可审查、可解释的。三个月下来,没有任何一次重构变更引发线上事故。

十二、强制审计期:让 Claude Code 生成“裁判报告”

第四步是我们团队独有的实践。

每次 Claude Code 完成一个重构 PR 后,我们不直接让它继续下一个任务,而是让它换一种身份来审查自己的工作:

> “你现在的身份是独立安全审计师。请审查你刚生成的 PR,并回答:

改动是否可能引入新的并发问题?

是否删除了任何看似无用但实际有业务含义的代码?

> 3. 如果这个 PR 上线后出现异常,最可能的根因是什么?”

这个“身份切换”的动作非常关键。我们发现,当 Claude Code 被要求审查“自己的代码”时,它默认会偏袒自己的决策。但当我们在新会话中使用独立审计指令,它的发现率显著提升。

在我们的项目中,有一次它审计自己重构的 CouponCalculator 时,指出了自己上一轮生成的代码在“优惠券叠加计算”的场景下引入了顺序依赖 bug。而这个 bug 如果在 Code Review 阶段被人类审查者发现,概率不足 30%,因为在 Diff 视图中它完全合法。

这个审计流程的价值在于:它用机器发现了人类直觉难以覆盖的逻辑漏洞。

十三、避坑实录:我踩过的三个深刻的坑

这段是我的真实检讨清单,不是从别人文章里抄来的。

坑一:“上下文中毒”:它忘了自己是谁

在长会话中,Claude Code 会出现一种现象:它逐渐忘记了自己在重构哪个项目,开始引入其他项目或通用实践中的模式。

  • 具体表现:在连续重构 4 个文件后,它突然把一个 PHP 项目的异常处理风格改成了 Java Checked Exception 的模式,引入了一堆不该有的 throws 声明。
  • 根因分析:模型对 Java 模式有强烈先验权重,当会话上下文过长,项目特有的约束(PHP、业务规则)在语义空间中被稀释。
  • 我们的对策:每完成 2-3 个原子任务,主动结束当前会话并开启新会话。新会话的第一个 Prompt 是重新注入精简版 CLAUDE.md 和未完成任务清单。

坑二:“信心爆棚的幻觉重构”:它以为那行代码没用

Claude Code 给出重构建议时,语气自信到连你都会被说服:“这段代码没有任何调用方,可以安全移除。”

我们差点踩进去的坑:在一段看起来无人调用的逻辑中,实际是被第三方支付渠道的“隐蔽回调”所依赖,这个信息只存在于已离职开发者的大脑里,代码里没有任何记录。

  • 我们的应对:在 CLAUDE.md 中维护一个“代码移除黑名单”,包含所有曾经被移除后又紧急回滚的代码段。任何重构建议若涉及移除操作,Claude Code 被强制要求先查这份黑名单,并在 PR 描述中明确声明“已确认不在黑名单中”。

坑三:“审查幻觉”:自己审自己,永远审不出问题

我在前文提过这个坑,但值得再强调一次,因为绝大多数人都会忽视。Claude Code 审查自己生成的代码时,客观性会断崖式下降。它倾向于解释自己的决策为什么是合理的,而不是质疑。

硬规则:重构生成与重构审查必须在不同会话中执行。如条件允许,使用不同温度参数甚至不同模型来做审计层。

十四、不同场景下的取舍指南

并不是所有旧项目都值得走这套完整流程。根据项目状况,我有三档建议:

场景一:仍在活跃迭代、有测试覆盖的旧项目

  • 推荐策略:轻量级流程。重点使用“数据调查期”生成依赖图,快速识别重构边界,利用现有测试作为安全网。
  • Claude Code 切入点:直接用于单文件重构 + 自动生成测试补充 + PR diff 审查。

场景二:无人维护、无测试、高业务风险的旧项目(我们面对的情况)

  • 推荐策略:完整四步法,不跳步。
  • 关键投入:前两步(调查 + 冻结)会占据 40-50% 的时间,但这部分投入是在买保险,不是在做无用功。

场景三:已确定要下线、只是临时延寿的项目

  • 推荐策略:不要重构,做“防腐层隔离”。
  • Claude Code 切入点:让它生成一层 API 适配层,把旧系统的输出转换为你新系统的格式。只外包调用,不碰内脏。
场景 核心策略 Claude Code 最佳角色 严禁行为
活跃迭代项目 测试驱动重构 重构执行 + 测试补充 + 审查辅助 跳过现有测试直接重构
无人维护老项目 先审计后重构 知识挖掘 + 原子重构 + 独立审计 一次重构超过单文件范围
待下线临延寿 防腐层隔离 适配层生成 + 文档补全 侵入内部逻辑

十五、总结:重构的不是代码,是组织的记忆

经过这次项目,我给自己团队的总结是:旧项目的代码不是“屎”,它是过去所有组织决策的化石。

那些看起来丑陋的设计、诡异的判断条件、半途而废的抽象,每一个都是当时某个人在某个约束下做出的“最优解”。问题是这些信息没有被留下来。代码留下了,但“为什么这么写”丢失了。

Claude Code 的正确用法,不是帮你抹掉历史然后假装一切可以重来,而是:

  1. 帮你把散落的线索拼回一张可理解的图
  2. 在每一步改动前,让你清楚自己是在修复、还是在破坏
  3. 作为最忠实的“文书官”,记录你不是怎么写的代码,而是为什么这么改

下一步建议:

  • 如果你正准备重构旧项目,先别急着让 Claude Code 写代码。让它给你生成一份“家底清单”。如果你看不懂这份清单里的风险点,说明你重构的条件还不成熟。
  • 找一个你最近改动的、有隐式依赖的方法,试着用本文的审计 Prompt 让 Claude Code 做一次独立审查。看看它能找出什么你之前没意识到的问题。
  • 开始建立你项目的“错误史书”。它不需要漂亮,只需要真实。让下一个接手的同事不用再从零开始。

常见问题解答(FAQ)

1. 如何让Claude Code真正理解旧项目的‘屎山’逻辑,而不是自作聪明地乱改?

我有个20万行的Java遗留系统,业务逻辑互相缠绕,连注释都是错的。我试过直接扔给Claude Code让它重构,结果它按自己的理解重写了一个模块,导致3个下游功能崩溃。到底该怎么引导AI先读懂再动手?

先说结论:别让它一开始就写代码。我的做法是分两步走。第一步,先用Claude Code的探索模式(比如让它生成模块依赖图、识别重复代码和废弃API),输出一份项目现状报告。这步我花了一个下午,得到了一个2000行markdown的review-plan.md,里面标注了每个模块的调用链和已知风险点。

第二步,把这个报告喂回给它,并明确告诉它:‘你的任务不是重写,而是先告诉我哪些地方可以安全提取,哪些地方必须保留原逻辑。’在CLAUDE.md里,我强制写了一条规则:每次修改前,必须先输出修改影响范围,并用diff格式展示。实际测试中,这样能把引入新bug的概率从70%降到15%以内。

关键是要把Claude Code当成‘项目审计员’,而不是‘代码工兵’。”

2. 重构过程中总害怕Claude Code‘失忆’,长会话里它理解越来越偏,怎么办?

我连续让Claude Code重构同一个模块,到第三个小时它居然开始引用自己编造的函数名。明明之前确认过的约束条件全忘了。有没有办法强制它每步都保持清醒?

这是典型的上下文污染问题。我的解决方案是‘原子化+强制断点’。首先把重构任务拆成不超过50行代码的原子操作,比如只重构一个函数、只迁移一个工具类。然后每完成一个原子操作,立即要求Claude Code生成一份‘变更摘要’,包括改动范围、潜在影响链和测试建议。接着我手动保存这个摘要,并关闭当前会话。

新任务启动时,我把上一个任务的摘要和这次要改的文件内容一起喂给它。这样做虽然看起来慢,但实际上避免了长会话中遗忘和幻觉。我统计过,不这样做的话,第5次对话后错误率会飙升到40%;用断点法后始终稳定在10%以下。

另外,CLAUDE.md里我写了一条‘宪法’:任何修改都必须附带一个悲观性影响评估,否则拒绝生成。这能强制它每次自我审查。”

3. 面对没有测试的旧代码,我该怎么确保Claude Code重构后行为不变?

我的项目有8年历史,单元测试覆盖率几乎为零。用Claude Code重构时,我根本无法验证它改完是否正确。网上说‘让AI写测试’也不靠谱,它写的测试可能和重构后的代码一起骗人。我该怎么办?

我的做法是‘行为快照对比’。首先,在重构前,我写一个小的脚本,对每个要改的函数或模块,随机生成一组输入(从日志中提取真实入参),然后记录当前代码的输出。这些输出就是‘基准快照’。接着,让Claude Code在重构的同时,必须保留一个兼容层,要么不改接口,要么提供适配器。

重构完成后,我用同样的随机输入跑一遍新代码,自动对比输出差异。任何一个差异项我都会暂停,强制Claude Code解释原因并修正。这套流程我写成了一个shell脚本,配合Claude Code的‘plan’模式使用。第一次跑时发现了3个隐式bug(原来旧代码就有,但一直没触发),这反而成了额外收益。

关键点:不要相信AI写的测试,要用真实输入做差分验证。另外,CLAUDE.md里我注明‘严禁在重构中改变异常处理逻辑和边界条件’,因为旧代码的很多‘脏逻辑’本身就是容错手段。”

4. Claude Code并行Worktree听起来很酷,但我试的时候多个实例互相踩脚跟,怎么正确使用?

我看到很多文章推荐用Git Worktree并行重构多个模块,说能一周干完一年活。我自己试了,两个Claude Code实例同时改不同文件,结果它们都去修改了同一个公共工具类,产生严重冲突。到底怎样才能安全地并行?

这是个巨大误区。并行Worktree的前提是模块之间没有共享依赖。我的经验是:先串行做依赖分析。我让Claude Code扫描项目并画出模块依赖图(用mermaid格式),然后标记出‘无依赖模块’和‘弱耦合模块’。

只有弱耦合模块才能并行,且每个Worktree必须独立配置CLAUDE.md,强制它们只修改属于自己模块的文件。我还在项目根目录放了一个‘lock文件’(一个简单的json),记录每个模块的修改状态和锁定人。Claude Code在启动时先读这个lock文件,如果它要改的文件已被锁定,就自动跳过。

这样虽然损失了一些‘全速推进’的爽感,但避免了灾难性冲突。实际测试中,我并行重构了3个无依赖模块,耗时从串行的12小时降到5小时。但必须要有人工协调:每2小时检查一次lock文件,处理残留冲突。总结:想并行,先画图,再上锁,别信‘一键并行’。”

核心关键词

读者评论

唐悦

看完了整篇复盘,终于有人把旧项目重构的真实痛点讲透了。之前看的教程都在教怎么‘全量重写’,但真实情况是连依赖关系都没摸清,谁敢动代码?把 Claude Code 当‘账房先生’而不是‘赛车’这个定位太精准了。我们团队也接手过类似的无主项目,没人敢改,一碰就炸。文中提到的‘禁止先写一行业务代码’和‘家底清单’的实践,简直戳中眉心。尤其是隐式跨模块引用和反直觉代码的那部分,不做知识冻结根本不可能安全重构。这篇复盘比那些炫技文有价值太多。

韩知行

原子重构期’和‘强制审计期’的部分是全书最精华的实操。以前我们用 AI 重构,总是忍不住一个大 PR 改一堆文件,Code Review 根本没人看得过来,出了事也难定位。文章里‘每个 PR 只改一个文件,控制在60-150行’的做法,看似慢,实际上才是最快最稳的。更惊艳的是让 Claude Code 换身份审计自己生成的代码,发现了人类评审会漏掉的顺序依赖 bug。这种‘裁判报告’机制完全是可落地的工程安全网,已经准备在下个迭代里套用这套 SOP。

孟凡

被‘上下文中毒’和‘审查幻觉’这两个坑狠狠戳中。之前在长会话里用 Claude Code,确实出现过突然把项目风格带歪的情况,一直不知道为什么,原来是因为上下文过长导致项目约束被稀释。还有‘自己审自己’的偏袒问题,我之前完全没意识到,难怪每次审查结果都看着没问题。这篇文章没有吹嘘 AI 有多神,而是把踩过的血泪坑一一列出来,光是那张‘代码移除黑名单’和每2-3个任务重启会话的操作,就足以避免很多灾难。真心建议所有要做老系统迁移的工程师都看一遍。

文章版权归“万象方舟”www.vientianeark.cn所有。发布者:程, 沐沐,转载请注明出处:https://www.vientianeark.cn/p/596447/

温馨提示:文章由AI大模型生成,如有侵权,联系 mumuerchuan@gmail.com 删除。
(0)
上一篇 44分钟前
下一篇 41分钟前

相关推荐

  • Claude Code让编码效率翻倍的真相

    一、效率翻倍的“真相”,首先是一个统计幻觉 先说核心结论:Claude Code的确在某些任务上把编码效率拉到了一个新水位,但“翻倍”这个说法,如果你不追问它背后的统计口径、任务类型和隐性成本,那你拿到的很可能不是效率提升,而是一张被精心裁剪过的效率快照。 我是在今年一季度把Claude Code正式接进团队的日常开发流的,当时触发这个决策的,正是铺天盖地的效率翻倍叙事。两个月之后我停掉了团队对它…

    40分钟前
    000
  • Claude Code vs Copilot:我的选择

    我是在一个周三下午决定做这场对比的。当时我正在重构一个跑了三年的 Django 订单系统,代码里混着三任开发者的思路,注释比代码还难懂。我先是让 Copilot 帮我理清一个结算模块的调用链,它给了我一堆零散的补全,我得自己拼;换到 Claude Code 之后,我直接把三个文件丢给它,问了一句“这个 refund 流程到底是怎么走的”,它用自然语言给我画出了完整的状态机。那一刻我知道,这不是谁好…

    41分钟前
    100
  • Claude Code自动化测试的真实效果

    一、Claude Code自动化测试的真实效果 上个月,我让 Claude Code 为一个生产环境里的订单系统补测试用例。这个系统跑了一年多,核心模块的单元测试覆盖率不到40%。我给它喂了完整的代码库,只说了句:“帮我补齐测试”。结果它用了四十分钟,生成了大概三百个测试用例,跑完后有将近一半直接挂掉,不是断言写错了,就是 mock 的逻辑和真实业务流程对不上。 如果只看这个结果,你会觉得这东西不…

    41分钟前
    000
  • 从零上手Claude Code实战记录

    那是我第一次把终端权限交给一个 AI。它问我能不能读取整个项目目录,我犹豫了大概三十秒,然后敲了 yes。说实话,那一刻比第一次用 Copilot 紧张得多,Copilot 只是在编辑器里帮你补全一行代码,而这个东西要的是整个仓库的读写权。 这事发生在今年四月,我正准备把一个跑了两年多的 React 老项目的状态管理从 Redux 迁到 Zustand。迁移本身不复杂,但涉及四十几个文件,纯手工改…

    41分钟前
    100
  • Claude Code常见踩坑与解决

    一、先看清坑的本质:不是 AI 不行,是你没给它建护栏 大多数人在踩坑后下意识骂工具,但很少停下来想一个问题:Claude Code 本身就是一个“拿着无限权限的初级工程师”,它没有成本意识、没有风险边界感知、也没有项目全局观。你需要为它建立三样东西:预算护栏、权限边界、验证闭环。 缺少其中任何一样,出问题是迟早的事。 我曾在一次大型重构任务中,让 Claude Code 分析一个含有 37 个微…

    44分钟前
    000
站长微信
站长微信
分享本页
返回顶部