mcpField
S
swift-api-design-guidelines

swift-api-design-guidelines

github.com/dpearson2699开发1.2k2.9k 次安装13 周前更新
代码仓库

关于 swift-api-design-guidelines

用于在 Swift API 中应用 Swift API Design Guidelines 的参考技能,涵盖命名、参数标签、文档和调用处可读性。面向设计或审查 Swift API 的开发者,并归纳副作用、变异方法配对和流畅调用的约定。

主要功能

  1. 01参数标签约定
  2. 02副作用与变异命名
  3. 03文档注释规则
  4. 04按角色命名与清晰度
  5. 05协议及大小写约定

适用场景

  1. 01审查公开 Swift API
  2. 02为方法参数选择标签
  3. 03记录声明与复杂度
  4. 04规范变异与非变异命名

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/dpearson2699/swift-ios-skills --skill swift-api-design-guidelines

安装后在 Claude Code 中输入/swift-api-design-guidelines确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

evals/
evals.json
references/
argument-labels-and-parameters.md
conventions-and-special-rules.md
naming-and-clarity.md
side-effects-and-mutating-pairs.md

详细介绍

Swift API 设计指南

将 Swift API 设计指南应用于命名、标签、文档和调用点清晰度。对于混合请求,在此处理 API 设计部分,并将语言/类型系统相关工作转交给 swift-language,将并发相关工作转交给 swift-concurrency,将 lint 配置转交给 swiftlint。

目录

参数标签规则

参数标签决定调用点的可读性。应用第一个符合的行:

情况规则示例
第一个参数补全语法短语省略标签,将词语合并到基本名称中addSubview(y)
保留值的初始化转换省略第一个标签Int64(someUInt32)
参数是无法区分的同类项省略所有标签min(x, y)
第一个参数补全介词短语使用介词作为标签fade(from: red)
前两个参数构成单一抽象将介词并入基本名称moveTo(x: b, y: c)
其他情况添加标签split(maxSplits: 2)

在需要确定抽象边界、多个介词、转换初始化器、无法区分的同类项、参数命名或默认参数时,加载参数标签与参数。

副作用命名

对具有副作用的操作使用祈使动词,对没有副作用的操作使用描述结果的名词或形容词短语,对布尔 API 使用断言式名称。

array.sort()
array.append(newElement)
let d = point.distance(to: origin)
line.isEmpty
set.contains(element)

在审查扩展的纯操作/可变操作示例或布尔命名时,加载副作用与可变配对。

可变与不可变配对

根据操作的自然描述,为可变/不可变配对命名:

  • 对动词操作,可变操作使用祈使形式,副本使用描述结果的分词形式:sort()/sorted() 或 append(_:)/appending(_:)。优先使用 -ed;仅当 -ed 不符合语法,或描述的是直接宾语而非返回结果时,才使用 -ing。
  • 对名词操作,副本使用名词,可变操作使用 form + 名词:union(_:) / formUnion(_:)。
  • 为创建新值的工厂添加 make 前缀。

当返回结果的语法不明确时,加载-ed/-ing 决策树。同一参考资料还包含扩展的 form 前缀、布尔值和工厂模式。

文档注释

每个公开声明都必须有文档注释。

按声明种类划分的摘要规则
声明摘要描述
函数/方法它的作用及其返回内容
下标它访问的内容
初始化器它创建的内容
类型/属性/变量它是什么

将摘要写成一个句子片段:动作以动词开头,实体以名词短语开头,并以句点结尾。

/// Returns the element at the specified index.
func element(at index: Int) -> Element { ... }

/// The number of elements in the collection.
var count: Int { ... }

/// Creates a new array with the given elements.
init(_ elements: some Sequence<Element>) { ... }

/// Accesses the element at the specified position.
subscript(index: Int) -> Element { ... }
符号标记

在相关情况下,于摘要后使用标准符号标记:

  • - Parameter name: 用于单个参数
  • - Parameters: 块用于多个参数
  • - Returns: 用于返回值
  • - Throws: 用于抛出的错误
  • - Complexity: 用于算法复杂度
/// Removes and returns the element at the specified position.
///
/// - Parameter index: The position of the element to remove.
/// - Returns: The removed element.
/// - Complexity: O(*n*), where *n* is the length of the collection.
mutating func remove(at index: Int) -> Element { ... }
O(1) 复杂度规则

对于任何复杂度不是 O(1) 的计算属性,都要注明其复杂度。调用方默认属性的复杂度为 O(1)。如果属性执行的工作不止常量时间,就要明确说明其复杂度。

/// The total weight of all items.
///
/// - Complexity: O(*n*), where *n* is the number of items.
var totalWeight: Double {
    items.reduce(0) { $0 + $1.weight }
}

有关文档编写模式和示例,请参阅 references/conventions-and-special-rules.md。

清晰度与命名

使用时的清晰度是最重要的目标。每项设计决策都应服务于阅读调用点的人。

清晰优先于简洁。 如果较长的名称能消除歧义,就可以使用较长的名称。不要缩写。

// GOOD
employees.remove(at: position)

// BAD — ambiguous: remove the element? remove at position?
employees.remove(position)

保留避免歧义所需的词语。 如果省略某个词会让调用点变得不清晰,就保留它。

// GOOD — "at" clarifies the argument's role
friends.remove(at: index)

