2009-12-12
■JPerl Advent Calendar 2009 にQudoの記事を書きました

12月1日より、日本のPerl界の有志によって実施されている
「JPerl Advent Calendar 2009」のhacker trackに
「Qudo」についての記事を書いてみました。
http://perl-users.jp/articles/advent-calendar/2009/hacker/13.html
正直hacker trackは名だたる有名なギークさんばっかりで場違い感が否めないのですが、、
数少ない自己モジュールからひねり出してみました。
内容としては、せっかくのadvent calerndarなのでクリスマスネタを入れてみました。
結果としては、オブジェクト指向入門書の第1章の
動物から馬が出来たり、乗り物から車が出来る、みたいな
読んでて違和感を感じるノリになってるかも知れません。
この記事自体はさらっと読み流していただいて、
その他のhacker trackや、casual trackにもカジュアル以上の
気合い入ったエントリがたくさん投稿されているので合わせて
ご覧ください。
同じくQudoの開発者のid:nekokakさんのDBIx::Skinny track(1人舞台)も展開中ですので、そちらもどうぞ。
さて、とは言ったもののインデックスページからの
リンクがない件が、nim のソースとかもチラっと見たんですが
わかりませんでした。。運営に支障をきたすような、なんか悪い事してなければいいんですが・・・大丈夫っぽい。
2009-11-09
■Params::Validate覚書き

