えせMVC?
[Ruby on Railsの「えせMVC」の弊害] というエントリが話題になっているので釣られてみます。
http://satoshi.blogs.com/life/2009/10/rails_mvc.html
MVCが指すもの
例のエントリの次のエントリ[O/Rマッピング技術の進化が皮肉にも助長している「えせMVC症候群」]で、
MVCのコンセプトは「はやりすたり」とは関係のない良いアプリケーションを設計する上での基本中の基本。Ruby on RailsやJ2EEを使ったウェブアプリケーションにも、Cocoa/UIKitの上のiPhoneアプリケーションにも通じる話だということを覚えておいてほしい。
確かにMVCは重要だけど、「「はやりすたり」とは関係のない」というのは言い過ぎだと思います。というのはGoFのデザインパターンとかが流行った頃のMVCと、現在のWebアプリ界隈でのMVCとは結構違っています。Strutsより前のMVCは主にデスクトップのGUIを実現するための仕組みで、Modelの変更をViewに伝えるためにObserverパターンを使うのが一般的だった気がします。
StrutsなどのWebアプリのためのフレームワールが流行ってMVCという言葉も、Observerパターンを使うMVCから、使わないパターンを主に指すようになりました。かつての過渡期には(今も?)MVC2とか呼ばれていましたね。
http://www.ibm.com/developerworks/jp/java/library/j-struts/index.html
かつてのObserverパターンを使うMVCもJavaScriptやFlashなどでGUIの部品を作る場合には重要だと思うんですけどね。あ、Flashではbindingがありましたっけ。iPhoneアプリはよく分からないけど、たぶん役に立つのはObserverパターンを使う方のMVCなんじゃないかな。
そんなに強制したい/させたいの?
いきなり脱線しましたが、元のエントリは「モデルにビジネスロジックを書くことを強要しないものはMVCじゃない。だからRailsはMVCじゃない」と言っているように僕は受け取ったのですが、どんなフレームワークでもMVCっぽくない書き方はいくらでもできるはず(例えばビューでSQLをいきなり発行するとか)なので、Railsが「えせMVC」なら他のフレームワークもほとんど「えせMVC」なんじゃないかなーと思います。
また、ビジネスロジックをモデルに書かせることをプログラマに強制するツールを使いたいならRailsは向いてないと思いました。いろんな書き方ができるっていうのがRubyの良いところの一つなわけだし。
僕もプロジェクトのメンバーに「ビジネスロジックはモデルに書け!」と口うるさく言ってますが、かと言って「モデルにしかビジネスロジックを書けないRailsっぽいやつ」が出てきたら・・・どうやってビジネスロジックか否かを判断するのかにもよりますが、あんまり使いたくないですね、なんかプラグインとか作り難くなりそうだし。
Skinny Controller, Fat Model
http://d.hatena.ne.jp/higayasuo/20091013/1255408723 でSeasarのひがさんが、Fat Modelについて書かれてますが、Railsに限って言えばFat Modelの方が良いと僕は思っています。理由は以下の2点。
- 1. コントローラよりモデルの方がscript/consoleで動かし易い
- 2. コントローラよりモデルの方がテストが書き易い
1については、ちょっと試したいときに非常に便利です。テストで書くべきかどうかをちょっと迷っちゃうところ ---例えば、このメソッドどう動くんだっけ?とか、正規表現のチェックとか電卓としてとか--- をサクッと試せちゃうところが素晴らしい。あ、正規表現とか電卓はirbを直で使ってるなw。irbが素晴らしいからですけど(関係ないけど、まつもとさんはirbじゃなくてruby -eを使ってたっけ)。
2については、RCovなどでのカバレッジ率を上げたい場合、複雑なパラメータを受け取るコントローラに条件分岐があると、条件分岐の数だけコントローラにget/post/put/deleteなどで複雑なパラメータを持つリクエストを送るようなテストを書かなければなりません。正直めんどいです。幾つかのテストで大量のパラメータの組み合わせが微妙に違ったりしやすいので、テストが読み難いし。できるだけ条件分岐をモデル側に移すことでテストのコードをすっきり読みやすくさせることができます。
ただし、モデルがメンテしにくいなーと思ったら別のクラスやモジュールに分けるべきです。べつにモデルはActiveRecord::Baseを継承しなくたっていいんだし(後述)。
個人的な感覚
さて、3年ほどRailsばっかりやってきましたが、MVCについて感覚的には「そういやRailsってMVCだよね」くらいです。モデル/ビュー/コントローラが、それぞれapp/models、app/views, app/controllers にあるクラスを指す感じで、特にいちいちMVCを意識しません。
慣れてくると役割をはっきりさせやすいので「テストし難いから」とか「他でも使うから」などの理由でクラス構成を見直すことはあっても、「MVC的にこのクラス構成は・・・」みたいな話は滅多に出ませんね。Railsの使いやすさが名前の浸透しやすさに繋がっているんだと思います。
具体的に言うと、app/models以下のビジネスロジックを書くところが「モデル」であり、そこにRDBに簡単にアクセスできる機能が付いている。RDBを使わないビジネスロジックもapp/modelsの下に入れるけど、その中のクラスではActiveRecord::Baseは継承しない。もちろんコントローラやビューへの依存はさせない。
コントローラやビューにビジネスロジックを書く人がメンバーにいたら「ここをこうすればモデルに持っていけるよね?」とコードをできるだけモデルに移すように促す。そこはメンバー間で話しながらやるべきでしょう。チームのレベルアップに繋がる大切なチャンスだし、フレームワークにその責任を持たせるのは現時点では難しいんじゃないかな、っていうかそんなのなんか勿体ない気がしてきました。