documenting-contracts
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseDocumenting contracts
契约文档编写
REQUIRED BACKGROUND: the skill (hard rules, truth rules, style).
technical-writing必备背景知识: skill(硬性规则、真实性规则、风格规范)。
technical-writingOverview
概述
A contract document is read by a stranger who cannot see the code and is about to depend on it. Core principle: document the wire, exhaustively, with each detail at its own level; the caller's language is the wire format and domain terms, never the implementation's types. Contract surfaces are reference kind, so the core Reference rule applies: every endpoint, every field, every error. An omission here is a hole a caller falls into.
契约文档的读者是无法查看代码但即将依赖该接口的外部人员。核心原则:详尽记录Wire层面的内容,每个细节对应其专属层级;调用者的语言是Wire格式和领域术语,而非实现层面的类型。 契约属于参考类文档,因此核心参考规则适用:每个端点、每个字段、每个错误都需记录。此处的任何遗漏都会成为调用者的“陷阱”。
When to invoke, and not
适用场景与非适用场景
Invoke when documenting anything machines call or parse: REST and RPC endpoints, message queues and topics, webhooks, CLI commands, file formats. The of a legacy campaign () is this skill's document. Do NOT invoke for internal code interfaces, which the code documents itself, or for configuration references, which belong in under the core Reference rule. Judging whether the contract is well designed is out of scope: this skill documents the contract that exists.
api-reference.mddocumenting-legacy-codebasesconfig-reference.md适用于编写任何机器调用或解析的内容文档:REST和RPC端点、消息队列与主题、Webhook、CLI命令、文件格式。旧版项目的()即属于此技能范畴的文档。不适用于内部代码接口(代码本身可作为文档)或配置参考(应归入核心参考规则下的)。判断契约设计是否合理不在本技能范围内:本技能仅记录已存在的契约。
api-reference.mddocumenting-legacy-codebasesconfig-reference.mdOne home versus generated specs
单一源规则与生成规范
When an OpenAPI or AsyncAPI spec exists, or the code generates one, that spec owns the field tables. The markdown then documents only what the spec cannot say (semantics, side effects, ordering, omitted-versus-null) and links the spec; hand-maintaining field tables beside a generated one builds a second home that drifts. The catalog below is for the common legacy case where no machine spec exists, and writing one is not this document's job.
当存在OpenAPI或AsyncAPI规范,或代码可生成此类规范时,字段表应由该规范主导。Markdown文档仅需记录规范无法表达的内容(语义、副作用、顺序、省略与null的区别)并链接至该规范;在生成规范旁手动维护字段表会形成第二个信息源,导致内容偏差。以下目录适用于无机器规范且无需编写规范的常见旧版场景。
The four detail levels
四个详细级别
Most bad contract documents mix these; this template gives each level its own home, and the writer moves detail found at the wrong level into the level that owns it:
| Level | The caller asks | Home |
|---|---|---|
| Index | What exists here | The endpoint, message, and command tables |
| Semantics | What invoking it does | Per-endpoint, per-message, and per-command prose: side effects, events published, idempotency, redelivery, exit behavior, quirks |
| Shape | What crosses the wire | The DTO catalog: one field table per DTO |
| Example | What it looks like | At most one illustrative example per DTO |
Repetition across levels is the defect to hunt: an endpoint section restating its DTO's fields, an example smuggling in a field the table lacks.
多数不合格的契约文档会混淆这些级别;本模板为每个级别提供专属区域,编写者需将错误层级的内容移至对应层级:
| 级别 | 调用者的问题 | 存放位置 |
|---|---|---|
| 索引 | 这里有哪些内容? | 端点、消息和命令表 |
| 语义 | 调用它会产生什么效果? | 每个端点、消息和命令的说明文字:副作用、发布的事件、幂等性、重投递、退出行为、特殊特性 |
| 结构 | Wire层面传输的内容是什么? | DTO目录:每个DTO对应一个字段表 |
| 示例 | 实际样子是怎样的? | 每个DTO最多一个示例说明 |
需避免跨层级重复:例如端点部分重复其DTO的字段,示例中出现字段表未包含的字段。
The DTO catalog
DTO目录
A DTO is defined once and referenced everywhere, because the same shape travels multiple endpoints and often multiple transports:
- Wire types, not language types. ,
string (date, ISO 8601),number (64-bit integer): the column says what crosses the wire, complete enough that no reader needs the implementation's type as a proxy. A 64-bit integer that exceeds the range or precision of a consumer's native number type is wire information; the type name that produced it is not.string (decimal) - One Source line per DTO, naming the owning class or schema file. Reference kind sanctions this evidence anchor, the same way a config reference carries binding evidence; it is the maintainer's one-click path and the drift check's hook.
- Required is a tri-state: ,
yes, ornowith the condition stated.if <condition> - Omitted versus null is stated wherever it matters, and always on a DTO used in a replace-style write, where an omitted field is absent from the result. Where the server assumes a value on omission instead, that value goes in the Default column.
- Enums get their own table, values with meanings; nested objects link to their own catalog entry, never a second inline copy.
- Constraints in domain terms: "past date", "1..100 chars", "must reference an existing budget policy", read from validation the code enforces.
每个DTO仅定义一次,并在所有引用处复用,因为同一结构会在多个端点甚至多种传输方式中使用:
- Wire类型,而非语言类型。例如、
string (date, ISO 8601)、number (64-bit integer):列中需明确Wire层面的类型,足够详细到读者无需通过实现类型来推断。超出消费者原生数字类型范围或精度的64位整数属于Wire层面信息;而生成该类型的类名则不属于。string (decimal) - 每个DTO对应一行Source,注明所属类或 schema 文件。参考类文档允许使用此证据锚点,就像配置参考包含绑定证据一样;这是维护者一键定位的路径,也是检查内容偏差的钩子。
- 必填状态为三态:、
yes或no(需说明条件)。if <condition> - 在重要场景明确省略与null的区别,尤其是在用于替换式写入的DTO中,省略的字段不会出现在结果中。若服务器在字段被省略时会默认填充值,则该值需写入Default列。
- 枚举类型单独建表,包含值及其含义;嵌套对象需链接至其自身的目录条目,绝不能在内部重复定义。
- 用领域术语描述约束:“过去的日期”、“1..100字符”、“必须引用已存在的预算策略”,需从代码执行的校验规则中提取。
The template
模板
markdown
undefinedmarkdown
undefinedAPI reference: <service>
API reference: <service>
Conventions
Conventions
[Once, never per endpoint: base path, auth, content type, the error
envelope, global (de)serialization behavior, idempotency defaults.]
[仅需写一次,无需每个端点重复:基础路径、认证方式、内容类型、错误信封、全局(反)序列化行为、幂等性默认值。]
Endpoints
Endpoints
| Method | Path | Purpose | Request | Response | Errors |
|---|---|---|---|---|---|
| POST | | Create a thing | ThingRequest | 200 Thing | 422, 404 |
| Method | Path | Purpose | Request | Response | Errors |
|---|---|---|---|---|---|
| POST | | Create a thing | ThingRequest | 200 Thing | 422, 404 |
POST /thing
POST /thing
[Semantics only: side effects, events published, idempotency, quirks.
No field lists; the index and catalog are not repeated.]
[仅包含语义:副作用、发布的事件、幂等性、特殊特性。
不得重复字段列表;索引和目录内容无需重复。]
Messages
Messages
| Direction | Destination | Payload | Reply | On error |
|---|---|---|---|---|
| in | | ThingRequest | | |
| Direction | Destination | Payload | Reply | On error |
|---|---|---|---|---|
| in | | ThingRequest | | |
thing.create
thing.create
[Semantics only: redelivery, ordering, events published, quirks;
what differs from the sibling transport is called out here.]
[仅包含语义:重投递、顺序、发布的事件、特殊特性;
需明确与其他传输方式的差异。]
Commands
Commands
| Command | Purpose | Arguments | Output |
|---|
| Command | Purpose | Arguments | Output |
|---|
<command>
<command>
[Semantics only: side effects, idempotency, exit behavior, quirks.]
[仅包含语义:副作用、幂等性、退出行为、特殊特性。]
DTOs
DTOs
ThingRequest
ThingRequest
Source:
api/ThingRequest| Field | Type | Required | Default | Constraints | Meaning |
|---|
[Omitted versus null, where it matters. At most one illustrative example.]
Source:
api/ThingRequest| Field | Type | Required | Default | Constraints | Meaning |
|---|
[在重要场景说明省略与null的区别。最多一个示例说明。]
Thing
Thing
[Response shapes are catalog entries like any other.]
[响应结构与其他条目一样,属于目录内容。]
Errors
Errors
| Status | When | Body |
|---|
undefined| Status | When | Body |
|---|
undefinedRules
规则
- Verify against the serializer, not the class. The wire is what the configured serializer emits and accepts: a global trimmer, a null-omitting mapper, or a custom date format changes the contract without touching any DTO. Read the serialization configuration before writing a single field row.
- Asymmetries are semantics. The mutation that publishes an event on one transport and nothing on the other, or the endpoint that skips a step its siblings perform, is documented at the semantics level. That is where the surprised caller will look.
- Examples are illustrative, never normative. One per DTO at most, labeled so, and containing no field the table lacks; the table is the contract.
- Errors are cataloged once, as envelope plus a status table; an endpoint lists only which entries apply to it. Command failures are cataloged the same way, by exit code.
- The exhaustiveness is checkable. The endpoint count and the DTO count are denominators like any other (core truth rules): a legacy campaign records them in its coverage ledger with the commands behind them and the date.
- 基于序列化器验证,而非类。Wire层面的内容是配置后的序列化器发出和接受的内容:全局修剪器、忽略null的映射器或自定义日期格式会在不修改任何DTO的情况下改变契约。在编写任何字段行之前,需先查看序列化配置。
- 不对称性属于语义范畴。某传输方式下发布事件而其他方式不发布的变更,或某端点跳过其他同类端点执行步骤的情况,需在语义层级记录。这是调用者可能产生疑惑的地方。
- 示例仅作说明,不具规范性。每个DTO最多一个示例,需标注清楚,且不得包含字段表未列出的字段;字段表才是契约主体。
- 错误仅需归类一次,以信封加状态表的形式呈现;端点仅需列出适用的错误条目。命令失败的归类方式相同,按退出码划分。
- 可检查完整性。端点数量和DTO数量如同其他指标(核心真实性规则):旧版项目需在覆盖记录中记录这些数量、背后的命令以及日期。