クラス命名のアンチパターンについては、世間でも問題意識が共有されていて、すでに記事が書かれているのですが(Qiitaならこの記事 など)、
私は正直「これは負け戦なのでは?」と感じていました。ダメな命名パターンは無数にあり、リストは長くなる一方だからです(そして長すぎるリストは読まれない)。
そこで戦況を巻き返すべく、無茶を承知でこう宣言させていただきます。
ルール「クラス名ではいかなる接尾語も禁止」
何らかの接尾語(サフィックス)が付いたクラス名は全てNGです。
Service, Manager, Controller, Filter, Handler, Validator, Visitor, Agent, Dao, Rule, Info, Data, Helper, Util, Type, Enum, Proxy その他とにかく接尾語(サフィックス)は悪いものです。命名を考え直してください。
また、Reader, Writer, Accessor, Getter, Fetcher などの「動詞-er/-or」も接尾語の一種だと思ってください。「動詞-er/-or」も悪です。
※例外条項:
- フレームワークやプロジェクトに接尾語のルールがある場合はそれに従います。
- (上級者向け)接尾語を新設するときはREADMEやコメントに明記します。
なんで接尾語はダメなの?
経験上、こういったクラスはえてして、とりあえずメンバやメソッドをぶち込む掃き溜めになるからです。
- 「
Userに関係する情報だからとりあえずUserInfoのメンバにしよう」とか - 「
Userに関連する処理だからとりあえずUserServiceの静的メソッドにしよう」とか
また、接尾語がつく名前は、深く考えずにクラスを設計してしまっていることや、不適切なクラス分割をしてしまっている事が多いです。
なんで接尾語はダメなの?その2
また、同じ接尾語が付くクラスは、共通性を持つと期待するのが人情です。例えば HogeValidatorとFugaValidatorがあった時は、
- それぞれ
HogeオブジェクトとFugaオブジェクトをチェックするんだろう - 同じメソッド(多分
validate)を提供するんだろう - 生成方法(
newなり DI なり)も同じだろう -
Piyoクラスを新設した時は、PiyoValidatorも必要なのかな?
と期待するでしょう。
しかし、こういった接尾語・カテゴリを正しく設計するのは案外難しいことです。
例えば一時期Rails界隈では「〜Service」が流行ったのですが、現在は下火です。最初は良いアイデアだと思われたのですが、実践してみると酷いコードが生まれる事も多かったからです。
じゃあ、どうやって接尾語を消せばいいんだよ!?
接尾語を避ける方法はいくつかあります。
1. そもそもクラスを作らない
UserInfoやUserUtilのメソッド・メンバは Userに移せるはずです。
その結果 Userクラスの行数は大きくなりますが、気にする必要はありません。いわゆる「クラスの肥大化」「Fat Model」は本当に大規模なコードでのみ問題となります。
2. クラスを細かく分ける
例えば、User関係のチェックが詰め込まれたUserValidatorがあるとしたら、チェック項目ごとにクラスを分けます。
User::NameIsNotEmptyUser::EmailAddressValidUser::AdultAge
etc...
3. 見方を変える
例えば、「ネットワーク越しにユーザーログを書き込むクラスNetworkUserLogWriterでログを書き込む」ではなく、「ユーザーログUserLogにログを書き込む(実際の処理はネットワーク越しに行われる)」のだと考えてみてください。
ログを生成する側(ControllerとかModelとか)からすれば、とにかく抽象化されたナニモノカにログを書けることが大事で、それが「ネットワーク越しに」「書き込んでいる」ことは重要ではありません。隠蔽されていて良いのです。隠蔽されるべきことを名前で表す必要もありません。
4. いっそオブジェクト指向を諦める
どうしても的確なクラス名が思いつかなかったり、既存のコードが既に破綻していてクラス設計は無意味な場合があります。そんなときは、オブジェクト指向を諦め、クラス・メソッドではなく、純粋な関数にしてしまう手もあります。
「関数」が無い言語も「staticメソッドを1個だけ提供するクラス(クラス名はstaticメソッド名と同じ)」などで同じ事ができます。
接尾語は絶対にダメですか?
もちろん、人気のフレームワークが提供する「接尾語」(RailsのControllerなど)は、長年の風雪に耐えたものであり、使ってもなんら問題ありません。プロジェクトで DDD / Clean Architecture を実践するつもりなら、RepositoryやUseCaseといった接尾語を使うことになるでしょう。
あなたが本当に必要だと思うなら、新たな接尾語を新設しても構いません。ただし、その際には以下に注意してください:
- 接尾語が的確であること(
Serviceの二の舞を避ける) - 接尾語が実際に必要であること(今回の1クラスだけで終わるんじゃないか?)
- 接尾語の使い方をREADMEやコメントで説明する事
接尾語以外にもダメな命名はあるよね?
もちろんです。
- 英語ではなく、ローマ字ですらない(
UserRegistKubunとか) - 名前が内容に反する(
ViewModelなのに、DBを更新するだと!?) -
Common(大抵雑多なメソッドの掃き溜めになる)
など、まだまだありますが、私にはその元気がありません。他の誰かが書いてくれることを望みます。
また、正しい名前を付けることは大切ですが、それは当たり前のことであって、プログラムが動き、人の役に立つ事が重要なのは言うまでもありません。
どっとはらい。