agentleFS
ly0o0oly0o0o/codex-engineering-skills/skills/nodejs-code-style/SKILL.md

nodejs-code-style

Skill2 starsChanged 3 months agoMITView on GitHub

Use when writing, reviewing, or refactoring Node.js/TypeScript backend code and the task needs strict code style, concise implementation, naming discipline, type-driven design, discriminated unions, runtime validation, error modeling, async control, refactoring judgment, readable main flow, and senior-engineer code cleanliness independent of any specific framework.

  • Reads credentials

The file

Files
SKILL.md

Node.js Code Style

定位

写像老练工程师写的 Node.js/TypeScript:代码短,但不是压缩;抽象少,但边界准确;主流程顺,但错误和状态不糊;类型不是装饰,而是把业务约束钉在代码里。

这个 Skill 管代码级设计和语法纪律。架构选择、模块边界、DDD、ports/adapters、任务队列和运行生命周期,使用 nodejs-backend-engineering。

先后顺序

  1. 正确性和业务语义
  2. 数据安全、权限、幂等、额度、租户隔离
  3. 类型表达和运行时校验
  4. 错误上下文和可观测性
  5. 主流程可读
  6. 紧凑和少抽象

简洁不是少写几行,而是让读者少猜。任何“省事写法”如果隐藏失败、状态、权限或副作用,都不算优雅。

工作方式

  1. 先读相邻代码:命名、错误类型、schema、logger、测试风格以项目为准。
  2. 找边界:API body、query、env、DB JSON、queue message、cache、第三方响应都不可信。
  3. 先建模再写流程:有限状态用 union;成功/失败分支显式;ID 和业务值别全用 string。
  4. 写主流程:入口做校验,业务函数拿干净输入,早返回减少嵌套。
  5. 收紧抽象:只保留能隐藏复杂度、保护不变量、减少真实重复的函数或模块。
  6. 自查验证:type-check/test/lint/build 按项目最小必要命令跑;不能跑就说明原因。

代码规则

1. 让非法状态尽量不可表示

不要靠注释解释“这个字段只在 completed 时有”。用 discriminated union 表达状态,让调用方必须处理分支。

type TaskResult =
  | { status: 'pending'; taskId: TaskId }
  | { status: 'running'; taskId: TaskId; startedAt: Date }
  | { status: 'completed'; taskId: TaskId; collectionId: CollectionId }
  | { status: 'failed'; taskId: TaskId; errorCode: string; message: string };

状态、错误码、provider、任务类型、权限类型都优先用有限集合。字符串散落判断是后端腐烂的早期信号。

2. 类型边界要窄,运行时边界要硬

TypeScript 不能校验线上输入。外部数据先 unknown,在边界用项目已有 schema/parser 校验,之后再进入 service/domain。

const input = CreateTaskSchema.parse(await req.json());
return taskService.createTask(input);

不要让业务函数到处接 Request、Context、process.env、第三方原始 response 或未解析 JSON blob。

3. 主流程连续,复杂度下沉

主流程应读得出业务动作顺序;复杂度放到有名字的深模块里,而不是拆成一堆浅 helper。

好函数边界:

  • 隐藏外部协议、重试、分页、签名、响应清洗。
  • 保护业务不变量,如配额预留、状态流转、金额计算、权限判定。
  • 独立表达算法、规则、排序、合并、去重。
  • 消除真实重复,且名字比代码更清楚。

坏函数边界:

  • 只调用一次,名字只是复述实现。
  • 把连续业务流程拆碎,读者必须来回跳。
  • 为“以后可能复用”提前抽象。
  • 为单测制造生产接口。

4. 命名必须带业务重量

  • ID 写全:userId、taskId、collectionId,不要跨函数传裸 id。
  • 布尔值用 is/has/can/should,避免反向布尔名。
  • 数组用复数,map/set 带 key 语义,如 tasksByCollectionId。
  • 函数动词准确:fetch 远程取,load 本地/DB 取,create 新建,reserve 预留,consume 扣减,release 回退,enqueue 投递。
  • 少用 data/info/result/item/temp/manager/helper/common/core,除非局部语境极小。

5. 错误是接口的一部分

catch 只能做四件事:补上下文、分类、补偿、重新抛出。禁止空 catch,禁止失败后返回空数组/空对象装作成功,除非业务明确允许且有日志/指标。

try {
  await quotaRepository.consume(reservationId);
} catch (cause) {
  throw new AppError('Failed to consume reserved quota', {
    cause,
    code: 'QUOTA_CONSUME_FAILED',
    context: { reservationId, userId },
  });
}

对外返回稳定错误码;日志保留内部 cause 和定位字段;响应不要泄露 secret、token、完整敏感 payload。

6. async 要有超时、取消和并发语义

  • 无依赖才 Promise.all。
  • 允许部分失败才 Promise.allSettled,且逐项保留上下文。
  • 第三方调用、批处理、流式处理要考虑 timeout、AbortSignal、限流和 backpressure。
  • 有顺序、事务、锁、额度、幂等或短路语义时,不要机械并发。
  • 后台任务必须能解释 retry、补偿、重复投递的结果。

7. 条件表达要显性

  • 业务分支优先早返回或 switch。
  • 有限状态分支用 exhaustive check,不要默认分支吞掉未来状态。
  • 三元只用于短小纯表达式;嵌套三元和有副作用三元要拆。
  • 可选链只用于确实可选的数据。已校验必传对象缺失,应暴露错误。

8. 注释记录约束,不复述代码

应该注释:

  • 业务规则背后的原因。
  • 历史数据、第三方怪癖、协议兼容。
  • 幂等、事务、缓存、锁、重试的不变量。
  • 不直观算法、正则、时间窗口。

不应该注释:

  • // get user by id
  • // loop items
  • // return result

9. 依赖和文件改动要克制

新增依赖前先查标准库和项目已有依赖。只为几行代码引入一个包,通常不是好交易。

只动任务相关文件。不要顺手重排、批量格式化、重命名、删除无关注释。发现旁边问题,记录,不混入当前改动。

按需读取

  • references/type-design.md:状态、错误、ID、Result、exhaustive check 的 TypeScript 建模。
  • references/refactoring-and-smells.md:基于 Fowler、Ousterhout、Google 工程实践的重构判断和坏味道。
  • references/real-code-patterns.md:Node.js 后端常用代码片段,包含边界校验、错误映射、并发、超时和日志。

交付自查

  • 外部输入已校验或窄化。
  • 状态和失败分支不是散落字符串。
  • 没有无意义 any、空 catch、生产 console.log。
  • 没有用可选链掩盖必传对象缺失。
  • 没有无业务语义兜底。
  • 没有把连续主流程拆成浅 helper。
  • 错误有 cause/context,日志有定位字段且不泄露敏感数据。
  • 改动跑过最小必要验证,或明确说明不能跑的原因。

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.