膨れ上がったモデルから機能を分離する切り口

Railsのモデルにちょびちょびと処理を追加していると、いつの間にかサイズが膨れ上がってしまっていたりする。

Railsでロジックを書く場所として与えられている場所はコントローラかモデルなので、「コントローラは単純にしなさい」という教えに従うと、必然的に多くの処理はモデルに書くことになってしまい、モデルが膨れ上がる結果に陥りやすい。

それを解消するために、モデルから切り出せるものは切り出しましょう、ということで、下記の記事に、膨れ上がったモデルから機能を別の独立したクラスに切り出すための7つの切り口が提示されていた。

http://blog.codeclimate.com/blog/2012/10/17/7-ways-to-decompose-fat-activerecord-models/

以下はそのメモ。

バリューオブジェクト

上の記事では例として、costという数値フィールドをRatingというバリューオブジェクトで取り扱っている。 Ratingはcostで初期化され、AからFの文字表現に変換される。 RatingにはRating値どうしの大小を比較する演算子が定義される。

サービスオブジェクト

複雑な処理、複数のモデルにまたがる処理、外部サービスへのアクセスなどをラップする。

フォームオブジェクト

複数のモデルを一つのフォームで更新するのに使う。 nested_attributesを使うよりもスッキリする。

クエリーオブジェクト

複雑なクエリーでActiveRecordのサブクラスがscopeやクラスメソッドだらけになったら、それらをクラスとして分離する。

ビューオブジェクト

画面表示用のみにデータを加工する必要があるときは、モデルにロジックを追加するのではなく、ビューオブジェクトとして独立したクラスに切り出す。 ダッシュボードページなどもか。

ポリシーオブジェクト

モデルの複数のフィールドの値を組み合わせて1ランク抽象度の高い状態を表すような場合に、独立したクラスでそれを表現する。 サービスオブジェクトが更新系の処理で、こちらは読み取り用のオブジェクト。

デコレータ

モデルの操作の前後に処理を追加する。 コールバックと同じ目的だが、そうした処理が毎回は必要ではない場合や、モデルに役割を持たせすぎるのを避けたい場合などに。 例としては、処理の実行後にSNSに投稿する処理を付け足すといったこと。