2008年3月アーカイブ

飯とか菓子パンとか

今更菓子パン関連のエントリを読んだ。

全然amachang本人とは関係ないんだけど、一言言わせていただきたい。

まずひとつ。コンビニで売ってる物を食べ続けて健康でいれるわけがない。あ、検証なんてなんもしてません。でも製造過程が不明なものをそこまで信用できん。俺が作った物は(当たり前だが)着色料も保存料も使ってないし塩分も油分も自分のさじ加減でちゃんとコントロールしてるもん。どちらかを信用しろと言われたら自分で作った物を信用する。農薬云々はこの際ほっとけ。どうせコンビニも似たような、もしくは俺が使ってるより悪い材料使ってる。

あともう一つ。飯に金を使わないのはそれもチョイスだ。だけれども、それによって現在の日本で経験できる様々な味(=文化)を享受しないのはもったいない。世界でもこれだけ多様な味が(しかも完成度の高い形で)てに入れられる国なんてそうそうないのに。

ちなみにこのエントリは酔っぱらって書いた。文句言うな。

チームバチスタの栄光

映画は以前に酷評した気がするが、この原作はひじょうにおもしろかった。

映画はまぁあれはあれでいいのかもしれんけど、これを読んだ後だと、ディテールをはしょりすぎだろ。 こちらの原作は素直に面白かったです。

ライドバック

本屋に寄って、特に何を買おうとも思ってなかったのだけれども目についたのが「ライドバック」。封がしてあって中身はチェックできなかったのでジャケ買いで買った・・・らおもしろかった!

これはちょっといいかも。今8冊出ているのだけれども、多分明日揃える。

なんか最近の漫画は絵が荒いほうがおもしろいなぁ。

追記:あ!作者さんははてなユーザーだ!

軽く花見

天気もいいので朝9時くらいに九段下へ。千鳥ヶ淵で桜鑑賞。そのまま靖国神社に向かって、軽く散歩。靖国神社の裏の池があるところではらはらと落ちる桜をながめる。

そのあと折角でばってきたので、そのまま神保町へ歩いて行ったら、ちょうど古書市だかなんだかをやっていてちょこちょこ本を見ながら神保町を散策。

ちょうどお昼の時間になったので人形町まで出て「キラク」へ。すこぶる久しぶりに暫定日本一のポークソテーを食べた。やっぱりうまいなぁ。サラダ大盛りとかできるってしらんかった。今度はそうしてみよう。人形町も桜さいてた。

以上で今日は帰宅。結構あちこちの桜ば見れた。
はてブでチラ見した知識だけでプログラマー同士の会話を妄想してみる。
http://neo.g.hatena.ne.jp/llpp/20080325#p1

俺は渋谷界隈のバーに出没しまくりですが、プログラマー二人なんて組み合わせの客はほとんどいねぇっすよ。俺とcharsbarさんが来るとか、そういうくらいじゃないの?と思ってしまいますが、笑いました。

ところでプログラマーは洋酒好きがあまりいないんでしょうか。みんな居酒屋に流れちゃうよな。まぁバーは騒ぐところでもないからかな・・・

静かにゆっくりが好きです。

渋谷でなんかあったぞ

9時半くらいに東急本店へとさしかかる道をスペリオールを読みながら歩いていたら、突然視界に警官が。テープはってる。

「すみませんがあちら側(車道)を通ってください!」

ん?なんだ?工事?と思ってたら地面に一面の血。ぎゃーす!

担架がある。でも人はいない。血だまりになってるところはほぼビルの入り口のところなのでそのまま視線を上にもっていくと、そこに警官に抱えられた顔が血みどろの男。ぎゃーす!

正直何がおきたんだか全然わからないが、とにかくビビった。

いったい何が起きたんだ。渋谷怖いよー。

やっぱり初心者だった

前のエントリのC++でmecab動かすと文字化けする??の件、id:download_takeshiさんのところでやってたプログラムが動いたとの事でコピペしてみたら、動く!違いを見るとg++の代わりにcc使ってる事くらいかと思ったけど、よーくみるとmecab-config --libs|--cflagsを明示的に指定している。俺はこれは適当に手で-I -L等を指定していたのだ。

するとよく考えると俺は今までこのコマンドを実行していた
g++ -lmecab mecab.cpp
ん・・・まてよ・・・mecab-config --cflagsと--libsの値は・・・?
daisuke@beefcake $ mecab-config --cflags -I/usr/local/include daisuke@beefcake $ mecab-config --libs -L/usr/local/lib -lmecab -lstdc++
あああ、ひょっとして・・・
daisuke@beefcake $ ls -l /usr/local/lib/libmecab.* /usr/local/lib/libmecab.1.0.0.dylib /usr/local/lib/libmecab.dylib /usr/local/lib/libmecab.1.dylib /usr/local/lib/libmecab.la /usr/local/lib/libmecab.a daisuke@beefcake $ ls -l /usr/lib/libmecab.* /usr/lib/libmecab.1.0.0.dylib /usr/lib/libmecab.dylib /usr/lib/libmecab.1.dylib
なああにいいいい。二つコピーがある・・・orz orz orz

っていうことは、去年の9月?くらいにコンパイルしたとおぼしきバージョンにはこの問題があるのかもしれん。もしくはなんかが根本的に違うのか。ともあれ、リンクしているライブラリのバージョンが違った!という落ちでした。はぁがっかり

ちなみにid:download_takeshiさんのプログラムを最初のg++ -lmecab takeshi.cppみたいにして動かすと、ハングしてました。明らかになんかおかしかったんだね。
ただ単純にC++でmecabでパースした文字列を表示したいのですが、文字化けします。なんでなんで?Perlに関してはえらそーに語る事もありますが、C++初心者っす・・・誰か教えてください

#include #include using std::cout; using std::endl; using std::hex; int main(int argc, char **argv) { char input[1024] = "もももすももももものうち"; char *args[] = { "", "-Owakati" }; const char *parsed; MeCab::Tagger *t = MeCab::createTagger(2, args); parsed = t->parse(input, strlen(input)); cout << "original input = " << input <<< "parsed string = " << parsed << strlen(input); i++) { cout << "input[" << i << "] = " << hex << (unsigned int) input[i] << endl; cout << "parsed[" << i << "] = " << hex << (unsigned int) parsed[i] << endl; } delete t; return 0; }
最初のoriginal inputとparsed stringのところでcoutが化けるのでバイト単位でcoutしてみたんだけど、これだとparsedのほうがほとんどのところで最後の1バイトが抜けてる感じ。何が間違ってるんでしょうか・・・

自分用enscriptメモ

gungho-poe-engine.jpgこれ、前にも書いた気がするけど、enscriptメモ。なにもせずに動いた気がするのでOS Xにはデフォルトで入っているのかな?一般的に1ページに2カラムで表示したものをプリントする場合
enscript -2uG filename.txt

これをどっかのpsファイルに保存しておく場合。これだとプリントプレビュー的な事ができる。
enscript -2uG -p example.ps filename.txt

ちなみにOS XのPreviewならこの一枚一枚をJPEGとかに保存することも可能。別名で保存を使うだけ



話の内容

