再学 AI
第 19 课 / improve-codebase-architecture
当前 · 工程阅读 → 对照 → 问答 → 场景

先找真实摩擦,再讨论重构

它扫描架构中妨碍理解、修改和测试的地方,形成候选报告;选中后才进一步讨论方案。

还不清楚 Skill、Agent、安装和调用?先读 从零开始的6节入门课

在关系图中查看 improve-codebase-architecture 与其他技能的关联 →

先把必要的概念讲清楚

这项技能帮助发现值得整理的代码结构,先形成候选与讨论,再决定是否改。你要学会看“为什么值得改”和“改完怎样证明行为没坏”。

下面是老师补充的入门说明;原作者的要求保留在中英对照正文中。所有例子均为帮助理解而构造的教学情境。

deep module|深模块

用相对简单的公开接口封装较多内部复杂性。调用者只说“为这节课生成复习安排”,模块内部处理规则、时间和重复项。深是接口与实现复杂性的关系,不是目录嵌套深,也不是函数越长越好。

module|模块

承担一组相关职责的代码单元,可以是文件、包或服务,不必等于一个文件。学习进度模块可以公开“记录进度”和“查询进度”,把计算完成比例、保存数据等细节藏在内部。划分是否合理,要看职责和依赖,不能只数文件。

seam|测试接入点

作者在测试语境中指测试进入系统、触发行为并观察结果的公共边界。例如调用“收藏课程”接口,再通过“我的收藏”接口检查结果。入口可以是模块公开函数、服务接口或页面,并非一定是浏览器。选择高层稳定入口能覆盖内部多个步骤;入口少不等于测试场景少。

refactoring|重构

在保持约定外部行为的前提下改善内部结构,例如合并重复逻辑、调整职责归属。用户仍能完成同样操作,但代码更容易理解和修改。重构不等于顺便加新需求;测试帮助证明外部行为未被意外改变。

interface / API|接口

使用者与一项能力交互时遵循的约定,包括可调用什么、传入什么、得到什么、失败怎样表示。接口可以是程序函数,也可以是网络请求。创建收藏接口接收用户和课程信息、返回收藏结果;它不需要向调用者暴露数据库表结构。这里的接口通常不是指页面外观。 本教材涉及更广义的“接口”时,还包括错误、调用顺序和约束等使用约定;不能把接口一概等同于网络 API。

读原文,理解每一步为什么这样做

左右内容按小节对应;窄屏先中文、后英文。两种语言均完整展示,对应讲解紧接在小节之后。译文传达原文要求;老师讲解补充概念、原因、例子与适用边界。

中文译文English · 英文原文
中文译文
name: improve-codebase-architecture
description: "扫描代码库寻找加深模块的机会,以 HTML 可视化报告展示,再围绕用户选中的候选开展深入访谈。"
disable-model-invocation: true
English · 英文原文
name: improve-codebase-architecture
description: Scan a codebase for deepening opportunities, present them as a visual HTML report, then grill through whichever one you pick.
disable-model-invocation: true
中文译文

寻找值得改善的代码结构

找出架构让人理解、修改和测试代码时遇到的实际困难,并提出加深模块的机会:通过重构,把对外用法复杂、内部承担工作很少的浅模块,改成对外用法简单、内部承担更多复杂工作的深模块。目标是改善可测试性,并让 AI 更容易在代码库中找到和理解所需内容。

这项工作以项目的业务模型为依据,同时使用一套共同的设计词汇:

  • 通过 Skill 工具加载 codebase-design,采用其中关于模块、接口、深度、衔接位置、适配器、调用收益和修改集中性的词汇,以及相应原则:假想删除检查、接口就是测试使用面,以及“一个适配器只表明假想的衔接需求,两个适配器才使这种需求成为真实”。每项建议都准确使用这套名称,不要随意换成 component、service、API 或 boundary 等其他说法。
  • CONTEXT.md 中的业务语言帮助你为合适的衔接位置命名。docs/adr/ 中的架构决策记录,则说明哪些决定已经作出,不应在这次审查中无缘无故重新争论。
English · 英文原文

Improve Codebase Architecture

Surface architectural friction and propose deepening opportunities: refactors that turn shallow modules into deep ones. The aim is testability and AI-navigability.

This command is informed by the project's domain model and built on a shared design vocabulary:

  • Call the Skill tool with "codebase-design" for the architecture vocabulary (module, interface, depth, seam, adapter, leverage, locality) and its principles (the deletion test, "the interface is the test surface", "one adapter = hypothetical seam, two = real"). Use these terms exactly in every suggestion, and don't drift into "component," "service," "API," or "boundary."
  • The domain language in CONTEXT.md gives names to good seams; ADRs in docs/adr/ record decisions this command should not re-litigate.
