がるの健忘録

エンジニアでゲーマーで講師で占い師なおいちゃんのブログです。

MVCについての考察:どらふと

大雑把にもやもやと、MVCについて考えてみました。
…いやなにせ、フレームワーク作るのに必須だったので(苦笑


MVCへの考察


まず確実な定義を試みてみたい。
MVC 〜 Model-View-Controller 〜。昨今耳にする単語だが、いまひとつ定義があまい。
Modelは概ね「業務ロジックの根幹部分」と考えられる。
Viewは出力、もしくは入出力と捉えられる(入力がある辺りが微妙ではあるんだが(個人的には「入力->処理->出力」はそれぞれ別にしたいほうなので)、まぁとりあえずここでは不問とす)。
ControllerはViewとModelの制御である。


入力への考察
とりあえず困るのが「入力はどこが受け取るの?」という部分である。
結論から出すと「入力はControllerが受け取る」のが妥当であるように思われる。Viewは「出力」できればよい。
そうすると、Controllerを基準に「入力データをModelに渡してViewに渡して終了」で、理論的には「処理して出力して」が片付く。
なお、一部の説明にあるような「スパイダーウェブのようなあちこちにメッセージが送信できるような流れ」は間違っても推奨しない(わかりにくいから)。
このあたりの考察から、とりあえず以下のように定義を直す。
Controller:入力を受け取り、Model、Viewを必要に応じて叩く。
Model:業務ロジックの根幹を成す
View:出力を担当する


テンプレートエンジン、もしくは「ロジックとテンプレートの分離」への考察
次に問題になるのがここである。ちょいと具体的に噛み砕いてみよう。
一般的に誤解されている…と思うのだが。「ロジックとテンプレートの分離」は、厳密には別にMVCではない。MVCで語られているのは「データ処理部分と出力部分の分離」である。出力部分のプログラムに「HTMLをベタ書き」したって別に問題は無いのだ。MVC的には。
ただ現実問題として「テンプレートとロジックの分離」は大変に重要であるし、実際に「テンプレートエンジン」とMVCは、概ねセットで語られているのが現状である。
というわけでこの二つを融合した状態であることを前提としたい。
以降、この発想をMVCではなくMVC with template と呼称する。


テンプレートへの考察
テンプレートは基本的に以下の構造を持つ。
・2つの異なる入力からのデータの取得:変動データとテンプレートファイル
・二つの異なる入力から一つのoutput(通常は動的なHTML)を作成
(一部テンプレートエンジン(具体的にはsmartyなど)は出力までの機能を備えているが、出力は切り分けるほうが利便性が高いので原則無視する)


テンプレートエンジンとMVCの融合 〜或いはViewとModel分離への考察〜
テンプレートエンジンの機能をMVCに振り分けてみたい。
二つの入力データのうち、テンプレートファイルの取得はまぁどこにおいても事実上実害はなく、動的なデータの作成はModelであることに疑いの余地はない。
では質問。「動的なデータをテンプレートエンジンに設定する」「テンプレートから動的にHTML(文字列)を作る」は、Modelだろうか? Viewだろうか?
Modelです。すべからく「処理」はModelに集約され、Viewはあくまで「出力を」制御する部分だからです。
Viewです。すべからく「出力に直接まつわる処理」はViewに集約され、Modelはあくまで「データそのものを加工したりする」部分だからです。
いずれの回答にもある程度の正当性があり、これの正誤をわけ隔てるに足るだけのものが現状ではないと考える。
動的データの設定に関しては、Modelで実装すると概ね「処理と設定が入り混じる」ことになり、Viewで実装すると「データを渡すだけのために画面ごとにクラスを作る」必要がある。
判断基準がもう一つ甘いのだが、とりあえず「Model内で処理と混在する」部分で、実質的な影響があまりないことから、一端「Modelで実装する」方向で作成を進める。
ただし「必要であれば」速やかにViewに移動する。


Modelにおけるengine部分分離への考察
Modelに「テンプレートからHTMLを動的に作成する」部分をincludeすると、時として起き得るのが「データを別の表現形式で表現したい」場合の移植性の弱さである。
具体的には、例えば「いままで表(Table)で出力していたデータを、同様のデータをCSV出力する機能を追加したい」ケースが一例である。
こういったケースに備え、データを作成する部分をengineとして、Modelのexecuteメソッドから外出しにすることでこの問題をヘッジする。
別のある見方をするのなら、Modelのexcuteの中にMVCがあり、その場合
Model.execute:Controller
engine部分:Model
という捉え方も可能である。Viewについては「ない」もしくは「テンプレートエンジンへのデータの設定」のいずれかとなる(Viewの定義次第)。
これを便宜的に「e」として捉える。そのまんまengineの略である。
ここから、以降MVCではなくMeVCとして捉える。全部あわせるとMeVC with template となる。


Controllerへの厳密な考察
Controllerは基本的に「必要なクラスに処理を流す」だけのクラスである。だとすると、このクラスに「初期化処理としてのinitializeなどがあるのはおかしい」という議論が当然のごとく成り立つ。
理論的にはなんらおかしいところは無い。
ただ、実際問題として切り分けるメリットがとりあえず見当たらないので、一端Controllerクラスに内蔵させる。


とりあえずまとめ
以上から、MeVC with template は以下の構成となる。
Model:業務ロジック。概ね「必要な値を設定してengineを叩き、その結果をテンプレートエンジンを使い動的なHTMLを作り出す」。ある意味ここもまたController的役割を果たす。
engine:業務ロジックの根幹部分。あくまで「データを処理する」ことを主眼とする。出力には原則クラス(のvector)を用い、あらゆる出力に耐えられるようにする。
View:Modelによって作られた「動的なHTMLなど」を出力する。結果的に「物凄く簡素になる」可能性が高いが、とりあえずよしとする。
Controller:各クラスを動的にnewして処理を振り分ける。ただし実際には初期処理、入力データ取得など、いくつかの「業務ロジックの前後に必ず必要になる処理」を、実用の観点から保持している。