D-7 <altijd in beweging>

Day to day life of a Perl/Go/C/C++/whatever hacker. May include anything from tech, food, and family.

2008年02月

この間から鼻をかむとなんか色がついてるなぁと思ったら、やっぱりというか、血が混ざっていた。もうかれこれ3日はこの状態なんだけど、大丈夫かなぁ。
    このエントリーをはてなブックマークに追加 mixiチェック

統計情報を計算する"R"というものがあるわけだ(日本語だとこの辺りとかこの辺りかな)。で、このスクリプト書くのはいいんだけど、Perlからうまく使えないかなぁ、と思ってR::Writerってものを書いてみた。そしてcodereposにいれようとしたら見事誤爆した。記録が残るからはずいなぁ(><)

R::Writerは基本JavaScript::Writerのパクリです。こんな感じ:
use R::Writer; my $R = R::Writer->new; $R->var(x => 1); $R->var(y => \'x + 1'); $R->call(cat => \'y'); print $R->as_string;

本当〜〜〜に一部の機能しか実装してません。もしRを使った事ある人がいるならガシガシ突っ込んでくれると嬉しい。
    このエントリーをはてなブックマークに追加 mixiチェック

こ・・・これは!フリースペースに他プレーヤーを走り込ませたり、マークをはずしたり・・・これはすごい。ドリブルでサイドを前進させている間に中盤のプレーヤーをパスを受けに走らせたり・・・。これはおもしろいぞぉ。サッカーゲームとしては革命的かもしれない。おススメ。

ちなみに「キャラゲー」としてサッカーゲーム買うのには不向き。あくまで「あ、そこのオープンスペースに走り込ませたかったのに・・・」というフラストレーションが今までのサッカーゲームで溜まってた人向き。
    このエントリーをはてなブックマークに追加 mixiチェック

追記:daemontoolsはMac OS Xではpollを無効にするような事をしなくてはならないらしいです(id:kazuhoさんありがとう!)。

の辺り参照

---

MacBook返ってきた><

電話が来て、その人によると「ハードウェア的に直せるところは全て直しました」「ですが、まだブート時にファンが相当まわっているようです。これはソフトウェア的な問題だと思っています。」「これを直すには初期化することをおすすめしますが、いかがいたしましょうか?」

ぎゃーす!初期化だけはノープリーズ。ってことでともかく受け取りに。

受け取り自体はスムーズに終わったが、その時にソフトウェア的な問題って?って聞いてみたら、なんかブート時にファイルが云々とか言っていた。「じゃあそのファイルってなに?後で見るから」と聞いてみると、エンジニアが問題だと言っていたファイル名が「supervise」だった

before_supervise.png
superviseっていったらdaemontoolsのそれじゃないか。topで見る限りCPUなんてほとんど使ってないけどなぁ・・・と、じゃあファンが動いているんだろうから、と温度をチェックしてみた。

右の図で見た通り、CPU温度は49度、ファンは1802rpmで回っている。これが正常なのかどうかはわからんが、とりあえずこの状態では特に問題はない。この状態から、svscanbootをつけて、5分か10分ほど待ってみた。

after_supervise.png
その5分後くらいの状態がこれです。69度ってCPU的に高い?それはともあれファンが確実にウォンウォン言い出している。6200rpmってあるし!

CPUは40%程度使っている感じ。superviseがものすごく無駄にCPUを回してるとかそういう感じではなさそうなんだけどなぁ。

ともあれ、なんかsuperviseとMacBookは相性がよくないのかもしれません。
    このエントリーをはてなブックマークに追加 mixiチェック

結局おいらのブラックなMacBookちゃんは店員に見せた瞬間に「じゃあ修理ですね!」みたいな感じでおいらの手のうちからするりと持っていかれました。うう...

まぁほとんど全ての必要なデータはgoogle mailやら、どこかのサーバーにおいてあるものばかりなので俺は端末が変わったところでたいしたロスはないんだけれども、何が辛いってキー配列が...

今使ってるマシンは事務所に置いてある雑用用のMacBookなわけですが、こいつが日本語キー配列なんだなぁ。日本語をうつためだけだったらなにも問題ないんですが、プログラム書くときに正直こいつだと無理。いやー、少なくとも短期間で乗り換えるのは絶対無理。多用する '"@#!~:;<>/_-= の類いの文字の位置が全部違うんだもん><

