# Ddt

> 检查并纠正 dont-do-that packaging 问题，包括过度封装、过度抽象、薄 helper、薄类型拆分、单次引用 enum / 常量、实例属性绕传参数、React 组件职责放置错误、React 前端 util 组织错误和 Node.js 后台分层职责错误；当用户要求 review 或修改代码结构、内联小函数、合并薄类型、收回单点常量、整理 React hook / TSX / 前端 util 职责、检查 Node.js service / logic / query 分层，或判断代码是否符合项目规范时使用。

- Skill: `jybill/ddt` (Agent Skill, multi-file: 3 files)
- Install (CLI): `npx skillmds@latest add jybill/ddt`
- Raw SKILL.md: https://api.skillmd.com/api/skills/jybill/ddt/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Web & Frontend
- Author: jybill (https://skillmd.com/u/jybill)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/jybill/ddt

---


# ddt

DDT 表示 dont-do-that packaging。

这个 skill 用来收掉没有真实收益的包装层，让代码更贴近人类阅读路径。目标不是“越少越好”，而是判断一层函数、类型、常量、文件或参数传递是否真的降低了理解成本。

## 先读项目规范

如果要审查或修改项目代码，先读取仓库内的 `CLAUDE.md` 和存在的 `AGENTS.md`，再读取相关模块旁的说明文件。判断时同时看项目规范、用户长期约束和当前代码，不要只按 DDT 规则下结论。

如果项目规范和 DDT 冲突，优先遵守更具体的项目规范；同时指出这会保留某些看起来偏薄的结构。类型文件命名和放置也优先按项目类型规范处理；只有项目没有明确类型文件约束时，才把业务 TS 源文件剥离出的类型放到同目录 `{源文件名}.d.ts`。

## 选择引用资料

按当前任务读取对应引用资料，不要一次性加载无关内容。

- React 组件、React hook、`.tsx`、组件配套 `util` 文件、前端状态链路：读取 `references/react/index.md`。
- Node.js 后台、service / query / logic、数据库读写、Kysely、接口 DTO、后端类型与枚举：读取 `references/nodejs/index.md`。
- 纯通用问题，例如小函数、薄类型、单点常量、实例属性参数绕行：只用本文件即可。

## 核心判断

先判断拆分有没有真实收益，再决定保留还是收回。

```text
看到一层函数 / 类型 / 常量 / 文件 / 参数传递 / 兜底分支
        │
        ▼
它是否被多个地方稳定复用？
        ├─ 是 ──► 保留，并确认命名和注释能表达业务语义
        │
        └─ 否
             │
             ▼
它是否明显降低主流程认知负担？
        ├─ 是 ──► 保留，但避免继续拆更薄的层
        │
        └─ 否
             │
             ▼
它是否表达独立业务边界、外部协议、测试边界或项目强约束？
        ├─ 是 ──► 保留，并让边界更清楚
        │
        └─ 否 ──► 收回：内联函数、合并类型、删除透传参数、中间层或重复兜底
```

## 通用流程

```text
开始 DDT 检查
        │
        ▼
读取 CLAUDE.md / AGENTS.md / 模块说明
        │
        ▼
按文件类型选择引用资料
        ├─ React / TSX / hook ──► references/react/index.md
        ├─ Node.js 后台 ────────► references/nodejs/index.md
        └─ 通用结构问题 ───────► 留在 SKILL.md
        │
        ▼
列出候选包装层
        │
        ▼
逐项判断收益：复用、主流程、边界、测试、项目规范
        │
        ▼
采取最小动作
        ├─ 无收益 ──► 内联 / 合并 / 删除绕行 / 收回单点常量
        └─ 有收益 ──► 保留，并改善命名、注释或放置位置
        │
        ▼
更新 import、类型引用和必要注释
        │
        ▼
运行最小必要验证并报告结果
```

## 通用规则

如果一个函数只有很少几行，只有一个调用方，而且函数名没有提供新的业务语义，默认这是过度封装，应该内联回调用处。不要为了看起来更模块化就保留这种薄函数。

如果一个类型只是从另一个类型里薄薄切出一层，没有形成稳定复用，也没有显著降低理解成本，默认合并回更直接的类型定义。只有在子类型真的被多个地方独立使用，或者拆出来以后能明显降低主类型复杂度时，才保留拆分。

如果业务 `.ts` / `.tsx` 源文件确实需要把类型从主文件剥离，先读取项目类型文件规则、同目录既有模式和上层模块约定。项目有规定时按项目规定，例如 `types.ts`、`<api-file>.types.ts`、`src/types/*.d.ts` 或其他约定位置；项目没有规定时，才使用同目录 `{源文件名}.d.ts`，例如 `ChatComponent.tsx` 对应 `ChatComponent.d.ts`，`agent.service.ts` 对应 `agent.service.d.ts`。不要为了单个源文件新增和项目规则冲突的泛化类型收集文件。

如果一个 enum、`const`、`as const` 对象、延迟时间、阈值、固定 key、mode、status 或 tool name 只有一个使用处，默认直接耦合到使用处。只有跨多个文件、多个分支、多个业务动作复用，或确实表达外部协议 / 复杂业务边界时，才抽到 `enum/**` 或常量文件。

class 内部已经稳定存在的实例状态，不要再为了“显式传参”沿着私有方法链路传递。私有方法本来就是实例行为，直接读 `this.xxx` 往往比 `const xxx = this.xxx; this.a(xxx); this.b(xxx);` 更能表达这个值属于对象状态。

兜底逻辑只在输入来自不稳定外部边界，或者缺少兜底会造成明确错误时保留。状态已经由生命周期、事件顺序、状态机或类型定义保证时，不要为了“更稳”保留重复防御分支。

代码优先服务人类阅读，不优先服务形式上的解耦。局部轻微耦合通常比多跳一层更好读。

## 判断表

| 对象        | 倾向收回                               | 倾向保留                                 |
| ----------- | -------------------------------------- | ---------------------------------------- |
| 小函数      | 2 到 5 行、单一调用方、函数名复述实现  | 多处稳定复用、表达业务动作、需要独立测试 |
| 类型        | 只是一层别名、摘字段、消费范围很窄     | 外部契约、消息体、事件载荷、稳定嵌套结构 |
| 常量 / enum | 只有一处引用、上下文已经自解释         | 多处复用、外部协议、复杂业务边界         |
| 参数        | 调用方只是从 `this` 读出再传给私有方法 | 参数来自调用现场，或每次调用会变化       |
| 兜底        | 已由状态机、生命周期或类型保证不会触发 | 外部输入不稳定，或缺少保护会造成错误     |

## 执行动作

当确认存在过度包装时，直接做这些事。

| 问题                             | 动作                                                 |
| -------------------------------- | ---------------------------------------------------- |
| 单一调用方的小函数               | 内联回调用处，删掉 helper                            |
| 无收益的中间层                   | 删除透传层，让调用关系更短                           |
| 过薄的类型                       | 合并回主类型或更直接的边界类型                       |
| 需要从业务 TS 源文件剥离的类型   | 先按项目类型规则；无约束时用同目录 `{源文件名}.d.ts` |
| 单一引用的 enum 或常量           | 内联回使用处，删掉 enum / const                      |
| 只是转手传递的实例属性参数       | 让目标私有方法直接读取 `this.xxx`                    |
| 主流程已经保证不会触发的兜底分支 | 删除重复防御                                         |
| 必要注释被薄封装掩盖             | 保留注释，但只解释关键意图                           |

修改后检查 import、循环引用、类型导入、JSDoc 和项目要求的最小验证。验证范围按影响面选择，至少覆盖受影响文件的 lint 或类型检查。

## 输出要求

如果用户要求直接修，就完成修改和验证后再回复结果。

如果用户要求 review，就按文件指出哪些函数、类型、常量或文件职责属于 DDT 问题，并给出最小修改建议。不要泛泛评价“抽象层次”。

解释原因时用短句说明即可，例如“只有一个调用方且逻辑过薄，内联后阅读路径更短”。