YAPCで話す話の内容をうっすら考えている。一応Perl界隈で俺の得意分野?というと多分XS使ったりなんだりってほうだと思ってたので最初はCache::Memcached::libmemcachedを作る過程と織り交ぜてXSの使い方みたいなのを話そうかと思ったんだが、最近のエントリの食いつきを見ていると「テストの書き方/リリースサイクルの自動化」について話したほうがいいのか?と思い始めている。

どうなんだろうね、そこ。迷い中。

バーゲン

金曜日は家に帰って鶏肉、油揚げ、もやし、その他残り物野菜を炒めてあんかけ風味にして。

土曜日は横浜でバーゲンやってたので行ってきた。期待して行ったんだけど、あんまりなかったのでいつものごとく消耗品のシャツとか靴下買ってきて終了。あとはユニクロでちょいと買い物。ひさしぶりに服買ったなぁ。昼は日吉のくるくる寿司。夜は蕎麦。卵を落とした。

今日は多分一枚残ってるえぼし鯛の干物かな。

グランプラスのペカンナッツショコラ

080302_1941~0001.jpg
ホワイトデーなんちゃらの関係でグランプラスというところの「ペカンナッツショコラ」を手に入れた。これがう、う、う、うまーーーーーーーーい。こいつ本当にうまいよ。口の中で溶ける。そして後にしつこい甘みが残らない。ペカンの香ばしい味。うまいー。ウィスキーともあいそうだわあ。おススメ。品川のエキュートに店があるっす

神経質(A型)なPerlハッカーあるある

ネタですが、実話です。

  • use Module; 宣言を書く時、全部ABC順にしないとイライラする。
  • s///とかをs{}{}って書くとエスケープいらないのに、s/\\\/\\\/\\\\/g s/\\\/\\\//\\\\/gとか見るとイライラする。(追記:なんか一個抜けてた)
  • qw// をqw()と書き直さずにはいられない。
  • for(my $i = 0; $i < 10; $i++) とかを見ると for my $i (0..9)に書き直さずにはいされない
  • 他人からもらったファイルを開ける前はとりあえず perl -i -pe 's/\r\n/\n/g'
  • if ( ... ) elsif (...) elsif (... ) else ... みたいなのを見るととりあえずディスパッチテーブルを書きたくなる
  • if ($foo eq 'XXX' || $foo eq 'YYY')を if ($foo =~ /^(XXX|YYY)$/) に書き直したくなる(追記:ベンチ取ったけど、比較する対象の数が6個になると正規表現のほうがはやかった。4個まではeqのほうが速い)
  • 配列かハッシュを宣言する時に最後の要素でも必ずカンマを入れないと気が済まない
なんかもっとありそうだな。

僕と一緒に書いてる方達、別にこれをやらないと僕が怒るわけじゃないです。
今回作った夙川アトムモジュール。モジュール自体は実にアホなモジュールなわけですが、まぁドキュメントにも書いた通り0.00001なんて全然変換が効いてませんでした。そこで「パッチはいらん、テストをくれ」と書いたわけですね。

そしたらまずtypesterさんがテストをTest::MoreからTest::Baseにしてくれて、otsuneさんがどんどんテストを足してくれたらどんどんアトム君が賢くなってきた。

今はAcme::Shukugawa::Atomのテストはt/01_basic.tにいわゆる最終テストのような、いわゆる文章を変換するようなものを置いて、それ以外のt/02_shisu.t t/03_waiha.t t/04_kuribitsu.tでそれぞれ内部で使ってる基本の変換である「シースールール」「ワイハールール」「クリビツルール」を単体テストしている感じ。やっぱり単純なソフトでもこの単体テストと最終テストの2段階があると問題点がすぐに浮き彫りになって実にやりやすい。

こんなモジュールでさえその恩恵を受けられるのだからテスト、愛しいよテスト。

というわけで段々賢くなってきているアトム君ですが、先ほど0.00004をリリースしました。このバージョンから板付き語(固定変換ルールが決まっている言葉)をshareファイルに抜き出して、モジュールとは別に変更できるようにしたり、デフォルトの板付き語ルールの他にオブジェクトインスタンスで指定できるようにしてあります。あと、棒(ー)が二つついちゃったりしてるような問題も結構直ってると思いますヨ。

ブラウザどうしましょう。

去年の終わりくらいからそれまで数年間MacBookでメインで使ってたFireFoxの調子が悪くなってよく落ちるようになってきた。最初はまぁいいやーぐらいで思ってたんだけどJavascript実行中に止まったりなんだりして段々うざくなってきたので先月からSafariに乗り換えてみた訳です。ちょうどその直後にdolipoも出たり、Javascriptの実行も速いし、なによりページのロードが速い!と、いい感じだった。が。

今日FireFox3 Beta4 を入れてみたら、なんかすげぇ速くなってる!gmailもサクサク、LDRもサクサク。まだ使い倒してないのでエラーとかそのあたりがどうなってるかわからないけど、これはいけるかも・・・と迷ってしまっている。もともとFireFox使いだしな。ただ、今のところFireBugが使えないというイヤンな状態。

さて、どうしようかな。

夙川アトム モジュール

この間のめちゃいけを見て夙川アトムに惚れた人も多いと思いますが、なんか今日急にルー語ばりに日本語を夙川アトム風に変換するモジュールを書きたくなったので書いてみた。そして先ほど無謀にもCPANにリリースしてみた

正直まだ全然変換自体には自信がないんだけれども、せっかくcodereposに入れたので、パッチをくれとは言わん。せめてテストを足してくれ!どういう変換が望ましいのか、いっぱい台詞をいれてくれ。なるたけそれに添えるようにテストしてみるよ。

