API 文档可读性评分准则

概览

本文档包含有关编写 Fuchsia API 文档的指南。它既适用于面向公众的 API(通过 SDK 呈现的 API),也适用于 Fuchsia 内部 API。API 委员会将审核公开的 API 文档,以确定其是否符合此评分准则。

总体评论规则

在大多数情况下,文档应遵循该语言的注释样式指南。如果本文档中有规则与特定于语言的规则相冲突,请遵循本文档中的指导原则。在某些情况下,特定于语言的规则优先;下面列出了这些特殊情况。

以下链接指向适用于 Fuchsia 代码库中可能使用的语言的特定语言指南:C 和 C++RustJavaKotlin。 我们还建议您阅读 Google 的 API 指南

谨慎沟通

Fuchsia 文档是公开发布的,在编写时应采用技术和中性的语气。下文对您可以撰写的内容有一些明确的限制,但这些限制并不全面,请根据自己的判断进行判断!

  • 请勿引用专有信息。这包括个人身份信息,例如个人身份信息和身份验证密钥。
  • 请勿使用脏话或其他可能具有攻击性的言语(例如,“愚蠢”)

一般样式

  • Fuchsia 使用美国英语,并遵循 Fuchsia 文档标准样式指南
  • 请勿明确列出作者。随着开发者转移到不同的项目,作者信息很快就会过时。考虑提供一个维护者文件,但也要小心,此文件也会过期。
  • 针对预期显示方式优化代码(例如,按预期使用 Markdown 或 Javadoc)。

仅在没有语言专用做法和指南时应用以下规则:

  • 文档应紧跟在其要记录的元素之前。
  • 为注释使用 Markdown。Markdown 的样式是最有可能使用相应 API 的工具可以理解的样式。
    • 为代码块使用反引号,而不是缩进 4 个空格。
  • 所有评论都应使用完整的句子。

API 元素

  • 面向公众的 API 元素是指通过 SDK 向开发者提供的 API 元素。所有面向公众的 API 元素(包括但不限于方法、类、字段、类型)都必须包含说明。内部库应该进行记录;如果没有,应该有充分的理由。

  • 所有参数都必须具有说明,除非该说明与类型和名称重复。

    • 如果从类型中无法清楚判断出参数的合法值是什么,请考虑更改类型。例如,{-1, 0, 1} 不如具有 {LESS_THAN, EQUAL_TO, GREATER_THAN} 的枚举有用。
    • 否则,请记录 API 针对所有可能的输入值的行为。 我们不建议使用未记录的值。
  • 所有返回值都必须具有说明,除非该说明与类型和名称重复。

    • 如果某个方法或函数返回其返回值类型的一个子集,请记录该子集。
    • 记录所有返回的错误以及可能出现这些错误的情况。
    • 例如,如果该方法的返回类型为 zx_status_t,并且仅返回 ZX_OK 和 ZX_ERR_INVALID_ARGS,那么您的文档必须明确说明这一点。
    • 如果特定返回值的含义不能一目了然,则必须对其进行记录。例如,如果某个方法返回 ZX_OK,您无需为其记录。如果某个方法返回了字符串的长度,则应对其进行记录。
  • 除非类型和名称可以显而易见地抛出异常,否则所有可能抛出的异常都必须有说明,其中必须包含抛出异常的条件。

    • 某些第三方代码不会以一致的方式记录异常。可能很难(或无法)记录依赖于此类 API 的代码的行为。我们可以尽最大努力解决可能出现的问题。
    • 记录异常是否可以恢复,如果可以,还要记录如何恢复异常。
  • 对于任何可扩展的 API 元素,请指明是否计划扩展这些元素,以及对可能想要扩展这些元素的人员的要求。

    • 如果某个 API 因内部原因(例如测试)是可扩展的,请注明这一点。例如,您应记录您是否允许扩展某个类,以便轻松创建测试替身。
  • 记录了已弃用的 API 元素。

    • 关于已废弃 API 元素的文档必须说明用户应执行的操作,而不是使用 API。
    • 对于弃用 API 的计划,应明确记录下来(如果有)。
    • 如果解释 API 元素的弃用状态会降低 API 文档的质量,请考虑提供一个指向更多信息的指针,包括网址和 bug 标识符。

API 行为

记录面向用户的不变量,以及前置条件和后置条件。

  • 通常,应确保有可强制执行这些条件的断言 / 测试。
  • 应记录需要明确用户操作的前提条件和后置条件。例如,如果需要在发生其他任何操作之前调用 Init() 方法,请提供相关文档。
  • 应记录参数或返回值之间的相关性(例如,某个值必须小于另一个)。

并发

