改进代码库架构
揭示架构摩擦并提出深化机会——将浅模块转变为深模块的重构。目标是可测试性和 AI 可导航性。
术语表
在每个建议中精确使用这些术语。一致的语言是重点——不要偏离到"组件"、"服务"、"API"或"边界"。完整定义在 LANGUAGE.md 中。
- 模块——任何具有接口和实现的东西(函数、类、包、切片)。
- 接口——调用者使用模块必须知道的一切:类型、不变量、错误模式、顺序、配置。不仅仅是类型签名。
- 实现——内部的代码。
- 深度——接口处的杠杆:小接口后面的大量行为。深 = 高杠杆。浅 = 接口几乎与实现一样复杂。
- 接缝——接口所在的位置;可以在不编辑位置的情况下改变行为的地方。(使用这个,而不是"边界"。)
- 适配器——在接缝处满足接口的具体事物。
- 杠杆——调用者从深度中获得的东西。
- 局部性——维护者从深度中获得的东西:更改、bug、知识集中在一个地方。
关键原则(完整列表参见 LANGUAGE.md):
- 删除测试:想象删除模块。如果复杂性消失,它是透传。如果复杂性在 N 个调用者中重新出现,它就在发挥作用。
- 接口是测试表面。
- 一个适配器 = 假设的接缝。两个适配器 = 真实的接缝。
此技能_参考_项目的领域模型。领域语言为好接缝命名;ADR 记录技能不应重新讨论的决策。
流程
1. 探索
首先阅读项目的领域术语表和你要接触的区域中的任何 ADR。
然后使用带有 subagent_type=Explore 的 Agent 工具遍历代码库。不要遵循僵化的启发式方法——有机地探索并注意你遇到摩擦的地方:
- 理解一个概念需要在许多小模块之间跳转的地方?
- 哪些模块是浅的——接口几乎与实现一样复杂?
- 纯函数是否仅为了可测试性而被提取,但真正的 bug 隐藏在它们的调用方式中(没有局部性)?
- 紧密耦合的模块在哪里跨越其接缝泄漏?
- 代码库的哪些部分未测试,或通过其当前接口难以测试?
对你怀疑是浅层的任何东西应用删除测试:删除它会集中复杂性,还是只是移动它?"是的,集中"是你想要的信号。
2. 展示候选者
展示深化机会的编号列表。对于每个候选者:
- 文件——涉及哪些文件/模块
- 问题——为什么当前架构导致摩擦
- 解决方案——用通俗英语描述会发生什么变化
- 好处——用局部性和杠杆来解释,以及测试将如何改进
对领域使用 CONTEXT.md 词汇,对架构使用 LANGUAGE.md 词汇。 如果 CONTEXT.md 定义了"Order",谈论"Order 接收模块"——而不是"FooBarHandler",也不是"Order 服务"。
ADR 冲突:如果候选者与现有 ADR 矛盾,仅在摩擦足够真实值得重新审视 ADR 时才提出。清楚地标记它(例如_"与 ADR-0007 矛盾——但由于……值得重新开放"_)。不要列出 ADR 禁止的每个理论重构。
不要提议接口。询问用户:"你想探索其中的哪一个?"
3. Grilling 循环
一旦用户选择了一个候选者,进入 grilling 对话。与他们一起遍历设计树——约束、依赖、深化模块的形状、接缝后面的内容、哪些测试幸存。
副作用随着决策的结晶内联发生:
- 以不在
CONTEXT.md中的概念命名深化模块? 将该术语添加到CONTEXT.md——与/grill-with-docs相同的纪律(参见 CONTEXT-FORMAT.md)。如果文件不存在则惰性创建。 - 在对话中 sharpening 模糊术语? 立即更新
CONTEXT.md。 - 用户以有负载的原因拒绝候选者? 提供 ADR,框架为:"想让我将其记录为 ADR,以便未来的架构审查不会重新建议它吗?" 仅在原因真正被未来探索者需要以避免重新建议相同内容时才提供——跳过短暂原因("现在不值得")和自明的原因。参见 ADR-FORMAT.md。
- 想要探索深化模块的替代接口? 参见 INTERFACE-DESIGN.md。