まだまだ続くモデル分離とか

なんつうかろくなタイトルが思いつかないのはいつものことで。

catalystMVCが駄目な理由

モデルを呼ぶのに$cというwebのコンテキストを通してしか得られないオブジェクトを使わなければいけないから。
そりゃコントローラにべったりになるし、テストも書けやしない。
railsだと User.new とかで呼べる。
ようやくCatalyst と MVC - Bulknews::Subtech - subtechで言われてる意味を理解した。
ブックマークしたのが約1年前だ。成長遅いよ俺。

名前空間

道家にいつものようにあれこれ聞いてたらこんなことを言われた。

Web/Controllerってより、Controller/Webじゃないの

コントローラの役割がロジックのハンドリングやURIディスパッチなら、確かにその通りだと思った。
リクエストがCLIからだろうがCUIからだろうがGUIからだろうが、ロジックを呼ぶのは同じなんだから。


で、それならモデルもそうで、MyApp/Web/Modelってより、MyApp/Modelだと思った。
この辺まで考えて、

  • ならController/CLIを作るの?
  • そんな二度手間するくらいならCLI/Hoge.pmにrunメソッド作ってそれ呼ぶよな
    • CLI/以下に置くpmにはロジック書いてもいいよね?駄目か?
  • つまりControllerってWebコンテキストでしか使われないな
  • Webって名前空間不要?

とか考えて力尽きた。


余計な事考えてるかもしれないけど、まだまだ考える余地はあるんじゃないかなとか思った。

ストレージ変更に備える

前にこんなことを書いた。

どんなストレージだろうと統一されたインタフェースで操作できるようにどっかにその処理を書いたほうがいいのでは
例えば、ストレージがDBだろうがcsvだろうが、find(4)って打ったら4番目のデータが取得できる、みたいな

この辺、頭にはあったけど、とりあえず動かしたいのでモダンPerl入門にならってこう書いてた。

  • コントローラ
$c->model('API::User')->find( $c->model('DBIC::User'), 1 )->id;
sub find {
    my ($self, $rs, $id) = @_;
    $rs->find($id),
}

道家から指摘。
「それじゃストレージ変えたときにAPIもコントローラも全部書き換えだよね」


その通りorz
この辺、モダンPerl入門で詳しく書いてないのだ。
Model::Adaptor使う前に、悪い例→直した例と載ってるが、直した例を「まだ悪いところがあるが、リファクタリングは後述」とあるけど、その後はスクリプトからの利用例のみ。
言われてから見れば一目で駄目だと分かるのに、言われるまで振り返りもせず進んでく駄目な俺。


でまたpixisを見る。
全然分かんないけど多分こんなん。

  • APIの中で毎回スキーマ取得してる
  • Pixis::Registryのクラス変数にスキーマ持たせてる
  • findとかsearchとかはPixis/API/Base/DBIC.pmでラップしてる

すげー。他にもDBエンジン切り替えにも対応できるみたいになってた。


やっぱり実際のソースは参考になりまくる。というか、こういうのも本に載せて欲しかったり。
親切にもソース公開してんだからそっち嫁って言われれば何も返せないけど!


自分の粗末なソースに戻る。考えをパクらせていただく。
要はスキーマをどっかにシングルトンで持っておけばいいと。

  • AutoTest::Web
our $schema;
sub setup {
    my $self = shift;

    $self->SUPER::setup(@_);

    my $connect_info = __PACKAGE__->config->{'Model::DBIC'}->{connect_info};
    $schema = AutoTest::Schema->connection(@$connect_info);
}
  • AutoTest::API::User
sub find {
    my ($self, $id) = @_;
    my $rs = $AutoTest::Web::schema->resultset('User');
    $rs->find($id);
}


見るからに残念さ漂う実装だけど、findのラップはできた。
以下、残念な点。

  • catalyst起動時のconnectと合わせて2回connect発行してる気がしてならない
    • DBI_TRACEで見たら1回だけだったけど。catalystが空気読んだのかもしれない
  • APIクラスでfind/searchのラップ書かなきゃいけない
    • これまたレガシーな方法でなんとかできそう
    • もちろんMyApp::ActiveRecordの考えである
    • 駄目なのが分かってるから最初からはやらないけど、解決策が分からなかったら分かるまでの繋ぎで使おう
  • 毎回スキーマ取得するのに長いタイプしなきゃならなくて面倒
    • モデル分離したんだから、catalystが自動でやってたところが面倒になるのはしょうがない
    • pixisもそうなんだから


まだまだやることも勉強することも山積み。