记录具有内部状态的 API 的并发属性。

  • FIDL 服务器执行请求的顺序可能不可预知。文档应考虑这可能会影响调用方观察到的行为的情况。
  • 每个具有内部状态的 API 都属于以下类别之一。使用以下字词记录具体是哪种:
    • 线程安全:这意味着,相对于其他并发进程,API 的各个元素(例如类中的方法)的调用是原子化的。调用方无需使用任何外部同步(例如,在方法调用期间,调用方无需获取锁)。如果调用方需要使用外部同步使对 API 实例的引用对其他线程可见(例如,通过设置并获取指向具有原子操作的类实例的全局指针),您仍可以将您的 API 描述为线程安全。
    • 线程不安全:这意味着所有方法都必须使用外部同步来确保保持不变(例如,由锁强制执行的互斥)。
    • 线程恶意:这意味着,不应从多个线程访问 API 元素(例如,其实现细节依赖于在后台对静态数据进行非同步访问,例如 strtok())。这应包括有关线程亲和性的文档(例如,它使用线程本地存储 (TLS))。例外情况仅在 Fuchsia API 中允许使用。
    • 特殊模式:这意味着您需要慎重考虑如何正确并发使用此 API,请阅读相关文档。当需要初始化实体并以特定方式发布对实体的引用时,这一点尤其重要。
    • 不可变:其他四个类假定内部状态是可变的,并且同步可以保证线程安全。不可变类看上去是不变的,无需任何额外的同步,但是您必须严格遵循有关序列化 / 反序列化以及如何在线程之间共享对对象的引用的规则。
  • 如果某个 API 不能保证进展,则会被视为“阻塞”。记录 API 的屏蔽属性。
    • 如果某个 API 是阻塞 API,则文档必须说明代码需要满足什么条件才能运行,除非阻塞是需要了解实现的低概率事件。
      • 一个必须记录方法的阻塞行为的一个例子是,该方法阻塞等待对通道的响应。
      • 举例来说,如果理论上讲,在高负载下可能会发生锁不足,那么该方法可能会阻塞,而无需记录方法的阻塞行为。
    • 我们不会仅仅因为 API 需要很长时间才能完成处理,才会将其视为阻塞。慢算法不应被记录为阻塞。
    • 文档应仅在非阻塞行为对其使用至关重要时(例如,如果 API 返回一个 future)声明 API 是非阻塞的。
  • 如果某个 API 在执行过程中可能会安全中断,然后重新调用,则该 API 属于可重入 API。记录 API 的重入属性。
    • 可能会假定 API 是可重入的。文档必须说明某个 API 是否不可重入。
  • 记录函数是否依赖线程本地存储 (TLS) 来保持其不变性,以及与该 TLS 相关的任何前提条件和后置条件(例如,如果每个线程需要调用一个初始化程序一次)。

所有权

文档所有权和活跃性属性。

  • 对于在函数生命周期以外存储的参数或返回值、由函数分配并传回调用方的资源,或具有必须由一组 API 观察到的特定所有权限制的资源(即共享资源),必须记录所有权和活跃性。
  • 记录负责释放所有相关资源的人员。
  • 在适当的情况下,文档中应说明释放这些资源的协议。当 API 的调用方和 API 之间的内存分配例程不同时,这可能是一个特殊问题。
    • 语言应在其样式指南中强调默认的所有权行为。

null 性

所有参数和返回值都必须定义其 null 性属性(如果它们的类型为可为 null)。

  • 即使是在 Dart 中!
  • 在适当的情况下,将参数和返回值指定为 nullable(可能包含 null)或 non-null(不得包含 null)。

单位

对于所有参数和返回值类型,必须明确定义单位(无论是按文档还是按类型)。

最佳实践

本部分介绍了在撰写注释时应考虑的指南。它包含意见,而不是上面给出的明确规则。

  • 读者不应该查看 API 的实现来了解其功能,考虑编写可让读者根据文档独立实现 API 的文档。如果您需要提供有关 API 工作原理的更多详细信息,请在 Fuchsia.dev 上创建并链接到其他文档。
  • 避免使用读者难以理解的术语(比如:“如果我对这个 API 感兴趣,我肯定会知道这个词的意思吗?”)。如果术语仅适用于 Fuchsia 且未定义,请将其添加到术语表中。
  • 避免使用缩写和首字母缩略词。在您需要时,请说明原因。 如果该缩写词在行业中广泛使用(例如,“传输控制协议 / 互联网协议”(TCP/IP)),则无需进行说明,但应考虑提供一个链接来了解更多背景信息。
  • 您应尽可能考虑代码示例。提供一个示例通常会使模式更加清晰。我们建议为每个顶级 API 元素(例如类)提供一个 API 示例。
  • 通过注释,应该能够清楚地知道如何使用您的 API。
    • 考虑将示例编写为单独的程序并链接到这些程序,但要注意文档中过时的链接。
    • 示例应全部编译并运行。
  • 当阅读文档的人提出应该由文档回答的问题时,请改进文档。
  • 始终提供附加值。不要重述类型签名已指示的内容。“不重复 (DRY)”原则适用。下面的代码没有用,因为它会将相同的信息重复两次:
 /**
  * Returns an instance of Foo.
  * @return an instance of Foo.
  */
 public Foo getFoo() { ... }
  • 同样,如果注释非常明显,也应避免发表此类评论。例如,如果类型系统保证某个属性,则您无需单独记录它。但请注意,您的 API 说明应足以支持独立实现。
  • 考虑记录性能注意事项和资源消耗问题,但也要记住,这些问题通常与实现有关,并且会随时间而变化,而您方法的协定可能会保持不变。不妨考虑改为在实现说明/版本说明中添加这些信息。
  • 避免创建非复合词。例如,“notready”就是两个单词一起运行。使用适当的分隔符,例如“not ready”“notReady”“not_ready”或“not-ready”。
  • 避免记录可能会随时间快速变化的功能,除非您明确指出该功能可能会随时间变化。您设定的设置越多,您为未来维护者提供的灵活性就越低。但请注意,这可能并不重要,因为您的用户将依赖于每一种行为。另请参阅 Hyrum's Law(希鲁姆定律)。