(追記 2008/03/15: @bayashiさんのバージョンがとまったらしいので暫定版をうちのサーバーにあげておいたよ

Text::CSV_XS 0.37がリリースされたよ

前のエントリで書いたメモリリークを修正したText::CSV_XS 0.37がリリースされたみたいですよ

メンテナのMerijnと何回かメールのやりとりをした。このメモリリークの根源は前のエントリで書いた通りだったのだけれども、それと連動する形でgetline()を使った時にmeta_info()が仕様通りに動かないというバグがあった模様。これを直すとメモりリークも直ったとの事。

このフィックスを見てはたと気づいたのだが、sv_2mortal()しないでも、new(SV|AV|HV|RV)した変数は他のコンテナに関連づけると(格納すると)メモリ解放が自動的に行われるのだったな。

例えば
my %h = ( a => 1, b => 2, c => 3 );

こんな状況の場合、値側の1, 2, 3はそれぞれSV なわけだが、%hが自分の子要素として1, 2, 3が存在するのを知っている状態なので、%hのリファレンスカウントを--した時(SvREFCNT_decが呼ばれた時)に同時に1, 2, 3にもそれぞれリファレンスカウントがひとつ下げられる。その時にメモリ解放が行われる。

これらのSVを作る時にnewSV()しただけでsv_2mortal()もせず、%hにも格納しなければ、これらのSVはリークする。なぜなら、newSV()した時点でREFCNTは1で、それをSvREFCNT_dec()しないとメモリ解放されないのに、mortal化もされてないからだ。これがText::CSV_XS 0.36の状態。

Text::CSV_XS 0.37の場合はこのリークしていた変数に対して明示的な解放が行われるケースと、$selfに該当するハッシュに格納されるケースが追加された。これで必ずメモリ解放が行われるのでリークもない、ということだ。

Happy CSV parsing.

即席豚丼。

今日は帰ったら冷蔵庫に晩飯になるものが何も無い。ご飯。豚肉。タマネギ。うーむ。

はっ、そうだ!豚丼つくるでぇ!醤油と砂糖1対1、3倍の水。そこにタマネギとニンニクと豚肉をつけこんで揉み揉み。30分くらい漬けて、できあがりぃ。焼く直前に胡麻油を混ぜ込んでフライパンでうわっと。

あとは熱々ご飯にのせてでーきあがり!

ってことで今日は豚丼でした。

Text::CSV_XS->getline()メモリリークパッチ

この間もメモリリークを通報してくれたところからまたメモリリークで困っているという通報が来たので、チェック。普段は$csv->parse(); $csv->fields()を使っているのだけれども、どうもパフォーマンス的にgetline()のほうが速いのでそちらを使いたいとのこと。

まず以下のテストコードを動かしてメモリを観察
use strict; use blib; use Text::CSV_XS 0.36; print "My PID: $$\n"; my $line = join("\t", ('a'..'z')) . "\n"; my $csv = Text::CSV_XS->new({ sep_char => "\t" }); my $iter = 10000; my $data = $line x $iter; my $count = 0; while(1) { open(my $io, '<', \$data); while(my $row = $csv->getline($io) ) { } $count += $iter; print "Did $count iterations\n"; sleep(2); }

これを自分のMacBookで見てると外側のwhileループを回す毎に600Kくらいずつメモリ使用量が増えて行く。リークしてるっぽいなぁ。

実はこの問題、ちょっと前にも見た事あったんですが、その時は特にひらめかなかったのです。今回もなんの気無しにText::CSV_XSのソースを見ていたら、リークしないparse()とgetline()を追って行くとどうも1個だけreturnされてるわけでもない、微妙に操作方法が違う変数があることに気づいた。

前のText::MeCabのエントリでも書いたけれども、Perlにはふたつメモリを解放するタイミングがある。そのうちのひとつでいわゆる一時変数が解放されるのだが、Perlでは一時変数も含めて、Perl内でデータとして扱えるもの全てのメモリ管理はリファレンスカウントで管理しているため、その調整を手動してやらないとプログラム終了時まで解放される事は無い。

でも一時変数まで全部律儀にそういうカウント云々していると面倒なので、Perl内部では"mortal"と呼ばれる変数が存在する。これらの変数は「今使い終わったら、次にチャンスがある時にメモリ解放される」という存在だ。これを設定するには、変数を作成後、sv_2mortal()という関数でフラグをつける:
SV *sv = sv_2mortal( newSVpv("Hello!", 6) ); AV *av = newAV(); sv_2mortal( (SV *) av);

これでこのCのセクションから抜けて、Perlインタプレタがチャンスがある時にメモリ解放が行われる。

さて、本題のText::CSV_XSだが、これがどうもある配列にされてなかった模様。以下パッチ
--- Text-CSV_XS-0.36/CSV_XS.xs 2008-03-06 00:26:41.000000000 +0900 +++ Text-CSV_XS-0.36.patched/CSV_XS.xs 2008-03-11 18:19:00.000000000 +0900 @@ -1083,6 +1083,7 @@ CSV_XS_SELF; av = newAV (); avf = newAV (); + sv_2mortal((SV *) avf); ST (0) = xsParse (hv, av, avf, io, 1) ? sv_2mortal (newRV_noinc ((SV *)av)) : &PL_sv_undef;

これでとりあえず先ほどのスクリプト上では問題がなくなったようなので、P5Pにメールを送っておいた。今のところレスポンスはないが・・・

#これだけ偉そうにしておいて間違ってたらどうしようと今軽く焦っている

ハッシュに値を振り分ける時のコード

例えばCSVなファイルを読み込んで、それをハッシュの中に展開、格納と言った感じの動作をPerlで行いたかったとします。例えば
1,2,3

と言った行を
my %hash = ( 'col1' => 1, 'col2' => 2, 'col3' => 3 );

のようなハッシュに展開する関数が欲しいわけです。皆さんはこれをどういう風に実装しますか?ぱっと思いつくのはforループですよね
my @colums = ('a', 'b', 'c'); my @values = (1, 2, 3); # もちろん実際にはsplit(/,/, $line)とか、CSVパーサーを使う my %h; for (0..$#columns) { $h{ $columns[$_] } = $values[$_]; }

実はこのようなCっぽい書き方はPerlでは大概遅いです。DWIMな言語なので、その辺りはPerl内のオプティマイザに任せるようなコードを書いたほうが俄然性能が良くなるのです。そこで僕は今まで自分の中でHash Magicと呼んでいるものを使ってました。これは、%hashとして定義した物に対して、複数の値を一度に挿入する事ができるものです。
my @colums = ('a', 'b', 'c'); my @values = (1, 2, 3); my %h; @h{ @columns } = @values;

%h から @hの辺りがややこしいかもしれませんが、これがハッシュに対して複数キーを一度に設定する時の書き方です。これはforループに比べると遥かに高速に動きますし、なにより@columnsの中身を一カ所変えるだけで勝手にカラム名の追加/削除/変更に対応してくれるのが嬉しい限りの書き方です。

ですが、どうやらベンチマークを取ってみると妙な事になってきました。

さて、ここからは実際のベンチマークコードをみてもらいましょう。まずは基本のベンチマークコードです。
sub run_bench { my %args = @_; my @columns = @{ $args{columns} }; my @values = @{ $args{values} }; cmpthese(500_000, { hash_magic => sub { my %h; @h{ @columns } = @values; }, forloop1 => sub { my %h; for (0..$#columns) { $h{ $columns[$_] } = $values[$_]; } }, forloop2 => sub { my %h; my $count = 0; $h{ $columns[$count++] } = $_ for @values; }, manual => sub { my %h; $h{a} = $values[0]; $h{b} = $values[1]; $h{c} = $values[2]; $h{d} = $values[3]; $h{e} = $values[4]; }, automanual => do { my $code = "sub {\nmy \%h;\n"; for my $i (0..$#columns) { my $col = $columns[$i]; $code .= "\$h{'$col'} = \$values[$i];\n"; } $code .= "}\n"; eval $code; }, }); }

ご覧のように2パターンのforループ、hash magic、そして手動でカラム名→カラム番号を紐付けるルーチンを用意してます。最後のautomanualは後ほど解説します。

これをまず、キーの文字列が1文字('a', 'b', 'c')と言った1文字だけの場合のベンチを取ってみます。すると結果はこんな感じになりました:
Rate forloop1 forloop2 automanual manual hash_magic forloop1 233645/s -- -20% -58% -59% -62% forloop2 290698/s 24% -- -48% -49% -52% automanual 561798/s 140% 93% -- -1% -8% manual 568182/s 143% 95% 1% -- -7% hash_magic 609756/s 161% 110% 9% 7% --

ぬはっhash_magic超速ス!とか思ってエントリを書きかけたのですが、その後カラムキーの長さを約30文字に変更してみたのです。そうしたらなんと結果が違ってきました:
Rate forloop1 forloop2 hash_magic automanual manual forloop1 201613/s -- -17% -54% -64% -64% forloop2 243902/s 21% -- -44% -56% -57% hash_magic 438596/s 118% 80% -- -21% -22% automanual 555556/s 176% 128% 27% -- -1% manual 561798/s 179% 130% 28% 1% --

今度は手動のほうが速い!ちなみにこの差はだいたいキーの長さが5文字くらいになったところで出始めます。先ほどのrun_bench()を使用してキーの文字列長を変えて行くベンチマーク用コードはこんな感じです:
use strict; use warnings; use Benchmark qw(cmpthese); { # Benchmark short keys my @columns = ('a'..'e'); my @values = (1..5); run_bench(columns => \@columns, values => \@values); } { # Benchmark medium keys my @columns = map { "col-$_" } (1..5); my @values = (1..5); run_bench(columns => \@columns, values => \@values); } { # Benchmark long keys my @columns = map { "col-abcdefghijklmnopqrstuvwxyz-$_" } (1..5); my @values = (1..5); run_bench(columns => \@columns, values => \@values); }

どうも推測するに長い文字列の入った配列を@hに代入する時にその取り出し分のコストのほうが上回ってくるということみたいです。だから固定文字列として指定した'manual'のほうがパフォーマンス的に上回ってくるわけですね。

元々hash magicを使おうと思ったのは、最終的な動作時までカラムの名前や数が分からない場合でも動くものが作りたかったからなんですが、これを見てくるとどうにかその辺をうまくできないかと思いだしたわけです。それが上記run_bench()中のautomanualという項目で指定されている関数です。

この項目、何をやっているかというと、動的に与えられたカラム名を明示指定した関数を作成してます。@columnsの中身によって関数の定義自体を文字列として作成し、evalしてるわけです。これで一応「動的」に「手動/明示指定」な関数が作れる訳です。

でも醜い。美しくない。そもそもこのコード自体がものすごく遅ければ問題ですが、正直それほど効果あるのかなぁ、という疑問も抱いています。要はこのようなトリックを使う事によって起こる可読性の損失と、実際のパフォーマンスの向上のバランスの問題ですね。

今回はこのコードが2000万回ほど呼ばれる予定なので多少差は出ると予測されるので多分使用しますが、僕は元々「いらん最適化は最適化しない場合と比べて改善どころか改悪になる」というスタンスの人間ですし、こういった、Perlビルトインなものに対してのベンチマークというのは結構その結果を鵜呑みするわけにもいかないので正直ちょっと悩みどころです。

まぁ多分もとの@h{@cols} = @valueと言った意図をコメントか何かに残しておいて、その上で最適化する方法を取ると思います。

Apache::Test事始め

年末前後からApache::Testで真面目にテストを書き始めている。

ところが全くドキュメントがないんだね。いや、あるんだけど、携帯の機能を使いたいだけなのにあの厚いマニュアル読むの?みたいな感じで。まぁというわけでとにかくざくざくっとドキュメント読んでテスト書いてたらようやくなんとなく分かってきた。この間ある程度他人にも説明できたので自信ついたしw

Apache::Testはmod_perlハンドラをテストするときに使う。ディストリビューション等でmod_perlをテストしようと思うとApache自体を立ち上げたりなんだりしなければいけなくて「一体どうテストすればいいんじゃ?!」となりがちだが、Apache::Testを使うと、
・・・などなどを行ってくれる。

これだけの事を行うのに色々と手続きが必要だと思いがちだが、そこはそれ、Laziness is a virtueと言い切るPerl界のハッカー達が作ったフレームワークである。超絶簡単。

まず、Makefile.PLの中身を書き換える。残念ながらModule::Installのようなクールなヘルパーは使えず、Apache::TestMMというExtUtils::MakeMaker互換のものを使う必要がある。書くのは以下のような内容:
use strict; use ExtUtils::MakeMaker; use Apache::TestMM qw(test clean); Apache::TestMM::filter_args(); Apache::TestMM::generate_script('t/TEST'); my %INFO = ( NAME => 'MyApp', ... ); WriteMakefile(%INFO)
これだけ。Apache::TestMMを呼び出して、filter_args()/generate_script()を呼ぶ。

上記のMakefile.PLを実行するとt/TEST.PLというファイルをパース、t/TESTというスクリプトを作成する。それとMakefile内にこのTESTを使ってテストを走らせるための設定がされる。

TEST.PLというファイルはもう定型でよい:
use Apache::TestRunPerl; Apache::TestRunPerl->new->run(@ARGV);
以上!あとはmake testするとApache::Testがよきようにはからってくれる。すばらしい。

さて、テストの中身だが、これは何をテストするかによってちょっと変わってくる。

まずハンドラ内で何かをテストする場合。例えばハンドラ内でなにかのオブジェクトを作成し、メソッドを実行した結果をテストする場合。その場合はHTTPリクエストを送るクライアント側はリクエストを送る以外何もする必要がない。普通だったら、
use strict; use LWP::Simple; get('http://localhost:8529/path/to/url');

みたいな.tファイルを書きたくなるが、まずテスト用Apacheのポートをハードコードしたくないし、それにそこはそれ、Laziness大好きっ子だから、ハンドラを書いたらただリクエストを送るだけのファイルなんて書きたくないよね?そういう場合はt/responseというディレクトリを作って、その中に適当にハンドラを突っ込む。すると、.tファイルを全て自動生成してくれるのです!

例えばこんなハンドラをt/response/MyApp/FirstTest.pmというファイルに入れておくと
package MyApp::FirstTest; use strict; use Apache::Test qw(-withtestmore); use Apache2::Const -compile => qw(OK); use MyApp::Object; sub handler { my $r = shift; plan($r, test => 2); my $obj = MyApp::SomeObject->new(); ok($obj); is( $obj->foo(), 'foo' ); return &Apache2::Const::OK; }
t/myapp/firsttest.tなんていうテストファイルを作ってくれる。内容はこれだけ
use Apache::TestRequest 'GET_BODY_ASSERT'; print GET_BODY_ASSERT "/MyApp__FirstTest";
このようにハンドラを作っておくと勝手にリクエストを送るところまで自動生成してくれるわけだ。しかも嬉しい事にmake testを実行する時点でtディレクトリ内にt/confというディレクトリが作られ、その中にhttpd.confが作られる。当然このt/response内のハンドラもそこに自動登録される。自動生成されたt/conf/httpd.confにはこんな感じの記述がされ、apacheからの呼び出し可能になっている
<Location /MyApp__FirstTest> SetHandler modperl PerlResponseHandler MyApp::FirstTest </Location>

make testを走らせるとクライアント側でテストフレームワークが走っているはずなのにテスト的なコードはハンドラ側にしか無い事にお気づきだろうか。実はこれ、MyApp::FirstTestの中でok()等を呼び出すとTAP形式の出力をクライアントに送り、それを自動生成されたテストスクリプトが解釈する、という仕組みになっている。

さて、これまでの説明した時点でt/ディレクトリの中はこんな感じになっている
t/response/MyApp/FirstTest.pm t/myapp/firsttest.t # 自動生成 t/conf/apache_test_config.pm # 自動生成 t/conf/httpd.conf # 自動生成 t/conf/modperl_inc.pl # 自動生成 t/conf/modperl_startup.pl # 自動生成

基本的にハンドラのテストに関してはあとはt/response/の中にハンドラモジュールを足して行くだけである。

万が一ハンドラの設定等をhttpd.conf内から指定したい場合は上記ファイルの他にもう一つextra.conf.inというファイルを作ると良い。たとえば、MyAppVar という変数を設定したい場合は以下のようなファイルを作り、t/conf/extra.conf.inに保存する。
<Location /MyApp__FirstTest> PerlSetVar MyAppVar "foo" </Location>

extra.conf.inはmake test時にパースされ、一部情報が置換されたあと、t/conf/httpd.conf内からIncludeされる。これで設定が反映されるわけだ。らくちん!

ここまではハンドラ内でテスト実行する際のやりかたでした。でもハンドラ自体は作成されていて、しかも部品別に分けてさきほどまでの方法でテストできない場合、クライアント側からその動きを確かめる必要がある。その場合は先ほどのextra.conf.inにハンドラを追加登録すると良い。
<Location /path/to/myapp/anotherhandler> SetHandler modperl PerlHandler MyApp::AnotherHandler </Location>

これに対して例えばt/anotherhandler.tというクライアント側のスクリプトを作る
use strict; use Apache::Test qw(:withtestmore); use Apache::TestUtil; use Apache::TestRequest 'GET_BODY'; use Test::More ( tests => 1 ); use URI; my $url = URI->new("/path/to/myapp/anotherhandler"); $url->query_form( foo => 1, bar => 2 ); my $data = GET_BODY $url; ok t_cmp($data, ...., "data okay");

GET_BODY等の関数はApache::Testフーレムワークが提供してくれるユーティリティ関数。GET_BODY等は先ほどの自動生成された設定を理解しつつ(ポート番号とか)リクエストを実行する。t_cmpは様々な構造体を理解してくれるツールだ。詳しくはApache::TestUtilを見た方がよろしいな。

こうして実行されたテストのログはt/logsに格納されるので、問題があったらそちらのerror_log等を参照すると良い。

さらに、デバッグ方法としては、t/TESTを使うという手もある。Apache::Testでmake testを実行する時はt/TESTが裏方で実行されているので、テストを単体で実行する時やその他の細かい捜査をしたい場合はそのスクリプトに引数を与える。よくあるのが「テスト実行時のサーバー側のレスポンスが知りたい」という状況だ。この場合は、以下のようにしてテストを実行する。
./t/TEST -verbose t/anotherhandler.t # これで標準出力にレスポンスを表示する

さあ、以上が分かればmod_perl上で動くソフトウェアのテストもばっちりだ。もう「mod_perl用のテストなんて書けません」なんて言えませんね☆

Longmorn 42yrs Old

(以下、自分はそれほど酒の味の表現とか歴史に詳しいわけでもないので、味の表現等筆者がそう感じている、という程度の認識でお願いします)

Longmornというスコッチがあるわけですよ。Longmorn自体についてはここが詳しそうだ(正直ある程度の知識は好きだが、あんま酒の歴史は興味なかったりする)。Longmornはまろやかな深い味と果実のような香りが素晴らしいスコッチで大好きなんだが、マイナーなのでいかんせんあちこちにあるわけではない。まぁマイナーっつっても別にもう作ってないわけでもないから手には入るけどね。

この間とあるバーに行ったら「木曜に来ると良い酒置いてあるよ」とわざわざ教えてくれたので金曜日に行った訳です。そしたらでてきたのがLongmornの42年。

普通スコッチと行ったら12年から18年、長期熟成の物でもだいたい24年前後。基本的に熟成期間が短ければ短い程熟成から来る香りが抑えめでアルコールのアタックが直接舌に来る。24年くらいの熟成だとアルコール分が飛び始め、まろやかな味に変貌し、なおかつ樽からうつる香り、熟成による香りが漂い始める。

なので下手な長期熟成ものを飲むと、香りだけでスコッチ特有のあの味の強さがなく、すかすかの味になる事もある。まぁそこまでいかなくとも微妙なバランスの上で成り立っているので長期熟成ものほど良い、というのはちょっと違う。

が。このLongmorn 42年。1960年代に樽詰めされたものなので俺は生まれてもいない。そんな頃にスコットランドのどこかで作られた酒だ。なのに飲んだ時のこの力強さ!バー中に漂う香り!味王でなくとも巨大化したくなるウマさ。すげぇ!

こいつ、ショットが4500円と値段もロケット級だが、スコッチ好きなら一回飲む価値はある。

ちょっと余談気味だが、酒に関しては味と値段のバランスさえ合ってれば、高い酒を飲む価値があると思う。お金を投資する価値がある。なぜなら酒は二度と同じ物には出会えないから。特に10年超の長期熟成が必要なスコッチのような酒は、蒸溜所そのものが無くなっている事もよくある上、どちらにしろ当時の材料を含めた環境を再現できる事は少ないから。

数十年かかるという手間と、2度と同じ酒に出会えないという事を考えると、このLongmornは興味がある人は是非飲んでみてほしい。値段との兼ね合いで自分は多分もう一回飲めたからおかわりはいらないが、スコッチ好きには超おススメ。

厳密にはそれほど日本人じゃないんだなぁ。

こんな事言われてるから補足しておくです。

2008年03月07日 K-Ono K-Ono 日本人がアメリカの大学の工学部に入学さらに卒業してしかも就職できていて「落ちこぼれ」とは方腹痛いわ。ふざけんな。

  1. 俺は元々海外住まい。今年31歳になるけど、そのうち21年間海外です。だから日本人というより外人に近い。DNAは100%日本人だけど。アメリカ人がアメリカの大学に入れても全然すごくないよね?ちなみにアメリカの大学、大学を選ばなければ英語喋れる外人はいい金づるだから結構さくさくと取ってくれるんだな。
  2. 就職はできたけど、決め台詞はなんだったと思います?面接の時に「最低賃金で良いからやとって!!!」って懇願したんだよ。それまで半年以上無職でした。ちなみにその時の最低賃金は$6.50/時

ちゃんと書いておくべきでしたね。すみません。

才能の無い人がやれる事

色んなところで自分の今までの経歴を話す時に話してるけど、俺は基本的に落ちこぼれです。大学は工学部でComputer Scienceを専攻したけど、イマイチぱっとせず、基本中の基本みたいなコースも落とした事あるし、授業なんて(アメリカの大学なのに)全然出てなかった。自分の専攻のクラスはさすがに退学にされたくなかったんで出てたけど、それ以外の数学、経済、化学、物理、ことごとく出席日数は50%以下だ。物理なんて全行程を通して2回しか出てない。

特に創造力があるわけでもない。若かりし頃、高校生とかその頃は漫画家を目指してみたり、ミュージシャンを目指してみてレスポールを膝くらいの位置に吊って弾いてたりしてみたけど、結局そういうシナプスがばりばり音を立てて何かをゼロから生み出すような事もたいしてうまくなかった。

だから正直大学卒業間際は相当焦ってた。卒業後紆余曲折あって、2年後くらいにNetwork Applianceという会社に入社できた時もまだ何も出来ず、俺はいつクビにされるんだろうと悩んでいた(まぁ、それとは別に俺は別にコンピューターの仕事をしなくても飯を食う分くらいには金は稼げるだろうという楽観的な意見もあったのだが)。

卒業後 からひどい貧乏なアメリカ生活を送っていたからその生活には戻りたくなかったし、かといって俺は使えない人間だったから仕事もあまりないし・・・。そんな状況で出来る事と言ったら一つしかなくて、それは自分でやる事を見つけて、とにかくそれを愚直に突き進めて行く事だけだった。

当時社内に初期開発後しばらく忘れられていたツールがあって、それが何かの話のおりに話題にあがったので、ふと興味を持ってそのツールを見てみる事にした。なんせ仕事ないしな。

ソースコードを読み解く事数日、どうにかこうにかなんとか何をやろうとしているのか分かってきたので、その時になっておずおずと当時のボスに「これ・・・動かせるようにしてみてもいい?」と聞いた訳です。返事は「おお、いいよいいよ」別になんの期待もなさそうだけど、そりゃそうだろ。仕事もねぇしw

そのツールは結局2ヶ月近くかかって動かす事に成功した。実はその間に日本に強制送還、もとい、ビザが切れたので日本支社で働く、というような事になってたりしたので微妙な環境だったのだが、それでもリモートから作業してなんとか動かした。

このツール自体はその後数年間運用されて、結局政治戦争に敗北した我が部署が乗っ取られたのでスクラップになったのだが、まぁそれはともあれ、この時自分は21か22。その語2年前後でCPANにモジュールを登録したりするようになっている。

ちなみに俺のような人間がCPANに出会えたのは幸運以外の何者でもないと思う。自分の才能のなさをどうしようというときに、自分がただのでくの坊だとさえ認められれば、「あとはCPANから借りてきました><」で自分の作りたい物が作れて、仕事になる。時々見つける事のできる細かいエラーとかを報告すればそれはそれで貢献できる。あきらかにWin-Winじゃんね。

ともあれPerlやCPANとの出会いはそこからだし、やはり明らかにターニングポイントはその掘り起こしてきたツールだったなぁ

学校を卒業して11年たった今、自分が「すごくなった」って全然思わない。今でも上に人がいすぎて(しかも最近は若い人がどんどん自分の上に来るし)悲しくてしょうがない時もあるし、なにより自分の才能を自分が信じてない。

そのかわり自分はでくの坊だと認められた。そしてその後はただひたすらコードを書いてきた。それだけは自分の自信につながってきてる。

天才でない人は愚直に書く、ノウハウをつける、積極的に手を動かす。人の意見を素直に取り入れる。これしかないんだと思うよ。才能の無い人が出来る事はそれだけだけど、それを続ければ何かが実るはず。

今は必死で手を動かしてるときっと後で戻ってくるものがあると、天才ではない、大多数の後進の方達には言ってあげたい。
前のエントリで調査した結果、Text::MeCab に深刻なメモリーリークが発見されました。

メモリを解放する処理自体は問題なく呼ばれていたのですが、そのタイミングがperlプロセスが終了する時点まで待たされている状態でした。最終的には確実に解放されていたのでなかなか気づかなかったのですが、node->nextやnode->prevのような関数を呼ぶとperlが終了するまでメモリが解放されませんでした。特に形態素解析する文章が巨大な場合、これは一瞬でメモリリークとなり、問題が顕在化します。

先ほどアップロードした0.20005でこの不具合を修正してありますので、CPAN登録が済み次第アップグレードを推奨いたします。急いでいる場合はcodereposからも入手できます。

ちなみに最終的なフィックスの決め手はXML::LibXMLのソースコードを読んだ事でした。自分は愚直にsv_blessという関数を使ってオブジェクトを作成していたのですが、XML::LibXMLではsv_setref_pvという関数で同等の事をしていました。とりあえずperlgutsを読み、このsv_setref_pvを使用したところ一瞬で問題が解決した次第です。matts++, pajas++

Perlのmakeフェーズの挙動

いわゆるCPANモジュール形式で展開されているモジュールに対して一般的に行う以下の手順:
perl Makefile.PL make make test make install # 以下はモジュール作成者のみが気にするであろう make clean make disttest make dist make manifest

これがそれぞれ何をしているのかって案外しられてないのかもしれない。

perl Makefile.PL - これはMakefile.PLを単純に実行している。この中では一般的にExtUtils::MakeMaker、Module::Build、Module::Install等のモジュールが使用され、インストールに使うMakefileというファイルを作る。これはmakeコマンドが自動的に検知して、使用してくれる。ちなみにmod_perlでテストを作成する時に使うApache::Testフレームワークの中ではApache::TestMMというような物がその代用をしたりする。

Makefile.PL内で使用しているモジュールによっては挙動に違いがあるかもしれないが、だいたいこのMakefile.PLを動かした時点でMakefileにインストール対象となるスクリプトやlibディレクトリ内に存在するモジュールのリストを作り、これ以降はそれらのファイルに対してのみ作業を行うようになる。

makeフェーズはこれがCで書かれたプログラムだったりするとコンパイルが始まったりするのだが、Perlでは基本的にファイルの移動とちょっとしたフィルタリングを行うだけで終わる。

基本的な動作としては、blibというディレクトリが作られ、lib内にあるモジュールがblibへ、実際にインストールされた状態と同じレイアウトでコピーされる。blib 内を見るとautoやらなにやら怪しげな名前のディレクトリができてるかもしれないが、その辺りはXSでコードを書いていたり、AutoLoader等の黒魔術的な魔法を使ってなければ無視して良い。

インストールするスクリプトを指定していた場合は、そのスクリプトの#!ラインがMakefile.PLを動かした時のperlのパスで書き換えられる。/usr/local/bin/perl Makefile.PLとやっていたら、#!/usr/bin/perlとなっていたものが#!/usr/local/bin/perlに書き換えられる。これもblib以下にとりあえず格納される。

あとはそれぞれのモジュールやスクリプトからPODを抽出してman化したものを作ったり。

blib内のファイルレイアウトを明示的に使用するにはblibというプラグマを使う。これを使用すると開発者モードのようなものがオンになりblib内のファイルレイアウトを理解した上でperlを実行できる(開発者モードと言ったって、blibのレイアウトを理解してくれるということだけだが)。だからmakeを通さずにt/内のテストを動かすにはperl -Mblib t/test.tとかする。これでblib内のモジュールを使いつつ、t/test.tを実行できる。

このblibにモジュールを入れるという作業が結構キモで、インストールする時はともかく、自分のモジュールを開発している時はエラーになったりするので注意が必要。makeの次のフェーズであるmake testで使用されるディレクトリはlibではなくblib内だからだ。

だから例えば、make を通さないでperl -Mblib t/test.tとかを実行していると、その途中でlib内に変更を加えてもテストには反映されない。いつまでたっても古いコードしか実行されなくて首をかしげる事になるだろう。それは単純にmakeを行っていないのでlibの中身がblibに反映されてないからだ。

同様にたまにlibにファイルを追加したのにいくらmakeを行ってもblibにその中身が反映されず、結果make testが落ちる。これはMakefileの中にモジュールのリストが書いてあったりするせい。Makefileでどのファイルをlibからblibにコピーするのか指定されていると、Makefile.PLを実行した時にlibディレクトリになかったモジュールは無視されてしまう。この場合は色々対処法があると思うが、個人的には素直にmake cleanして(後述)perl Makefile.PL、make、make testと行うのが良いと思う。間違いがないから。

make cleanは読んで字のごとし、ディレクトリ内を掃除してくれる。主にblibの中身を消してくれたり、その他一時ファイルを消してくれる。Module::Installはincの中に色々とメタデータを入れたりするのでそれを確実に消したい場合はこれを実行するといい。あとMakefileも削除されるので、再度作業するにはperl Makefile.PLが必要

make manifestはMANIFESTファイルを作る。MANIFESTファイルはCPANにあがっているディストリビューション(いわゆるCPANモジュールのtar ball)内に入っているべきファイルのリスト。ディストリビューションに必要なファイルが全部揃っているかどうかはこのファイルと実際に格納されているファイル群を比べる。

make manifestを実行すると、基本的に現在のディレクトリ以下に格納されている全てのファイルをMANIFESTに追加する。.svn等の隠しファイルは無視されるが、それは良く知られている隠しファイルだけ。あとは全て追加されてしまうのでMANIFEST.SKIPで指定するか、一度MANIFESTを作ってしまったら手動で削除しないといけない。必要なファイルのみをMANIFESTに追加しないと、この後のmake dist/disttestフェーズで問題が出てくる

make distとmake disttestは最終結果であるディストリビューション用のtar ballを作るのに使う。基本的な動作としては"MyModule"のバージョン"0.01"というディストリビューションを作っている場合、現在のディレクトリにMyModule-0.01というディレクトリを作成し、ディストリビューションに必要なファイルを全部コピーする。そしてこれはtar + gzipでtar ballを作成してくれる。

make disttestは最後のtar ballを作成する動作の代わりに、該当ディレクトリ内でmake testを走らせてくれる。これで開発ディレクトリ以外でmake testを動かした時の動作を確認できる。

気をつけなければいけないのはmake distがディレクトリにコピーするファイル群は、MANIFESTに記されているファイルである、ということ。だから例えば必要なファイルなのにMANIFESTに入ってなかったり、不必要なファイルがなぜかMANIFESTに存在していても、MANIFESTに書いてある通りのファイルがコピーされる。余計なファイルがあった場合は恥ずかしいだけだが、ファイルが足りない場合はmake testでこける事が多いのでちゃんと確認すべきだ。そのためにもディストリビューションを作成する場合はmake disttestは必須ステップと言える。

と、こんなところかしら。なんか間違ってたら突っ込みいれてください。




Text::MeCabのメモリ管理(調査中)

Text::MeCabがおかしい。某社社内より報告アリ。毎度ありがとうございます。

で、すでに数時間そのコードとにらめっこしている。なぜ思い通りに動かないのかよくわからない。根本的な問題はわかった。Text::MeCab::NodeオブジェクトがDESTROYされるのがなぜかスコープを脱出した時ではなく、Global Destruction時のタイミングで起こっているのが問題。

どういうことかというと、Perlは2つのタイミングでガーベッジコレクションを行う。ひとつはステートメントとステートメントの間(スコープが変わる時も含む)、そしてもうひとつはPerlのインタプレタ自体がメモリから削除されるGlobal Destruction時。

現在のText::MeCabでは、以下のように$nodeオブジェクトをどんどん変更して行っても、さっきまで入っていたオブジェクトのDESTROYが呼ばれずに、次のループに行ってしまう。そしてGlobal Destruction時に大量のDESTROYが走る。

my $mecab = Text::MeCab->new(); for(my $node = $mecab->parse($string); $node; $node = $node->next) { # do whatever }
でもこれだと(当たり前だけど)、for()内、いや、プログラムが終了されるまでメモリが解放されることがない。これでは駄目なのだ。SvREFCNT_incやSvREFCNT_decを色んなところに入れてみたんだけど、唯一正しいタイミングでガーベッジコレクトされるのは最初からSvREFCNTを0にしてしまう方法だけだった(これは当たり前のようにエラーがでる)

いったいどうすればいいんだ・・・?誰かヒントを・・・

MVCのモデルはDBじゃなくてもいいんだよ


後半その通りなわけですが、CatalystはModel::DBIC系のせいでMVCが誤解されてるのよねー

と言っておられる。たしかにその通り。「モデルってDBでしょ?」みたいな印象が一般的にあると思う。

そういう印象を持ってる人に説明すると、「モデルを作る」って何かというと、DBのようなストレージにあるものをどうこうする、ではなくて「データに対する操作を抽象化したものを作る」ということです。例えば、ブログを作ると、Blog、BlogEntry、BlogUserみたいなモデルを作ります。そしてその操作方法はこんな感じ:


# ブログを登録するみたいなAPI MyApp::Model::Blog->create({ user => $blog_user, title => $title, .... }) # その後どこかでエントリを作るようなAPI my $blog = MyApp::Model::Blog->find_by_id ( blog_id => $id ); MyApp::Model::BlogEntry->create({ blog => $blog, title => $entry_title, content => $entry_content });

こんな感じ?見て分かる通り、裏ではDBを使ってるかもしれないけれども、モデルという概念はそれより上の概念。ストレージも含め、ブログエントリを作成する時に行われる全てのステップ(ビジネスロジック)をカバーするのがモデルだ。例えばブログエントリを書く時にHTMLのフィルタリングをするとか、他のサーバーにアクセスしてなんらかのRESTで話すとか、わかんないけど、とにかく「エントリを書く」という行為を抽象化できるところがモデル。

じゃあ元々のブクマコメントのModel::DBICはどうすんだよ、いらないのかよ、みたいなところに行き着くかと思うのだが、そこはそれ、モデルに「格納先」を指定するのにDBを抽象化したModel::DBICを使ってやる、っていう手もある
my $c = shift; # Catalyst的なcontextがあると仮定します MyApp::Model::BlogEntry->create({ storage => $c->model('DBIC::BlogStorageSchema'), blog => $blog, title => $entry_title, content => $entry_content });

これで全く問題なくDBICの良いところを使える。

要はDBICはRDBMS特有ストレージのモデル的抽象化であり、本来は他のビジネスオブジェクトの裏で消えているべきところが、実際にはものすごくよく使うものだから同レベルでのモデルが存在する、というそれだけの事。

あなたがこれから書くCatalystアプリはDBICを使うにしてもControllerから直接の呼び出しは避けましょう。それは本来抽象化されているべきことです。そういうふうに組み立てて行くとうまく密結合を防ぐ事ができるはず。
最近ソフトウェアエンジニアリングに置ける開発手法に関して考えている。

ぶっちゃけ言ってしまうと「やっぱりTDDっぽいのがいいな」というところに落ち着きつつあるのだが、厳密にTDDをしたほうがよい、と思ってるわけではない。TDDとかExtremeプログラミング、Agileプログラミングにしても理想はいいんだけど、原理主義っぽい使い方は現実にそぐわないと思ってるからだ。

前置きはこれくらいにしておいて・・・重要だと思うのは以下の点:

  1. 開発サイクルに自動テストツールを組み込む
  2. エンジニアによるバグ/不具合発見時には「動かない」は許可しない。必ず再現コードを提出してもらう
  3. テストを自動テストツールを組み込む(=次回リリース前にはかならずテストを実行できる状態にする)
  4. テストが通るまで修正を続ける
という開発サイクルを取るべきだ、という結論に落ち着きつつある。

当たり前と言えば当たり前なんだけれども、開発をしている人はバグを例えば口頭で説明されたらその場で直して「直したよ!」って言って終わっちゃう事も多いので、そういう事を回避したい、という思いから上記サイクルを強く推奨したいのだ。

開発エンジニアとしてはバグを修正するために製品コードに手を入れるのは簡単だ。でもマーフィーの法則ではないけれども「一度起こったバグは必ずもう一度起こる」と俺は信じている。他のコードに手を入れた瞬間か、バージョンアップ時にコードを書き換えた時か・・・とにかくバグは起こるべくして起こる。

でもテストを作成せずに製品コードに手を入れてしまった瞬間、そのバグが起こったという事実さえ記録に残らない。次回起こるかどうかチェックができない。「なんでまた起こったんだ?」というクライアントの問いに答えられない。

それらを解決するのはリグレッションテストを増やす事しかないと俺は考えている。

とにかくあれだ、make test必須ってことだ。t/ディレクトリの中がt/regression-*.tというファイルで埋まってる状況こそ望ましいはずだ。世の諸君、テストを書くんだ!

さてここからは余談だが、そういう事を踏まえるとMVCを使う別の理由が見えてくる。

MVCは一般的にコードとプレゼンテーションを分けるのに使う、と言われがちだが、MVCパターンを使う事によって以下のようなシナリオを防げる:

  1. Webアプリで不具合発生
  2. 修正するも、テストが書けないとエンジニアに言われる
  3. 「なんで?」と聞いても「Webサーバを通さないとテストできないから」「うちのネットワーク構成だと本番サーバーにアクセスせざるを得ない」とか言われる
  4. テストがない状態で運用。将来また問題が起きないかどうか((((;゜Д゜)))ガクガクブルブルしながら過ごす
それがどうMVCとだと解決できるかというと、WebアプリがうまくMVC構造になっているとロジックがほとんどモデルに落ちてくる。

するとモデルは当然Webサーバと結合してない(べき)なので単体でテストできる!

やった!テストできるじゃん!

ちなみにモデルなら・・・と書いたけど、Catalystのような構造になっていればCだってVだって同じようにバラして単体テストできる。

そういうわけでMVCの利点を話す時は旧来の利点だけでなく「テストが容易に書ける」と足したほうがいいと思う。

世の諸君!テストを書くんだ!ボーイズ・ビー・アンビシャス!どげんかせんといかん!All Your Tests Are Belongs To Us!

# 最後わけわからんくなった。

Cache::Memcached::libmemcached 0.02000

Cache::Memcached::libmemcachedの0.02000をリリースしました

このバージョンからMemcached::libmemcachedを継承するようにしており、前バージョンより約10%前後のパフォーマンス改善が見られます。概ねCache::Memcachedの6〜8倍のスピードで動きます。Cache::Memcached::Fastとの差はget_multi()以外は5〜10%程度libmemcachedのほうが速い感じ。get_multi()はいまだになぜかFastより遅いです。理由はよくわかりません・・・

機能要望等ありましたらお気軽に連絡してくださいまし。

酒バトン

なんかまわされてきたぞー

  1. 酔うと基本的にどうなりますか?
    • 外見:顔の色がすぐかわる。赤→深紅→青。青になると危険
    • 行動パターン1: 下ネタ開始。最近のはまりネタはソーセージ。
    • 行動パターン2:そでをまくりはじめ、オヤジモードON
    • 行動パターン3:キス魔になる。一応空気は読めると思うが。ちなみに男女問わずこの状態ではキスできる。
    • 最終形態:これは絶対に心を許してる人の前でしかならないけど、泣くこともある。これはあんま見せた事ない。
    • でも多分俺は基本的に「普通」のよっぱらいのような気がする
  2. 酔っ払ったときの最悪の失敗談は何ですか?
    麻布十番で初対面の人達8人くらいと飲んでる時に、焼酎が原酒だということを計算にいれずに飲みまくり、ゲロゲロしてしまったこと・・・かな。酒飲みにあるまじき失態。しくしく
  3. そのときはどのくらい飲みましたか?
    なんか強い(40度くらい)の焼酎原酒をそのままストレートで10杯くらい飲んでたんだよなぁ。ちなみに失態をさらして別れた後その後すぐ素面に戻って飲み直したのはナイショだ。
  4. 最悪の二日酔いはどんな感じでしたか?
    朝東横線→日比谷線と満員電車に揺られながらもなんとか六本木ヒルズまで辿り着いたのにとうとう我慢しきれずに一階のトイレでゲボゲボして、結局その日休んだ。・・・一番ひどいわけではないが、我慢しないといけない状況が1時間弱続いたので思い出としては最悪の部類に入る。
  5. 酔っ払って迷惑かけた人にこの場で謝りましょう
    ヨッパライ仲間の人達は「酔ってる時はしゃあないべ」で済むのでよいとして、やっぱり一番迷惑かけたのは問い3の人達だな。すみません、すみません。
  6. 冷蔵庫に入っているお酒の量は?
    冷蔵庫にはあんまり入ってないなぁ。今はタリスカーと余市と黒霧島が冷蔵庫の脇にあるよ。ビールは飲みたい時に買ってきてる。夏になったら多分金麦のケース買いを再開します。
  7. 好きな銘柄は?
    • Port Ellen
    • Auchentoshan
    • Bowmore
    • Talisker
    • ビールはモルツかキリンラガーでお願いします。
    • ベルギービールはやっぱり Chimayですね
    • 日本酒は広島の「神髄」とか福島(福井なの?すみません)の「黒龍」が好きですが、最近さわやか系に走ってるんで澤之井とかでも全然おいしくいただけます。
  8. 最近最後に飲んだお店は?
    中目黒「まんてん」。ホルモン食いながらぐびぐび
  9. よく飲む、思い入れのあるお酒5品
    酒自体にあまり思い入れはないが・・・元彼女達と一緒に飲んだ酒といえば「Chimay」「マンハッタン」「Laphroig」あたりでしょうかね。
  10. バトンのジョッキを渡す人
    • 酒飲みっつーとid:osawa? うさぎのぴょん子?ぴょんこはすでにやってそうだな。

今敏

080302_1941~0001.jpgひょんなことから今日は新宿でやってる今敏の個展のようなものに行ってきた。昨日からやってるんだけど、普通に覗いて終わりにしようと思ってたらなんと本人がいた!わ!

ってこと「PERFECT BLUE」のDVDを購入しサインもらってきたのです。しかも絵つきだ!わーい。ちなみに、これを描いているのを見ていたわけだが、線を描くのにまったく迷いがない。すげぇきれいに線が引かれて行く。

備考:今敏は思っていた以上にでかい。

PERFECT BLUEは初めて見たけど、おもしろかった。

金曜日

  • S社のAさん来社につき、ついでに飯を食いに行く事に。いや、酒を飲みに行くの間違いか。
  • ソーセージに関して大いに盛り上がった。
  • 終電が心配なので割と早めに解散
  • 帰りの電車で降りたらdropd...もといSさんと遭遇。正直すげぇ最近までネットのアイデンティティとSさんが合致してなかった。改札でるまで雑談。
  • 飲みが足りないので地元でシガー&モルト。オーヘントッシャン。シガーはちょっと贅沢な吸い方をしてしまった。最後はインセンス代わり。

Author

Daisuke Maki (a.k.a lestrrat): Perl hacker, Director of Japan Perl Association, YAPC::Asia Tokyo Organizer (2009-2012), Fluent in Japanese, English. Ex-Brazilian (sorta)

#perl #c #ruby #java #mysql #english #japanese #opensource #stf #cooking #scotch #cigar


このエントリーをはてなブックマ
ークに追加

翔泳社よりモダンPerl入門(2010)を出版させていただいております。できれば内容をアップデートしたいので是非皆様・・・現在の在庫処理にお力をお貸しください!><

月別アーカイブ