Hatena::Groupcatalyst

dann@catalyst このページをアンテナに追加 RSSフィード

2008-03-07

CatalystでのMVCの私的まとめ

20:40 |  CatalystでのMVCの私的まとめ - dann@catalyst を含むブックマーク はてなブックマーク -  CatalystでのMVCの私的まとめ - dann@catalyst  CatalystでのMVCの私的まとめ - dann@catalyst のブックマークコメント

id:miyagawaさんやid:charsbarさんのお陰もあって、自分の中では一通り考えがまとまったので、まとめてみることにしました。

僕の場合、Catalystでテスタビリティが高いWebアプリを作るためにはどうすればよいのかとここ数週間考えていて、それを実現するにはどうすればいいのかという点に興味がありました。Catalyst::Model::Adaptor使っても、うまくいかないなぁと思っていたので、なんかいい方法ないのかなと思ってました。

特に、DBICSchemaにロジックを置くということに何か問題があるか、またテスタビリティ上問題がないのかという点がよくわからなかったので疑問点を書いたわけでした。

最終的には、http://catalyst.g.hatena.ne.jp/dann/20080305/1204732092 で書いた構成と殆ど変わらない形でも、テスタビリティは維持できそうだという結論に至りました。

Model

  • CatalystのModel」は使わない
  • テーブルのデータに固有のロジックは、DBのモデル(DBICSchema)にロジックを記述する
    • データに関連のあるオブジェクトがデータに対する責務を担う
    • 前提条件は、DBのモデルのStubが簡単に作れ、DBを介さずにユニットテストができること
  • 複数のDBのモデルにまたがるロジックは、Serviceクラス(Cというクラス)に記述する
  • Serviceクラスは、Catalystのモデルには依存させない
    • Catalystでの依存を断ち切ることで、フレームワークに依存せず、ユニットテストができるようにすること
    • フレームワークに依存していなければ、CLIなどでも簡単に使えるようにもなるということ。これはプロダクトの性質だけの問題で必要がない人もいるでしょうが、メンテナンス用の管理コマンドとして、プロダクトの場合には特にCLIのツールは必要かなという気がします。

Controller

  • Controllerにはロジックは記述させず、ServiceクラスまたはDBのモデルに処理を委譲するだけ
  • Webのコンテキストに依存する部分のみをControllerに残す
  • Controllerの主な役割は、URLマッピングとViewへのフォワードだけ

View

  • Catalyst依存
    • Viewだけの単体テストをする必要はないから

まだ、以下のエントリで書いた疑問点は完全に解決はしていませんが、大体どんな形になりそうかは想像がつきます。

http://catalyst.g.hatena.ne.jp/dann/20080307/1204847350

# miyagawaさんからのブクマコメントで、Catalyst界隈では、以下のBread BoardがDIコンテナとして注目されているとのことでした。

http://search.cpan.org/~stevan/Bread-Board-0.03/

銀の弾MVCアーキテクチャ

20:40 |  銀の弾MVCアーキテクチャ - dann@catalyst を含むブックマーク はてなブックマーク -  銀の弾MVCアーキテクチャ - dann@catalyst  銀の弾MVCアーキテクチャ - dann@catalyst のブックマークコメント

どんな要求をも満たすMVCアーキテクチャというのはないわけで、全てトレードオフがあると思うんですね。それで、フレームワークは、全ての要求を満たすものである必要も当然ないと思っています。

アーキテクチャの議論でありがちなアンチパターンは、何の前提条件もなく、このアーキテクチャは良い、悪いという議論をしてしまうことかなと思っています。ですから、どんな条件のときに、どんなアーキテクチャであればマッチするのかというのを抜きに、アーキテクチャの議論をしてみても、あまり意味がないかなと思っています。

ORマッパーの変更がVCにも影響がでないように設計したいという状況があれば、DBICSchemaにロジックを置くということは当然できないわけです。ただ、そうした要求が無ければDBICSchemaにロジックを置いても問題がないわけです。

他にも、LDAPDB、FileなどのStorageの抽象化が必要な場面で抽象化するというのも、抽象化が必要なんであればそういうデータモデルの抽象化をするというのは必要なんだと思います。ただ、Storageが切り替わる必要がなければ、その抽象化をする必要がないわけです。

システムに必要とされる前提条件があるもとでのアーキテクチャの良し悪しについては興味があって、こうしたほうがいいよ、こんなときにはダメだよっていう話は、いろいろとしてみたいなぁって思ってます。

Serviceクラス(Cというクラス)のCatalystのModelからの依存を断ち切るには?

08:49 |  Serviceクラス(Cというクラス)のCatalystのModelからの依存を断ち切るには? - dann@catalyst を含むブックマーク はてなブックマーク -  Serviceクラス(Cというクラス)のCatalystのModelからの依存を断ち切るには? - dann@catalyst  Serviceクラス(Cというクラス)のCatalystのModelからの依存を断ち切るには? - dann@catalyst のブックマークコメント

SpringなどのDIコンテナでは、DAOがどのDBを見に行くかとかというのは、DIコンテナがDAOを生成するときに設定する。それは、Webなどのコンテキストには依存していないし、Webのフレームワークには依存していない。

今は、CatalystのConfigLoaderでmyapp.ymlを読み込んで、Modelはその情報を参照している。要するに、CatalystがDIコンテナの一部の役割を担っているということになる。Webのコンテキストという意味では依存していないのだけれど、Catalystには依存している。

ここを切り離さないと、Cというクラス(自分はServiceと呼んでいる)の、Catalystへの依存というのが切れない。依存を切り離す一つの解は、Catalyst::Model::Adaptorを使うことなのだけれど、Configurationを参照させる部分、または、DIコンテナを作るというほうが自然なのかもしれないと思った。

仮にCatalyst::Model::Adaptorを使って、Serviceに処理を委譲する形にしても、Serviceのバックエンドで動作するDBICSchemaは、どのDBにConfigLoaderを見にいくのかというのを知りたいわけだし、そうするとCatalystからの依存はCatalyst::Model::Adaptorを使っただけでは依存が切れないような気がした。

これはどう解決するのが綺麗なんだろうなぁと思っていたのだけれど、miyagawaさんのエントリを読んでから考え直した。

ControllerでのURLマッピング、Viewへのフォワード部分だけを、Catalystの機能として使って、後の部分はPOPO(Plain Old Perl Object)として扱って、DIコンテナで間を繋ぐという形が綺麗なのかもしれない。DIコンテナで繋がなくても、ConfigurationのデータをPOPOが参照できる仕組みがあれば、「Catalystに依存したCatalystのModel」の部分はなくすことができる気がする。

CatalystのModelでyaml参照させるためだけに、Catalystに依存してしまうということ自体が間違いかもしれないということが分かったのは、大きな収穫な気がするなぁ。

大分すっきりしてきた気はするので、あともう少し詰めれば、Catalystを使って、テスタビリティの高いアプリケーションも作れるような気がするなぁ。別の解もある気がするから、もう少し考えよう。

ゲスト



トラックバック - http://catalyst.g.hatena.ne.jp/dann/20080307