Params::Validateを触ってみようと思い、色々ソースを見たんですが、イマイチわからなかったです。。そんな時に限って、ググっても意外にヒットしない・・・
普通の人は解読して、何かを残すほど難しいモジュールじゃないのかな、、と思いつつ
ドキュメント見るのは正直いまだに苦手なので、とりあえずサンプル書きながら体で覚えようとしてみました。
なんか落ち着いて読んでるうちに理解出来たと思う部分もあるけど、
まぁせっかく試したので貼っておきます。
必須項目のテストコード(test_mandatory.pl)
#!/usr/bin/perl use strict; use warnings; use Params::Validate; my %test = ( foo => 'hoge', bar => 'moge', baz => 'tete' ); &test_func( %test ); delete $test{baz}; &test_func( %test ); delete $test{foo}; eval { &test_func( %test ); }; print $@ if $@; sub test_func{ Params::Validate::validate( @_, { foo => 1, bar => 1, baz => 0, } ); return 1; }
上の実行結果
Mandatory parameter 'foo' missing in call to main::test_func
at test_mandatory.pl line 23
main::test_func('bar', 'moge') called at test_mandatory.pl line 19
eval {...} called at test_mandatory.pl line 19
一番単純なパターンですね。
対象のキー値に対して1を渡せば必須。0を渡せばnot必須。
だから「delete $test{baz};」しても怒られないけど、
「delete $test{bar};」したら怒られる。
これだけで、済ませるっていうのはさすがに少ないかも知れません。
型チェックのサンプル(test_type.pl)
#!/usr/bin/perl use strict; use warnings; use Params::Validate qw/:all/; my $scalar = 'scalar_ref'; my %test = ( 'scalar' => 'abcde', 'scalarref' => \'scalar_ref', 'arrayref' => [qw/ 1 2 3 4 5 /], 'hashrref' => { 'key1' => 'value1','key2'=>'value2' }, 'coderref' => sub{ return 'test_code'.'ref_test';}, 'boolean' => '1a2b', ); # All OK &test_func( %test ); # Scalar Error $test{'scalar'} = {key => 'value'}; eval { &test_func( %test ); }; print $@."\n" if $@; # ScalarRef Error delete $test{'scalar'}; $test{'scalarref'} = [qw/6 7 8/]; eval { &test_func( %test ); }; print $@."\n" if $@; # ArrayRef Error delete $test{'scalarref'}; $test{'arrayref'} = 9; eval { &test_func( %test ); }; print $@."\n" if $@; # HashRef Error delete $test{'arrayref'}; $test{'hashref'} = 9; eval { &test_func( %test ); }; print $@."\n" if $@; # CodeRef Error delete $test{'hashref'}; $test{'coderef'} = {'key' => 'value'}; eval { &test_func( %test ); }; print $@."\n" if $@; # Boolean Error delete $test{'coderef'}; $test{'boolean'} = [qw/ 10 11 12/]; eval { &test_func( %test ); }; print $@."\n" if $@; sub test_func{ Params::Validate::validate( @_, { 'scalar' => {type => SCALAR}, 'scalarref' => {type => SCALARREF}, 'arrayref' => {type => ARRAYREF}, 'hashrref' => {type => HASHREF }, 'coderref' => {type => CODEREF }, 'boolean' => {type => BOOLEAN }, } ); return 1; }
上の実行結果
The 'scalar' parameter ("HASH(0x826670)") to main::test_func was a 'hashref', which is not one of the allowed types: scalar
at test_type.pl line 49
main::test_func('boolean', '1a2b', 'scalar', 'HASH(0x826670)', 'coderref', 'CODE(0x826460)', 'arrayref', 'ARRAY(0x800d80)', 'hashrref', ...) called at test_type.pl line 20
eval {...} called at test_type.pl line 20
The 'scalarref' parameter ("ARRAY(0x82679c)") to main::test_func was an 'arrayref', which is not one of the allowed types: scalarref
at test_type.pl line 49
main::test_func('boolean', '1a2b', 'coderref', 'CODE(0x826460)', 'arrayref', 'ARRAY(0x800d80)', 'hashrref', 'HASH(0x826664)', 'scalarref', ...) called at test_type.pl line 25
eval {...} called at test_type.pl line 25
The 'arrayref' parameter ("9") to main::test_func was a 'scalar', which is not one of the allowed types: arrayref
at test_type.pl line 49
main::test_func('boolean', '1a2b', 'coderref', 'CODE(0x826460)', 'arrayref', 9, 'hashrref', 'HASH(0x826664)') called at test_type.pl line 30
eval {...} called at test_type.pl line 30
The following parameter was passed in the call to main::test_func but was not listed in the validation options: hashref
at test_type.pl line 49
main::test_func('boolean', '1a2b', 'hashref', 9, 'coderref', 'CODE(0x826460)', 'hashrref', 'HASH(0x826664)') called at test_type.pl line 35
eval {...} called at test_type.pl line 35
The following parameter was passed in the call to main::test_func but was not listed in the validation options: coderef
at test_type.pl line 49
main::test_func('boolean', '1a2b', 'coderef', 'HASH(0x8267b4)', 'coderref', 'CODE(0x826460)', 'hashrref', 'HASH(0x826664)') called at test_type.pl line 40
eval {...} called at test_type.pl line 40
The 'boolean' parameter ("ARRAY(0x800eac)") to main::test_func was an 'arrayref', which is not one of the allowed types: scalar undef
at test_type.pl line 49
main::test_func('boolean', 'ARRAY(0x800eac)', 'coderref', 'CODE(0x826460)', 'hashrref', 'HASH(0x826664)') called at test_type.pl line 45
eval {...} called at test_type.pl line 45
実際に多く使いそうなパターンですね。
テストはそれぞれの型が順番にこけるのを確認しつつ、
終わったものはエラーが出ないようにdelete していっています。
「{type => 『hoge』}」のhashrefを対象のキー値に対して渡してやります。
チェックできる型のタイプは上で全部じゃなくて、
GLOBとかOBJECTとかまだまだあるようです。詳しくはドキュメント参照。
OBJECTは後述のisaの方がいいんじゃないかと思いますが、違うかな。
オブジェクトと正規表現のチェック(test_isa_regex.pl)
#!/usr/bin/perl use strict; use warnings; use Params::Validate; my %test = ( object => (bless{},'Test::Object') , regex => 111 ); &test_func( %test ); # Object Error $test{object} = bless{}, 'Test::Object2'; eval { &test_func( %test ); }; print $@."\n" if $@; # REGEX Error $test{object} = bless{}, 'Test::Object'; $test{regex} .= 'a'; eval { &test_func( %test ); }; print $@."\n" if $@; sub test_func{ Params::Validate::validate( @_, { object => {isa => 'Test::Object'}, regex => {regex => qr/^\d+$/}, } ); return 1; }
上の実行結果
The 'object' parameter ("Test::Object2=HASH(0x800e34)") to main::test_func was not a 'Test::Object' (it is a Test::Object2=HASH(0x800e34))
at test_isa_regex.pl line 24
main::test_func('object', 'Test::Object2=HASH(0x800e34)', 'regex', 111) called at test_isa_regex.pl line 15
eval {...} called at test_isa_regex.pl line 15
The 'regex' parameter ("111a") to main::test_func did not pass regex check
at test_isa_regex.pl line 24
main::test_func('object', 'Test::Object=HASH(0x81ffe4)', 'regex', '111a') called at test_isa_regex.pl line 20
eval {...} called at test_isa_regex.pl line 20
ちょっとオマケっぽくやってみました。
ただ、regexは結構使いますね。数値チェックとかそういや各所にある気がします。
使い方は型の時と同じで指定が違うだけです。
まとめると、ドキュメントにあること以上はやってない。。
けど、なんとなくわかった気がするのでこれはこれでOKかと。
(勘違いしてる部分がなければいいのですが・・・)
途中から気づいたというか思い出しましたが、
どっちかって言うと、validationの指定方法より
validate , validate_pos , validate_with あたりが区別ついてなくて混乱してたんじゃないか、という気がしてきました。
「validate_pos」は「validate_posisitional」の事をおそらく指していそう。
引数の渡し方(ハッシュor配列)の違いで、配列を受け取る用かと思われます。
んで、validate_withがやっぱりわからない、、
文字通りvalidateしつつ、何か出来そうなんだけど・・・
というところで眠くなってきたので一旦終了します。
2009-10-22
■mixiボイスからはてなブックマークできる、連携機能をでっち上げました

