Zend_Formで実現できるMVC粒度の調整

noopable2009-01-26

MVCの分離(初期)

ソフトウエア開発の基本の一つに、MVCの分離がある。
PHPは1ファイル中で完結させることも可能なテンプレートスクリプト(異論はあるかもしれない)である。さらに効率的なテンプレートエンジンが開発され、プログラムをMVCに分離して保守性の向上が図られた。MVC構成によるアプリケーションが一般的となった。
しかし、一部にはコントローラーでリクエストを受け取り、データを準備してビューに渡すという典型的なパターンがMVCのゴールであると誤解されている節がある。

さらなる大型化、高機能化

システム全体で几帳面なMVC分離を考えると、コヒージョンの低下を招き、結果として、スクリプトが分離されているのに、それぞれの結合度が高くなってしまう現象が発生する。
たとえば、アプリケーションのディレクトリ構造をMVCに切って、すべてのスクリプトをその構成の中にカテゴライズしたとする。すると複雑なモデルや状況依存を実現するにはビューにどうしてもロジックが必要になる。そこで、テンプレートエンジンはニーズに応えるべく高機能化が進む。
純粋なテンプレート言語にしても、CMSなどに含まれるテンプレートにしても、高機能化を図るあまり、ビューの中に大幅なロジックが埋め込まれたり、モデルの変更をするのに、ビューの変更が必要になったりする。
これは、システム全体からみたMVC分離が1レイヤーしかない場合は顕著だ。
もし、MVC分離が目的なら、それはかくあるべきという話で終了してしまうのだが、MVC分離は最終目的ではない。

MVC分離の背景

MVCの分離が必要とされた背景の一つには、ルースカップリングとタイトコヒージョンの実現がある。そのほかにも参照すべき原則はあるが、いずれにしても目的としているのは、MVC分離の実現ではなく、開発効率、保守性、信頼性の向上である。
http://c2.com/cgi/wiki?CouplingAndCohesion
http://homepage3.nifty.com/koha_hp/SCNews/hpblock96/SCNews96.html

1レイヤーMVCの限界

このケースではルースカップリングとタイトコヒージョンを例にするのがわかりやすい。
MVC分離は全く分離されていない状態よりは「マシ」だが、全体を1レイヤーで分離しようとすれば、コヒージョンの低下を招くことは間違いない。
たとえば、複雑な階層を持ったドキュメントモデルに対して、階層毎、項目毎に違うビューをユーザーの指定に合わせて実現したいというニーズを実現しようとしたとする。
これをさっくり1レイヤーで分けたとすると、ビューファイルではifを立てて、ユーザー指定を読み取ってビューファイルを選択するという"ロジック"、モデルの中には、そのモデルに対してどんなビューを組みたいかという"ビュー"が相互依存として組み込まれることになる。

それでいいのか。

MVC分離が目的なら「それでいいのだ」が、保守性を考えるならそのような実装は避けるべきだ。
そのような構成は特定のモデルに依存していて、ビューの再利用性が低いし、モデルの変更に合わせてビューのカスタマイズ、コントローラーのカスタマイズがそれぞれ必要になっており変更の依存先が分散しており保守性が悪い。

Zend_Formが実現してみせた粒度のコントロール

Zend_Formを使うと、フォーム要素Zend_Form_Elementにも、モデル機能、コントローラー機能、ビュー機能が内包されていることに気づく。ビューはデコレーターによって作成され、利便性もあるので、デコレーターではビュースクリプトも扱えるようになっている。
Zend_FormにはMVCのミニチュアが含まれていると考えるとわかりやすい。しかし、これを持って、MVCの分離ができていないと考えるのは早計。

  • 複雑な要素をZend_Formに移譲した後のビュースクリプトは非常にシンプルで再利用性が高い。
  • 手前みそだが、Zend_Formを拡張したオレオレクラスのコールバックを利用すれば、コントローラーは本来必要なロジックの記述だけ。
  • モデルについていえば、コンフィグから読めば済むので、変更があってもコンフィグの書き換えだけで済む。

FormやElementの基底を適切に設計すれば、任意の粒度でビューやモデルをコントロールできるようになる。このコヒージョンの高さが魅力だろう。実はこれ、コンポーネント志向な人には普通すぎる話ではある。
http://d.hatena.ne.jp/noopable/20090127/1233014697
まだまだ、荒削りな部分が多いZend_Formだが、現在の実装を決めた方々の勇断に感謝したいし、今後の開発方針に期待したいと思う。
自前で継続状態マシン用のクラスを書いたが、Zend Frameworkチームからそれに相応するものがリリースされたらそっちに換装するつもりだ。

今後の期待

できれば、Zend_Formで利用しているデコレーターを通常の表示系でも違和感なく使えるように、Zend_View_Decoratorとして統合してくれたらなぁという気はする。
もう一つ、Zend_Formで実現した利便性はコンポーネント的な扱いにあるので、Zend_Components_Abstractみたいな形にして、MVC粒度をコントロールするためのひな形にしてもらえたらなぁという気はする。

参考:Zend_Formのデコレーター実装に関する解説
http://devzone.zend.com/article/3450-Decorators-with-Zend_Form