Files
XCEngine/docs/api-skill.md

9.3 KiB
Raw Blame History

XCEngine API Documentation Skill

目标

本规范用于维护 XCEngine 的唯一正式 API 文档树,并约束后续所有模块级重构的工作方式。

硬性要求:

  1. docs/api/XCEngine/** 必须与 engine/include/XCEngine/** 保持平行。
  2. canonical API 文档只保留一套;迁移完成后必须删除旧目录与旧入口。
  3. 每个 public header 对应一个独立文档目录,每个类型页都使用 {TypeName}/{TypeName}.md
  4. 方法页优先使用源码中的原始函数名;不要改成 kebab-case、全小写或其它再命名形式。
  5. API 文档必须以源码、实现、测试和真实调用点为依据,禁止只根据名字猜测行为。

Canonical 目录结构

docs/api/
├── main.md
├── XCEngine/
│   ├── XCEngine.md
│   ├── Debug/
│   │   ├── Debug.md
│   │   ├── Logger/
│   │   │   ├── Logger.md
│   │   │   ├── Get.md
│   │   │   ├── Initialize.md
│   │   │   └── Log.md
│   │   └── RenderDocCapture/
│   │       ├── RenderDocCapture.md
│   │       └── BeginCapture.md
│   └── ...
├── _guides/
│   └── Debug/
└── _meta/

说明:

  • docs/api/XCEngine/** 是唯一 canonical API 树。
  • docs/api/_guides/** 用于概念、教程、设计理念和工作流说明,不是第二套 API 树。
  • README.md 不用于 canonical 模块索引页;模块索引页统一使用 {DirName}.md

强制命名规则

1. 目录索引页

  • 根索引页:docs/api/XCEngine/XCEngine.md
  • 模块索引页:docs/api/XCEngine/{ModuleName}/{ModuleName}.md
  • 子模块索引页:docs/api/XCEngine/{ModuleName}/{SubmoduleName}/{SubmoduleName}.md

示例:

  • docs/api/XCEngine/Debug/Debug.md
  • docs/api/XCEngine/Core/Core.md
  • docs/api/XCEngine/RHI/D3D12/D3D12.md

2. 类型目录

  • 每个 public header 对应一个独立文件夹。
  • 文件夹名必须与 header stem 或主要类型名一致。
  • 保留源码中的大小写,不做风格改写。

示例:

  • docs/api/XCEngine/Debug/Logger/
  • docs/api/XCEngine/Core/Asset/ResourceManager/
  • docs/api/XCEngine/RHI/D3D12/D3D12Device/

3. 类型总览页

  • 固定为 {TypeName}/{TypeName}.md
  • 不允许把类型总览页直接平铺在模块目录中

4. 方法详情页

  • 方法页放在所属类型目录内。
  • 文件名优先使用原函数名。
  • 重载共享同一页,在页内按签名分节说明。

示例:

  • Get.md
  • Initialize.md
  • SetCaptureFilePath.md
  • LoadSceneAsync.md

5. 特殊命名

  • 构造函数:Constructor.md
  • 析构函数:Destructor.md
  • 运算符使用可读的 PascalCase 名称

建议映射:

  • operator= -> OperatorAssign.md
  • operator+= -> OperatorPlusAssign.md
  • operator[] -> OperatorSubscript.md
  • operator() -> OperatorCall.md

写作前的取证流程

在编写任何 API 页之前,必须完成下面的最小取证:

  1. 阅读对应 public header。
  2. 阅读对应 .cpp 或内联实现。
  3. 搜索测试、示例和真实调用点。
  4. 确认生命周期、线程语义、所有权、失败路径和平台限制。

至少回答以下问题后才能落文:

  • 这个类型解决什么问题,边界在哪里?
  • 调用前需要什么前置条件?
  • 调用失败时返回什么,或者会静默失败?
  • 谁拥有对象,谁负责释放资源?
  • 多线程下哪些调用安全,哪些只能在初始化阶段使用?
  • 当前实现是不是完整的?有没有空实现、占位实现或只做轻量封装?

禁止行为:

  • 只根据 GetCreateSet 之类的前缀写模板句。
  • 把“设计意图”当成“当前实现行为”来写。
  • 把测试里假设成立的场景,误写成通用保证。

契约分层规则

文档必须明确区分下面三层信息:

1. 接口契约

来自 public header属于使用者可以依赖的 API 形状。

例如:

  • 函数签名
  • 参数和返回值
  • 可见的数据结构
  • 明确暴露的枚举值和宏

2. 当前实现行为

来自 .cpp、内联实现、测试和调用点,描述当前版本的真实行为。

例如:

  • 是否自动初始化
  • 是否加锁
  • 是否会写日志、刷新文件、拉起窗口焦点
  • 是否只是 no-op 或 stub

这一层必须使用明确表述,例如:

  • “当前实现中……”
  • “按 engine/src/... 的实现……”
  • “当前版本会……”

3. 合理推断

只在确实有必要时使用,而且必须标明是推断。

例如:

  • “从 API 形状看,设计上显然是为后续 Chrome Trace 导出预留扩展点。”

如果不能证明,就不要写。

页面职责

1. 模块页 / 子模块页

负责:

  • 说明模块职责、边界和典型使用场景
  • 列出子目录与 public headers
  • 给出与相邻模块的关系
  • 链接相关 guide 页

不负责:

  • 展开所有方法细节
  • 重复 header 全量声明

2. 类型页

必须包含:

  • 命名空间
  • 类型分类
  • 头文件
  • 角色概述
  • 生命周期
  • 线程语义
  • 所有权 / 资源管理方式
  • 当前实现限制
  • 与相关方法页、guide 页的跳转

如果类型是枚举或结构体,还应补充:

  • 字段或枚举值说明
  • 值之间的语义关系
  • 典型使用方式

3. 方法页

必须包含:

  • 准确签名
  • 调用目的
  • 前置条件
  • 参数说明
  • 返回值说明
  • 副作用
  • 线程语义
  • 失败路径或 no-op 条件
  • 最小可信示例

方法页不能只写“获取对象”“设置状态”这种空描述。

内容深度要求

1. 解释“是什么”

说明类型或方法的职责,而不是简单复述名字。

2. 解释“怎么用”

给出最小可运行或最小可信的使用顺序,让用户知道放在初始化、运行时还是销毁阶段。

3. 解释“为什么这样设计”

结合引擎架构解释:

  • 为什么做成 singleton、service、interface、sink、builder、handle
  • 这样做的收益是什么
  • 有哪些代价或约束

4. 解释“当前实现做到哪一步”

商业级 API 文档不能假装所有接口都同样成熟。

对于未完成能力,必须明确说明:

  • 当前是占位接口
  • 当前只有基础实现
  • 当前只覆盖某个平台 / 某条后端路径

教程与概念页规范

当某个模块仅靠 API 页不足以让用户理解时,应增加 _guides 页。

适合写 guide 的内容:

  • 前置知识
  • 架构设计理念
  • 推荐工作流
  • 和 Unity / Unreal / RenderDoc 等常见工具的概念对照
  • 最佳实践与反模式

guide 页不是第二套 API 参考,它们负责回答:

  • 为什么要这样组织模块
  • 用户第一次接触时该从哪里开始
  • 这套 API 与常见引擎的对应关系是什么

guide 页应尽量包含:

  • 问题背景
  • 设计目标
  • 推荐流程
  • 优点与代价
  • 与现有 API 页的链接

Unity 风格的解释性要求

当模块涉及常见引擎概念时,可以增加 Unity 对照,但必须克制且准确。

推荐写法:

  • “可以把 Logger 理解为比 Unity Console 更底层的日志分发中心。”
  • “当前 Profiler 只覆盖轻量 CPU 埋点,不等同于 Unity Profiler 的完整时间线分析。”
  • RenderDocCapture 更接近引擎内置的 RenderDoc 工作流桥接,而不是 Unity Frame Debugger 的替代品。”

禁止写法:

  • “和 Unity 完全一样”
  • “等价于某商业引擎的完整系统”

页面模板

1. 模块页模板

# {DirName}

**命名空间**: `{Namespace}`

**类型**: `module` / `submodule` / `module-root`

**描述**: {一句话说明当前目录职责}

## 概述

{解释职责边界、典型场景和相邻模块关系}

## 设计要点

- {要点 1}
- {要点 2}

## 头文件

- [TypeA](TypeA/TypeA.md) - `TypeA.h`
- [TypeB](TypeB/TypeB.md) - `TypeB.h`

## 相关指南

- [GuideA](../../_guides/.../GuideA.md)

2. 类型页模板

# {TypeName}

**命名空间**: `{Namespace}`

**类型**: `class` / `class (abstract)` / `class (singleton)` / `struct` / `enum class`

**头文件**: `XCEngine/.../{Header}.h`

**描述**: {一句话说明}

## 概述

{说明角色、状态、边界、典型使用方式}

## 生命周期

- {初始化与销毁方式}

## 线程语义

- {线程安全说明}

## 公开成员

| 成员 | 说明 |
|------|------|
| [Initialize](Initialize.md) | {说明} |
| [Shutdown](Shutdown.md) | {说明} |

3. 方法页模板

# {TypeName}::{MethodName}

{一句话说明方法职责}

```cpp
{完整签名}

行为说明

{说明前置条件、后置状态、副作用和当前实现细节}

参数

  • param - {描述}

返回值

  • {Type} - {描述}

线程语义

  • {线程安全、只建议初始化阶段调用、或必须同线程配对等}

示例

{最小可信示例}

## 验收清单

- `docs/api/XCEngine/**` 与 `engine/include/XCEngine/**` 目录平行
- canonical 树下没有模块级 `README.md`
- 每个 public header 都有对应类型目录
- 每个类型总览页都位于 `{TypeName}/{TypeName}.md`
- 方法页使用原函数名或规范化运算符名
- 所有链接都指向真实存在的 `.md` 页面
- 文档中明确区分接口契约、当前实现和合理推断
- 重要模块拥有必要的 guide 页
- 重要限制、stub、平台条件和线程语义都已写清