Back to skills
SKILL.md
Deep Module Design Zh
ASecurity深模块设计、模块接口设计、接缝(seam)放在哪、可测试性设计、找加深机会、设计两次。当用户说「这个模块接口怎么设计」「代码太碎了怎么合并成深模块」「接缝放哪」「怎么让代码更好测」「帮我设计几种不同的接口方案比较」「什么是深模块」时使用。给一套统一词汇(模块、接口、实现、深度、接缝、适配器、杠杆、局部性);深 vs 浅模块;原则:深度是接口的属性、删除测试、接口即测试面、一个适配器是假接缝两个才是真的;为可测试性设计(接受依赖、返回结果、小表面积);加深一簇浅模块时按依赖类别(进程内 / 本地可替代 / 远程自有 / 真外部)决定测试策略与端口适配器;「设计两次」并行产出 3 个以上截然不同的接口再按深度/局部性/接缝位置比较并给有主见的推荐。也覆盖「合成一个深模块」「截然不同的接口」「一堆内部函数」这类说法。改编自 Matt Pocock 的 codebase-design(MIT)。
- 2 stars
- 0 votes
- 0 copies
- 0 views
- Added October 13, 2026
Works with
Security analysis
100/100Pro scans all 2 files and shows the line behind each finding
npx -y skills add po-et/workbuddy-skills --skill deep-module-design-zh --agent claude-codeAre you the author of Deep Module Design Zh?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/po-et-deep-module-design-zh)---
name: deep-module-design-zh
description: 深模块设计、模块接口设计、接缝(seam)放在哪、可测试性设计、找加深机会、设计两次。当用户说「这个模块接口怎么设计」「代码太碎了怎么合并成深模块」「接缝放哪」「怎么让代码更好测」「帮我设计几种不同的接口方案比较」「什么是深模块」时使用。给一套统一词汇(模块、接口、实现、深度、接缝、适配器、杠杆、局部性);深 vs 浅模块;原则:深度是接口的属性、删除测试、接口即测试面、一个适配器是假接缝两个才是真的;为可测试性设计(接受依赖、返回结果、小表面积);加深一簇浅模块时按依赖类别(进程内 / 本地可替代 / 远程自有 / 真外部)决定测试策略与端口适配器;「设计两次」并行产出 3 个以上截然不同的接口再按深度/局部性/接缝位置比较并给有主见的推荐。也覆盖「合成一个深模块」「截然不同的接口」「一堆内部函数」这类说法。改编自 Matt Pocock 的 codebase-design(MIT)。
author: Captain
version: 0.1.1
display_name: "深模块设计(接口·接缝·可测性)"
display_name_en: "Deep Module Design (zh)"
description_zh: "用统一词汇设计深模块:小接口大实现、接缝位置、适配器、杠杆与局部性;删除测试与接口即测试面;按依赖类别加深并选测试策略;设计两次比较多个接口方案。"
description_en: "Design deep modules with a shared vocabulary: small interface, large implementation, seam placement, adapters, leverage and locality; the deletion test and interface-as-test-surface; deepen by dependency category; design it twice and compare."
tags:
- "深模块"
- "接口设计"
- "接缝"
- "seam"
- "可测试性"
- "适配器"
- "设计两次"
examples_zh:
- "这几个薄薄的 service 层能不能合成一个深模块,接缝放哪"
- "给订单模块设计三种截然不同的接口并比较"
- "怎么改才能不 mock 一堆内部函数就能测"
examples_en:
- "Can these thin service layers merge into one deep module, where does the seam go"
- "Design three radically different interfaces for the order module and compare"
- "How do I make this testable without mocking internals"
metadata:
{ "openclaw": { "requires": { "bins": [] }, "os": ["darwin", "linux", "windows"], "emoji": "🧊" } }
---
# 深模块设计
设计**深模块**:小接口后面藏很多行为,放在干净的接缝上,通过接口可测。这套语言和原则用于任何设计或重构代码的场合。目标:调用者得到杠杆,维护者得到局部性,所有人得到可测性。
## 词汇(精确使用,别换成"组件/服务/API/边界")
- **模块**:任何有接口和实现的东西,刻意不分尺度——函数、类、包、跨层切片。避免:单元、组件、服务。
- **接口**:调用者正确使用模块必须知道的一切:类型签名,还有不变量、顺序约束、错误模式、必需配置、性能特征。避免:API、签名(太窄)。
- **实现**:模块内部的代码体。区别于**适配器**:一个东西可以是小适配器大实现(Postgres 仓储),也可以是大适配器小实现(内存 fake)。谈接缝时用"适配器",否则用"实现"。
- **深度**:接口处的杠杆——调用者(或测试)每学一单位接口能驱动多少行为。大量行为藏在小接口后是**深**,接口几乎和实现一样复杂是**浅**。
- **接缝**(Michael Feathers):不在那个地方编辑就能改变行为的位置,即模块接口所在之处。接缝放哪是独立的设计决策,与放什么在后面不同。避免:边界(与 DDD 的限界上下文冲突)。
- **适配器**:在接缝处满足接口的具体物;描述角色不描述内容。
- **杠杆**:调用者从深度得到的——每学一单位接口得到更多能力;一份实现回报 N 个调用点和 M 个测试。
- **局部性**:维护者从深度得到的——变更、bug、知识、验证集中在一处而不是散在调用者里。修一次到处都好。
## 深 vs 浅
深模块 = 小接口 + 大实现(少量方法、简单参数、复杂逻辑隐藏);浅模块 = 大接口 + 薄实现(很多方法、复杂参数、只是透传)——避免。设计接口时问:能减少方法数吗?能简化参数吗?能把更多复杂度藏进去吗?
## 原则
- **深度是接口的属性,不是实现的**。深模块内部可以由小的、可 mock、可替换的部件组成,只是它们不在接口上。模块可以有**内部接缝**(实现私有,供自己的测试用)和接口处的**外部接缝**。
- **删除测试**:想象删掉这个模块。复杂度消失 → 它只是透传;复杂度在 N 个调用者里重新出现 → 它在挣自己的饭。
- **接口即测试面**:调用者和测试跨同一道接缝。想测到接口"后面",模块大概形状不对。
- **一个适配器是假接缝,两个才是真的**:没有东西真的在接缝两侧变化就别引入接缝。
## 为可测试性设计
接受依赖而不是创建依赖(`processOrder(order, gateway)` 而不是在函数里 `new StripeGateway()`);返回结果而不是产生副作用(`calculateDiscount(cart): Discount` 而不是就地改 `cart.total`);小表面积(方法少测试少,参数少准备简单)。
## 加深一簇浅模块(按依赖类别)
1. **进程内**:纯计算、内存状态、无 I/O——总能加深,合并后直接通过新接口测,不需要适配器。
2. **本地可替代**:有本地替身的依赖(Postgres 的 PGLite、内存文件系统)——有替身就能加深,测试套件里跑替身;接缝在内部,外部接口不开端口。
3. **远程但自有**(端口与适配器):你自己的服务跨网络——在接缝定义**端口**(接口),深模块拥有逻辑,传输以**适配器**注入;测试用内存适配器,生产用 HTTP/gRPC/队列适配器。推荐句式:"在接缝定义端口,生产实现 HTTP 适配器、测试实现内存适配器,逻辑仍在一个深模块里,尽管跨网络部署。"
4. **真外部**(mock):你不控制的第三方(支付、短信)——深模块把它作为注入的端口,测试提供 mock 适配器。
接缝纪律:至少两个适配器才引入端口(通常生产 + 测试),单适配器接缝只是间接层;内部接缝不要因为测试用了就暴露到接口上。
**测试策略:替换而不是叠加**:加深后的模块接口处有了测试,浅模块上的旧单元测试就是垃圾,删掉;新测试写在加深模块的接口处;断言接口可观察的结果而不是内部状态;测试应该扛得住内部重构——实现一改测试就得改,说明测过了接口。
## 设计两次(Ousterhout)
第一个想法很少是最好的。用户想为选定的加深候选探索不同接口时:
1. **框定问题空间**(面向用户):新接口必须满足的约束;依赖及其类别;一段示意性草图把约束具体化(不是提案)。给用户看,然后立刻进第 2 步——用户边读边想,你并行工作。
2. **并行产出 3 个以上截然不同的接口**(有子代理就并行派发,没有就自己依次做但要真的不同):各带不同的设计约束——A 最小化接口(1–3 个入口,最大化每入口的杠杆);B 最大化灵活性(支持多用例与扩展);C 为最常见调用者优化(默认情况极简);D(如适用)围绕端口与适配器处理跨接缝依赖。技术简报独立于第 1 步的用户说明:文件路径、耦合细节、依赖类别、接缝后面是什么;同时使用本技能词汇与项目领域词汇。每个方案输出:接口(类型、方法、参数,加不变量、顺序、错误模式);调用示例;实现在接缝后藏了什么;依赖策略与适配器;取舍(杠杆高在哪、薄在哪)。
3. **依次呈现并比较**:让用户逐个吸收,再用文字对比——按**深度**(接口杠杆)、**局部性**(变更集中在哪)、**接缝位置**。然后给你自己的推荐:哪个最强、为什么;不同方案的元素能组合就提混合方案。要有主见——用户要的是明确的判断,不是菜单。
## 边界
不要为了"以防万一"引入端口:接缝纪律是至少两个真实适配器才值得抽出来,单适配器只是多一层间接。已经是深模块就别再拆细追求"更多小函数"——深度是接口的属性,不是文件数。讨论时不用"组件/服务/API/边界"这类词,统一用本技能词汇。设计两次不是为了拖延决策:收敛到一个有主见的推荐,不是甩给用户一份菜单。
自检:
```
- [ ] 每个接缝至少有两个真实适配器,不是猜想的未来需求
- [ ] 接口在概念上比实现小得多,调用者不需要理解内部结构
- [ ] 讨论里没有出现"组件/服务/API/边界"这类被否决的词
- [ ] 给了不少于 3 个截然不同的候选方案,并有一个明确推荐
```
## 被否决的框架
把深度定义为"实现行数 / 接口行数"(奖励往实现里灌水,我们用杠杆定义);把"接口"理解为 TS 的 interface 关键字或类的公有方法(太窄,这里包括调用者必须知道的每个事实);"边界"(与 DDD 冲突,说接缝或接口)。
---
改编自 [mattpocock/skills](https://github.com/mattpocock/skills) 的 `codebase-design`(MIT)。改动见 ATTRIBUTION.md。
Files in this skill
- ATTRIBUTION.md
- SKILL.md
Attribution
Comments
Loading comments…
Newsletter
Get the weekly list of safe new skills, and the ones we pulled.