Fat Model, Skinny Controllerという考え方


Railsのリファクタリングでよく出てくる言葉として、「Fat Model, Skinny Controller」というものがあります。ちなみに、リファクタリングとはソースコードを書き換えることでアプリケーションを改善することを言います。
もう少し詳しく説明すると外部への振る舞いを変更せずに、内部構造のみを変更します。
テストを書いているのであれば、テストの結果は変わらないような変更を指しますので、機能の振る舞いが変わってしまうような変更はリファクタリングとは言いません。
目的は、誰にとっても読みやく、活用しやすいコードや同じ処理を個別に何度も記述している箇所をまとめる(DRYの原則に従う)ことを目指します。
目的をまとめると下記のようになります。

  • ソフトウェア設計の改善
  • ソフトウェア設計の劣化を防ぐ
  • 可読性の向上
  • バグを見つけ出す

次に、リファクタリングの必要性ですが、アプリケーションのコードは日々変化するものなので、当初は完璧に設計されたアプリケーションでも運用するにあたって技術的夫妻が溜まっていきます。
技術的負債とは、コードの書き方から開発体制に及んで広い意味を持ち、例えば下記のようなものが挙げられます。

  • バージョンが古いまま放置された言語やフレームワーク
  • 行き当たりばったりなアーキテクチャ
  • 不必要に複雑化したコード
  • カバレッジの低い、もしくは書かれていないテストコード
  • 開発者や関係者間で共有されていない知見
  • コーディング規約に従わないコード

このような技術負債が溜まっていくと、品質や開発効率が低下します。その結果、運営負荷が上がり開発コストは上がっていきます。この負債は日々小さくしていくことが重要なので、リファクタリングが必要とされています。

さて、本題に戻って「Fat Model, Skinny Controller」とはレスポンスに関係のないロジックはコントローラではなくモデルに寄せることで、コントローラを小さくしようというものです。
モデル ⇄ コントローラ ⇄ ビューという関係性の中ではコントローラはモデルとビューをつなく役割になりますので、そのインターフェイスを綺麗に保つことでそれぞれの関係性が明確になったり、可読性を向上させることができます。

下記のコードは具体例です。

Before

controller
def index
  @published_posts = Post.where(published: true).order(created_at: :desc)
  @unpublished_posts = Post.where(published: false).order(created_at: :desc)
end
model
class Post < ApplicationRecord
end

After

controller
def index
  @published_posts = Post.published
  @unpublished_posts = Post.unpublished
end
model
class Post < ApplicationRecord
  scope :published, -> { where(published: true).order(created_at: :desc) }
  scope :unpublished, -> { where(published: false).order(created_at: :desc) }
end

記述量はそれほど変わっていないように見えますが、もし、Post.publishedを別のコントローラから呼びたくなった場合はどうでしょう?アプリケーションが肥大化するにあたって、同じことを記述している箇所を抑えられ上記に挙げたリファクタリングの概念に沿っていることがわかります。

オススメの記事

Ruby Ruby on Railsを導入しよう Rails CSVファイルのデータを読み込んで処理をする
Rails Fat Model, Skinny Controllerという考え方 Swift guard - else 文
React importとexport Swift オプショナルチェーン
BLOG コード鉄道の夜がGoogleにインデックスされた件 Rails DBから条件を指定せずに、ランダムにレコードを取得する
次の記事 >> CSVファイルのデータを読み込んで処理をする
前の記事 >> DBから条件を指定せずに、ランダムにレコードを取得する
Railsの記事一覧へ戻る