本日はてなよりアナウンスがあった、
Twitter のつぶやきからブクマできる連携機能
(http://hatena.g.hatena.ne.jp/hatenabookmark/20091022)
に触発されて、mixiボイスからブクマするのを勢いで適当に作ってみました。
以下コード
#!/usr/bin/perl use strict; use warnings; use AnyEvent::Impl::Perl; use AnyEvent; use WWW::Mixi::Scraper; use WebService::Hatena::Bookmark::Lite; use Config::Pit; use Date::Calc; my $hatena_conf = Config::Pit::pit_get('http://www.hatena.ne.jp'); my $mixi_conf = Config::Pit::pit_get('http://mixi.jp'); my $mixi = WWW::Mixi::Scraper->new( email => $mixi_conf->{email} , password => $mixi_conf->{password} , mode => 'TEXT' ); my $org_post_time = $ARGV[0] || join('', map{ sprintf( "%02d", $_); } Date::Calc::Today_and_Now() ); my $cv_timer = AnyEvent->condvar; my $timer; $timer = AnyEvent->timer( after => 0, interval => 60, cb => sub { my @echo_list = $mixi->list_echo->parse(); if( _is_bookmark_post( $echo_list[0]->{comment} ) && _is_new_post( $echo_list[0]->{'time'} ) ){ # post to hatena bookmark _post2hatena( $echo_list[0]->{comment} ); } }, ); $cv_timer->recv; sub _is_new_post{ my $post_time = shift; $post_time ||= 0; if( $post_time > $org_post_time ){ $org_post_time = $post_time; return 1; } else{ return 0; } } sub _is_bookmark_post{ my $comment = shift; $comment ||= ''; return $comment =~ /B\!/; } sub _post2hatena{ my $comment = shift; my( $str , $url ) = split( /B!/, $comment); my $hatena = WebService::Hatena::Bookmark::Lite->new( username => $hatena_conf->{username} , password => $hatena_conf->{password} ); return $hatena->add( url => $url, comment => $str ); }
以下が実験結果。
mixiで発言する
はてブで確認する
なんか出来ているように見えます。
とりあえず勢いすぎた反省ポイント。
・AnyEvent意味ない。
はい、、使ってみたかっただけです。
ここのところの流れに追いつきたいと思いつつ、触る機会を作れてなかったので、無理矢理です。
gihyo.jpで連載されている内容(http://gihyo.jp/dev/serial/01/modern-perl/0013)を参考にさせていただき、書いてみました。
別にこれならwhileでループすればいいと言われたら何も言えません。
・毎回スクレイピングしている
はい、、RSSフィードでも吐く形式にすれば良かったんですが、ちゃんと勉強します><
これのせいで、posttimeをずっと保持しておいて、それより最新だったら、なんて比較もしてます。お恥ずかしい限り。
もしくはmixiボイスにAPIでもあれば、一番ラクだったのに(多分、今はないハズ)
※ちなみに
$mixi->list_echo->parse();
を
$mixi->recent_echo->parse();
に変えると、マイミク全員のボイスをブクマできます。(だから何だ!)
今回も勢い余って痛さだけが残る形に終わってしまいました・・・
2009-09-25
■『4Gbpsを超えるWebサービス構築術』読了

- 作者: 伊勢幸一,池邉智洋,栗原由樹,山下拓也,谷口公一,井原郁央
- 出版社/メーカー: ソフトバンククリエイティブ
- 発売日: 2009/08/21
- メディア: 単行本
- 購入: 41人 クリック: 697回
- この商品を含むブログ (41件) を見る
昼休みにご飯食べながら読むという進め方だったせいもあって、かなり時間かかりましたが読み終わりました。
ライブドアが誇る技術が幅広く書かれているとの事でしたが、その内容は。
■Chapter1 Webサービスの概要と要素技術
タイトル通り、Webサービスというものの歴史とその概要についての章。
Webエンジニアとしてはアイスブレイクと捉えられないとちょっとマズいかもしれません。
■Chapter2 キューイング
負荷分散のよくある一つの解決策、キューイングによる後回し。
僕も普段から考えている場所だけあって、凄くすんなり読めました。
逆に言うとGearmanとTheSchwartzの概要説明に終始していたので、もうちょっと
ライブドアなりの工夫みたいなものが知りたいと思ったりしました。
ちょっと話がそれますが、YAPC::Asia2009でも思いましたがやっぱりこの
キューイングはトラフィックが多いサイトではもはや必須対応なのかと。
もともと使っていたsix apartをはじめ、livedoorでも(malaさんセッションより)、
はてなのコーポレートトラックでもTheSchwartzを使っているらしきことが
伺えたので各社でどんな感じなのかなーと改めて興味が沸きました。
■Chapter3 DBキャッシング
来ました、memcached。今の職場ではこれがないなんて想像出来ない。。。
そんな11211ポートに住まう偉大なシステムですが、確かに前の職場で普通のサイトを
運営する分にはむしろどんなもんかすら触る機会すらなかった。
ここでは導入の前提となるWebアプリにおけるDBのボトルネックの部分も
解説されているので、それも合わせて読みたいところ。
そして、書かれていますが便利な上に導入するデメリットがほとんどない
というのがmemcachedのいいところだと思います。
と言いつつ、僕もプロジェクトの関係上ガリガリ使えてる訳ではない、、、
引っかかるところなんかが書かれても良いかと思いましたが、まぁそういうノウハウは
ネット上に溢れているという割り切りで、それはそれでよいと思います。
■Chapter4 HTMLキャッシング
この辺からは個人的に名前と概要は知っているけど、使った事とかはあんまりない
という部分になってきます。
Squidなんかはまさにその典型。confファイルの例まで書かれているんですが、
リアクションが出来ない自分。同時に説明の図の中にある箱の数が飛躍的に増えてきます。
■Chapter5 検索サービスの技術
この本は全体的に章の最初というか導入だったり・前提だったりの説明が明瞭
に感じましたが、この章の「検索」という項目の前提となる検索方式・言語解析の仕組み
の部分に触れていたのが非常にわかりやすかったです。
この章も社内ではそれに特化して研究している人がいたりするので、自分が
あんまり触れてない。。
■Chapter6 入出力パフォーマンス
恥ずかしながら、Blackholeエンジンについて無知でした、、
そんなんを読み進めていくと、この章はタイトルから察する事が出来るように
内容が複合的。前の章の技術なんかも含まれてきます。
特に気になったのが「最終出力に近い部分でのキャッシュ」。理由まで読んでみると
確かに納得ですが、やはり細かい運用という意味ではちょっと聞いてみたいなと
思う部分があったりしました。
あとCache::Memcached::Managedはこれまた知りませんでした。あとで読みます、、
■Chapter7 分散ストレージ
タイトルはストレージとなってますが、物理的な話のみならず運用するモジュール
の部分にも踏み込んでます。
最初がNFSから始まったことに歴史を感じますし、そこから現在まで試行錯誤で
運用されているという事に実績を感じます。
■Chapter8 モバイルの技術
ここは他とはちょっと毛色が変わって、日本のモバイル事情を浅く広く紹介。
またまた弊社の話ですと、モバイルもある程度切り分けがされているので
普段それ程触れられてません。なのでちょっと遠めから眺める視線で読ませて
いただきました。
内容的にはYAPC::Asia2009のkazeburoさんのセッション内容を合わせて
確かめると良いのではないでしょうか。
■Chapter9 ネットワークを取り巻く技術
自分が一番弱いところ、低いレイヤーの話はホントにダメです。
ここは多分何度も読み直した方がいいな、、、
ここら辺は知識として知っておくだけではなく、実際に動かさないと真の理解には
繋がらないんだろうなとつくづく感じます。
1台のサーバーすら運用せず、ネットワークを学ぶのがそもそもの間違いな気がしているので
そろそろroot権限のあるようなレンタルサーバー借りるか、自鯖を立てるか
しなければと思いました。
■Chapter10 Webサービスの性能評価
大規模サービスにおいて必要なのは、新技術の投入。ただそれよりも現状のチューニング。
と感じさせる、これだけは・まずはこれからやるべし、っていう内容。
もしMySQLのEXPLAIN構文を知らない人がいたら絶対読んでおいた方がいいです。
■まとめ
やっぱり自分が何を知っていて、何を知らないかが凄く良くわかりました。
アプリケーションで意識するmemcachedなんかは普段触っているので、
すっと頭に内容が入ってくるし、キューイングの部分なんかは正直物足りませんでした。
逆に後半になってくると、若干くじけそうな程知らない事が多すぎる。。。
所詮自分はイチアプリプログラマーに過ぎないんだなと痛感させられました。
とてつもない巨大サイトでなくていいので、この10分の1のトラフィックのサイトを
こういう技術を使って作ってみたいなと思いました。
今の会社ではなかなかそういう事がしにくいのが難点ですけどね、、
ただ、僕のようにプログラマーな人が「エンジニア」になるのに何が足りないのか
検定試験的に読むのにはオススメな1冊でした。著者の方々、執筆ありがとうございました。
2009-09-13
■YAPC asia 2009 まとめて感想

一応業務の一環で来ているので、会社用にレポートを書かないといけないのだけど、
数多あるまとめサイトとスピーカー本人様達のエントリを集めればそれで十分すぎると思ったので、とりあえず私的感想から。
◎前夜祭
yokohama.pm出張版。
・なにより自分が喋れなくて残念。準備不足でした。次回のyokohama.pm通常版ではまた何か喋れるよう今からネタ仕込んでおかねば。
ざざっと書くと
・acotiesさん: AnyEvent的ななにか(仮)
AnyEventとは何か、がホントに軽くわかった気がする。2週間くらいしか触ってないと言っていたのでスゲー
・spiritlooseさん: Schenker - DSL for quickly creating web applications in Perl
記述量の少なさが半端ない。最近思う事は他言語を知っている人は皆凄い。
・kawanetさん: YAPC::Europe 2009(ポルトガル)参加報告
海外のYAPCではトーク聞くのと同じ位BOFが重要。今回終わってみて確かに
そうだと思った。会場移動しまくりで疲れたし。
・k-z-hさん: PerlのWAF今昔
非常によくまとまった話でした。
・amachangさん: Web的ななにか
HTML5の話。DOMとは違う木構造とか初めて知った。JSですぐデモるあたりはさすがamachangだと思った。
本編には来ていなかったようで、懇親会とかで話したかったのに残念・・・
・sugyanさん: 全裸でワンライナー(仮)
全裸イナー!一番ウケてました。1行野郎としての男気を感じました。
・nekokakさん: SmokerっていうぷらっがぶるWAFをつくってみたよ!
「それPla」の一言で片付いてしまう動きが直前に発生しつつも、使いやすいと言われているものを使ってサクっと実際に作ってしまうあたりは見習わなければと思った。
・junichiro x btoさん: PHP的な何か(仮)
すみません、外にシュウマイ食いに行ってて聞いてませんでした><
・yusukebeさん: エロサイト管理者の憂鬱2
これほど感想の書きにくいトークもなかなかないけど、内容はともあれやっている事は凄かった。
世界は広い?/狭い?
◎YAPC本編
このペースで書いていくと終わらなそうなので、本編は省略・・・
それこそ皆書いてるしね。
でも、一番印象に残ったのはmiyagawaさんとtokuhromさんの1日目のPSGIのセッション。
とんでもない勢いで進んでいるプロジェクトだけど、もうまとまりつつあるって。。。
HTTP::Engineを元に再構成しつつ、既に作成されたアプリについては手を加える必要がないフォローつき。
PSGIは仕様
Plackは実装
この前提重要。とりあえず引き続きwatchしていこうと思います。
あとはコーポレートトラックも多くの企業が「自社でのperlの使い方」風なセッション内容になっていて、JPAが目指すperlの啓蒙という意味で良かったのはないかと。six apartの使用ツール群の紹介がおもしろかった。
今回一番関わりが深かったのが、id:nekokakさんの「Qudo」のセッション。
自分も開発をお手伝いさせてもらっているものだったので、どういった反応が出るか結構ドキドキしてた。
フタを開けてみると、同時間のセッションがどれも魅力的だったため思ったより人少ない^^;
かと思いきや、質問タイムにはdanさんやyappoさんから質問来たり。どれも的確な内容でした。
セッション終了後に、Lin You-Anさんさんからの英語の質問にあたふたしつつ、ちょうど僕も
欲しいと思っていた複数ジョブの一括管理(っぽい事だと思う)機能を求められたりしていて、これは発表して正解だったというか、宿題がたくさん出来て良かったと思いました。
最近あんまり触ってなかったので、これを期にちょいちょいコミットしようとモチベーション上がりました。
懇親会ではもっと色んな人と話たいと思いつつ、道半ばでした。それでも
退職された元同僚の方々
yokohama.pmでお世話になっている方々
などなどをはじめ、1日目のLTでイカしたマイク持ちをしていたkamipoさんなんかとも
お話させていただき楽しかったです。
さて、来年こそは自分がトーク出来るようになってみたいなと思います。
LTこそヘタな事が出来ない場だとわかったので、本編で。
id:precuredaisukiさんとも話してましたが、やっぱりちゃんと喋ろうとすると20分くらい
使いますよね、という考えにも至極納得しました。
今回、実は2日目のmiyagawaさんのLTに向けて、手元のCPANモジュールをアップしておいたのですが、
どうやらあのトークの最中にアップしないと意味なかったみたいですね、、、
唯一参加している気分になれるかもと淡い期待をしてましたが、残念でした。。
なにはともあれ,lestrratさんをはじめ運営者の方々(ボランティアの方含め)お疲れさまでした。
次回も楽しみにしています。

