Hatena::Groupcatalyst

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

2008-04-30

Moose::Roleのインターフェースとしての役

Moose::Roleのインターフェースとしての役 - dann@catalyst を含むブックマーク はてなブックマーク - Moose::Roleのインターフェースとしての役 - dann@catalyst Moose::Roleのインターフェースとしての役 - dann@catalyst のブックマークコメント

かっちり作りたいときに「これはインターフェースですよ」と明示する仕組みが重要で、JavaInterfaceは優れた言語仕様の一つです。Moose::Roleは、そのInterfaceとしての役割を果たしています(一応、Mixinとしての役割も)。

このMoose::RoleのInterfaceの仕組みは、実装するべき箇所を明文化するのにとても向いています。特にフレームワークを作りたい場合には、役に立つと思います。

YAPC::AsiaでもMooseでフレームワーク作ろうみたいなセッションがあったような。そこだけ聞きたいな。今ならid:tokuhiromさんのMoose版HTTP::Engineが、フレームワークにどうMooseを使うのかのわかりやすい例かも。特にMoose::Roleの使い方は。

# Mooseは、Perlの言語仕様にあったほうがよいものを補完する仕組みが色々とあって、いいなぁと思う今日この頃。OOのシンタクス補完もその一つだけれど、それだけだと思われてしまうとすごい勿体無い仕組みだなぁと。

Moose::Autoboxの拡張

Moose::Autoboxの拡張 - dann@catalyst を含むブックマーク はてなブックマーク - Moose::Autoboxの拡張 - dann@catalyst Moose::Autoboxの拡張 - dann@catalyst のブックマークコメント

Moose::Autobox->mixin_additional_roleでオレオレ拡張ができるようになってます。Moose::Autobox::Arrrayとかに足りないけど追加したいってメソッドは、これで生やしていくのがいいのかも。

以下例。

#!/usr/bin/env perl
use strict;
use warnings;
use Moose::Autobox;

{
    package    # hide me from PAUSE
        Moose::Role::List::More;
    use Moose::Role;
    use Moose::Autobox;
    use List::Util;
    use List::MoreUtils;

    sub sum {
        my ($array) = shift;
        List::Util::sum(@$array);
    }

    sub minstr {
        my ($array) = shift;
        List::Util::minstr(@$array);
    }

    sub maxstr {
        my ($array) = shift;
        List::Util::maxstr(@$array);
    }

    sub true {
        my ( $array, $sub ) = @_;
        List::MoreUtils::true { $sub->($_) } @$array;
    }

    sub false {
        my ( $array, $sub ) = @_;
        List::MoreUtils::false { $sub->($_) } @$array;
    }

}

Moose::Autobox->mixin_additional_role( ARRAY => 'Moose::Role::List::More' );
use Perl6::Say;

say [ 1, 2, 3 ]->sum;
say [ 1, 2, 3 ]->minstr;
say [ 1, 2, 3 ]->maxstr;
say [ 1 .. 10 ]->true( sub { defined($_) } );
say []->false( sub { defined($_) } );

# ActiveSupportっぽいのほしいなぁ。

LorenzoLorenzo2012/10/30 18:26Was totally stuck until I read this, now back up and rnuinng.

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

2008-04-29

Moose::AutoboxでList::RubyLike

Moose::AutoboxでList::RubyLike - dann@catalyst を含むブックマーク はてなブックマーク - Moose::AutoboxでList::RubyLike - dann@catalyst Moose::AutoboxでList::RubyLike - dann@catalyst のブックマークコメント

#!/usr/bin/env perl
use strict;
use warnings;
use Moose::Autobox;
use Test::More qw(no_plan);

my $list = [ 1 .. 2 ];
is $list->push(3)->join(','), '1,2,3';
is $list->map( sub { $_ * $_ } )->reduce( sub { $_[0] + $_[1] } ), 14;

Rubyっぽくなっていい。片っ端からRubyのメソッドを追加して遊ぶのもいいかも。

See also:

http://d.hatena.ne.jp/naoya/20080419/1208579525

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

2008-04-25

RE:Catalyst::Component(Catalyst::Model::DBIC::Schema)を使った方がうれしいこと

RE:Catalyst::Component(Catalyst::Model::DBIC::Schema)を使った方がうれしいこと - dann@catalyst を含むブックマーク はてなブックマーク - RE:Catalyst::Component(Catalyst::Model::DBIC::Schema)を使った方がうれしいこと - dann@catalyst RE:Catalyst::Component(Catalyst::Model::DBIC::Schema)を使った方がうれしいこと - dann@catalyst のブックマークコメント

http://d.hatena.ne.jp/charsbar/20080425/1209129640

ということをすると「そういうのはControllerで!」と全力でDISられるわけですが、

うーん、自分が考えている話とはずれてるようなので書いておきます。

既存のAuthentication系のPluginで$c->modelでユーザークラスを参照してたりしますよね。あれを使うためには、「CatalystのModel」を用意してやる必要があると。そうしたときに、POPOのUserのモデル作るだけだと、Catalyst::Model::Adaptorでラップして、Catalystのモデルにしてやる必要がありますよね。で、Catalyst::Model::DBIC::Schemaをベースクラスに使えば、その手間を省けるのかなと思ったわけです。

要するに、Catalyst下では、Catalystのモデルとしても扱いつつ、Catalyst外(内でも)ではPOPOっぽくも扱えるというメリットもあるのかなと思ったわけですが、charsbarさんがそう考えているわけではないというとこですかね。

AuthenticationもPlugin使うのではなくて、「Controllerで」と言われると、charsbarさんの発言の意味を多分理解していないのだろうなぁとは思います。

それはさておき、あらたまって「ベースクラスにすることの意味」と言われると、configのマージを実装しなくてすむ(スクリプトなどから必要な部分のみ上書きできるし、Catalystアプリ上からは ConfigLoaderで上書きできる)ことくらいしか大きな利点はないと思います。

Catalyst::ComponentにしておくとConfig周りの恩恵を受けられるってことですかね。DBICのベースクラスとしての利点よりも。

Configのマージ処理とWAF下で動作するときにPOPOのモデルにConfigをinjectするための仕組みを汎用化すれば、モデルを完全に切り離せるのかなって気がしました。

少し先が見えた気がします。

Catalyst::Model::DBIC::Schemaに依存していても困らないかも?

Catalyst::Model::DBIC::Schemaに依存していても困らないかも? - dann@catalyst を含むブックマーク はてなブックマーク - Catalyst::Model::DBIC::Schemaに依存していても困らないかも? - dann@catalyst Catalyst::Model::DBIC::Schemaに依存していても困らないかも? - dann@catalyst のブックマークコメント

http://d.hatena.ne.jp/charsbar/20080425/1209053541

id:charsbarさん、id:typesterさん、どうもありがとうございます。

Catalyst::Model(要するにCatalyst::Component)に依存しているといっても、実質はCatalystという名前がついてるだけで、WAFというレベルでの依存じゃないんだから、ベースクラスに使ったっていいんじゃないか?っていう話だと理解しました。名前にだまされてるっていうのは、こういう話なのかなと。

それで、Catalyst::Model::DBIC::Schemaを継承したクラスで、Catalyst依存にならないようにだけすれば、WAFに依存すると言うものではないので、いいんじゃないかという話なのかなぁと。

後は、継承したクラスをnewしたときに設定されるschemaのインスタンスを使えば、POPOも同然じゃないかって話なのかなと思いました。

あまりこれは考えていなかったんですが、案外これでもいいのかなぁという気もしました。Catalyst::Componentに依存することの気持ち悪さはありますが、実質上の大きな問題は確かにないわけなので。

ただ、POPOとしてだけ扱いたいというときに、schemaのインスタンスを生成して保持しといても大差ないように思えるので、ベースクラスにすることの意味がどれだけあるのかは、よくわかりませんでした。

ただ、CatalystのComponentとしても扱えるようにしておくと、例えばプラグインなどでCatalystのModelを参照している場合に楽できるというのはあるかなぁという気もします。何か他にあれば、是非教えてください!

Catalyst::Componentがベースクラスになっていることに、微妙に違和感はあるものの、Catalystありきという前提であれば、実用上はそれでも問題はないので、charsbarさんがDBIC::Schema isn't so bad...という表現をされているのかなぁという気もするのですが。

# RailsライクにMember->findのような形で扱いたいというのは、DBICの話で、Catalystの話とは関係ない話なので、ここではとりあえず触れずに。

charsbarcharsbar2008/04/26 00:23Authentication::Store::DBIx::Classは、::Userのnewを見ればわかる通り、

resultset => $c->model($config->{'user_class'})

という形で$c->modelがresultsetを返すことを期待していますので、そもそもACCEPT_CONTEXTが埋め込まれているModel::DBIC::Schemaを使うのが大前提です(Adaptorとかでも頑張ればできるでしょうが……)

danndann2008/04/26 02:34orz.. そう考えると、何となくModel::DBIC::Schema自身をベースクラスにすることの意味もある気がしますね。

または、POPOモデルだけを使えるようにするには、$c->model($config->{'user_class'})と参照しているところをオーバーライドできるようにしておいて、サブクラスでresultsetを返せるようにしておくんですかね(Schemaから)。なんだか、この話は前に日記に書いた気がしますね。

悩ましいところですが、Catalystを使う分だと、DBIC依存部分はModel::DBIC::Schema使ったほうが結局楽なのかなぁという気もしてきました。もうちょっと考えてみます。

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

2008-04-24

Catalyst::Model::DBIC::Schemaの困るところ

Catalyst::Model::DBIC::Schemaの困るところ - dann@catalyst を含むブックマーク はてなブックマーク - Catalyst::Model::DBIC::Schemaの困るところ - dann@catalyst Catalyst::Model::DBIC::Schemaの困るところ - dann@catalyst のブックマークコメント

Catalyst::Model::DBIC::Schemaの困るところは、例えば、Catalyst::Model::AdaptorでPOPOモデルに委譲したときも、そこからDBICのモデルを参照しようとすると、結局$c->model('DBIC::Member')などと参照しなければいけなくなってしまい、POPOのモデルが結局Catalystに依存してしまうところ。

