2021-07-26
タイトルが過激、すみません。
utilクラスは良くないよねってありふれた話。
以下webアプリケーションの文脈の話。
最近コードレビューでこんなコードを見て思った
src/util/UserLogic
class UserLogic{
public Boolean isValid(User user) {
//なんかの処理
}
}
User ってドメインモデルが既に存在してて、そのUserに対する処理を新たに書いたutilクラス。
まずそもそもこのリポジトリには util ってパッケージ(ディレクトリ)は切ってなくて、これは新しくパッケージを切ったようなPRだった。なのでこのクラスも新規クラス。
ダメ、かな......。
そもそもこういうロジックのあるメソッドはどこに書くべきだろう?
これはありきたりな言葉を借りて一旦結論を出すと、ドメインモデルあるいはドメインサービスに書くべき。
ドメインモデルとかそういう用語はコーディングに関するDDDの文脈とかで出てくるやつ。
そう、これは正しい。
ロジックを共通化するという考え方は良くて、どちらかというとutilなんてメソッドの切り方をしていること。
メソッドの処理がどういうドメインに属しているかを意識できていないこと、このあたりが問題である。
Userというドメインこういうコードが生まれるのはドメインを捉えてないから、というのが大きい。
浅い考え方なのかもだけど、少なくとも今の僕にはこの感想が大きい。
(ドメインという言葉に関しては、エリックエヴァンスなどを要参照......)
上記のメソッドを例に挙げて言うと、User ってクラスのインスタンスを受け取って Boolean を返す。User はもちろんプリミティブでもなんでもなくて、自作クラス。
なのでこの時点で全然utilにはなっていなくて、User ってドメインにかなり寄ったメソッドになっている。
属するドメインが明らかなのでロジックを置く場所はドメインに沿ったサービスかモデルのメソッドとなる。
UserLogic ってクラスに書いてるんだから良くない?良くない。
極端な話、serviceクラスかドメインモデル、どちらかに殆どのメソッドを切れるはず。
全ての処理に関して、どういうドメインに属した処理なのか、どこに関心のあるオブジェクトなのか、を意識してコーディングしてくと何かしらのドメインクラス(サービス/モデル)が生まれることになり、 util って切り方をすることはなくなる。
そんなことはなくて、「ドメインに属さないような本当に基本的な処理」なら別にutilに切り出しても良いと思う(文字列操作やlist操作など)
ただそういうutilメソッドを書きたくなったときは、言語仕様としてそういうapiが既にないかを確認するべきなタイミングである気がする(webで使うような言語は便利なメソッドがあること多い)
処理が内部でリポジトリに依存(外部リソースに依存)するならサービス一択。インスタンスが量産されるようなモデルでそういう処理はNG。
またあるモデルの状態に依存するような処理は、基本的にモデル側のpublicメソッドで良い。今回の例に挙げたメソッドも、Userのフィールドだけを見て処理するようなロジックなら同じように当てはまる。
状態を持っていたり、状態を変化させる処理も基本的にモデル側。
serviceはシングルトンであるべきというのも意識しないといけない。
この話はもっと他の資料を見て勉強するのが良い気がします。
結論だけど、UserService のクラスとか User のオブジェクト側にメソッド切ってほしい。utilクラスは極力要らない。utilってクラス作ろうとしてたり、どこにメソッド書いていいか迷うときはドメインが何かを見極めれていないことが多い気がします。
過激な主張でした、すみません。間違っているところもあるかも知れません。
ではでは。