From c876f0733362fc2822f96c2f1ead497e528fed76 Mon Sep 17 00:00:00 2001 From: wehub-skill-sync Date: Mon, 13 Jul 2026 21:36:19 +0800 Subject: [PATCH] chore: import zh skill improve-codebase-architecture --- DEEPENING.md | 39 ++++++++++++++ HTML-REPORT.md | 122 ++++++++++++++++++++++++++++++++++++++++++++ INTERFACE-DESIGN.md | 46 +++++++++++++++++ LANGUAGE.md | 5 ++ README.wehub.md | 9 ++++ SKILL.md | 81 +++++++++++++++++++++++++++++ 6 files changed, 302 insertions(+) create mode 100644 DEEPENING.md create mode 100644 HTML-REPORT.md create mode 100644 INTERFACE-DESIGN.md create mode 100644 LANGUAGE.md create mode 100644 README.wehub.md create mode 100644 SKILL.md diff --git a/DEEPENING.md b/DEEPENING.md new file mode 100644 index 0000000..98a59d8 --- /dev/null +++ b/DEEPENING.md @@ -0,0 +1,39 @@ +--- + +# Deepening + +如何安全地深化一组浅层模块(给定其依赖关系)。假设您已熟悉 [LANGUAGE.md](LANGUAGE.md) 中的词汇——**module(模块)**、**interface(接口)**、**seam(接缝)**、**adapter(适配器)**。 + +## 依赖分类 + +在评估一个可供深化的候选模块时,请对其依赖进行分类。分类决定了深化后的模块如何在其接缝处进行测试。 + +### 1. 进程内(In-process) + +纯计算、内存状态、无 I/O。始终可深化——合并模块并通过新接口直接测试。无需适配器。 + +### 2. 本地可替代(Local-substitutable) + +具有本地测试替身的依赖(PGLite 替代 Postgres、内存文件系统)。如果替身存在则可深化。深化后的模块使用测试套件中运行的替身进行测试。接缝是内部的;模块外部接口上没有端口。 + +### 3. 远程但自有(端口与适配器,Ports & Adapters) + +你自己跨越网络边界的服务(微服务、内部 API)。在接缝处定义一个**端口(port)**(接口)。深层模块拥有逻辑;传输层作为**适配器(adapter)**注入。测试使用内存适配器。生产环境使用 HTTP/gRPC/队列适配器。 + +建议表述:*"在接缝处定义一个端口,为生产环境实现一个 HTTP 适配器,为测试环境实现一个内存适配器,这样即使跨网络部署,逻辑也位于一个深层模块之中。"* + +### 4. 真正的外部(模拟,Mock) + +你不控制的第三方服务(Stripe、Twilio 等)。深化后的模块将外部依赖作为注入的端口接收;测试提供模拟适配器。 + +## 接缝规范 + +- **一个适配器意味着一个假设性的接缝。两个适配器才意味着一个真实的接缝。** 除非至少有两个适配器有合理理由(通常是生产环境 + 测试环境),否则不要引入端口。单个适配器的接缝只是间接层。 +- **内部接缝与外部接缝。** 一个深层模块可以有内部接缝(对其实现私有,供自身测试使用),也可以有其接口处的外部接缝。不要仅仅因为测试使用了内部接缝,就将其暴露到接口上。 + +## 测试策略:替换,而非叠加 + +- 一旦深化模块接口处的测试存在,浅层模块上的旧单元测试就变成了废物——删除它们。 +- 在深化模块的接口处编写新测试。**接口就是测试面。** +- 测试应通过接口断言可观察到的结果,而非内部状态。 +- 测试应能经受内部重构——它们描述的是行为,而非实现。如果实现发生变化时测试也必须随之变化,说明它测试到了接口之外。 diff --git a/HTML-REPORT.md b/HTML-REPORT.md new file mode 100644 index 0000000..0ed3164 --- /dev/null +++ b/HTML-REPORT.md @@ -0,0 +1,122 @@ +# HTML 报告格式 + +架构评审渲染为 OS 临时目录下的单个自包含 HTML 文件。Tailwind 和 Mermaid 均来自 CDN。Mermaid 能可靠处理图形化图表;手写的 div 和内联 SVG 负责更偏编辑性的视觉元素(质量图、横截面)。两者混合使用——不要事事依赖 Mermaid,否则会显得千篇一律。 + +## 脚手架 + +```html + + + + + 架构评审 — {{仓库名称}} + + + + + +
+
...
+
...
+
...
+
+ + +``` + +## 页头 + +仓库名称、日期,以及一个紧凑图例:实线框 = 模块,虚线 = 接缝,红色箭头 = 泄漏,粗深色框 = 深层模块。无需引言段落——直接进入候选方案。 + +## 候选卡片 + +图表承载主要信息。文字描述应简洁、平实,直接使用词汇表中的术语(参见 [LANGUAGE.md](LANGUAGE.md)),无需额外说明。 + +每个候选方案为一个 `
`: + +- **标题** —— 简短,指明深化方向(例如"折叠订单接收管道")。 +- **徽章行** —— 推荐强度(`强烈推荐` = 翠绿色,`值得探索` = 琥珀色,`探索性` = 石板色),外加依赖分类标签(`进程内`、`本地可替代`、`端口与适配器`、`模拟`)。 +- **文件** —— 等宽字体列表,`font-mono text-sm`。 +- **改造前/改造后对比图** —— 核心内容。两列并排。具体模式见下文。 +- **问题** —— 一句话。痛点所在。 +- **解决方案** —— 一句话。变更内容。 +- **收益** —— 要点列表,每项不超过 6 个词。例如"测试仅命中一个接口"、"定价逻辑不再泄漏"、"删除 4 个浅层包装器"。 +- **ADR 标注**(如适用)—— 琥珀色背景框中的一行文字。 + +无需解释性段落。如果图表需要一段文字才能理解,请重新绘制图表。 + +## 图表模式 + +根据候选方案选择匹配的模式。可混合使用。不要让每张图表看起来都一样——多样性本身就是目的之一。 + +### Mermaid 图(依赖/调用流的常用方案) + +当表达要点是"X 调用 Y,Y 调用 Z,一团乱麻"时,使用 Mermaid 的 `flowchart` 或 `graph`。将其包裹在 Tailwind 风格的卡片中,使其不显得突兀。使用 classDef 将泄漏边着色为红色,将深层模块着色为深色。时序图非常适合"改造前:6 次往返;改造后:1 次"的场景。 + +```html +
+
+    flowchart LR
+      A[OrderHandler] --> B[OrderValidator]
+      B --> C[OrderRepo]
+      C -.leak.-> D[PricingClient]
+      classDef leak stroke:#dc2626,stroke-width:2px;
+      class C,D leak
+  
+
+``` + +### 手写方框箭头图(当 Mermaid 的布局不合心意时) + +模块使用带边框和标签的 `
` 实现。箭头使用内联 SVG `` 或 `` 元素,在相对定位的容器上进行绝对定位。当你想让"改造后"图看起来像一个粗边框的深层模块,内部元素变灰显示时,可以使用这种方式——Mermaid 无法以合适的视觉重量渲染这种效果。 + +### 横截面图(适用于层次化浅度分析) + +堆叠水平条带(`h-12 border-l-4`)来展示调用经过的层次。改造前:6 个薄层,每层无所作为。改造后:1 个厚条带,标注合并后的职责。 + +### 质量图(适用于"接口与实现等宽") + +每个模块两个矩形——一个表示接口表面积,一个表示实现。改造前:接口矩形几乎与实现矩形一样高(浅层)。改造后:接口矩形矮小,实现矩形高大(深层)。 + +### 调用图折叠 + +改造前:以嵌套方框形式呈现的函数调用树。改造后:同一棵树折叠为一个方框,原内部调用在方框内以淡显方式显示。 + +## 样式指导 + +- 偏编辑风格,而非企业仪表盘风格。留白充足。标题可选衬线字体(`font-serif` 与 stone/slate 搭配效果良好)。 +- 颜色慎用:一种强调色(翠绿或靛蓝),加上用于泄漏的红色和用于警告的琥珀色。 +- 图表高度保持约 320px,使改造前/改造后能舒适地并排显示,无需滚动。 +- 图表内模块标签使用 `text-xs uppercase tracking-wider`——它们应呈现为示意图风格,而非 UI 风格。 +- 唯一的脚本是 Tailwind CDN 和 Mermaid ESM 导入。报告其他部分均为静态内容——无应用代码,除 Mermaid 自身渲染外无交互功能。 + +## 最佳推荐部分 + +一张较大的卡片。候选方案名称、一句话说明理由、以及指向其卡片的锚点链接。仅此而已。 + +## 语气 + +简明英语,简洁——但架构名词和动词直接来自 [LANGUAGE.md](LANGUAGE.md)。简洁不是偏离术语的借口。 + +**精确使用:** module(模块)、interface(接口)、implementation(实现)、depth(深度)、deep(深层)、shallow(浅层)、seam(接缝)、adapter(适配器)、leverage(杠杆效应)、locality(局部性)。 + +**切勿替换为:** component(组件)、service(服务)、unit(单元)代替 module(模块)· API、signature(签名)代替 interface(接口)· boundary(边界)代替 seam(接缝)· layer(层)、wrapper(包装器)代替 module(模块),当你的意思是 module 时。 + +**符合该风格的表述:** + +- "订单接收模块较浅——接口几乎与实现相当。" +- "定价逻辑跨越接缝泄漏。" +- "深化:一个接口,一个测试点。" +- "两个适配器证明了接缝的价值:生产环境用 HTTP,测试环境用内存。" +- "收益要点"使用词汇表术语说明收益:*"局部性:bug 集中在一个模块"*、*"杠杆效应:一个接口,N 个调用点"*、*"接口缩小;实现吸收了包装器"*。不要写 *"更易维护"* 或 *"代码更整洁"*——这些术语不在词汇表中,不应占位。 + +不要含糊其辞、不要铺垫、不要写"值得一提的是……"。如果一个句子可以写成要点,就写成要点。如果一个要点可以被删除,就删除它。如果某个术语不在 [LANGUAGE.md](LANGUAGE.md) 中,在创造新术语之前,先使用已有的术语。 diff --git a/INTERFACE-DESIGN.md b/INTERFACE-DESIGN.md new file mode 100644 index 0000000..27bb5a8 --- /dev/null +++ b/INTERFACE-DESIGN.md @@ -0,0 +1,46 @@ +```markdown +# 接口设计 + +当用户想要为选定的深化候选项探索替代接口时,使用此并行子代理模式。基于「设计两次」(Ousterhout)——你的第一个想法不太可能是最佳方案。 + +使用 [LANGUAGE.md](LANGUAGE.md) 中的词汇——**模块**、**接口**、**接缝**、**适配器**、**杠杆**。 + +## 流程 + +### 1. 界定问题空间 + +在生成子代理之前,为选定的候选项撰写面向用户的问题空间说明: + +- 任何新接口需要满足的约束条件 +- 它所依赖的依赖项,以及这些依赖项属于哪个类别(参见 [DEEPENING.md](DEEPENING.md)) +- 一个粗略的示意代码草图,用于具象化约束条件——不是提案,只是让约束条件更具体的一种方式 + +向用户展示此内容,然后立即进入第 2 步。用户在阅读和思考的同时,子代理并行工作。 + +### 2. 生成子代理 + +使用 Agent 工具并行生成 3 个或更多子代理。每个子代理必须为深化后的模块生成一个**截然不同**的接口。 + +为每个子代理提供单独的技术简报(文件路径、耦合细节、[DEEPENING.md](DEEPENING.md) 中的依赖类别、接缝背后隐藏的内容)。该简报独立于第 1 步中面向用户的问题空间说明。为每个代理指定不同的设计约束: + +- 代理 1:「最小化接口——最多 1-3 个入口点。最大化每个入口点的杠杆效应。」 +- 代理 2:「最大化灵活性——支持多种使用场景和扩展。」 +- 代理 3:「针对最常见的调用者进行优化——让默认情况变得微不足道。」 +- 代理 4(如适用):「围绕端口和适配器设计,以处理跨接缝依赖。」 + +在简报中同时包含 [LANGUAGE.md](LANGUAGE.md) 词汇和 CONTEXT.md 词汇,使每个子代理的命名与架构语言以及项目的领域语言保持一致。 + +每个子代理输出: + +1. 接口(类型、方法、参数——以及不变约束、顺序、错误模式) +2. 使用示例,展示调用者如何使用 +3. 实现隐藏在接缝背后的内容 +4. 依赖策略和适配器(参见 [DEEPENING.md](DEEPENING.md)) +5. 权衡——哪些地方杠杆效应高,哪些地方薄弱 + +### 3. 展示与比较 + +依次展示设计方案,以便用户逐一理解,然后用散文形式进行比较。按**深度**(接口处的杠杆效应)、**局部性**(变化集中的位置)和**接缝位置**进行对比。 + +比较之后,给出你自己的建议:你认为哪个设计最强,以及理由。如果不同设计中的元素可以很好地组合,提出一个混合方案。要有主见——用户想要的是一个有力的判断,而不是一份菜单。 +``` diff --git a/LANGUAGE.md b/LANGUAGE.md new file mode 100644 index 0000000..d64fdc2 --- /dev/null +++ b/LANGUAGE.md @@ -0,0 +1,5 @@ +- 这个 agent 的**用途**是什么? +- 它需要哪些**工具**(读文件、搜索、执行命令等)? +- 有什么**特殊指令**需要加入? + +请确认,我好继续。 diff --git a/README.wehub.md b/README.wehub.md new file mode 100644 index 0000000..18d7752 --- /dev/null +++ b/README.wehub.md @@ -0,0 +1,9 @@ +# WeHub 来源说明 + +- Skill 名称:`improve-codebase-architecture` +- 中文类目:软件系统架构设计与评估 +- 上游仓库:`mattpocock__skills` +- 上游路径:`skills/engineering/improve-codebase-architecture/SKILL.md` +- 上游链接:https://github.com/mattpocock/skills/blob/HEAD/skills/engineering/improve-codebase-architecture/SKILL.md +- 本仓库为 WeHub 中文 Skill 汉化包,基于 skill 市场筛选 Top200 清单整理 +- 原作者、版权和许可证信息以上游仓库为准 diff --git a/SKILL.md b/SKILL.md new file mode 100644 index 0000000..671ce80 --- /dev/null +++ b/SKILL.md @@ -0,0 +1,81 @@ +--- +name: improve-codebase-architecture +description: 查找代码库中可深化的机会,依据 CONTEXT.md 中的领域语言和 docs/adr/ 中的决策记录。当用户希望改进架构、寻找重构机会、整合紧耦合模块,或使代码库更可测试且更易于 AI 导航时使用。 +--- + +# 改进代码库架构 + +暴露架构摩擦并提出**深化机会**——将浅层模块转变为深层模块的重构。目标是可测试性和 AI 可导航性。 + +## 术语表 + +在每一条建议中精确使用这些术语。统一语言是关键——不要偏离到"组件"、"服务"、"API"或"边界"上。完整定义见 [LANGUAGE.md](LANGUAGE.md)。 + +- **模块(Module)**——任何拥有接口和实现的东西(函数、类、包、切片)。 +- **接口(Interface)**——调用者使用模块所需了解的一切:类型、不变式、错误模式、顺序、配置。不仅仅是类型签名。 +- **实现(Implementation)**——内部的代码。 +- **深度(Depth)**——接口处的杠杆效应:一个小接口背后承载的大量行为。**深(Deep)**= 高杠杆。**浅(Shallow)**= 接口的复杂度几乎等同于实现。 +- **接缝(Seam)**——接口所在之处;可以在不原地修改代码的情况下改变行为的地方。(使用这个词,而不是"边界"。) +- **适配器(Adapter)**——在接缝处满足某个接口的具体实现。 +- **杠杆效应(Leverage)**——调用者从深度中获得的好处。 +- **局部性(Locality)**——维护者从深度中获得的好处:变更、缺陷、知识集中在一处。 + +关键原则(完整列表见 [LANGUAGE.md](LANGUAGE.md)): + +- **删除测试**:想象删除该模块。如果复杂度消失了,它只是一个透传模块。如果复杂度重新出现在 N 个调用方中,那它物有所值。 +- **接口即测试面。** +- **一个适配器 = 假设性接缝。两个适配器 = 真实的接缝。** + +本技能受到项目领域模型的**启发**。领域语言为好的接缝提供了命名;ADR 记录了本技能不应重新争论的决策。 + +## 流程 + +### 1. 探索 + +首先阅读项目的领域词汇表以及你将要触及的区域的任何 ADR。 + +然后使用带有 `subagent_type=Explore` 的 Agent 工具来遍历代码库。不要遵循僵化的启发式规则——有机地探索,并在你感到摩擦的地方做记录: + +- 在哪里理解一个概念需要在许多小模块之间来回跳转? +- 哪些模块是**浅的**——接口的复杂度几乎等同于实现? +- 哪些纯函数仅仅为了可测试性而被提取出来,但真正的缺陷隐藏在其调用方式中(没有**局部性**)? +- 哪些紧耦合的模块跨越了它们的接缝? +- 代码库的哪些部分未经测试,或者通过当前接口难以测试? + +对你怀疑是浅层的任何东西应用**删除测试**:删除它会集中复杂度,还是仅仅转移它?"是,会集中"就是你要找的信号。 + +### 2. 将候选方案呈现为 HTML 报告 + +编写一个自包含的 HTML 文件到操作系统临时目录,这样不会有任何内容落入代码库。从 `$TMPDIR` 解析临时目录,回退到 `/tmp`(在 Windows 上为 `%TEMP%`),并写入到 `/architecture-review-.html`,这样每次运行都会生成一个新文件。为用户打开它——Linux 上使用 `xdg-open `,macOS 上使用 `open `,Windows 上使用 `start `——并告知他们绝对路径。 + +报告使用**通过 CDN 引入的 Tailwind** 进行布局和样式设计,以及**通过 CDN 引入的 Mermaid** 用于绘制能可靠传达结构的图形/流程图/时序图。将 Mermaid 与手写 CSS/SVG 可视化效果混合使用——当关系呈图形结构(调用图、依赖关系、时序图)时使用 Mermaid,当你想要更具编辑性效果(质量图、截面图、折叠动画)时使用手写 div/SVG。每个候选方案都附带一个**前后对比可视化图**。要可视化。 + +每个候选方案使用与之前相同的模板,但以卡片形式呈现: + +- **文件**——涉及哪些文件/模块 +- **问题**——当前架构为何导致摩擦 +- **解决方案**——将发生什么变化的纯英文描述 +- **收益**——用局部性和杠杆效应来解释,以及测试将如何改进 +- **前后对比图**——并排展示,自定义绘制,说明浅层性和深化效果 +- **推荐强度**——`强烈推荐`、`值得探索`、`推测性`之一,以徽章形式呈现 + +报告以**首要推荐**部分结尾:你会优先处理哪个候选方案以及原因。 + +**对领域使用 CONTEXT.md 的词汇,对架构使用 [LANGUAGE.md](LANGUAGE.md) 的词汇。** 如果 `CONTEXT.md` 定义了"订单",那就说"订单接收模块"——不要说"FooBarHandler",也不要说"订单服务"。 + +**ADR 冲突**:如果一个候选方案与现有 ADR 相矛盾,只有当摩擦确实足够大、值得重新审视该 ADR 时才将其呈现出来。在卡片中清晰标注(例如警告提示:_"与 ADR-0007 冲突——但值得重新讨论,因为……"_)。不要列出每个被 ADR 禁止的理论性重构。 + +详见 [HTML-REPORT.md](HTML-REPORT.md) 了解完整的 HTML 脚手架、图表模式和样式指南。 + +暂时不要提出接口。文件写入后,询问用户:"你希望探索其中的哪一个?" + +### 3. 反复质询循环 + +一旦用户选择了一个候选方案,进入质询对话。与他们一起遍历设计树——约束条件、依赖关系、深化后的模块形态、接缝背后是什么、哪些测试仍然有效。 + +当决策逐渐明确时,副作用会就地发生: + +- **将一个深化后的模块以 `CONTEXT.md` 中不存在的概念命名?** 将该术语添加到 `CONTEXT.md` 中——与 `/grill-with-docs` 相同的规范(见 [CONTEXT-FORMAT.md](../grill-with-docs/CONTEXT-FORMAT.md))。如果文件尚不存在,则惰性创建。 +- **在对话过程中明确了某个模糊术语?** 立即更新 `CONTEXT.md`。 +- **用户以某个关键理由拒绝了候选方案?** 提供一份 ADR,表述为:_"想让我将其记录为一条 ADR,这样未来的架构审查就不会再次推荐它了吗?"_ 只有当该理由确实会被未来的探索者需要以避免重复推荐同一内容时才提出——跳过短暂的理由("现在不值得")和不言自明的理由。详见 [ADR-FORMAT.md](../grill-with-docs/ADR-FORMAT.md)。 +- **想为深化后的模块探索替代接口?** 详见 [INTERFACE-DESIGN.md](INTERFACE-DESIGN.md)。