Railsだと、Member.find のように書けるので、これに近い感じで書きたいなぁと思うんだけど、まだそこまで綺麗にかけてない。schemaを隠蔽するところまでは来たんだけれど。週末少し考えたい。

Class::Componentみたいな仕組みはJavaでもできるか?

Class::Componentみたいな仕組みはJavaでもできるか? - dann@catalyst を含むブックマーク はてなブックマーク - Class::Componentみたいな仕組みはJavaでもできるか? - dann@catalyst Class::Componentみたいな仕組みはJavaでもできるか? - dann@catalyst のブックマークコメント

技術的にはできる、正確にはできなくはないといったほうがいいかもしれません。ただ、Javaの場合、仮にできても使われない可能性が高いという感じでしょうか。

これは、

  • メタプログラミングが簡単にはできないこと
  • 静的言語ではあまりメリットがないこと
  • プラグインシステムが流行りにくいライブラリの提供形態であること

の3点の理由からなのかなと思ってます。

1つ目は、メタプログラミングが簡単にできる仕組みがJavaにないからです。バイトコードレベルで操作するライブラリは幾つかあって、AOPもそれらのライブラリで実現されているわけですが、LLと比べて簡単に出来るとはお世辞にもいえません。

2つ目は、動的にメソッドを追加したりということを静的言語でやることのメリットが殆どないということ。コンパイラによる静的チェックの恩恵とIDEでの補完を受けられるところが、Javaでの生産性を支えている要因なので、メタプログラミングなどをすることが多くの場合でメリットがないこと。

3つ目はプラグインのシステムとしての仕組み自身が、Javaのライブラリの提供単位と合わないという話。Javaだとライブラリがある程度大きな単位で提供されていて、CPANのようにミクロな単位でモジュールが提供されることは殆どない。Pluginを追加しようとするときには、割と大きな単位(Jar)での再利用形態しかモジュールを利用できないので、それはちょっと困るわけです。

それで、自分が思っているのは、LLにはLLらしい面白い手法や開発形態があるんじゃないかと思っていて、Perlで面白いなぁと思っていることの一つが、プラグインの仕組み。プラグインの仕組みそのものには、違いはあっても、プラグインの機構は流行っていて、それが面白いなぁと思ったりします。

LLでのDIとDIコンテナの利用

 LLでのDIとDIコンテナの利用 - dann@catalyst を含むブックマーク はてなブックマーク -  LLでのDIとDIコンテナの利用 - dann@catalyst  LLでのDIとDIコンテナの利用 - dann@catalyst のブックマークコメント

id:ZIGOROuさんから解説キボーンという話があるので、

  • DIの利点とDIコンテナの利点というのが違うという話
  • DIの概念そのものは昔からあったけど、DIコンテナの概念はあまりなかったこと
  • DIはLLだとどういうところで活きる可能性があって、どういうケースではいらないのか

については、少し書こうかなぁと思ってます。

LLでは、DIコンテナがなくても解決できる解があるので(それがBetterかはちょっと微妙で自分でもいいのかわるいのかは自分でもわかってはいませんが)、それについて書いていきたいと思ってます。

typesterさんに、もっとコードベースで!という話もあったので、Perlでのコードを交えて話を書こうかなぁとも思ってます。

最初、CatalystConのスライドには、もっとDIが前面に押し出たスライドになってたのですが、Catalystと全く関係なくなりそうだったので、ばっさり削ってしまいました。

ここらの話はYokohama.pmでかな?

ModelがWebのフレームワークから切り離されていることの重要さ

 ModelがWebのフレームワークから切り離されていることの重要さ - dann@catalyst を含むブックマーク はてなブックマーク -  ModelがWebのフレームワークから切り離されていることの重要さ - dann@catalyst  ModelがWebのフレームワークから切り離されていることの重要さ - dann@catalyst のブックマークコメント

JavaでModelをWebのフレームワークから切り離すのは、かなり早い段階から行われていました。で、これはTestabilityうんぬんという話ももちろんあるのですが、もっと切実な理由から行われていました。

JavaではWebアプリケーションをWARという形で、アプリケーションサーバーにデプロイするわけですが、このデプロイがとにかく遅い。普通に2-3分かかったりするわけです。

で、モデルが密にWAFにくっついているとどうなるか?コードを1行修正する度に、デプロイのために2-3分待ってテストとかいうことになります。

これだと生産性うんぬんというレベルではなくなってしまうわけです。だからこそ、JavaではWAFからモデルを切り離すっていう話がすごい受けたわけです。

Perlだったとしても、例えばmod_perlに完全に依存して、Apache再起動しないとテストができないなんて環境でやっている場合には、Perlでも同じように困るんじゃないかと思います。修正する度にデプロイしてテストなんてことになります。Catalystのテストサーバーもそれほど遅くはないですが、それでもモデルのテストをやるという目的には、あまりに遅すぎます。

テスト数が増えれば増えるほど、環境に結合されたモデルなどのテストの実行速度が影響がでてきます。機能規模が大きくなればなるほどテストの実行速度が遅くなります。

そうすると、どうなるか。

結果として、一部のテストしか実行されなくなり、コミットの度にデグレードが発生するということになります。製品開発やサービスの開発をしている人であれば、経験したことがある人は結構多いんじゃないでしょうか。

ですから、極力モデルはWAFからは切り離したほうがいいと思っています。

# 最近は、少しずつJavaでもホットデプロイメントの機構がぽつぽつと目立ち始めているけれど、それでも本質的にはJVMレベルで対応できないと特定の条件、特定の環境でしかホットデプロイメントができないわけで、Java界隈では解決にはもう少し時間がかかりそうです。

typestertypester2008/04/25 10:56> Catalyst::Model::AdaptorでPOPOモデルに委譲したときも、そこからDBICのモデルを参照しようとすると、結局$c->model('DBIC::Member')などと参照しなければいけなくなってしまい

えこれ全然そんなことないですよ。$c に依存していない限りSchema内だけで完結できると思います。

テーブルクラスのメソッドなら
$self->result_source->schema->resultset('Member') とかとか。

typestertypester2008/04/25 11:04隣の席の人に聞いたらそういうことを言ってるんじゃないってことがわかりました。

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

2008-04-23

モデルを拡張していくための仕組み

モデルを拡張していくための仕組み - dann@catalyst を含むブックマーク はてなブックマーク - モデルを拡張していくための仕組み - dann@catalyst モデルを拡張していくための仕組み - dann@catalyst のブックマークコメント

モデルを切り離すことの意味として、

  • Testabilityを高めるため
  • Webのコンテキスト以外の再利用ができるようになる

と書いたのだけれど、モデルを切り離したいというのは、それだけが理由ではなかったりします。

モデルを切り離した後には、もう少し先があるんじゃないかなぁと思っていて、スライドの付録に書いていました。WAFとは独立させて、POPOのモデルだけを拡張していけるための仕組みがあったら、モデルを資産として残せる(これは幻想かもしれませんが)、もしくはモデルの後からの拡張が容易になるんじゃないかなぁと思っていました。

拡張する方向としては、以下の二つがあるかなぁと思いました。

  • プラガブルにモデルの機能を追加する仕組み
  • モデルから横断的な関心毎を切り離して、任意の箇所に適用する仕組み

POPOに上記の二つの拡張する仕組みを提供できると、Webの世界と切り離して、モデルだけを育てる仕組みができ、モデルを資産として残していける部分ができるんじゃないかなぁと思っていました。そうでなくても、拡張性の高いモデルを作れる可能性がありそうです。

1つ目。モデルをプラガブルに拡張するための仕組み。id:YappoさんのClass::Component。これはいかにもLLらしい面白いコンポーネントだなぁって思ってます。これはいかにもPerlっぽくて、絶対Javaの世界にはない話なんですよね。モデルをプラガブルに拡張するための仕組みがあれば、モデルを資産として残せる部分もでてきそうです。

2つ目。Javaな世界では、Caching、Transaction、Loggingなど、モデルの横断的な関心毎を切り離して、モデルの外からコードを付与してやる仕組みが流行りました(実際成功したのは、Transaction、Loggingくらいなわけですが。)Transactionなどが、POPOのコードから消えるので、POPOそのもののTestabilityが高くなるわけです。これはこれで価値がありますね。

Class::Component, Moose, (Class::MOP)は上記を実現できる可能性のある面白いライブラリだなぁと思っていて、とても注目しています。

Catalystかわいいよ!

 Catalystかわいいよ! - dann@catalyst を含むブックマーク はてなブックマーク -  Catalystかわいいよ! - dann@catalyst  Catalystかわいいよ! - dann@catalyst のブックマークコメント

自分のスライドも、「CatalystのModel」はいらないと一見DISってるようになってるけど、自分の場合、全然WAFはCatalystでOKなんじゃないかと思ってるということだけ、一応かいときたい!

Catalystの良くないところ

 Catalystの良くないところ - dann@catalyst を含むブックマーク はてなブックマーク -  Catalystの良くないところ - dann@catalyst  Catalystの良くないところ - dann@catalyst のブックマークコメント

CatalystConででたDISの殆どは、$c依存の強さ、Plugin、モデルのWAFへの依存の3点なんじゃないかと思った。けれど、$c依存の強さ、Plugin、については、実際大して問題ないんじゃないかなぁと思った。

というのは、

$cの依存の強さ」については、VC$cに依存していても、フレームワークから切り離して、VC使うことがないので、依存していても気にならないから。Vだけをテストしたいという要求も特になく、それでいいんじゃないかなぁと思ってしまう。だから、VCはフレームワークにある程度密に結合してても、いいんじゃないかと思う。

Pluginについては、プラグインのロード順に副作用があるのとアプリケーションワイドに機能を追加してしまうところが、気持ち悪さの原因なんじゃないかなぁと思った。

