えせMVCについてそろそろ一言言っておくか

Ruby on Railsの最大の問題点は、それが持つ「一見そのフレームワークMVCの形をとりながら、MVCの最も大切なところを外している『えせMVC』である」点にある

RailsのえせMVC疑惑で盛り上がってますね。Railsが「えせMVCフレームワーク」ではないのは、みんな知っていると思うので、記事、コメントをみて勘違いしている人が多そうな部分に一言書いておきます。


まず、おかしいのはsatoshiさんのこの意見。

PhotoShareは主にRailsで作られているので、ModelはActiveRecordが担当しているわけだが、Modelのレイヤーが非常に薄いために(O/Rマッピングをしているだけ)、データベースの整合性の責任がController側にある。そのため、ちょっとした機能変更のたびにAPIレベルでのテストを大量に走らせなければならないし、それでもどうしてもミスが生じてしまう。

 そこでデータベースの整合性の責任を100%Modelに負わせ(つまりModelを単なるO/Rマッパーではなく、ビジネスロジックを含んだモジュールとして設計して作り込む)、そこだけは徹底的なテストケースを作って強固なものにしておくことにより、Controller側の変更で多少のミスをしてもデータベースの整合性が壊れたりしない、という設計にしておくとController側の変更がもう少し気楽に、かつ頻繁にできると考えている。

Modelを分厚くして徹底的にテストしておけば、Controllerの変更が気楽に頻繁にできるというこの意見、即座に突っ込みを入れなければいけません。


Controllerも徹底的にテストしろよ
RailsはController用のテストケースの雛形も自動生成してくれるので、テストを書く敷居はかなり低いはずです。今現在、Controllerにかなりの量のコードがあるのなら、まずController用のテストケースをきっちり書いた上で、必要ならControllerからModelにコードを移すようにリファクタリングするのをお勧めします。


はっきりいって、ロジックをModelに書こうがControllerに書こうが、整合性の考慮漏れは、どうしても出てきます。Modelに書いたからといって、Controllerに書いていたときの考慮漏れが自動的に解決することはないのです。


データベースの整合性が大切なら、データベースのトリガや制約などでデータの整合性を確保するほうがお勧めです。そのほうが堅い。その上で、早期にエラーを検知し報告するために、ControllerやModelでのチェックも入れるのがいい。


次の間違いは、Skinny Controller, Fat Modelが最良だと信じている点。
Fat ModelはFat Controllerと同様にテストはしにくいし、理解しづらくなる。ロジックはそれぞれ適切なところで実装すべきで、Fatなのはやはりよくないのです。


私は、Modelには収まりが悪いビジネスロジックはServiceにおくことをすすめています。この辺は好みで、永続化されないModelにおく方法もあります。Controllerにあったほうが良いこともあるでしょう。
Modelは複数のユースケースから使われるので、あるユースケースでしか使わないようなロジックは、そのユースケース用のControllerにあっても良いと思っています。Controllerに対応するServiceにおいてもいい。


正解はいろいろあると思いますが、Skinny Controller, Fat Modelは、最良の選択肢ではないことは言っておきたいと思います。

追記:一昔前のフレームワークなら、ControllerはWebのAPIに依存していてテストしにくいというのもあってControllerからロジックを追い出せということがよく言われてきましたが、いまどきのちゃんとしたフレームワークは最初からControllerもテストできるように考慮されています。
追記:Serviceは永続化されないModelなので、カテゴリはModelです。置く場所は、フレームワークによって変わってくるでしょう。Modelはデータから導き出されることが多いのに対して、Serviceはユースケースから導き出されるところが違います。