improve-codebase-architecture
- 信任分
- 88/100
- 兼容 Agent
- 1
- 领域
- 工程开发
- 兼容 Agent
- Claude Code
- 信任分
- 88 / 100 · 社区维护
- 作者 / 版本 / 许可
- @mattpocock · 未声明 license
- 安装命令数
- 1 条
需要注意: 未限定 allowed-tools,默认拥有全部工具权限。
想读作者英文原文? ↓ 滚到正文区切换 · 在 GitHub 查看 ↗
设计思路
improve-codebase-architecture 是 mattpocock 的「架构改进」skill——用《A Philosophy of Software Design》里的「deep / shallow module」这把尺子,找出当前代码库里浅 + 漏的接口,提议加深它们。skill 的灵魂是 grilling loop——选定候选后并不直接动手,而是和用户一起拷问设计树,让候选在对话中成形。
Glossary(按作者原文)
- Locality:彼此调用得很近的代码应该住得很近——降低跳转成本。
- Deletion test:怀疑某个模块「shallow」时问:删掉它是把复杂度集中了,还是只是搬家了?「集中」就是好信号——这正是我们想加深的对象。
流程
1. 寻找候选 扫代码库找:
- 哪些重复模式调用方式各异(缺 locality)
- 紧耦合模块在哪些 seam 漏出去
- 哪些部分没测试 / 通过当前接口很难测
对怀疑「shallow」的部分跑 deletion test,回答「集中」就是候选。
2. 呈现候选(编号列表) 每条候选给:
- Files 涉及哪些文件 / 模块
- Problem 为什么当前架构在制造摩擦
- Solution 改成什么样(白话)
- Benefits 用 locality / leverage 解释、说测试如何变好
用 CONTEXT.md 的领域词汇 + LANGUAGE.md 的架构词汇——CONTEXT.md 里定义了「Order」就说「Order intake 模块」,不要叫「FooBarHandler」也不要叫「Order service」。
ADR 冲突处理:候选与现有 ADR 冲突时,只在摩擦真实到值得 reopen ADR 时才提;并明确标注「contradicts ADR-0007 — but worth reopening because…」。不要列出 ADR 禁止的所有理论 refactor。
关键纪律:还不要提议接口形状——先问用户:「想探索哪一项?」
3. Grilling Loop 用户选定候选后,进入拷问对话——和他一起遍历设计树:约束、依赖、加深后的模块形状、缝隙后藏什么、哪些测试存活。
对话中即时副作用:
- 加深的模块用了
CONTEXT.md没有的概念 → 当场加进去(同grill-with-docs纪律) - 用户用了模糊词 → 当场把它沉淀进
CONTEXT.md - 用户拒绝候选并给出 load-bearing 理由 → 提议建 ADR:「Want me to record this as an ADR so future architecture reviews don't re-suggest it?」仅当理由对未来探索者有用时才提;临时性理由("not worth it right now")和不证自明的不要提。
- 探索接口形状 → 跳到
INTERFACE-DESIGN.md
适合谁
- 重构准备阶段的资深工程师
- 想用「集中复杂度而非搬家复杂度」标准做架构判断的 Tech Lead
- 准备做 deep / shallow 评估的代码 review 时机
何时不该用
- 项目早期、形状没定——加深动作过早
- 简单 bug fix——不到架构层
配套
grill-with-docs(同源的拷问 + CONTEXT 纪律)、design-an-interface(接口形状探索)、request-refactor-plan(提出重构 plan)、diagnose(Phase 5/6 暴露架构问题时的上一步)。
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.
Glossary
Use these terms exactly in every suggestion. Consistent language is the point — don't drift into "component," "service," "API," or "boundary." Full definitions in LANGUAGE.md.
- Module — anything with an interface and an implementation (function, class, package, slice).
- Interface — everything a caller must know to use the module: types, invariants, error modes, ordering, config. Not just the type signature.
- Implementation — the code inside.
- Depth — leverage at the interface: a lot of behaviour behind a small interface. Deep = high leverage. Shallow = interface nearly as complex as the implementation.
- Seam — where an interface lives; a place behaviour can be altered without editing in place. (Use this, not "boundary.")
- Adapter — a concrete thing satisfying an interface at a seam.
- Leverage — what callers get from depth.
- Locality — what maintainers get from depth: change, bugs, knowledge concentrated in one place.
Key principles (see LANGUAGE.md for the full list):
- Deletion test: imagine deleting the module. If complexity vanishes, it was a pass-through. If complexity reappears across N callers, it was earning its keep.
- The interface is the test surface.
- One adapter = hypothetical seam. Two adapters = real seam.
This skill is informed by the project's domain model. The domain language gives names to good seams; ADRs record decisions the skill should not re-litigate.
Process
1. Explore
Read the project's domain glossary and any ADRs in the area you're touching first.
Then use the Agent tool with subagent_type=Explore 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 — 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.
2. Present candidates
Present a numbered list of deepening opportunities. For each candidate:
- 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 also in how tests would improve
Use CONTEXT.md vocabulary for the domain, and LANGUAGE.md 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 (e.g. "contradicts ADR-0007 — but worth reopening because…"). Don't list every theoretical refactor an ADR forbids.
Do NOT propose interfaces yet. Ask the user: "Which of these would you like to explore?"
3. Grilling loop
Once the user picks a candidate, drop into a grilling conversation. Walk the design 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:
- Naming a deepened module after a concept not in
CONTEXT.md? Add the term toCONTEXT.md— same discipline as/grill-with-docs(see CONTEXT-FORMAT.md). Create the file lazily if it doesn't exist. - Sharpening a fuzzy term during the conversation? Update
CONTEXT.mdright 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. See ADR-FORMAT.md.
- Want to explore alternative interfaces for the deepened module? See INTERFACE-DESIGN.md.