Rails MVCの責務を知る
なぜ書くのか?
Railsの責務を理解していないために、メソッドをどこに書けばいいのか?を考えたり、どこにあの実装があったか?を探すのに時間がかかってしまっています。本記事は、RailsのMVCの責務の理解し、適切な場所に実装を書けるように、また検索の速度を上げるために書きます。
やらないこと
- 手段の深堀り
Railsをレイヤードアーキテクチャで捉えてみる
レイヤードアーキテクチャとは?
簡単にいうと、アプリケーションを責務に応じたいくつかの層としてとらえる設計手法のことです。このレイヤー間のやりとりにおいて、一方向かつ隣接するレイヤーとしかやりとりを行えないようにする事が多く、層状になるのでレイヤードアーキテクチャと呼ばれます。
レイヤードアーキテクチャのメリット
どこのレイヤー何をするのか?が定義されいることで、アプリケーションが成長しても開発者は実装の構造を把握しやすく保守性を高めることができます。また、グループ間のやり取りの仕方を決めて制限し層状にする事のメリットは、もしアプリケーションに対する変更があった場合に、その影響範囲を、層を直接参照している層のみに限定する事ができるようになることなどがあります。
Railsのレイヤードアーキテクチャ
Railsは、大きく分けると4つの層から構成されます
レイヤ | MVC | 役割 |
---|---|---|
プレゼンテーション層 | View | ユーザに情報を表示し、ユーザの入力を解釈する。 HTMLや、WebAPIならリクエスト、レスポンス |
アプリケーション層 | Controller | ドメイン層とプレゼンテーション層のやり取りをする。ビジネスロジックに関する知識を持たず、作業を調整するだけ。 |
ドメイン層 | Model | いわゆるビジネスロジックを表現する。 システムで業務を表現するモデルや処理が置かれる。業務的なバリデーションやルールの適応など。 |
インフラ層 | 上位レイヤを支える一般的な技術。MySQLとかRedisとか。 |
前述のレイヤーごとの関係性を考慮すると、下記のことを意識する必要がある
- ModelはControllerやViewでどう呼び出されるか知るべきではない
- ControllerはViewがどのように描画するか知るべきではない
レイヤーのルールに当てはめるのは合理的か?
どうしてもMVCをレイヤにあてはめて考えると無理が生じる場面があります。例えばViewの中でどういう内容がレンダリングされるのか知らなければ、Conrollerでデータを用意してViewに渡すことなどできない、などです。
つまり、厳密に言えばMVCをレイヤードアーキテクチャに当てはめることはできないが、心構えとしてはそこに層があると捉えることで、保守性の高いコードにつながる!ということだと思います。
ファットコントローラーの対処法
レイヤーごとに責務を分けるべきなのは分かったのですが、目の前の問題を解決しようと責務のことなどを忘れ、すべての処理をコントローラーについつい書いてしまい、ファットコントローラになりがちになります。
僕のコントロラーを図にするとこんな感じ↓
Model クラスがデータの入れ物 (多くの場合、DB スキーマとほぼ一致) で、Service クラスが存在せず、プログラムの処理が全て Controller に書かれている状態
ファットコントローラの問題
- Controller が肥大化し、コードの見通しが悪くなる
- Controller ごとで、似たようなコードが分散している
- 依存関係が増えるためにメンテが大変
依存関係が増えるためにメンテが大変↓
Controller にビジネスロジックを書かない
ファットコントロラーの状態になっときに、度々指摘をいただくのが「ビジネスロジックをコントローラーに書かない!」です。
ビジネスロジックとは何か?
調べるにビジネスロジックとして扱うのは、「システムのコアの部分」とか「システムの目的になる処理をするところ」といった説明をよくみかけます。が、僕の中での解釈はこうです。アプリケーションを、プレゼンテーション(画面の描画)とデータアクセスとロジックの3つの観点で見た時に、プレゼンテーション(画面の描画)とデータアクセスに当てはまらないものが、ロジックビジネスとして扱うです。
分かる方がいましたら教えてください🙇♂️
ファットモデル問題
前述までのやりかたを採用し、一旦コントロラーのファットは逃れることができたかと思います。
ですが、次に出てくるのはファットモデルの問題です。
ファットモデル自体が問題ではない
- ファットモデルは目指すべきものなので、ファットモデル自体が問題ではない
- ドメイン層(モデル)にくるべきでないロジックが含まれていることが問題
- モデルに書くべき処理によってコード量が多いのであれば、それは問題ではない
ファットモデルの対応
下記は対応方針だけを書き、別途具体的な実装を記す
機能ごとに処理を切り出す
- 外部ファイルでmodule化する
- serviceクラスに切り出す
gemで対応する
パッケージ名 | 用途 |
---|---|
ActiveDecorator | viewで必要とする処理 |
CarrierWave | 画像を保存するためのメソッドや、サイズを変換する |
ActiveModelSerializers | json形式でレスポンスする |
感想
RailsのMVCのそれぞれの責務の概要の理解と、保守性を高めるために層ごとにあった実装をすることの大切さを知ることで、以前よりもMVCの理解が深まったと思います。ただ、まだまだ概要をなんとなく把握したくらいなので、今後は具体的なファットモデルの解決方法を実装レベルで理解できるようにしていきたいと思います。
参考記事
後ほど追加します。