swiftの設計ガイドラインを参考にまとめます。
https://swift.org/documentation/api-design-guidelines/
swift2.xからswift3.0に、大きく破壊的な変更が設けられたことは今でも記憶に新しいです。
swift3.0以降の設計はAPI Design Guidelinesに起因するので、
今からswiftを初める人も、Objective-CからiOSに触れている人も、よりswiftらしい記述を求められているため、まとめました。
原則
- 英文として違和感のない記述をする
- 簡潔さより明快さを大切にする
命名規則
明快な使用を促進
- 曖昧さを避けるために必要な単語を全て含めること
employees.remove(at: x) //Good
employees.remove(x) //Bad ⇒ unclear: are we removing x?
- 必要のない単語は省略すること
allViews.remove(cancelButton) //Good
allViews.removeElement(cancelButton) //Bad
- 型の制約ではなく、役割に応じた命名をすること
//Bad
var string = "Hello"
protocol ViewController {
associatedtype ViewType : View
}
class ProductionLine {
func restock(from widgetFactory: WidgetFactory)
}
//Good
var greeting = "Hello"
protocol ViewController {
associatedtype ContentView : View
}
class ProductionLine {
func restock(from supplier: WidgetFactory)
}
- 引数の役割を明確にするために情報を補うこと
grid.addObserver(self, forKeyPath: graphics) //Good
grid.add(self, for: graphics) //Bad
流暢な使い方に努める
- メソッドや関数を英文法的に成り立たせる
x.insert(y, at: z) //Good
x.subViews(havingColor: y) //Good
x.capitalizingNouns() //Good
x.insert(y, position: z) //Bad
x.subViews(color: y) //Bad
x.nounCapitalize() //Bad
- オブジェクトを作成するメソッドは
make
をつける
x.makeIterator()
- 暗示されるフレーズには、第一引数に含めない
let foreground = Color(red: 32, green: 64, blue: 128) //Good
let foreground = Color(havingRGBValuesRed: 32, green: 64, andBlue: 128) //Bad
- 副作用に応じたメソッドを命名する
- メソッドの動作を動詞で表現する場合
ed
やing
を付与する - メソッドの動作を名詞で表現する場合
form
を付与する
- メソッドの動作を動詞で表現する場合
x.sort() => z = x.sorted()
x.append(y) => z = x.appending(y)
x = y.union(z) => y.formUnion(z)
- 真偽判定するメソッドを分かるように命名する
array.isEmpty
view.isHidden
- プロトコルが何であるかを表す場合は名詞にする
Collection, Iterator など
- プロトコルの能力を表す場合は末尾を
able
,ible
,ing
にする
Equatable, ProgressReporting など
- その他の型/引数/変数/定数は基本的に名詞にする
専門語は上手に用いる
- 曖昧な言い回しを避ける
- 確立された意味に固執する
- 略語は避ける
- 先例を受け入れる
慣習
一般
- computed プロパティの複雑化に注意する
- グローバル関数よりメソッドやプロパティを使う
min(x,y,z) //明確な selfが存在しない場合
print(x) //慣習が汎用的な場合
sin(x) //関数の構文が確立されたドメインの表記の場合
- キャメルケースに従う
UpperCamelCase //型やプロトコル名
lowerCamelCase //それ以外
- メソッドで基底の名前を共有する
extension Shape {
func contains(_ other: Point) -> Bool { ... }
func contains(_ other: Shape) -> Bool { ... }
func contains(_ other: LineSegment) -> Bool { ... }
}
extension Collection where Element : Equatable {
func contains(_ sought: Element) -> Bool { ... }
}
パラメータ
- 引数名に説明の役割を持たせる
mutating func replaceRange(_ subRange: Range, with newElements: [E]) //Good
mutating func replaceRange(_ r: Range, with: [E]) //Bad
- デフォルト引数を利用する
第二引数以降の関連しない情報を隠す
let order = lastName.compare(royalFamilyName) //Good
let order = lastName.compare(royalFamilyName, options: [], range: nil, locale: nil) // Bad
- デフォルト引数は最後に配置する
- デフォルト値を持たない引数は、メソッドにおいて重要な意味を持つためです。
引数ラベル
func move(from start: Point, to end: Point)
x.move(from: x, to: y)
- 引数が区別出来ない場合は、ラベルを省略する
min(number1, number2)
zip(sequence1, sequence2)
- 初期宣言の第一引数ラベルは省略する
- メソッド名に引数ラベルを付ける
- 第一引数が英文の一部を構成する時に、他の引数を考慮してバランスが悪くなる場合の対応
- しかしラベルを省略することで逆に、曖昧になる場合にはラベルを付与する
a.moveTo(x: b, y: c) //Good
a.fadeFrom(red: b, green: c, blue: d) // Good
a.move(toX: b, y: c) //Bad
a.fade(fromRed: b, green: c, blue: d) //Bad
view.dismiss(animated: false) //Good
let text = words.split(maxSplits: 12) //Good
view.dismiss(false) //Bad ⇒ Don't dismiss? Dismiss a Bool?
words.split(12) //Bad ⇒ Split the number 12?
- それ以外に対しては全てにラベルをつける