// BAD — is "index" the element to remove or the position?
friends.remove(index)

省略不必要的词语。 不要重复上下文中已有的类型信息。

// GOOD
allViews.remove(cancelButton)

// BAD — "Element" repeats the type
allViews.removeElement(cancelButton)

按角色而非类型命名变量和参数。 使用实体在当前上下文中的角色,而不是其类型名称。

// GOOD — describes the role
var greeting: String
func add(_ observer: NSObject, for keyPath: String)

// BAD — names the type
var string: String
func add(_ object: NSObject, for string: String)

弥补类型信息不足。 当参数类型为 Any、AnyObject 或 Int、String 之类的基本类型时,在名称中添加能明确其角色的词语。

// GOOD — role is clear despite weak types
func addObserver(_ observer: NSObject, forKeyPath path: String)

// BAD — what does "string" mean here?
func add(_ object: NSObject, for string: String)

有关更多命名示例和模式,请参阅 references/naming-and-clarity.md。

流畅用法与协议

调用点读起来应符合语法。 优先选择能让调用点构成合乎语法的短语的名称。

// GOOD — reads fluently
x.insert(y, at: z)          // "x, insert y at z"
x.subviews.remove(at: i)    // "x's subviews, remove at i"
x.makeIterator()             // "x, make iterator"

// BAD — ungrammatical
x.insert(y, position: z)
x.subviews.remove(i)

初始化器的第一个参数。 初始化器的第一个参数不应与类型名称连起来构成短语。

// GOOD
let foreground = Color(red: 32, green: 64, blue: 128)

// BAD — "Color with red" reads awkwardly
let foreground = Color(havingRGBValuesRed: 32, green: 64, blue: 128)

协议命名约定:

协议描述的内容命名模式示例
某物是什么名词Collection、IteratorProtocol
一种能力使用 -able、-ible 或 -ing 后缀Equatable、Hashable、Sendable

一般约定

大小写。 类型和协议使用 UpperCamelCase。其他所有内容使用 lowerCamelCase。在美式英语中通常全大写的首字母缩略词,应根据其位置统一使用全大写或全小写。

var utf8Bytes: [UTF8.CodeUnit]
var isRepresentableAsASCII = true
var userSMTPServer: SMTPServer

优先使用方法和属性,而非自由函数。 优先使用方法和属性。仅在以下情况下使用自由函数:

  1. 没有明显的 self — min(x, y)
  2. 函数是无约束的泛型 — print(value)
  3. 函数语法是已确立的领域记法 — sin(x)

优先使用默认参数,而非方法族。 优先使用一个带默认参数的方法,而不是一组仅在接受哪些参数上有所不同的方法。将带默认值的参数放在末尾。带默认值的参数应始终带有参数标签 — 带默认值的参数通常会在调用点省略,因此在出现时,其标签必须清晰明确。

// GOOD — labeled with defaults
func decode(_ data: Data, encoding: String.Encoding = .utf8) -> String?

// BAD — method family
func decode(_ data: Data) -> String?
func decode(_ data: Data, encoding: String.Encoding) -> String?

重载安全性。 方法可以共用基名称,前提是它们适用于不同的类型领域,或者其含义能从上下文中明确看出。避免仅按返回类型区分、导致调用点出现歧义的重载。

有关大小写的特殊情况、重载模式以及元组/闭包命名,请参阅 references/conventions-and-special-rules.md。

常见错误

错误修正
标签含糊不清或缺失让调用符合语法,例如 remove(at:)。
可变/不可变形式使用不当对修改操作使用祈使动词;对副本使用符合语法的 -ed/-ing 形式或名词形式。
名称描述类型或实现方式按角色和语义效果命名。
公共 API 缺少用途或复杂度文档添加简明摘要,并记录复杂度不是 O(1) 的属性。
错误使用 form 或工厂前缀将 form 保留给名词操作;工厂使用 make。
重复类型信息删除声明和上下文中已明确的词语。
重载仅在返回类型上有所不同添加语义名称或参数差异。
元组或闭包组件仅按位置区分为公共组件和闭包参数添加标签。

审查清单

参数标签
  • 第一个参数遵循正确的标签规则(语法短语、介词短语、转换或带标签)
  • 介词标签不会错误地将独立参数归为一组
  • 保留值的转换初始化器省略第一个标签
  • 所有非特殊情况的参数都有标签
命名语义
  • 可变更方法使用祈使动词形式
  • 不可变更方法使用 -ed/-ing 形式或名词形式
  • 可变更/不可变更方法对遵循正确模式(动词对或名词/形式名词对)
  • 布尔属性读起来像断言(isEmpty、isValid、contains)
  • 变量和参数按角色命名,而非按类型命名
文档
  • 每个公开声明都有文档注释
  • 摘要是以句号结尾的单句片段
  • 摘要根据声明类型描述正确的内容(操作、访问、创建、实体)
  • 非 O(1) 的计算属性注明其复杂度
  • 参数、返回值和抛出的错误均使用符号标记进行说明
约定
  • 类型和协议使用大驼峰命名法;其他内容均使用小驼峰命名法
  • 根据位置统一缩略词的大小写
  • 优先使用默认参数,而非方法族
  • 重载不能仅在返回类型上有所不同
  • 协议名称遵循名词(is-a)或后缀(能力)约定

参考资料

评论

支持 Markdown