中文译文

执行过程

English · 英文原文

Process

中文译文
1. 先确定范围,再探索

先决定看哪里,再开始扫描。 原文用 YAGNI 提醒你,不要为尚不存在的需要提前做设计。加深模块的收益,在于以后修改它更容易,因此应更加关注近期经常变化的代码区域。

  • 如果用户已经指定方向,例如某个模块、子系统或实际痛点,就沿着这个方向查看,跳过下面的推断过程。
  • 如果没有指定方向,就使用 git log --oneline 往回查看足够一段提交历史,找出反复出现的文件和区域,优先关注这些变化热点。如果改动非常分散,看不出明显热点,再扩大探索范围。

先阅读项目的业务术语表 CONTEXT.md,以及本次所涉及区域的 ADR。

随后启动一个子 Agent 探索代码库。不要机械套用僵硬的判断规则,而应在实际阅读时记录遇到的阻力:

  • 理解一个业务概念,是否需要反复跳转于许多小模块之间?
  • 哪些模块的接口几乎与内部实现一样复杂,因而属于浅模块?
  • 哪些纯函数只是为了方便测试才被提取出来,而真正的 bug 却藏在调用方式中,相关逻辑没有集中在容易理解和验证的位置?
  • 哪些紧密相关的模块,把本应留在内部的细节泄露到了彼此的衔接位置之外?
  • 哪些代码尚未被测试,或者很难通过现有接口进行测试?

对疑似浅模块进行假想删除检查:如果删掉这个模块,复杂性会集中到一个更合适的位置,还是只是被搬到别的地方?“确实能使复杂性更集中”是值得继续调查的信号。

English · 英文原文
1. Explore

Scope before you scan: YAGNI. Deepening a module pays off by making future changes to it easier, so put extra weight on the parts of the codebase that have recently changed. Decide where to look before you look:

  • If the user named a direction (a module, a subsystem, a pain point), take it, and skip the inference below.
  • Otherwise, walk back a good stretch of the commit history (git log --oneline) to find the codebase's hot spots, the files and areas that keep coming up, and let those paths pull your attention first. If the changes are scattered with no clear hot spot, widen the net.

Read the project's domain glossary (CONTEXT.md) and any ADRs in the area you're touching first.

Then spawn a sub-agent to walk the codebase. Don't follow rigid heuristics; explore organically and note where you experience friction:

  • Where does understanding one concept require bouncing between many small modules?
  • Where are modules shallow, with an interface nearly as complex as the implementation?
  • Where have pure functions been extracted just for testability, but the real bugs hide in how they're called (no locality)?
  • Where do tightly-coupled modules leak across their seams?
  • Which parts of the codebase are untested, or hard to test through their current interface?

Apply the deletion test to anything you suspect is shallow: would deleting it concentrate complexity, or just move it? A "yes, concentrates" is the signal you want.

老师讲解 · 对应上方原文 · 含教学举例

架构问题要从实际理解成本中发现

探索时观察调用关系、重复知识、隐藏依赖和测试边界。例如 AI 每次改课时完成条件,都需要同时调整统计、提醒和页面三个不同实现,这可能意味着业务规则散落。

不要只依据目录不漂亮或函数很长就判定坏架构。真正有价值的候选应指出某种修改为何困难,哪些调用者被迫知道内部细节,以及集中职责后可能节省什么工作。

这里的扫描是调查,不是默认把整个仓库重写。真实项目越大,越需要清楚候选范围与证据。

先说明维护哪里费劲,再讨论改结构有什么收益

假设三个页面都自己调用模型、解析题目、补缺字段。模型格式一变就得修改三处,还常漏一处。这是具体维护困难,不只是“代码不够优雅”。

改进候选可以是建立出题模块,页面通过简单入口获取已校验结果。报告应指出实际重复位置,展示前后调用关系,并解释一次修复怎样让多个页面受益。

看提交历史,是为了找反复变化、改善后可能很快受益的区域。很少改动且没有实际困难的模块,仅因短或小,不一定值得重构。

报告先帮你挑值得解决的问题,选中后再设计接口。如果已有 ADR 要求某些流程分离,应说明为何现有证据值得重审,不能为了统一形式直接推翻。

假想删除的核心是减少无价值转发,同时避免把集中承担的复杂性重新撒到调用者。它是帮助思考的测试,不是机械删除命令。

中文译文
2. 用 HTML 报告展示候选

把报告写成一个独立 HTML 文件,保存在操作系统临时目录中,避免报告文件进入代码仓库。先查找 $TMPDIR;没有时使用 /tmp,Windows 则使用 %TEMP%。文件名采用 architecture-review-<timestamp>.html,让每次运行都生成一个新文件。

