目次
中学校あるいは高校生の時だったでしょうか。英語の第5文型というものを習いましたよね。
SV、SVO・・というアレです。
さまざまなプログジェクトでコードレビューをさせて頂く機会が多いのですが、
メソッドのネーミング(命名)に悩む人が多くいらっしゃいます。
今回は第5文型を意識すれば、メソッドのネーミングはそんなに難しくないよというお話です。
ここでは、メソッド名は動詞から始まるという一般的なルールを想定し、使うプログラム言語をJavaとして説明させていただきます。
第5文型とはそれぞれ次のようなものです。
文型 | 例文 |
---|---|
第1文型(SV) | The system launched. |
第2文型(SVC) | The system is down. |
第3文型(SVO) | The system creates a default password. |
第4文型(SVOO) | The system sends user an email. |
第5文型(SVOC) | The system keeps an email unread. |
普段、コードを書くときは、もしかするとあまり意識をしていないかもしれません。
ところで、メソッドのJavadocをしっかりと書いているでしょうか?
「publicメソッドなら書く」というルールがあるかもしれません。
Javadocでは1行目の句点までに、メソッドの振る舞いを端的に説明するコメントを書きます。
例えば、
* メールを送る。
* (詳しい説明)
* @param, @return...など
*/
public void send(Email email) {
...
}
この「メールを送る。」という一文ですが、英語で訳すと文型1〜5のどれでしょうか?
sendは自動詞ですか?それとも他動詞ですか?
これは第3文型で、sendは他動詞ですよね。
Javadocを書かないケースであってもメソッドには必ず仕様がありますし、Javadocに書く1行目のコメントは必ず第1〜第5までの文型のいずれかに当てはまるはずです。
それを意識するだけでネーミングはとってもラクになりますよというお話です。
さて、前置きが長くなりましたが実際のネーミングに話を戻します。
「S」(主語)
「S」は省略されたり、文脈で解釈されたりする割とアバウトな存在ですが、
呼び出すメソッドを保持しているインスタンスの変数(レシーバ)名が「S」(主語)になるようにすると、英語を読んでいる感覚でコードを読むことができます。
ただ、getterなどは、文型の「S」を意識しすぎると意味不明になるので、昔からそういう文化だと割り切り、あまり深く考えないようにしてください。
プライベートフィールドの公開方法がgetterメソッド経由にならなかったり、カッコを省略出来る言語も多くなって来ているように思います。
Record型ではgetXXXの呪縛から解き放たれるでしょう。LTSになるのが待ち遠しいですね。
「V」(動詞)
「V」に関する基本的なルールとしては、どの文型に照し合わせても動詞が2つ連続するということはありませんので、以下のようなメソッド名は誤りです。
- password.isValidate()
- mailer.sendConfirm()
正しくは、以下のようになるでしょう。
- password.isValid()
- mailer.sendConfirmation()
それぞれの文型について
これより先は、メソッドの振る舞いを端的に表した1文が、一体どの文型なのかを意識しながら読み進めてください。
第1文型(SV)
引数がないメソッドがこれにあたり、メソッド名は自動詞になります。
事前にそのインスタンスの操作が行われていて、最終的に何らかの処理のトリガーにしたいようなメソッドが第1文型になることが多いように思います。
仮に「add」などの他動詞でネーミングしたメソッド名で引数がない場合は、不安になりますのでご注意を。
" hello ".trim(); // trimは他動詞としての用法もあるが、前後のスペースを除去するとい共通理解が得られている動詞。
第2文型(SVC)
第2文型を意識したネーミングとしては、以下のようなものがお馴染みでしょう。
// 省略
}
if (thread.isInterrupted()) {
// 省略
}
「リストが空ならtrueを返す。」など、メソッドの仕様を言語化した時は、「〜という状態であるかどうか」という文脈になることが多いと思われます。
「C」は形容詞や受動態などの補語ですね。
booleanを返し、オブジェクトの状態尋ねる真偽値で返すようなメソッドは、迷わず「is」から始めると自然なネーミングができると思います。
第3文型(SVO)
第三文型以降で使われる目的語(O)は、メソッドの引数になるケースが多いと思います。
「V」であるメソッドは必ず他動詞になります。
目的語をメソッドの引数とすると、スパッと短いネーミングで済ませることができるんですね。
具体的な例を標準APIで見ていきましょう。
list.remove("banana"); // リストは"banana"という文字列を削除する(第3文型)
「addElementToIndex(“banana”, 2)」のように、振る舞いをそのまま説明するようなメソッド名にする方もいると思うのですが、標準APIにあるように「add(2, “banana”)」だけでも伝わります。
シグニチャー的に第一引数はインデックスを指定するのかなと直感的に解釈できますし、「addElementToIndex」のようなネーミングは、書く方も読む方も疲れちゃいますよね。
引数があるbe動詞のメソッドなら文型上は第2文型(SVC)になります。
(引数が「C」を表しています。)
引数の型やその名前は「S」自体の比較対象になるべきものを受け取ったり、状態などを表す列挙型(enum)にすると良いでしょう。
第4文型(SVO1O2)
O1にO2を〜する
(ex. This machine gives my cat drinking water.)
第四文型の場合、以下のようにO1の前に前置詞をつけても意味が通りますから、第3文型にしてしまうとネーミングもしやすくなると思います。その場合はO2が第一引数になります。
mailer.send(user, email)
// 第3文型にするなら。
mailer.sendTo(email, user);
もし、メソッドのパラメータが3つ以上になったら、そのメソッドの責任が重すぎるか、パラメータの型が責任を果たしていない傾向がありますので注意しましょう。
こういうときは大概ユニットテストも大きくなりがちです。
第5文型(SVOC)
メソッドの振る舞いを端的に表現した1文が第5文型である場合も、「C」は「O」状態を表した型などにするとコードが読みやすくなりますし、メソッド名も短くなります。
こういう場合は、無理に第5文型で処理せず、messageにステータスをプライベートフィールとしてに保持させてしまうと、1行だけ長くはなりますが、読みやすさという点では劣らないでしょう。
messageThread.update(chat);
その他
- 型変換系のメソッドは「to名詞」を積極的に使いましょう。そしてconvertという動詞との混在は避けましょう。
- インスタンスのビルダー系メソッドでは「of」のオーバーロード積極的に使いましょう。(Ex. Map.of, List.of, Optional.ofなど)
- lengthなど自明なフィールド公開用のメソッドは、名詞でネーミングしても問題ないでしょう。
長くなりましたのでこの辺で!
それでは!