[Swift] Protocolの名前の付けかたのお話

命名論は各エンジニアの思うスタイルがあると思うので「こうあるべき」というお話はしません。 名前付けに迷うことが多い方の参考になればと思います。
2020.09.03

はじめに

CX事業本部の中安です。まいどです。

以前に社内でコードレビューをしてもらった際に「プロトコルの命名」についての指摘をいただきました。その時に自分の中で「けっこう曖昧に名前を付けていたなぁ」と反省しました。

では、プロトコルの命名とはどういうものがベターなのか。

今回は「プロトコルの名前の付けかた」に絞って少し調べてみたものを、まとめてみたいと思います。

ドキュメントから読み解いてみる

まずは、Appleが公開している「Cocoa向けコーディングガイドライン」を見ていくと

Protocols should be named according to how they group behaviors:

プロトコルは振る舞いのグループ化の方法に応じた名前にすべきです。

Most protocols group related methods that aren’t associated with any class in particular. This type of protocol should be named so that the protocol won’t be confused with a class. A common convention is to use a gerund (“...ing”) form:

ほとんどのプロトコルは、特にどのクラスにも紐付いていない関連メソッドをグループ化しています。そうした種別のプロトコルは、クラスと混同されないような名前をつけるべきです。一般的な慣例としては、動名詞(“...ing”)形式を使用します。

と書かれています。

また

Some protocols group a number of unrelated methods (rather than create several separate small protocols).

いくつかのプロトコルはいくつかの関連しないメソッドでグループ化されています(いくつもの小分けされた小さなプロトコルが作成されているわけではなく)。

These protocols tend to be associated with a class that is the principal expression of the protocol. In these cases, the convention is to give the protocol the same name as the class.

これらのプロトコルは、プロトコルの主要な表現であるクラスと紐付られている傾向にあります。そういった場合は、慣例ではクラスと同じ名前がつけられます。

と書かれていますね。

ただし、このドキュメントは Objective-C が主流だった時 Objective-C コーディングに向けた古いドキュメントになります(最終更新が2013年10月になっています)。現在はアーカイブされたドキュメントとしてカテゴライズされており、日本語訳版のページはなくなっているようです。

では次に、Swiftという観点で見ていくため、Swift.orgの命名規則のドキュメントを見てみます。

Protocols that describe what something is should read as nouns (e.g. Collection).

何かを説明するプロトコルは、名詞として読むべきです(例: Collection)。

Protocols that describe a capability should be named using the suffixes able, ible, or ing (e.g. Equatable, ProgressReporting).

能力を説明するプロトコルは、接尾語に -able、-ible、または -ing を使用した名前にすべきです (例 Equatable, ProgressReporting)。

おおよその命名方法は変わっていませんが、ずいぶんとニュアンスは変わっています。 Swiftライクなプロトコル命名方法とは何なのかもう少し掘り下げてみましょう。

標準ライブラリから読み解いてみる

英語での資料ですが、「What the 55 Swift Standard Library Protocols Taught Me」 (55個のSwift標準ライブリのプロトコルが私に何を教えてくれるか) というものがありました。

ここでは標準ライブラリに定義されたプロトコル群を見ると、プロトコルをいくつかにカテゴライズすることができるのではないかと書かれています。 たしかに標準ライブラリの傾向を読み解いていけば、命名のセオリーみたいなものも自ずと見えてくるような気がします。

この資料に書かれているパターンをかいつまむと、3つのパターンがあるとされています。

〜ができる

そのプロトコルが「能力」を表しているパターンです。前項でも書いたとおり、能力を表すプロトコルなので最後に「-able」か「-ible」をつけられています。

代表例でいえば、EquatableComparable などです。

Equatable に準拠していれば「等価性を判定できる」能力があるということで、その結果として == 演算子で比較をすることができると、ソースコードを読む人が判断できます。

〜である

そのプロトコルが「属性」を表しているパターンで、プロトコル名としては名詞になります。

代表例でいえば、Collection などがあります。

Collectionに準拠していると、ソースコードを読む人が「これは要素の集合体だ」という "これは何だ?" の判断ができると思います。

Collectionであれば count で要素数が取れることも想像できますし、firstで最初の要素を取得できることも想像できます。

「〜ができる」のパターンであれば「要素数を取得できる」という意味で Countable とつけるべきでしょうが、 ここでは「コレクション」という抽象化された言葉にすることで、具象型の属性を言い表すことができるのだと思います。

〜になれる

そのプロトコルが「変換可能」を表しているパターンです。上記記事によると、標準ライブラリ上では「-Convertible」と名付けられているパターンが多いとされています。

代表例でいえば、CustomStringConvertible などがあります。

「-Convertible」が「-ible」で終わっているため「〜ができる」パターンと同じようにも見えますが、 CustomStringConvertibleに準拠した具象型オブジェクトは「カスタムな文字列を変換できる」という能力が備わっていることを表現したいわけではありません。

たとえば、print()関数 にInt型の値を渡してやると、オブジェクトの情報ではなく数字そのものが出力されると思います。

これは、Intは遡ればCustomStringConvertibleに準拠していて、その必須プロパティであるdescriptionを実装しているため、 Intprint()関数が呼ばれた時には文字列として振る舞うことができるからです。

このことから「カスタムな文字列を変換できる」能力ではなく、「カスタムな文字列そのものになれる(変換される)」という表現になるのです。

ややこしいですね…

あくまでも元の資料の登壇内容を意訳したものなので、この分類の仕方が絶対的に正解というわけではないとは思いますが、 標準ライブラリの命名傾向を調べた上での分類なので納得感はありますね。

こう思ってみた

iOS開発で代表的なプロトコルといえば Delegateではないでしょうか。 UIApplicationDelegateをはじめ、UITableViewDelegateUICollectionViewDelegateなど挙げると数多くあると思います。

del・e・gate

名詞 複 ~s | -ts
1 (会議などへの/…からの)代表者, 代表委員, 代理人
2 下院議員
3 準州選出の下院議員

動詞 他動詞
1 (権限・責務などを)委任する、任せる
2 (会議などに人を)代表として派遣する
3 (人に)債務を転付する

上記のように辞書で見てみると Delegateは英語的には「代理人(委任された人)」という名詞と「委任する」という動詞の意味があるそうです。

ここで例に出すと AppDelegateは、UIApplicationDelegateに準拠した具象型クラスになるわけですが、 仮にUIApplicationDelegatableという名前であるとどういう不都合があるでしょうか。

この場合「委任する」に「-able」がつくので「委任することができる」という能力が付されるように見えてしまわないでしょうか。 準拠した側のAppDelegateが他人に委任をするためのクラスではないにも関わらずです。

あくまでも AppDelegateは、UIApplicationの「代理人」「委任されたもの」という属性。すなわち「〜である」の意味でないといけません。 したがって、各Delegateプロトコルは「それが何か」を表す名詞での命名となっているのだと思います。

Delegateはよく使われるものなので、自然と命名方法もしっくりとくるのですが、 開発をしていく中で自分で命名をしなければならないときに、このあたりが曖昧になっていると他人に渡した時に分かりづらいという印象を与えかねません。

名前を決めるときには「"それが何か"を説明するプロトコル」なのか「"何ができる"という能力を表すプロトコル」なのかという文脈づけた命名を意識をしたいものですね。

では、また。