使用相应系统的打开命令为用户打开报告:Linux 使用 xdg-open <path>,macOS 使用 open <path>,Windows 使用 start <path>。同时告诉用户报告的绝对路径。

报告通过 CDN 引入 Tailwind 处理布局和样式。当图形能准确表达调用关系、依赖关系或动作顺序时,通过 CDN 引入 Mermaid 绘图。也可以结合手写的 CSS 或 SVG:关系适合用图时采用 Mermaid;要表现模块大小、剖面或折叠变化时,采用定制的页面元素或 SVG。每个候选都要有修改前与修改后的视觉对照

每个候选用一张卡片展示,包含:

  • 涉及文件:会影响哪些文件或模块。
  • 当前问题:现有架构为什么让理解、修改或测试变得困难。
  • 改进办法:用容易理解的自然语言说明准备改变什么。
  • 预期收益:从修改能否集中、调用者能否用较少知识完成更多工作,以及测试如何改善这几个角度解释。
  • 改前与改后示意图:并排展示当前浅模块的问题,以及加深后会形成什么结构。
  • 推荐程度:使用 StrongWorth exploringSpeculative 其中一种徽标,分别表达强烈推荐、值得进一步探索、仍属推测。

报告最后增加最优先建议:说明你会先处理哪个候选,以及选择它的理由。

业务概念使用 CONTEXT.md 中的词汇,架构概念使用 /codebase-design 中的词汇。例如,术语表已经定义 Order,就说“订单接收模块”,而不是只说难懂的 FooBarHandler,也不要随意改叫“订单服务”。

如果某个候选与已有 ADR 冲突,只有在当前困难确实足以支持重新考虑该决定时,才把它列出来。在卡片中明确标注,例如:“与 ADR-0007 冲突,但值得重新讨论,因为……”不要把所有理论上能做、却被已有决定禁止的重构都列入报告。

完整报告结构、图示方式和样式指导,见 HTML-REPORT.md

此时还不要提出具体接口设计。 写完报告后,先问用户:“你想深入讨论其中哪一个?”

English · 英文原文
2. Present candidates as an HTML report

Write a self-contained HTML file to the OS temp directory so nothing lands in the repo. Resolve the temp dir from $TMPDIR, falling back to /tmp (or %TEMP% on Windows), and write to <tmpdir>/architecture-review-<timestamp>.html so each run gets a fresh file. Open it for the user (xdg-open <path> on Linux, open <path> on macOS, start <path> on Windows) and tell them the absolute path.

The report uses Tailwind via CDN for layout and styling, and Mermaid via CDN for diagrams where a graph/flow/sequence reliably communicates the structure. Mix Mermaid with hand-crafted CSS/SVG visuals: use Mermaid when relationships are graph-shaped (call graphs, dependencies, sequences), and hand-built divs/SVG when you want something more editorial (mass diagrams, cross-sections, collapse animations). Each candidate gets a before/after visualisation. Be visual.

For each candidate, render a card with:

  • Files: which files/modules are involved
  • Problem: why the current architecture is causing friction
  • Solution: plain English description of what would change
  • Benefits: explained in terms of locality and leverage, and how tests would improve
  • Before / After diagram: side-by-side, custom-drawn, illustrating the shallowness and the deepening
  • Recommendation strength: one of Strong, Worth exploring, Speculative, rendered as a badge

End the report with a Top recommendation section: which candidate you'd tackle first and why.

Use CONTEXT.md vocabulary for the domain, and the /codebase-design vocabulary for the architecture. If CONTEXT.md defines "Order," talk about "the Order intake module," not "the FooBarHandler," and not "the Order service."

ADR conflicts: if a candidate contradicts an existing ADR, only surface it when the friction is real enough to warrant revisiting the ADR. Mark it clearly in the card (e.g. a warning callout: "contradicts ADR-0007, but worth reopening because…"). Don't list every theoretical refactor an ADR forbids.

See HTML-REPORT.md for the full HTML scaffold, diagram patterns, and styling guidance.

Do NOT propose interfaces yet. After the file is written, ask the user: "Which of these would you like to explore?"

老师讲解 · 对应上方原文 · 含教学举例

候选报告应支持你作取舍

HTML 报告是一个可阅读的决策材料。它应说明哪里值得改、当前结构如何造成问题、可能怎样加深模块以及怎么验证。仅给模块评分和一堆图,仍然不能帮初学者判断。

**例子:**候选 A 把三处完成条件集中到学习进度模块,预计减少规则重复;候选 B 只是重命名目录。前者可能直接减少返工,但仍需要确认现有差异是否刻意存在。