というわけでただいま生産効率が著しく落ちています>関係者各位。がんばってます。でもすみません。

080219_1808~0001.jpg
追記:結局我慢しきれずにワイヤレスのキーボードつないだ。ずいぶん前はこのセットアップで仕事してたな。この装備で仕事してた頃の俺を知ってる人は相当なDaisuke Makiマニア。
    このエントリーをはてなブックマークに追加 mixiチェック

これってもうCPANにあるのかな。

Plaggerみたいにプラグインで構成するライブラリが欲しいんだけど、別にアグレゲーターしたいわけじゃなくて、全然違う用途に使いたいのです。しかも、フックポイントをアプリケーション毎に変えたいから、それさえも設定ファイルに入れたいわけ。

で、ないのかと思って書いてみた。

もしよかったらコメントしてください。同等のモジュールを見落としてるだけという可能性もあるのでそれPla的なコメントでもいいので。
=head1 NAME Plugal - Generic Plugin Execution Framework =head1 SYNOPSIS use Plugal; Plugal->bootstrap('config.yaml'); Plugal->run; =head1 DESCRIPTION Plugal is a simple framework to define hooks, and run associated plugins. (If you're familiar with Plagger, think of it as Plagger without the bells an whistles for fetching feeds) =head1 USAGE Plugal is designed to read in all of its configuration from a file. Plugal->bootstrap('config.yaml'); The config file should contain at least two sections. One is to specify the hook points that Plugal witll call the plugins from: hook_points: - start - foo - bar - end These hook points can be something totally arbitrary: You get to decide in what order you want to execute things. This basically translates into: foreach my $hook_point qw(start foo bar end) { $plugal->run_hooks($hook_point); # above translates to # foreach my $hook (@hooks_at_particular_hook_point) { # execute $hook; # } } i.e., hooks associated with the named $hook_point are run in order. The hook points are now defined. You now need to define which plugins are executed at those hook points The other section you need is a plugins section. This tells Plugal which plugins to load: plugins: - module: Foo # Note: loads Plugal::Plugin::Foo args: # Note: Passed to Plugal::Plugin::Foo->new() arg1: foo arg2: bar - module: '+My::Plugin::Bar' # Note: loads My::Plugin::Bar args: # Note: Passed to My::Plugin::Bar->new() arg1: foo arg2: bar Each of these plugins should register itself, so Plugal knows when to call them. This is done in the plugin's C<register()> method. For example, package Plugal::Plugin::Foo; use base qw(Plugal::Plugin); sub register { my ($self, $c) = @_; ... whatever initialization ... $c->register_hook('start', \&coderef); $c->register_hook('foo', [ $self, 'do_foo', @args ]); } The above snippet registers plugin Plugal::Plugin::Foo so that (1) \&coderef is called at "start" hook point (2) $self->do_foo($c, @args) is called at "foo" hook point The first form is pretty straight forward. It calls a code reference at the hook point 'start' (which is defined prefivously in the "hook_point" configuration). \&coderef will receieve 2 arguments: a reference to the plugin, and a reference to the context object (the main Plugal instance). Thus, the coderef should be defined as such: package Plugal::Plugin::Foo; ... sub coderef { my ($self, $c) = @_; # do whatever } Of couse, \&coderef can be an anonymous routine, or whatever you please. The second form is slightly more complex. It allows you to specify a method call without explicitly specifying a closure. If the second argument to register_hook() is an arrayref, we expect the form: [ $object, $method_name, @extra_args ] This is then called as $object->$method_name($c, @extra_args) So your method definition should be sub method { my ($self, $c, @other_args) = @_; ... } $c is the same $c that you received in the register() method. And now you're ready. Initialize Plugal with the config as above, and then call C<run()> my $plugal = Plugal->bootstrap('config.yaml'); $plugal->run(); =head1 AUTHOR Copyright (c) 2008 Daisuke Maki E<lt>daisuke@endeworks.jpE<gt> Concepts and some code taken from Plagger. =head1 LICENSE This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. See http://www.perl.com/perl/misc/Artistic.html =cut
    このエントリーをはてなブックマークに追加 mixiチェック

これはとても細かいところなんだけど、最近流行のYAMLでオブジェクトの初期化方法を全部書くよ、的なヤツ:

plugins: - module: Hoge config: foo: 1 bar: 2
みたいなヤツ。

これで、"config"ってキーがとても気になるのです。コンフィグは確かに設定なんだけど、設定がコンストラクタの引数になるべきなのかどうか?みたいな、すごい細かい違和感があるのね。

それにCatalystとかに慣れてると、configってパッケージレベルのもの、みたいな感じがする。Catalyst内ではCatalyst::Baseから(今ソースコード見る気しないけど、確かそのあたり)継承してきて、->config()はクラスメソッドになってるはず。これと、例えばPlaggerとかGunghoとかを見ると妙な違和感を感じるわけだ。

HTML::FormFuだと、こういうインスタンス引数はconstructor_argsとかtt_argsみたいになっている。でもconstructor_argsは一般化するには長過ぎるよね。

ってことで、argsはどうかと思うんだけど、どうだろう。これならなんか既存のクラス変数的なconfigとも分離ができるし、DWIM的な言語表現としても有りだと思うんだな。基本的にそれらを同時に表記する事はないと思うんだけど、コンストラクタとクラス設定初期化みたいなのが入り乱れる場合に区別がついていいと思うのです:
plugins: - module: Hoge config: foo: 1 bar: 2 - module: Hoga args: foobar: "x" hoopla: "y"
こんな「これが定番ね」程度の決まり事はどうでしょう?
    このエントリーをはてなブックマークに追加 mixiチェック

怖いので今日はマシンを落とします。今度はマシンが風邪ひいたか?

明日アップルに持ってく。
    このエントリーをはてなブックマークに追加 mixiチェック

http://xinha.gogo.co.nz/xinha-nightly/examples/ExtendedDemo.html

すげぇ。WYSIWYGエディターもここまできたか。サファリが使えるのは↑のNightly Demoだけなんだぜ!
    このエントリーをはてなブックマークに追加 mixiチェック

水曜朝に喉に痛みを感じていて、やばいかな?と思っていたら案の定その夜には結構やばい感じになってしまった。ふえぇ。木曜の朝9時台なんて時間にミーティングを入れていたのでそれだけ行って、あとは木、金、土、日とずーっと寝てた。

日曜の夜になってなんとか回復してきた。
    このエントリーをはてなブックマークに追加 mixiチェック

自分でFORTRANが必要なソフトウェアをビルドしたかったので、調べてたら、どうもG77(gfortran)はgccのソースコードがないと後からインストールできないようだったので、ついでにGCC 4.2.3を入れてみる事にした。

gcc普通にconfigure; make;してもFORTRANはコンパイルしてくれないので、./configure --enable-languages='c,c++,objc,java,fortran'のように指定する必要がある。なのでまずそのフラグをつけてコンパイル。

つまずいたのはFORTRANを入れるのにGMPとMPFRが必要な事。これらはどちらも演算処理用のライブラリ。GMPの入れ方にはちょっと手こずった。これまた普通に./configure; makeしたら通らない。ビルドしている環境はMacなのだが、調べていたら こちらのページに当たったのでその通りにしてからビルド。ちなみに←の方法はソースツリーがまっさらな状態から初めたほうがよろしいようなので、途中で間違ったら一旦ソースツリーを消して最初からやりなおすくらいがよろしいかと。その後MPFRインストールはうまくいった。

そしてここからが苦行。設定してgccをビルド。途中でラップトップを一時停止したりして中断も有ったんだけど、多分コンパイルだけで数時間かかった。面倒くさかったぁ
    このエントリーをはてなブックマークに追加 mixiチェック

俺は普通にアクセス数稼ぎのサイトだと思ってた。昔からよくあるような感じだから別に文句を言う必要もなかったし、ある意味俺にもSEO?的な効果あるから「ふぅ〜ん」でおしまいだったけど。はてブとの大きな違いはあちこちに「俺がクリップしましたよ」的な足跡が残るかどうかじゃないかね?

基本的には叩かれる必要はないと思うよ。でも上記の通り、アクセス数稼ぎだと思ってたから気をつけて見に行かないようにしてたな。
    このエントリーをはてなブックマークに追加 mixiチェック

Fuck Planet Earth

「Fuck」は動詞、名詞、形容詞、形動詞、感嘆詞、その他諸々として使える英語の言葉の中でももっとも多用な用途がある言葉なわけですが、その一部の使い方に関してちょっとだけ学べます。
    このエントリーをはてなブックマークに追加 mixiチェック

別のサーバーにMTを移動させて、ついでにMT4.1にアップグレードしてみた。コメントとか動いてんのかな。何か問題あったらご連絡のほどお願い致します。
    このエントリーをはてなブックマークに追加 mixiチェック

チームバチスタの栄光を見てきた。う〜ん。最初に期待させられたほどの落ちではなかったなぁ・・・
    このエントリーをはてなブックマークに追加 mixiチェック

Rage Against The Machineを幕張で見てきた。いやぁオジさんにはきつかったです。でもやっぱRenegadesとSleep now In The fireは燃えました。トニー最高だ。
    このエントリーをはてなブックマークに追加 mixiチェック

# 前のエントリーに加筆するとか言ってまだ書いてないのに次の事書きますが。

Tritonnの謎」で書いてたソート云々だけど、コメントをもらったので補足しておくと、sen_records_sort()で問題が解決するというのはつまり (1) sennaで全文検索するとすごい数のレコードがひっかかる (2) MySQLでいくらインデックス使おうにも、使えない量なのか、なにかそれを妨げる条件を満たしている (3) 結局ファイルソートになってしまう (4) 遅い。激重。・・・という事が起こっていたのだと思う。

sen_records_sort()を使った時には、自分はSQLとの結合とかよくわかんなかったので自分が使う最大レコード数 * 10くらいで固定してしまった(これくらいあれば大丈夫だろう、という適当な計算の元)。それでもレコード数としてはせいぜい100の単位なので、大したI/Oは発生しない。結果的にファイルソートになってるんだかなんだかようわからんが、ともかくも一瞬で終わるようになった。当たり前だが。

以上、とりあえず補足。
    このエントリーをはてなブックマークに追加 mixiチェック

滅多にコラム的な事は書かないけど、ちょっと今日は書いてみたい。オープンソースプログラマとしてソースコードのリリースをしていく上での判断の仕方について。

オープンソースソフトウェア(クローズドでももちろんそうでしょうが)を書いているとよくわかるのだが、コードというものは常に進化し続ける。関数の引数が変わったり、内部動作が微妙に変わったり。そう言った変更自体はバグの修正やそれまで想定していなかったユースケースをカバーするという命題においては常に推奨されるべき事ではある。そして、その進化し続けるコードに古いバージョンとの互換性を100%求めるのは現実的ではない。

ただしそれを踏まえた上で、我々オープンソースプログラマーは最大限自分がリリースしているソフトウェアに依存しているソフトウェアへの突然の変更を強いる事を避けなくてはいけない。これが私の主張。

例えばとあるライブラリがあったとして、そのライブラリに依存する他のソフトウェアが色々あったりするわけです。ライブラリAとソフトウェアXとでもしましょうか。XはAのfoo(int x, float y)という関数に依存してると仮定しましょう。これを、ライブラリAの作成者である自分がある日はたと「あ、これだと動かないケースがある!」と気づきます。今までの通常のケースであればそれで動いていたけれども、潜在的なバグがある。こういう場合直さないわけにはいかない。

具体的には元々
int foo( int x, float y )
だった関数のシグナチャを
int foo (int x, float y, double z)
にしたいと仮定します。

さて、ではデベロッパーである私はどうするべきか。ここは具体的にコード自体をどうこうする、というより前にまずポリシーとして「可能な限り現存の利用者のソフトウェアを壊さない」というスタンスこそが正しいと主張したい。

なぜこれを強く主張したいかというと、これがオープンソースで、誰がどこで使っているか分からないからだ。バグは存在するのかもしれない、でも関数のシグナチャのような物が変わってしまったら、それまで安定して運用できていた人達にはアップグレードする事イコール自分の今まで使っていたソフトウェアを書き換える、という事になってしまう。当然コストも発生する。

さらに問題なのは、この非互換APIがリリースされたバージョンに、他のバグフィックスが入っていた場合だ。ライブラリAを使っているソフトウェアXは、そのfoo() という関数は今まで問題なく使っていて、別に今回のフィックスでは特に恩恵を被れないのに、その他のバグフィックスが欲しい場合はどうするの?これではいくら「改良」とうたわれても、正直「余計なお世話」でしかない。しかもそれが断続的に行われるライブラリだったら使う気をなくす事請け合いだ。

だからこそ我々オープンソースに何かを提供している人達はコードの進化とリリースのタイミングや実際の変更の適用の仕方に一定のバランス感覚を持たなければならない。

前置きが長かった。じゃあ実際どうすればいいの?ということだが、そこはとにかく「ユーザーにチョイスを与える」が正しい。

例えば一番シンプルな方法では、普通に新しい関数を作る:
int foo_XXX (int x, float y, double z) /* 別にXXXはなんでもいい。"new"でもなんでも、分かりやすい名前にする */
そして、Changes(更新履歴を記したファイル)やドキュメントに、ちゃんと書いておく:
* バージョン x.xx.xxより、foo()に変わるfoo_XXX()を実装しました。 ◯◯◯という潜在的なバグを回避するにはfoo_XXX()を使用してください。 なお、foo()はバージョンy.yy.yyにはライブラリより削除されます
これだけでいい。それまでfoo()を使っていたライブラリは問題なくそのままアップグレードできる。もし新しい機能を使いたければ、ライブラリアのバージョンx.xx.xx以降に対応した新規バージョンのソフトウェアXをユーザーに特に混乱を与えずに後からリリースすることができる。

関数の名前が変わると面倒な事がある。じゃあその場合どうするか?これまた色々なやりかたがあるが、先ほど言ったチョイスさえあればいい。例えばconfigureやperl Makefile.PL時にユーザーにどっちを使いたいか聞く、という手もある。Cだと自分は手法に疎いのでちょっと具体的なベストプラクティスは思いつかないが、LL言語ならば、ビルド時に適正な方を選ぶようにする事や、もしくは暗黙のうちにコンパティビリティAPIを呼び出す事も簡単にできるはずだ。

色々と手法はあるわけだが、どの方法も駄目だったら、そこは素直に変える。でも変えるタイミング、そして下位互換のAPIを削除するタイミングは考慮を要する。Perl本体の場合のポリシーは特にメジャーバージョンじゃないと変更しちゃいけないとかそういうルールはない事が多いけど、ユーザーに対する影響が大きい場合は必ず年単位で先にアナウンスされてる。しかも具体的には

  1. MLでのディスカッション
  2. ML等でアナウンス
  3. コードに警告を発するコードを挿入
  4. バージョンアップの時に最終的に変更/削除
という手順を取ってる。まぁ言語とライブラリでは扱いは多少違って当然だとは思うが。

ともあれ、ユーザーの事を考えるとやはり警告を発するバージョン→最終的な変更が入ったバージョン、というステップを入れるのはほぼ確実に守るべきスタイルではないだろうか。

会社の都合で「アップグレードさせる」という手順を踏ませる決断をできる、そもそもオープンではないライブラリならギリギリわからないでもない。しかし「オープンソース」はただコードをオープンしているのではない。その「開発過程」をオープンにしているものだ。だからコードレポジトリが重要だったり、MLが重要だったりする。わざわざオープンソース開発をするのならいつのまにかAPIが変わるような事はしてはいけないと思うのです。
    このエントリーをはてなブックマークに追加 mixiチェック

ちゃんと写真の撮り方を知っている人が撮ると、きれいに見える、ということですね。

ちなみに最近スパムコメントが多すぎてどこに本当のコメントがまぎれてるのかわからないなぁ。
    このエントリーをはてなブックマークに追加 mixiチェック


080206_1018~0001.jpg
東京で昼間っから雪が降っていた時、ちょうど雪の降り具合が良い感じだったのでいつもバスで通勤するところを40分弱くらいかけて歩いてみた。

雪がはらは らと落ちてきて美しいのなんの。緑道があるのでそこを歩いていたら、途中で梅らしき木が!咲いてる?俺は全然そういうの詳しくないのでこれが梅じゃなかっ たりしたらすげぇ恥ずかしいんだが・・・。ともあれ、はらはらと落ちてくる雪と梅、とても良い風情で少し立ち止まって鑑賞してしまいました。

しかし写真だと全然美しくないな!本当はここで雪が降ってたんだが・・・

ちなみに雪が降っていたというだけが歩いた理由ではなく、その前の晩に結構いい感じで飲んだのがやはり良かった模様。どうも俺はたくさん仕事してがつーんと飲むと次の日も元気にやれるようだ。
080205_2158~0001.jpg
その前の晩立ち寄ったバーでこんなキャンディーをもらった。中身はただのキャンディー。しかし「どうでも医院」って・・・

ちなみに昨日373君に食べさせたけど、別にキスされなかった。
    このエントリーをはてなブックマークに追加 mixiチェック

このページのトップヘ