これは確かに気持ちが悪い。ただ、実際問題使うプラグインそのものがそんなに多くないわけで、そんなに気にすることないんじゃないかなぁという印象なんだけれど、そういうもんでもないのかなぁ。

仮に20個程度のプラグインをロードして、バッティングする組合わせが複数のセットで考えられますとなると、頭が痛い問題かもしれない。ただ、実際問題使うプラグインは数個と限られているわけで、どちらのケースも問題にならないんじゃないかと思った。ロード順を気にしなきゃいけないというのは正直どうかとは思うけれど、実用上問題ないんじゃないかってこと。

で、モデルについて。モデルについて切り離したほうがいいと思っているのは、単体テストのしやすさ、速度の問題と、他のコンテキストからの利用がありうるケースが多いから。逆に、これが問題にならない規模のアプリケーションでは、あえてモデルを切り離すことのメリットがないわけで、密に依存していても大きな問題にはならないんじゃないかと思う。

プラグインを使ってはいけないケース (wrap some prepare_* or finalize_*)

 プラグインを使ってはいけないケース (wrap some prepare_* or finalize_*) - dann@catalyst を含むブックマーク はてなブックマーク -  プラグインを使ってはいけないケース (wrap some prepare_* or finalize_*) - dann@catalyst  プラグインを使ってはいけないケース (wrap some prepare_* or finalize_*) - dann@catalyst のブックマークコメント

http://d.hatena.ne.jp/charsbar/20080423/1208920975#seemore

wrap some prepare_* or finalize_*

If your functionality needs to wrap some prepare_* or finalize_* stages, you won't get around a plugin.

Catalystのマニュアルで言われていた、「wrap some prepare_* or finalize_* stages」っていうのは、charsbarさんが書いている以下の問題のことなのかな。

prepare_*とか)にNEXTで機能を突っ込むときにロード順を気にしないといけない

これは確かに気持ちが悪い。けど、実際問題使うプラグインそのものがそんなに多くないわけで、そんなに気にすることないんじゃないかなぁという印象なんだけれど、そういうもんでもないのかなぁ。

けど、ロード順に副作用があるから、実装見ないと使えないというのは「プラグイン」としてはいまいちだよねというのはわかる気がする。

ただ、実際問題プラグインも5-6個くらいしか使わないわけで、そう考えるとそんなに気にならないんじゃないかって気がするのだけれど。そんなにたくさんのプラグインを使うことが前提になってるような気もしないし。

CatalystCon#1資料-Catalystからモデルを切り離せ

CatalystCon#1資料-Catalystからモデルを切り離せ - dann@catalyst を含むブックマーク はてなブックマーク - CatalystCon#1資料-Catalystからモデルを切り離せ - dann@catalyst CatalystCon#1資料-Catalystからモデルを切り離せ - dann@catalyst のブックマークコメント

slideshareのほうにアップ。

http://www.slideshare.net/techmemo/catalyst-367905/

後で。

# slideshareだとやっぱりスライド変換途中でレイアウトが少し崩れるね。

BaysideBayside2008/04/24 12:30すごく同感です。Java の struts と PHP の Zend Framework に明示的なモデルがないのは、フレームワークは VC だけ用意しておけばOKということなのかもしれませんね。

danndann2008/04/24 22:57仮にWAFがMを提供するにしても、WAFにMが依存しない形でもMを使えるような形でも提供するべきだろうなぁとは思います。要するに、WAFのM --> POPOのM という感じで。

2008-04-22

プラグイン作るな、使うな その2

プラグイン作るな、使うな その2 - dann@catalyst を含むブックマーク はてなブックマーク - プラグイン作るな、使うな その2 - dann@catalyst プラグイン作るな、使うな その2 - dann@catalyst のブックマークコメント

マニュアル嫁って話なわけなので、とりあえず読んでみた。ただ、やっぱりプラグイン作るな、使うなって話はなんか書いてない気がしたなぁ。

http://search.cpan.org/dist/Catalyst-Manual/lib/Catalyst/Manual/ExtendingCatalyst.pod

読む限り、

Pluginを使っていいと言ってるのは、以下の2点

  • request lifecycleの一部を変更したい場合。

When is a plugin suited to your task? Your code needs to be a plugin to act upon or alter specific parts of Catalyst's request lifecycle.

  • 本当にアプリケーションワイドに機能が必要なケース。
    • session, authenticationがその例

Another valid target for a plugin architecture are things that really have to be globally available, like sessions or authentication.

使うなってケースは、以下の二つ。

  • prepare_* or finalize_* stagesなどをwrapするケース。
    • wrapってのがいまいち意味がつかみきれないのと、なんでダメなのかがよくわからない。もっと別の解があるからかな。

If your functionality needs to wrap some prepare_* or finalize_* stages, you won't get around a plugin.

  • 適切なスコープがある場合には、Globalに機能追加するな。これはまぁそうだろうなぁ。
    • ただ、どのスコープでどんな拡張ポイントを用意するのかについては、フレームワーク側で明示すべき話な気はするけど。もっと例がほしいね、ここは。

Please do not release Catalyst extensions as plugins only to provide some functionality application wide. Design it as a controller base class or another suiting technique with a smaller scope, so that your code only influences those parts of the application where it is needed, and namespace clashes and conflicts are ruled out.

ということで、プラグインを使うなって話を、Catalystの中の人が書いているという話しではないというところまでは分かった。上記の中でも、まだ不明点があるから、もう少し考えないといけないね。

プラグイン使うなって話

プラグイン使うなって話 - dann@catalyst を含むブックマーク はてなブックマーク - プラグイン使うなって話 - dann@catalyst プラグイン使うなって話 - dann@catalyst のブックマークコメント

割と多くの人が言っていたのが、Plugin使うな!(作るな?)って話。多くの人が言っていたけど、その理由がよくわからなかった。

認証とかすんのに誰もプラグイン使ってないのかなという素朴な疑問。。。どういうコンテキストでプラグインを使うなと言っているのかが、全然わからなかったからここら辺をえろい人に解説してもらいたいなぁ。

時間あったら、ゆっくりid:charsbarさんとかに聞いてみたい。テーブルがちょっと分かれてしまったからあまり聞けなかったのだけど、ちょっと突っ込んで聞いてみたかったなぁ。

# エロイ人から、少しだけ教えてもらった。

  • Plugin作るな、使うなっていうのは、Catalystの制御フローに割り込むのを作るなってことなんじゃないか?prepare_xxx よんで NEXT するの全部。
    • けど、それが何故まずいのかが、いまいちよくわかってない。
  • C::P::Authentication なんかは controller で呼ぶから別物と考えればいいと思う
  • ExtendingCatalyst

あざーっす。まだ、全く何故ダメなのかということの理解はしてないのだけれど、ちょっと情報あさってみます。lazy-people++

エロイ人が言ってたからとか、マニュアルに書いてあるからという理由じゃ全然納得できないんだなぁ、自分の場合。なんか明確な理由がないと気持ち悪いなぁという。自分の言葉で説明できないと、なんか納得できないんだよね。

CatalystCon#1 感想

CatalystCon#1 感想 - dann@catalyst を含むブックマーク はてなブックマーク - CatalystCon#1 感想 - dann@catalyst CatalystCon#1 感想 - dann@catalyst のブックマークコメント

  • id:ikasam_aさんのROA+Catalystな話
    • Catalyst::Controller::ResourcesでROAって話。既に便利に使わせてもらってる!
  • id:charsbarさんのCatalystの歴史など
    • Pluginダメ、Component使えなど。$cの汚染よくないなど。
      • Pluginダメって理由をもっと詳しく聞きたかった。
  • id:YappoさんのCatalyst::Engineがらみの話
    • HTTP::Server::Wrapperだっけかな(ちょっと違うかも)。Yappoさんの話面白かったなぁ。Catalystと密な話でもないんだけど、WAFのデザインについての話。15分枠で聞きたかった。
  • id:tokuhiromさんのSledge+Catalystのネタ
    • ネタのインパクトが強くてすげー面白い。LTっぽい感じ。
  • id:hide-KさんのModel::Adaptorの話
    • Model::Adaptorが便利なケースがあるのは納得。
  • id:typesterさんの再利用の話
    • Validatorの話がcool. nameベースのValidatorほしい!

CatalystCon#1 プレゼン

CatalystCon#1 プレゼン - dann@catalyst を含むブックマーク はてなブックマーク - CatalystCon#1 プレゼン - dann@catalyst CatalystCon#1 プレゼン - dann@catalyst のブックマークコメント

何回かやった割にはさくっと時間オーバーしてしまった。さらに、コンセントがささってるのに休止状態に orz

本当に伝えたかったことは、

  • MVCのMはWAFの仕事じゃないよ
  • POPOモデル重要

これだけなんだけど、ちょっとスライド引っ張りすぎたのかも。スライドのアップは後で。

MildredMildred2011/08/04 09:52Short, sweet, to the point, FREE-exactly as information shulod be!

vivzenmrmvivzenmrm2011/08/04 22:13opiHjr <a href="http://sxhjtmarrmol.com/">sxhjtmarrmol</a>