你可以挑一个候选继续深入,不必一次全部接受。收益不确定、影响很大的重构,应先把问题说清而不是被报告气势推动。

中文译文
3. 围绕选中的候选深入讨论

用户选定候选后,通过 Skill 工具加载 grilling,与用户逐步走过相关决定:有哪些约束和依赖;加深后的模块是什么形状;哪些行为放在衔接位置之后;已有测试中哪些还应继续保留。

讨论中,决定一旦明确就同步记录。加载 domain-modeling,让业务模型随着讨论持续更新:

  • 给模块采用了术语表中还没有的业务名称? 将该术语加入 CONTEXT.md。如果文件还不存在,等确有内容需要写时再创建。
  • 讨论中把含糊的词说清楚了? 当场更新 CONTEXT.md,不要等会话结束才回忆整理。
  • 用户因一个会长期影响判断的关键理由拒绝候选? 可以询问:“要不要把这个理由记成 ADR,避免以后的架构审查再次提出同样建议?”只有未来阅读者确实需要这个背景,才能避免重复建议时,才值得记录。像“目前不值得投入”这类临时理由,以及不言自明的理由,可以跳过。
  • 希望比较加深后模块的不同接口方案? 加载 codebase-design,采用其中“设计两次”的并行子 Agent 设计方式。
English · 英文原文
3. Grilling loop

Once the user picks a candidate, call the Skill tool with "grilling" to walk the decision tree with them: constraints, dependencies, the shape of the deepened module, what sits behind the seam, what tests survive.

Side effects happen inline as decisions crystallize; call the Skill tool with "domain-modeling" to keep the domain model current as you go:

  • Naming a deepened module after a concept not in CONTEXT.md? Add the term to CONTEXT.md. Create the file lazily if it doesn't exist.
  • Sharpening a fuzzy term during the conversation? Update CONTEXT.md right there.
  • User rejects the candidate with a load-bearing reason? Offer an ADR, framed as: "Want me to record this as an ADR so future architecture reviews don't re-suggest it?" Only offer when the reason would actually be needed by a future explorer to avoid re-suggesting the same thing; skip ephemeral reasons ("not worth it right now") and self-evident ones.
  • Want to explore alternative interfaces for the deepened module? Call the Skill tool with "codebase-design" and use its design-it-twice parallel sub-agent pattern.
老师讲解 · 对应上方原文 · 含教学举例

选中候选后,先设计边界与验证方式

澄清循环会追问新模块公开什么、隐藏什么、原行为怎样保持、哪些调用者需要迁移。深模块的目标不是把所有逻辑塞进一个文件,而是减少使用者必须掌握的内部知识。

例如把“计算完成状态”集中后,外部只需传学习记录;但若不同课程本来有不同完成规则,接口必须保留这种差异,不能为了统一而改变业务。

本 skill 产出可讨论的改进方向。是否实施、拆成哪些小步骤、回归测试从哪里进入,仍需按后续流程明确。隔几天运行是作者使用习惯,不是适用于所有项目的固定频率。

原作者:Matt Pocock · 中文翻译为非官方译本

来源:skills/engineering/improve-codebase-architecture/SKILL.md ↗

固定版本:3cca18b368ae95cdbdebbff572ccafa662551015

配套参考资料(英文)

先作答,再看参考思路

Q1 · 理解

用自己的话说明:它解决什么问题,完成后会留下什么?

请各用一句话回答。若它只做规划或解释,不要把“已开发”“已部署”写成产物。

Q2 · 判断

发现一个能重构的地方,是否就应该立刻改?

我已思考,查看参考思路

不。先评估真实摩擦、近期变更需求和旧决定,再选择是否进入设计。可改不等于值得现在改。

Q3 · 追问

原文中哪条要求在你的环境下可能不成立?

说出具体一句及其前提,例如工具不可用、资料缺失、已有项目约定冲突,或它只是作者偏好。把你的答案带回课堂,我们据此继续讨论。

课堂回传格式:第 19 课 / 我的理解 / Q2 回答 / 仍不理解的原句。这里是阅读教材;实时问答在我们的对话中进行。

把方法放进一个具体情境

教学案例:三个 Agent 都各自解析任务状态,导致同一状态在不同报告里含义不同。候选可能是集中状态解释;应说明哪些调用者受影响、测试怎样覆盖,不能只说“统一架构”。

边界与容易误读的地方

不要把定期扫描变成定期大改。报告中的收益是待验证假设;只有热闹图表、没有实际摩擦证据,不值得进入重构。

讨论后再实践:先判断上述情境是否适用,再选择真实任务。现在无需安装、运行命令或修改现有项目。

关联阅读