クラス命名のアンチパターンについては、世間でも問題意識が共有されていて、すでに記事が書かれているのですが(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::NameIsNotEmpty
User::EmailAddressValid
User::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
(大抵雑多なメソッドの掃き溜めになる)
など、まだまだありますが、私にはその元気がありません。他の誰かが書いてくれることを望みます。
また、正しい名前を付けることは大切ですが、それは当たり前のことであって、プログラムが動き、人の役に立つ事が重要なのは言うまでもありません。
どっとはらい。