ksxgjfokfjksxgjfokfj2011/08/05 20:29OZQ5Zv , [url=http://vsgviiwrgcye.com/]vsgviiwrgcye[/url], [link=http://poqjypxwnxkn.com/]poqjypxwnxkn[/link], http://qmjlmfohnnzo.com/

ihqiprzcgihqiprzcg2011/08/07 00:55ovLaIT <a href="http://irzktwxpxhea.com/">irzktwxpxhea</a>

ixricpqetwixricpqetw2011/08/07 22:07whA4Gx , [url=http://dizpwhgfquda.com/]dizpwhgfquda[/url], [link=http://wurmcvefktra.com/]wurmcvefktra[/link], http://lteysztnyloi.com/

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

2008-04-20

CatalystCon1

CatalystCon1 - dann@catalyst を含むブックマーク はてなブックマーク - CatalystCon1 - dann@catalyst CatalystCon1 - dann@catalyst のブックマークコメント

東京メトロ 銀座線・南北線「溜池山王駅」12番出口より徒歩約5分

東京都港区赤坂2-17-22 赤坂ツインタワー東館 15F

http://labs.cybozu.co.jp/access.html

# スライドは完成。一応14分.

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

2008-04-19

Data::ObjectDriverでmaster-slave構成にするには

Data::ObjectDriverでmaster-slave構成にするには - dann@catalyst を含むブックマーク はてなブックマーク - Data::ObjectDriverでmaster-slave構成にするには - dann@catalyst Data::ObjectDriverでmaster-slave構成にするには - dann@catalyst のブックマークコメント

頭の中では、D::ODからmaster,slaveを透過的に扱う方法をイメージしていたけれど、実はmaster用とslave用のモデルを分ければいいだけかもしれない。そもそも、masterにRWしたい場合には、透過的に扱えないような気がする。

DriverをMaster用、Slave用に用意すればいいってことかな。master, slave構成にするだけなら、DBICとそんなかわらなそうな気がしてきた。

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

2008-04-18

Data::ObjectDriverでのSlaveへの接続

 Data::ObjectDriverでのSlaveへの接続 - dann@catalyst を含むブックマーク はてなブックマーク -  Data::ObjectDriverでのSlaveへの接続 - dann@catalyst  Data::ObjectDriverでのSlaveへの接続 - dann@catalyst のブックマークコメント

Data::ObjectDriverのコードを見るとread用とwrite用のhandleが分けられるようになっている。実装は*r_handle = \&rw_handle;となっていて、r_handleをサブクラスで用意してねって形になっている。

ただ、これだとRead用のdbh取得の実装を分けられるだけで、上記のようなmasterでrwしたいってケースに対応できないように見える。Data::ObjectDriver使ってる人はどうしてるのかなぁと、先週思ったのでした。

#id:miyagawaさんのブクマコメントで 「master-masterだから関係ないよ!」という話が。ありがとうございます!あまり意図を理解してないかもしれないけれど、master-masterのreplicationをしていて、r_handleでreplicationしたmasterを見にいっているという話なのかなぁ。で、masterしかないからmaster-slave構成を考えなくてもよいということなのかなぁ。何か全然違う理解な気もする...

MasterとSlaveのconnectionを分ける

 MasterとSlaveのconnectionを分ける - dann@catalyst を含むブックマーク はてなブックマーク -  MasterとSlaveのconnectionを分ける - dann@catalyst  MasterとSlaveのconnectionを分ける - dann@catalyst のブックマークコメント

http://d.hatena.ne.jp/nitsuji/20080418/1208446612

以前、みんなどうやってるのかなぁと思って聞いてみたら、大体同じで、masterとslaveのconnectionを明示的に分けて管理しているという話でした。理由は、masterでRWしたいケースがあるからというもので、それはそういうケースがあって当然な気がする。

ただ、slaveのconnectionをアプリ側で複数管理すべきかはちょっと意見が分かれるだろうなという気がする。nitsujiさんのだと複数じゃなくて一つでもいいわけだけれど。

基本的にはアプリケーション側では一つの仮想Slave相手にして、仮想SlaveのバックエンドのリアルSlaveの存在はロードバランサに任せるという形にしないといけないんだろうなとは思う。そうしないと、ロードバランサの仕事を全部アプリケーション側で面倒みなきゃいけなくなるので、アプリケーション側のロジックが複雑になりすぎるから。

miyagawamiyagawa2008/04/19 09:51はい、その理解であってます。Master Master なのでアプリ側からは slave にかいてるか master に書いてるかは read も write も気にする必要なしです。気にしなきゃいけない場合はちょっとめんどうかもしれませんね。

nitsujinitsuji2008/04/19 10:44>基本的にはアプリケーション側では一つの仮想Slave相手にして、仮想SlaveのバックエンドのリアルSlaveの存在はロードバランサに任せるという形にしないといけないんだろうなとは思う。

今仕事とかではこういうことはやってなくてアプリ側で管理してるんですが、みなさんどうしているんでしょうか?
mysql proxyとか使うとできるみたいなんだけど本番で使われてたりするのかなあ・・
http://forge.mysql.com/wiki/MySQL_Proxy

danndann2008/04/19 10:48どうもありがとうございます。お陰様でよく理解できました!

danndann2008/04/19 11:42nitsujiさん> LVS(+keepalived) 使うのがpopularみたいですよー

danndann2008/04/19 12:34nitusjiさん> 自分の1行コメントだけでもなんなので... naoyaさんの説明がとてもわかりやすいですよー。http://d.hatena.ne.jp/naoya/20060901/1157109663

nitsujinitsuji2008/04/19 20:20おー、なるほど・・。ありがとうございますー。

novinhonovinho2012/07/22 02:40Aritlecs like this just make me want to visit your website even more.

crzhsdwmurcrzhsdwmur2012/07/22 19:23xxPvBo <a href="http://rgxyoqpvajqf.com/">rgxyoqpvajqf</a>

pvchsevzlpvchsevzl2012/07/23 09:10v9wrfc , [url=http://viruyuyhiaoa.com/]viruyuyhiaoa[/url], [link=http://xdspdffzbvzx.com/]xdspdffzbvzx[/link], http://dyviyoyelviu.com/

dfjapksxdfjapksx2012/07/24 08:39vI7Le1 <a href="http://iitpcphcpvdn.com/">iitpcphcpvdn</a>

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

2008-04-17

DBIx:::Class::Cursor::Cached

23:58 |  DBIx:::Class::Cursor::Cached - dann@catalyst を含むブックマーク はてなブックマーク -  DBIx:::Class::Cursor::Cached - dann@catalyst  DBIx:::Class::Cursor::Cached - dann@catalyst のブックマークコメント

コード見た限りでは、

  $rs->all
  $rs->next

のタイミングでキャッシュ。

searchした後とかに使うのはなんとなくイメージができるんだけれど、findとかで使う方法がいまいちわからない。findした結果をキャッシュとか、そういう用途に使うものではないのかな。

cursorとの関係がいまいち理解できてないからなのかも。後、keyが何になってるのかが、dumpしないと何なのかよくわからないから、後でそれは調べる。

update, deleteするときにcacheクリアしたりとかも、DBIx::Classのコンポーネントとして実現できないかと思ったけれど、cursorのことがわかってないからかよく分からなかった。

idをキーにしてキャッシュするというイメージから違うから理解が進まないというのもあるのかもしれない。

DBIx::Class

23:58 |  DBIx::Class - dann@catalyst を含むブックマーク はてなブックマーク -  DBIx::Class - dann@catalyst  DBIx::Class - dann@catalyst のブックマークコメント

ResultsetもCursorも含めて、JavaJDBCに凄い似ている。クラス構成もそっくり。mstな人は実はJava屋さんなんじゃないか。

rzfdltxuarzfdltxua2012/11/02 09:38qX7XOE <a href="http://sievvobronhc.com/">sievvobronhc</a>

ouqkgpouqkgp2012/11/02 14:187W41Zb , [url=http://idxpfqszcxyo.com/]idxpfqszcxyo[/url], [link=http://sqvltntpqyss.com/]sqvltntpqyss[/link], http://bynebjajlais.com/

hhhgrjqzogehhhgrjqzoge2012/11/04 22:58LJ09jb <a href="http://bebzuoaslxkb.com/">bebzuoaslxkb</a>

ccxmxqkdpclccxmxqkdpcl2012/11/05 12:19vrswjm , [url=http://tddwujvcmhqb.com/]tddwujvcmhqb[/url], [link=http://dhmunohsahnp.com/]dhmunohsahnp[/link], http://gaegtufejrjs.com/

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

2008-04-16

AOP的な仕組み

18:39 |  AOP的な仕組み - dann@catalyst を含むブックマーク はてなブックマーク -  AOP的な仕組み - dann@catalyst  AOP的な仕組み - dann@catalyst のブックマークコメント

Moose使わなくても、Class::Triggerだけでいいんじゃないかという気がした。Data::ObjectDriverのコードを見ていて思った。あーいう感じでさくっとhookを登録できるのはいいなぁ。色々と応用できそう。

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

2008-04-15

コネクションが切れた場合の再接続

23:33 | コネクションが切れた場合の再接続 - dann@catalyst を含むブックマーク はてなブックマーク - コネクションが切れた場合の再接続 - dann@catalyst コネクションが切れた場合の再接続 - dann@catalyst のブックマークコメント

ありがたいことにブクマコメントで幾つかヒントをもらったので、少し考えてみました。

id:naoyaさんから、「DBIのconnect_cached」

id:kazeburoさんから、「mysqlのreconnectの機能」

DBIx::Class::Storage::DBIにも

connect_cachedのコードでは、以下のようなチェックをして、それ以外の場合に$dbhを作り直すという処理になっていました。

if ($dbh && $dbh->FETCH('Active') && eval { $dbh->ping }) {

mod_perl+connect_cachedでは、プロセスレベルでコネクションが保持されるようになるので、コネクションは張りっぱなしになるのでDBサーバーに負荷はかかるかもしれませんが、十分にDBサーバーに余裕があれば、connect_cachedでよいのかなぁという気がしました。

最終的にはコネクションが張りっぱなしにならないようにしてDBサーバーの負荷を下げるために、リクエスト単位でコネクションを取得する形になるのかなぁという気もしてますが、これも後々調べようかなぁと思ってます。

キャッシングの機構

22:56 | キャッシングの機構 - dann@catalyst を含むブックマーク はてなブックマーク - キャッシングの機構 - dann@catalyst キャッシングの機構 - dann@catalyst のブックマークコメント

Catalyst+DBIx::Classでしばらく遊んでいこうかなぁと思っています。

ただ、分散構成にしてMemcachedでのキャッシングまでを考えた場合、DBIx::Classだとキャッシング周りの機構がかなり厳しいかなぁという印象がありますが、折角初めてさわるPerlのORマッパなのでしばらく遊ぼうかなぁと思っています。

キャッシングだけを見ると、Data::ObjectDriverのほうが相当よく考えられているなぁという感じです。fallbackの仕組みが綺麗に考えられていて、キャッシングの仕組みを実装するときには参考になります。ORマッパとキャッシングの機構というのは切っても切り離せない関係にあるのだなぁという気がしました。

DBIC内でのキャッシュの難しさ

18:26 |  DBIC内でのキャッシュの難しさ - dann@catalyst を含むブックマーク はてなブックマーク -  DBIC内でのキャッシュの難しさ - dann@catalyst  DBIC内でのキャッシュの難しさ - dann@catalyst のブックマークコメント

dbic内でキャッシュするときに難しいのは2点あって、

  • Relationがある場合にその関連先のデータをキャッシュできない
  • 最終的に到達するのが、DBIx::Classs::Storage::DBIで、そこではid引っ張るのが大変

DBICの外側でキャッシングしようとしても、Relationがなければキャッシュしてもいけますが、Relationがあるとキャッシュ時にResultSourceの情報が落ちてしまって、キャッシュができないからなんじゃないかなぁと。

has_oneとかのあるRelationがあるデータをキャッシングするときってどうすればいいのかがよくわからなくて、どうすればキャッシングできるのかわからないなぁという感じです。

DBICの外側でも内側でも、簡単にキャッシングできる方法があればなぁと思っているのですが。

自分が理解してないだけなのかはよくわからないけど、うまくキャッシングできる気がしない。逆にRelationはってなければ、普通にキャッシュできると思うんだけれど。

# Data::ObjectDriverのコードを見ても、has_aのキャッシュはexperimentalとなってますが...

# id:typesterさんにDBIx::Class::Cursor::Cachedを教えてもらった!前に試してみた気もするけど記憶がない... ということで、まじめに後で試す!

http://search.cpan.org/~mstrout/DBIx-Class-Cursor-Cached-1.0.1/lib/DBIx/Class/Cursor/Cached.pm

$rs->cursor->clear_cacheと書かなきゃ行けないのは何とかしたいから後で調べる。

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

2008-04-13

Xenで環境構築

| 20:03 | Xenで環境構築 - dann@catalyst を含むブックマーク はてなブックマーク - Xenで環境構築 - dann@catalyst Xenで環境構築 - dann@catalyst のブックマークコメント

CentOS+Xenで実験環境を作ろうと思って、仮想サーバーを幾つか並べてみました。

Front1台(mod_proxy_balancer)、App Server(mod_perl)2台、DB(mysql)1台という構成でまず環境を作ってみました。

ここから発展させて、

  • (上記) + Master1台 + Slave2台 + Memcachedサーバー1台
  • Master + Slaveの前にLVS

という構成の実験環境を作って、しばらく勉強してこうかなぁと思ってます。

AffeAffe2012/07/23 13:25Always the best content from these prodigiuos writers.

dweqvactuzdweqvactuz2012/07/23 22:17XIOYpf <a href="http://yiuxqmmvsofq.com/">yiuxqmmvsofq</a>

rislfyrislfy2012/07/24 11:56jXksVK , [url=http://mxdrfjniftri.com/]mxdrfjniftri[/url], [link=http://bmwwfyuhsvwk.com/]bmwwfyuhsvwk[/link], http://mzbwmjmmnqjf.com/

tkgzclvxdtkgzclvxd2012/07/25 22:48eP94Bt <a href="http://qvfgklyksise.com/">qvfgklyksise</a>

xrbtftavcahxrbtftavcah2012/07/26 23:12g0WOLj , [url=http://qggnrutlqhie.com/]qggnrutlqhie[/url], [link=http://jtumlqlopjll.com/]jtumlqlopjll[/link], http://lpdjyvbkmuva.com/

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

2008-04-12

CentOS5.1のPerlにパッチ

| 04:19 |  CentOS5.1のPerlにパッチ - dann@catalyst を含むブックマーク はてなブックマーク -  CentOS5.1のPerlにパッチ - dann@catalyst  CentOS5.1のPerlにパッチ - dann@catalyst のブックマークコメント

Xenの環境整えようと思ったら、親切にもDBICwarningを。

後でやる。

http://d.hatena.ne.jp/dayflower/20080108/1199771246

EssenceEssence2011/12/27 20:54I'm not eiasly impressed but you've done it with that posting.

xsdjzidxsdjzid2011/12/28 18:57UEIXT9 <a href="http://ifklpiopxoju.com/">ifklpiopxoju</a>

ieehgdkwieehgdkw2011/12/28 22:59flzZwm , [url=http://grwdbcopbhqi.com/]grwdbcopbhqi[/url], [link=http://mtnndqixlyjz.com/]mtnndqixlyjz[/link], http://qlveyyabstft.com/

mxktcsdczvhmxktcsdczvh2011/12/29 19:26I1rMgG <a href="http://msfsgovemumc.com/">msfsgovemumc</a>

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

2008-04-10

コネクションが無効になった場合のコネクションの再取得?

22:51 |  コネクションが無効になった場合のコネクションの再取得? - dann@catalyst を含むブックマーク はてなブックマーク -  コネクションが無効になった場合のコネクションの再取得? - dann@catalyst  コネクションが無効になった場合のコネクションの再取得? - dann@catalyst のブックマークコメント

プロセス毎に一つのコネクションを保持している場合、何らかのタイミングでそのconnectionが切れてしまったら、そのプロセスではずっとエラーになってしまう気がする。こういう場合、どういう対応をするのだろう。

「コネクションを破棄して新たなコネクションを作り直なおすのをアプリケーション側で作りこむ」というのがあるけれど、できればアプリケーション側で頑張りたくないなぁという気はする。

Javaではこういうのは、connection pool側の仕事でアプリケーション側からは見えない。connection poolは割と色んな実装があって

  • poolしているconnectionの接続が切れててもそのままpoolしていて、いざ使おうとすると例外があがっちゃうもの
  • プールされたconnectionの接続が切れていると、pool中のコネクションを破棄して、再度コネクションを作りなおそうとするもの

とか、色んな実装があるのは見てきたので(マニュアル読んでも書いてなくて、ソースも見れないアプリケーションサーバーとかね...)、再接続の問題って必ず何かを作っていると問題になるので、Perl界隈でもなんか解があるんじゃないかなぁという。

できれば、アプリケーション側で頑張りたくないなぁという。物理的なコネクションと論理的なコネクションを分けているところに、Connection Poolの意味の一つはある気がしていて、それがないと、Connectionが切れていた場合に、アプリケーション側で頑張らないといけなくなっちゃうなぁと。

Javaの界隈だとアプリケーションサーバーの機能として、無効なConnectionを破棄するようなものが多い

こういうのって、Perl界隈でどうやって解決しているものなのかが、ググってはみたものの良く分からなかった。

頑張れる場所は、多分3つあって、Connection Pool or DBそのものの機能で頑張れれば、アプリケーション側はあまり気にしなくてもいいかもしれない(というのは嘘か...) 。

  • アプリケーション
  • Connection Pool
  • DBそのもの

永続的に無効なコネクションを保持したまま、プロセスが生き残ってしまうということだけが問題なので、コネクションが無効になって何らかの例外があがった段階で、そのプロセスを殺してしまうというのが現実解なのかなぁと思いました。

何か他に解があれば、是非教えてください。

# kazeburoさんから、reconnectというコメントが!

reconnectってこっちのことかなぁ。

http://dev.mysql.com/doc/refman/5.1/ja/mysql-reconnect.html

DB側でがんばるって形だなぁ。ただ、この文面読む限りだと使う場面を選びそうな気はする。ただ、DB側でreconnectして失敗した場合のこともアプリケーションはやっぱり意識しないといけないかな。

# もう少し考えてみると、アプリケーション側でプロセス単位でコネクション保持するんじゃなくて、リクエスト単位で保持したほうがBetterなのかもしれないなぁ。そうすれば、最悪そのリクエストだけで死ぬわけで、害は小さいかもしれない。

物理コネクションと論理コネクション

22:51 |  物理コネクションと論理コネクション - dann@catalyst を含むブックマーク はてなブックマーク -  物理コネクションと論理コネクション - dann@catalyst  物理コネクションと論理コネクション - dann@catalyst のブックマークコメント

DBIでconnectする度に毎回物理connectionが取れちゃうっていうんだと、各DAOでconnection取得すると、そのTransactionコミットするとき、どうなっちゃんだという疑問はある。

Javaの場合だと、コネクションプールから論理コネクションが取得されて、その論理コネクションから対応する物理コネクションに対応している。論理コネクションと物理コネクションの対応関係は、多:1になる。

例えば、あるトランザクション中から複数のDAOで論理コネクションを取得しても、実際に対応する物理コネクションが一つになっているということになる。(これはコネクションプールの実装次第ではあるのですが)

なんで、Perl界隈で論理コネクションの話がでてこないのかと不思議に思っていたのだけれど、Perl界隈ではプロセス単位でコネクションを保持するからじゃないかと思った。

要するにPerlではプロセス中心のモデルが主流だけれど、Javaではスレッド中心のモデルが主流になっているという違いがあるということだ。Javaでは普通スレッドベースのアーキテクチャでしか考えないし、プロセスベースで考えることが殆どない。

確かにプロセスレベルで物理コネクションを共有してしまえば、各DAOで論理コネクションを取得する必要なんて殆どない。

違うかなぁ。

Cowなメモリ共有のプラクティス with mod_perl

22:29 |  Cowなメモリ共有のプラクティス with mod_perl - dann@catalyst を含むブックマーク はてなブックマーク -  Cowなメモリ共有のプラクティス with mod_perl - dann@catalyst  Cowなメモリ共有のプラクティス with mod_perl - dann@catalyst のブックマークコメント

mod_perlのことを全然分かっていないので、最近少しずつid:hidedenに聞きながら勉強している今日この頃です。いくつかの記事とid:hidedenなどに聞いた話を含めて、自分の理解している範囲内でまとめてみました。

forkしたプロセス間でのメモリ領域の共有

forkでは全てのメモリが共有された状態・親プロセスと子プロセスでメモリが共有された状態になっている。子プロセスをforkするときには、forkする前に確保したメモリは共有される。しかし、子プロセスがforkしてからモジュールをロードされた場合は、子プロセス数分のメモリを確保しなくてはなりません。

メモリ領域×MaxClients(子プロセス数)分のメモリが、新たに消費されることになります。従って、子プロセスのサイズを小さくできれば、最大で、(減少できるメモリ量)×MaxClients分だけメモリを小さくできるので、極力親プロセスと子プロセスでメモリを共有したほうがよいということになる。

特にmod_perlのプロセスは基本的に1プロセスサイズあたりのメモリサイズが大きくなってしまう。だから、1プロセスのメモリのサイズを小さくすることが重要になってくる。

親プロセスと子プロセスでメモリを共有するためには、以下のことをする必要がある。

  • 親プロセスと子プロセスで共有されているメモリ量を調べる
  • GTopで計測して、特にメモリ使用量が多いものについては、startup.plでロードするようにする
  • 共有されている率が低い場合は、動的にロードされていないモジュールがあるかを調べる
  • useするだけではロードされないものもあって、それはモジュール毎にmod_perl用の初期化方法があるものもあるので、モジュールに従う

ということが必要。

共有メモリの割合

共有メモリのサイズはLinux::Smapsで確認。具体的には、id:naoyaさんの以下のスクリプトで確認。Shared_Clean と Shared_Dirtyのサイズが他のプロセスと共有しているメモリのサイズになるのがポイント。

#!/usr/bin/env perl
use strict;
use warnings;
use Linux::Smaps;

@ARGV or die "usage: %0 [pid ...]";

printf "PID\tRSS\tSHARED\n";

for my $pid (@ARGV) {
    my $map = Linux::Smaps->new($pid);
    unless ($map) {
        warn $!;
        next;
    }

    printf
        "%d\t%d\t%d (%d%%)\n",
        $pid,
        $map->rss,
        $map->shared_dirty + $map->shared_clean,
        int((($map->shared_dirty + $map->shared_clean) / $map->rss) * 100)
}

各モジュールをuseしたときにかかるメモリ量は、Gtopで確認。iandeathさんのサイトから。

http://iandeth.dyndns.org/mt/ian/archives/000624.html

#!/usr/bin/perl
use strict;
use warnings;
use GTop;
my $gtop = GTop->new;
my $before = $gtop->proc_mem($$)->size;
eval $ARGV[0];
die $@ if $@;
my $after = $gtop->proc_mem($$)->size;
my $diff = GTop::size_string($after - $before);
print "$diff : $ARGV[0]\n";

startup.plで読み込まれたファイルでは、apache restartでは読み込みされないので、apache stop/startを実行する。

動的にロードされるモジュールの調査

動的にロードされるモジュールも事前にロードしておけば、親プロセスと子プロセスでメモリを共有できる。

動的にロードされたモジュールを調べる方法は、id:hidedenが詳しく解説している。

http://d.hatena.ne.jp/hideden/20080409/1207740439

ポイントは、子プロセスが死んだときに、INCの差分を見ればよいというものだ。これで動的モジュールがロードできる。

プロセスサイズを小さくするためのその他の検討事項

プロセスのサイズを小さくするという点に限れば、

  • 不要なApacheのモジュールを読み込まない
  • mod_perl上ではなく、Geamanなどに処理を委譲して別のプロセスにする

などをまず先に検討した上で、さらに上記を検討していくという形なのだとは思います。

プロセスサイズを小さくするために、CPANモジュールを使わない!というレベルまでチューニングをやっているという某所もあるらしいので、ここらはスケールアウトさせるレベルと、保守性とのバランスの兼ね合いだとは思います。

Catalystでのプラクティス

id:spiritlooseさんの話も反映すると、startup.plでは、

  • use MyApp ();
  • DBImysqlを指定
  • 動的モジュールのロードチェックして、ロード
use DBI ();
DBI->install_driver("mysql");


その他

  • runtimeでforkさせないのがベストではあるが、メモリリーク対策でMaxRequestsPerChildなどを使っていて、子プロセスが再forkするケースもありうるので、そのときにはfork+fork後に子プロセスが動き新しくモジュールがロードされたときにはコストが高くなるわけなので、そのためにもメモリが共有された状態にしておいたほうがよい
  • startup.plでuseすると、挙動不審になる子もいるので注意が必要
    • これについては、どんなケースでどんなモジュールがダメなのかがよくわかってないので、またわかったら。

参考

  • CoWについてはkounoikeさんの説明が詳しいのと、naoyaさんの実際の例での説明はとてもわかりやすいですね。
  • 動的にロードされているモジュールを調べる方法についてはhidedenの説明が詳しいです。

http://www.typemiss.net/blog/kounoike/20060202-61

http://www.typemiss.net/blog/kounoike/20060212-65

http://devel.aquahill.net/doc/apache_mod_perl_tune.html

http://d.hatena.ne.jp/naoya/20050830/1125365504

http://d.hatena.ne.jp/naoya/20080212/1202830671

http://d.hatena.ne.jp/tokuhirom/20071017/1192589429

http://iandeth.dyndns.org/mt/ian/archives/000624.html

http://d.hatena.ne.jp/hideden/20080409/1207740439

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

2008-04-09

startup.plに書くモジュールを探す

| 20:38 |  startup.plに書くモジュールを探す - dann@catalyst を含むブックマーク はてなブックマーク -  startup.plに書くモジュールを探す - dann@catalyst  startup.plに書くモジュールを探す - dann@catalyst のブックマークコメント

INCDiffのアイデアが秀逸。

http://d.hatena.ne.jp/hideden/20080409

これでstartup.plかなり作りやすくなる!id:hideden++

spiritloosespiritloose2008/04/09 23:27Catalystアプリのstartup.plは基本的に use MyApp (); のみでほとんど読んでくれますよね。
それにプラスしてid:hidedenさんのINCDiffを使えばだいぶよさげです。

danndann2008/04/10 22:57どうもありがとうございまーす。新しくエントリを作って書いておきましたー。

StitchesStitches2011/08/02 19:46Stands back from the keyboard in aamzemnet! Thanks!

kolajjkolajj2011/08/03 17:08okwyEL <a href="http://yepkiciibnmo.com/">yepkiciibnmo</a>

cwfbugjzcwfbugjz2011/08/03 20:42NAKsQh , [url=http://eiywgngdollr.com/]eiywgngdollr[/url], [link=http://ekcftcjrzjmf.com/]ekcftcjrzjmf[/link], http://diwhvihagapt.com/

znhyfonzznhyfonz2011/08/05 17:24GxuH6L <a href="http://szgmwkcglxgx.com/">szgmwkcglxgx</a>

rwpgxukwrowrwpgxukwrow2011/08/05 22:41TR2M7C , [url=http://oxpqeafuvklc.com/]oxpqeafuvklc[/url], [link=http://mldbcryplooz.com/]mldbcryplooz[/link], http://fhxsukykrsiv.com/

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

2008-04-06

モジュールのメモリの使用量とプロセスのサイズについて

| 21:11 |  モジュールのメモリの使用量とプロセスのサイズについて - dann@catalyst を含むブックマーク はてなブックマーク -  モジュールのメモリの使用量とプロセスのサイズについて - dann@catalyst  モジュールのメモリの使用量とプロセスのサイズについて - dann@catalyst のブックマークコメント

後で読む.

http://iandeth.dyndns.org/mt/ian/archives/000624.html

http://d.hatena.ne.jp/naoya/20050830/1125365504

http://d.hatena.ne.jp/naoya/20050829/1125276915

http://modperlbook.org/html/10-1-Sharing-Memory.html

# 大体読んだ。結論としては、Catalyst or Sledgeのプロジェクトで使っているstartup.plを誰かが公開してくれればいいんじゃまいか。という丸投げスタイルはどうか。

Catalyst::Model::DBIC::SchemaでCatalystのmodelとして登録する処理

16:07 | Catalyst::Model::DBIC::SchemaでCatalystのmodelとして登録する処理 - dann@catalyst を含むブックマーク はてなブックマーク - Catalyst::Model::DBIC::SchemaでCatalystのmodelとして登録する処理 - dann@catalyst Catalyst::Model::DBIC::SchemaでCatalystのmodelとして登録する処理 - dann@catalyst のブックマークコメント

これをどこでやればいいのかなぁと思ってたけど、DIコンテナ側でやればいいんだということに気づいた。Modelクラスのサブクラスを生成しようかと思ってたけど、これより筋はよさそう。

ただ、Dynamicに生成するとDIコンテナ側で扱いにくそうだなぁ。あとちょっと検討が必要。

# 追記: MyApp::Model::DBICというクラスで動的にクラスを生成するようにしてみた。

starter

15:37 | starter - dann@catalyst を含むブックマーク はてなブックマーク - starter - dann@catalyst starter - dann@catalyst のブックマークコメント

id:cho45さんのをベースに、一部をマージして全面移行しました。

cho45さんのstarterの形式だと、ApplicationからTemplateの作成が簡単にできるところがCool. これで、starterの不満は殆どなくなりました。

http://coderepos.org/share/browser/lang/perl/misc/catstarter/dann

cooooooooool!

zobhbjzobhbj2012/07/24 08:515ruSdH <a href="http://wiwgjgodaqwx.com/">wiwgjgodaqwx</a>

aypwamaypwam2012/07/24 13:31Kq3vJV , [url=http://uswcxhzqhnnj.com/]uswcxhzqhnnj[/url], [link=http://dnipwiyiddlm.com/]dnipwiyiddlm[/link], http://saxethlajrmc.com/

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

2008-04-05

Capistrano + git

03:23 |  Capistrano + git - dann@catalyst を含むブックマーク はてなブックマーク -  Capistrano + git - dann@catalyst  Capistrano + git - dann@catalyst のブックマークコメント

gitへの移行に伴って、Catalystのdeploymentスクリプトもgit使うように変更した。repository, scmの設定を変えるのがポイント。全体は長いので、一部だけ。

# SSH OPTIONS
ssh_options[:keys] = %w(~/.ssh/id_rsa)
ssh_options[:forward_agent] = true

# git config
set :repository, "dann@192.168.0.30:/var/git/repos/#{application}"
set :scm, :git
set :scm_username,  ENV['USER'] || Proc.new { Capistrano::CLI.password_prompt('SCM User: ') }
set :scm_password, Proc.new { Capistrano::CLI.password_prompt('SCM Password: ') }

catalystアプリをgitで管理

02:36 |  catalystアプリをgitで管理 - dann@catalyst を含むブックマーク はてなブックマーク -  catalystアプリをgitで管理 - dann@catalyst  catalystアプリをgitで管理 - dann@catalyst のブックマークコメント

今日はgitに入門してみました。ということでCatalystアプリもgitで管理すべく、スクリプトをgitに移行。

#!/bin/bash
CATALYST_CMD='/home/dann/devbin/catsetup.pl'
APP_NAME=$1
APP_PREFIX=`echo $APP_NAME | tr "[A-Z]" "[a-z]"`
GIT_REPOS=dann@192.168.0.30:/var/git/repos

if [ -z $1 ]; then
    echo "You need to give a catalyst project name."
    return 1
fi

if [ -f $1 -o -d $1 ]; then
    echo "$1 exist in current directry.\nYou should change directry."
    return 1
fi

$CATALYST_CMD $APP_NAME
cd $APP_NAME
git init-db
git add .
git commit -a -m "initial commit"
cd ..
echo "after commit"
git clone --bare $APP_NAME/.git $APP_PREFIX.git
echo "after clone"
scp -r $APP_PREFIX.git $GIT_REPOS
rm -rf $APP_PREFIX.git
cd $APP_NAME
git remote add origin $GIT_REPOS/$APP_PREFIX.git
git fetch origin

モデルをCatalystから切り離す方法

16:55 |  モデルをCatalystから切り離す方法 - dann@catalyst を含むブックマーク はてなブックマーク -  モデルをCatalystから切り離す方法 - dann@catalyst  モデルをCatalystから切り離す方法 - dann@catalyst のブックマークコメント

id:nitusjiさんのブクマコメントで、DIコンテナを使って依存関係を切り離すのは、「Model::Adaptorと比べて何がいいんだろう」というコメントが書いてあったので、今回は、Catalyst::Model::Adaptorで依存を切り離すことがあまり嬉しくない理由についてだけ書きます。あまり書いてしまうと、CatalystConで話すことがなくなってしまうで (^^;

まずはじめに、モデルをCatalystから切り離す方法についてですが、大体以下の4つがあります。

  • Catalyst::Model::Adaptor + POPO
  • POPO + Factory
  • POPO + ServiceLocator
  • POPO + DIコンテナ

Catalyst::Model::Adaptor + POPOで切り離すことのデメリット

このうち、Catalyst::Model::Adaptor + POPOを用いることがあまり嬉しくない理由の一つは、miyagawaさんが書いていることです。

http://subtech.g.hatena.ne.jp/miyagawa/20080306/1204761778

%opt は設定ファイルに書く、っていう、ただそれだけなんですね。これじゃ全然つかいものにならないし、Model::Adaptor のラッパーで使いたければそれでもいいかもしれないけど、単にオブジェクト生成するところやメソッド通すときにラッパー一段増えるだけで別になにもうれしくない。

暗にmiyagawaさんも書いていますが、「POPOのモデルを作るたびに、CatalystのAdaptorを作らないといけなくなる」、というのは大きなデメリットです。

Catalyst::Model::Adaptorを使うことのメリット

デメリットの裏返しではありますが、メリットは、Catalystで読んだConfigが参照できるところだと思います。デメリットを超えたメリットがあるかというと、今のところは殆どないのかなという印象です。

ただ、Catalyst::Model::Adaptorを使わずに、Catalystからモデルの依存を切り離すためには、自前でConfigLoaderを用意する必要があります。ですから、デメリットはあるものの、お手軽に依存関係を切るための方法として、Catalyst::Model::Adaptorを使うというのはありなんじゃないかと思います。

ModelをPOPOだけで構築することについて

POPOだけで構築すれば、Catalystからの依存は切れるわけで、以下の3つの方法はどれを使ってもCatalystへの依存関係を切り離すことはできます。

  • POPO + Factory
  • POPO + ServiceLocator
  • POPO + DIコンテナ

上記にどのような違いがあるかについては、CatalystConの時間内に収まればしてみようかなと思っています。ただ、Catalyst(or WAF)の話とは関係なくて、アプリケーションを作るときにDIコンテナを使うことのメリット・デメリットという話になってしまうので、CatalystConで話す内容かな?という気は少しします。

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

2008-04-04

yasnippet for vimが欲しい

04:52 |  yasnippet for vimが欲しい - dann@catalyst を含むブックマーク はてなブックマーク -  yasnippet for vimが欲しい - dann@catalyst  yasnippet for vimが欲しい - dann@catalyst のブックマークコメント

snippetsEmuはsnippetが書きにくくて、気軽に追加しようとする気になれないのが最大の欠点。Perl系のsnippetをまとめて登録したいんだけど。

Wiki+Blogみたいなのでやりたいな

04:35 |  Wiki+Blogみたいなのでやりたいな - dann@catalyst を含むブックマーク はてなブックマーク -  Wiki+Blogみたいなのでやりたいな - dann@catalyst  Wiki+Blogみたいなのでやりたいな - dann@catalyst のブックマークコメント

日記でやるものではない気がする俺ガイル

Perlのプラグイン機構のお勉強

| 03:17 |  Perlのプラグイン機構のお勉強 - dann@catalyst を含むブックマーク はてなブックマーク -  Perlのプラグイン機構のお勉強 - dann@catalyst  Perlのプラグイン機構のお勉強 - dann@catalyst のブックマークコメント

後でまじめに見てみる。Perlのリフレクション機構も後で。

Mooseへ移行

| 03:17 |  Mooseへ移行 - dann@catalyst を含むブックマーク はてなブックマーク -  Mooseへ移行 - dann@catalyst  Mooseへ移行 - dann@catalyst のブックマークコメント

Mooseに移行。requiredでチェックできるのはなかなか便利。before,afterもキャッシング・トランザクション周りを綺麗に扱えそうなので、結構面白そう。

Bread::Boardを使いやすくするには、Attributeを理解しないといけないな。Attributeってメソッドにしかつけられないのかな。それだとなんか足りないな。

cho45さんのstarter

| 03:17 |  cho45さんのstarter - dann@catalyst を含むブックマーク はてなブックマーク -  cho45さんのstarter - dann@catalyst  cho45さんのstarter - dann@catalyst のブックマークコメント

http://github.com/cho45/catstarter-pl/tree/master/catstarter.pl

Path::Classの使い方がわかったから暇あったら取り込もう。templateのほうを期待!

Catalyst+ DIでアプリケーションのCatalystへの依存を切り離す

| 00:31 |  Catalyst+ DIでアプリケーションのCatalystへの依存を切り離す - dann@catalyst を含むブックマーク はてなブックマーク -  Catalyst+ DIでアプリケーションのCatalystへの依存を切り離す - dann@catalyst  Catalyst+ DIでアプリケーションのCatalystへの依存を切り離す - dann@catalyst のブックマークコメント

Catalyst中でDIコンテナを使い、CatalystからService、ModelクラスのCatalyst依存部分を切り離すようにする方法を以下に示します。

やることは至って単純で、

  • BaseのControllerでServiceContainerからServiceクラスを取得
  • ServiceContainerではモジュールのロードタイミングでDIコンテナを初期化しWiringをする

の二つだけです。

これによって、利用者はDIコンテナからServiceを取得すればよくなります。

BaseのController

package MyApp::Base::Web::Controller;
use base 'Catalyst::Controller';

sub service: Private {
    my ($self, $service_name) = @_;
    return MyApp::ServiceContainer->get($service_name);
}

1;

ServiceContainer.

package MyApp::ServiceContainer;
use strict;
use warnings;

use Bread::Board;

our $container;
BEGIN {
    $container = container 'AppContainer' => as {
         service 'Service::Blog' => (
             class     => 'MyApp::Service::Blog',
             lifecycle => 'Singleton',
         );
    };
}

sub get {
    my $class= shift;
    my $service_name = shift;
    $container->fetch($service_name)->get;
}

1;

利用する側のコード

Controller中で以下のように参照する。

$self->service('Service::Blog')->create_entry($title, $content);

これで、ServiceクラスはCatalystに依存することがなくなります。これにより、CatalystはWAFとしての役割にだけ集中すればよく、アプリケーション側はPOPOベースでドメインモデルを構築することに専念することができます。これによって、アプリケーションはCatalystからの依存関係を断ち切ることが出来るようになるため、Testabilityが高くなります。DIコンテナから参照できるオブジェクト(Service、Model)は、Catalystには依存していないため、CLIからもWebAPIからも使うことが出来ます。

ServiceContainerは、今は手で書いてますが、ここの部分は工夫の余地があります。Bread::Boardは旧世代のDIコンテナだという話を前に書きましたが、その理由はこのWiringする部分を一箇所で集中して書かなければいけないからです。JavaでいうAnnotationを使うと綺麗に解決できるので、おそらくPerlでもAttributeで解決できることなんだろうと思います。

DIコンテナはどのような形であるべきかについては、また後のエントリで書きたいと思います。自分がもう少しPerlが分かっていたら、解決策までコードベースで提示できそうなんですが、まだ大分Perlの知識が足りないですね...

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

2008-04-02

AOPによる宣言トランザクションとDBIx::Class::Service

01:56 |  AOPによる宣言トランザクションとDBIx::Class::Service - dann@catalyst を含むブックマーク はてなブックマーク -  AOPによる宣言トランザクションとDBIx::Class::Service - dann@catalyst  AOPによる宣言トランザクションとDBIx::Class::Service - dann@catalyst のブックマークコメント

DBIx::Class::Service

http://d.hatena.ne.jp/ZIGOROu/20080401/1207037478

DBIx::Class::Serviceの仕組みは、JavaAOPによる宣言トランザクションの仕組みにとても近いです。クラス登録時にTransationアトリビュートがついていたら、トランザクションの開始・終了を行うようなProxyクラスでラッピングしてやるわけです。

Javaではこれをバイトコードレベルでそういうコードを差し込む形になっています。AOPでTransation用のInterceptorを設定してやると、そのメソッドはトランザクショナルなメソッドになります。このときに、サービスのクラスには一切トランザクションのコードが埋まっていないわけです。

DBIx::Class::Serviceと、JavaでのAOPの宣言トランザクションの仕組みはとても似ていますが、仕組み以外では少し違うところがあります。Javaでいう宣言トランザクションの仕組みは、ORマッパには全く依存していません。トランザクションのAPIJTAAPI)にしか依存していません。そこが大きな違いです。

ただ、将来的に同じような仕組みで実現されていくのではないかと思います。Javaと同じように以下の形になっていくのではないかと思います。

  • DIコンテナがサービス登録時に、トランザクショナルなProxyを介してトランザクショナルなメソッドに変換するのはする
  • 宣言トランザクションはメソッドのアトリビュートとして指定する
  • トランザクションの開始・終了は、ORマッパに依存させない
  • サービスというクラスは、ORマッパの外にある Service->ORマッパ といった構成になる。

Bread::Boardを使った場合には、

「serviceの定義にtransactional_methodsというトランザクショナルなメソッドを指定するものを用意して、そこにメソッドが指定されていた場合には、before, afterでトランザクション開始終了を行うようなServiceとして登録する」

といったような形での実装になっていくのではないかと思います。

ただ、DBIx::Class::Storage::DBIの実装を見ると、切り離すのは少し面倒そうだなぁという気はします。

何故宣言トランザクションがJava界隈でもてはやされているかというと、宣言トランザクションの仕組みがあれば、サービスのクラスのビジネスロジックがトランザクションの管理から解放され、それがPOJOとして扱えるからです。

これはTestabilityの点で望ましいということになります。これについては、PerlでもJavaでも変わらないかなとは思います。

ただ、以前も書きましたが、DBIx::Classだけを用いる場合でも、テスト時にtxn_doメソッドをMonkey Patchingでトランザクショナルなメソッドにしないようにしてしまってもいいわけで、労力をかけて頑張ろうという気になれないのも確かです。

CatalystConでの発表内容

00:09 |  CatalystConでの発表内容 - dann@catalyst を含むブックマーク はてなブックマーク -  CatalystConでの発表内容 - dann@catalyst  CatalystConでの発表内容 - dann@catalyst のブックマークコメント

以下のような構成で話そうかと思ってます

ただ、DIとDIコンテナについての説明をいれると、時間的に入らなそうなので、それについてはこの日記で書いていこうと思います。

Dependency Injection

00:09 |  Dependency Injection - dann@catalyst を含むブックマーク はてなブックマーク -  Dependency Injection - dann@catalyst  Dependency Injection - dann@catalyst のブックマークコメント

外部から依存関係を挿入する。ただ、それだけのことです。

Dependency Injectionのパターンを使うことで何が嬉しくなるのか?

依存関係が挿入されるため、依存するオブジェクトの詳細が、その依存関係を挿入されるクラスから切り離されます。要するに、単体テストが簡単になるということです。

では、具体的な例を見てみましょう。

MyApplicationが何らかのLoggerに依存していたとします。仮にLoggerが以下のように依存関係があったとします。

package MyApplication;
use Moose;

sub run {
    my $self = shift;
    my $logger = FileLogger->new(log_file_name => 'hoge.log');
    $logger->log();
}

1;

このように依存関係がハードコードされている場合、FileLoggerを違うLoggerに変えてテストをすることが難しくなってしまいます。例えば、依存先がDBに依存していたりすれば、DBなくしてはテストができなくなってしまいます(Monkey Pachingで回避できないことはないですが)

では、どうすれば、MyApplicationからこのloggerの実装への依存を断ち切れるでしょうか。こんなときに依存関係を断ち切るために使われるのが、Dependency Injection(IoCパターン)です。

以下のようにします。要するに、loggerの依存関係をMyApplicationの外に出してしまいます。MyApplicationに任意のLoggerを設定すれば、MyApplicationは任意のLoggerでrunメソッドを実行できるようになります。外からLoggerへの依存関係を注入することになるので、Dependency Injectionといわれています。

Dependency Injectionそのものは、とてもシンプルなアイデアですが、Testabilityを高めるための重要なテクニックの一つです。他にも依存関係を切る方法はあるのですが、ここではDependency Injectionのパターンだけを紹介することにします。

package MyApplication;
use Moose;
has 'logger' => (is =>'ro', required => 1);

sub run {
    my $self = shift;
    $self->logger->log();
}

1;

では、このDependencyは誰がInjectしてくれるのでしょうか。もっと簡単に言えば、誰がMyApplicationのコンストラクタに、FileLoggerというLoggerの実装のインスタンスを設定してくれるのでしょうか。

そこで出てくるのがDIコンテナです。手動でFileLoggerをnewして設定する方法もありますが、それだとMyApplicationを利用するクラスが実装に依存してしまうことになります。結局それはテスタビリティを損なうことになるかもしれません。

DIコンテナ

00:09 |  DIコンテナ - dann@catalyst を含むブックマーク はてなブックマーク -  DIコンテナ - dann@catalyst  DIコンテナ - dann@catalyst のブックマークコメント

DIコンテナの一つの役割は、オブジェクトの依存関係をWiringして、上記のような依存関係を解決することです。以下にBread::Boardを利用したDIの例を説明します。

package MyApplication;
use Moose;
has 'logger' => (is =>'ro', required => 1);

sub run {
    my $self = shift;
    $self->logger->log();
}

1;
package FileLogger;
use Moose;
has 'log_file_name' => (is=> 'ro', required => 1);

sub log {
    my $self = shift;
    print "log\n";
}

1;

実行するコードは、以下のようになります。下記の例は、Bread::BoardというPerlのDIコンテナを利用したものです。

my $c = container 'MyApp' => as {

    service 'log_file_name' => "logfile.log";

    service 'logger' => (
        class        => 'FileLogger',
        lifecycle    => 'Singleton',
        dependencies => [ depends_on('log_file_name'), ]
    );

    service 'application' => (
        class        => 'MyApplication',
        dependencies => {
            logger => depends_on('logger'),
        }
    );

};

$c->fetch('application')->get->run;

applicationサービスを取得すると、MyApplicationのオブジェクトはFileLoggerオブジェクトが設定された状態(依存関係がwiringされた状態)で取得されるため、MyApplicationのrunメソッドを実行すると、Loggerのlogメソッドが呼ばれます。

このようにDIコンテナが外から依存関係を注入してくれるため、各種サービスは依存関係のあるクラスの実装の詳細を知ることがないため、互いに疎に結合されます。それによって、各サービスは単体でテストができるようになります。

MccadeMccade2011/08/02 12:38This forum needed sakhing up and you've just done that. Great post!

kmeyilypzkmeyilypz2011/08/03 20:4915ggJ4 , [url=http://qeznvwezdxfs.com/]qeznvwezdxfs[/url], [link=http://nuwhqfxgeivl.com/]nuwhqfxgeivl[/link], http://srnfyjntrpcw.com/

hvqabaqxdhvqabaqxd2011/08/05 22:13fSEfDn , [url=http://hitejlqemnsf.com/]hitejlqemnsf[/url], [link=http://ldrpnarvjijm.com/]ldrpnarvjijm[/link], http://mvfzvlgrqjjn.com/

2008-04-01

CatalystCon1

22:32 |  CatalystCon1 - dann@catalyst を含むブックマーク はてなブックマーク -  CatalystCon1 - dann@catalyst  CatalystCon1 - dann@catalyst のブックマークコメント

http://coderepos.org/share/wiki/CatalystCon1

いつのまにかテーマが決まってるw 以前書いたMVCの私的まとめを、ちょっと分かりやすく説明するのがいいのかな。

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

最初は、Catalystフレームワークに足りないものを、Java系のフレームワーク and Railsと比較して話そうかなぁと思っていたのだけれど、ちょっと話が発散してしまうかもしれないし、1テーマで話をしたほうがいいのかも。

転職しましたのお知らせ。

20:17 |  転職しましたのお知らせ。 - dann@catalyst を含むブックマーク はてなブックマーク -  転職しましたのお知らせ。 - dann@catalyst  転職しましたのお知らせ。 - dann@catalyst のブックマークコメント

本日、2008年4月1日付けで、Cisco Systamsへ入社しました。

学生時代からやってきたCatalystの技術を、Webという世界に応用し

たい! そんな、ここ数年やりたかったことを実現できそうな環境です。

思いっきりとある処理まわりの開発に従事したいと思います。

自分の持つ(そしてこれから得ていく)知識・技術で社会全体に何かしら

貢献できるようがんばります。

わくわく。

私といっしょにこの分野で腕をふるいたい方、ぜひご連絡ください。

BrysonBryson2011/08/04 03:41You've hit the ball out the park! Incrdeible!

nczkylnczkyl2011/08/04 22:176VeVEt <a href="http://xwdhxspsqshn.com/">xwdhxspsqshn</a>

dxnmjgykcadxnmjgykca2011/08/05 01:50MCJHxY , [url=http://vowpqbquwyiw.com/]vowpqbquwyiw[/url], [link=http://plmienfiapva.com/]plmienfiapva[/link], http://jrzanzluscpz.com/

kmcenyxrvqkmcenyxrvq2011/08/06 18:58xs6qyX <a href="http://aetgcyubylad.com/">aetgcyubylad</a>

vctusiiiztvctusiiizt2011/08/07 00:08dZnmd5 , [url=http://mcwbrcfrsrdh.com/]mcwbrcfrsrdh[/url], [link=http://kjowvxlbfmez.com/]kjowvxlbfmez[/link], http://kcbhustvaluy.com/

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