2009年 08月 13日

gerry++

2009年 08月 12日

gerry++

2009年 08月 06日

JSDeferred を github に

http://github.com/cho45/jsdeferred/tree/master

あるプロジェクトで submodule に jsdeferred を追加したいとか、svn のコマンドを忘れたとか、いろいろあって github に

$ sudo gem install nirvdrum-svn2git 
$ svn2git http://svn.coderepos.org/share/lang/javascript/jsdeferred --verbose --trunk trunk --branches branches --tags tags --authors ~/authors.txt  2>&1 | tee svn2git.log

authors.txt

cho45 = cho45 <cho45@...>
mattn = mattn <mattn.jp@...>
hakobe = hakobe932 <hakobe@...>
yappo = yappo <yappo@...>
drry = drry <drry@...>
kga = Wataru TOYA <watrty@...>
yoko = yksk <yoko@...>
nanto_vi = nanto_vi <nanto@...>

*.html を直接見ることができないので、 cho45.github.com プロジェクトの submodule に jsdeferred.git を追加してトップレベルに symlink をはってる。

git submodule add git://github.com/cho45/jsdeferred.git jsdeferred
for i in jsdeferred/*.html; do; ln -s $i jsdeferred-$(basename $i); done;
for i in jsdeferred/*jsdeferred*; do; ln -s $i $(basename $i); done;

gh-pages ブランチを作る方法がいまいち気にいってないので苦肉の策

やめた。post push hook で自宅鯖のフックを叩き、git clone, pull, submodule update を走らせてホスティングサービスに rsync するようにした

http://cho45.stfuawsc.com/jsdeferred/

2009年 08月 05日

はてなグループトップに最新日記を表示するグリモン

わーべんり

2009年 08月 02日

test

2009年 07月 25日

WAF の設計方法

結局、アプリケーション (not Web App = WWW 非依存) なものを Web っぽい部分とつなぐ Dispatcher (Router) があればよくて、あとはおまけっぽいので、HTTP::Engine + Router で WAF っぽい部分は終わりになるような気がした。

http://subtech.g.hatena.ne.jp/cho45/20090517/1242556113

と書いたのですが、あれを書いたときから、「そうだろうか?」というのを薄々と思っていました。Web + App ではなく、WebApp にしてしまうのもいいんじゃないかということについてです。

Web + App は大人気 Sinatora もそういう考えっぽいですが (誤解しているかもしれません)、Web というのが App へのインターフェイスの一つにすぎず、例えば CLI + App という組み合せもあるし、Desktop GUI + App という組み合せも考慮されています。ロジックのテストはしやすそうでいいですね。でも、もっと富豪的でもおこられないんじゃないかなぁとも思うのです。

WebApp の場合、Web (というより HTTP) を唯一のインターフェイスとして提供し、例えば CLI だろうが GUI だろうが、HTTP を仲介するようにします。HTTP + App, CLI → HTTP + App, GUI → HTTP + App。これは例えば GAE だと、そもそもこういう方法をとることしかできません。Cron も HTTP で特定のURLが叩かれるだけです。ユーザ向けAPIみたいなのがだいたいのサービスでありますが、それをアプリケーションのオーナーまで権限を拡張しているような感じです。

これは一昔前のシェルに入れない CGI サーバみたいな趣きがあって古い気もしますが、こうすると Web + App に比べていくつか楽をできるようになります。「楽」とは違うかもしれません。自然と良い方向にアプリケーションが進化する、という感じでしょうか。

  • バッチ処理だろうがなんだろうが、専用の CLI 環境みたいなのを考えなくても、他のハンドラと同じように書ける
  • 自然と結合テストを書くようになる
    • Web + App にすると App のまでのテストは書いても、Web 側の結合テストを怠りがち
      • 最終的にユーザがみるのは Web なインターフェイスなのだから、ちゃんと書かないとだめ
  • 自然と API に必要な機能が揃う
    • CLI から叩こうと思ったとき必要な機能が勝手にできる

一方、微妙なところもあります

  • バッチ処理しかしないサーバーでも HTTPD を立ち上げてることになる
  • 各ハンドラだけの実行をしにくい
  • テストが遅くなりがち

この辺はフレームワークでモックリクエストを充実させたら解決できます、というかちゃんとしたモックリクエストの仕組みがテストのために必須です。

[めんどくさくなったのでまた考えて追記する]

DBIx::RewriteDSN

http://search.cpan.org/~satoh/DBIx-RewriteDSN/lib/DBIx/RewriteDSN.pm

というのを作ってみました。DBI->connect に渡しされた dsn を別の場所で一括して書きかえるモジュールです。

  • dsn がハードコードされている
  • ソースコードが膨大で DBI->connect を全部探しだすのが困難
  • DB 情報を管理する Config インスタンスがない

ような場合に、それなりに安全にテスト環境を構築するのに使えると思います。

例えば

use DBI;
use DBIx::RewriteDSN -rules => q{
    (dbi:mysql:database=foobar;host=192.168.0.1) $1

    # fallback
    dbi:mysql:database=([^;]+)(?:host=.+)? dbi:mysql:database=$1_test;host=127.0.0.1
};

みたいな感じにすると、dbi:mysql:database=foobar;host=192.168.0.1 についてはそのまま繋いで、それ以外はローカルホストに繋ぎにいくようになります。ローカルにDBがなければエラーになるだけなので意図せず production に繋ぐような事故が防げると思います。

2009年 07月 24日

京都の神社を google map にプロットする

地図にマップされたやつがなかったのでてきとうに……

を元にプロット。京都府神社庁からは郵便番号 (京都市内ものだけ) をスクレイピングし、Google の geocode にあらかじめかけておいたやつを表示している (青のマーカー)。Wikipedia からは、JSONP の API を使って、神社一覧を取得し、さらにそれぞれに神社のページに埋め込まれている緯度経度情報を JSONP でとってきてる。


Wikipedia のほうは動的なので京都市以外でも

とか、カテゴリからひっぱってこれる。北海道の神社は今のところ全く緯度経度情報を持ってないのでプロットされない。

2009年 07月 16日

gerry++

2009年 07月 14日

Google App Engine がマイブームだけど、いまいち使いかたがわかってない。

datastore api って想像していたよりもずっと遅くて、普通に read するだけでも結構 CPU Time を消費してしまう (50-80msec?)。ここらへんの感覚は、デプロイしてみないとわからないのでとてもやりにくい。

hookhub.com のトップは、最近フックされたウェブフックを表示しているけど、毎回 datastore に last_hooked 的なプロパティでソートしてつつひいて、さらにそれぞれについての 10 回ぐらい user 情報をひいたりすると、それだけで GAE のログに「最適化が必要なページ」として警告がでる。

少なくともどこかの段階でちゃんとキャッシュしないといけないけど、いまいち感覚がわからない。アプリケーション内のメモリにインスタンスキャッシュさせていけばいいのか、それとも memcache をつかえばいいのか…… 普通どうするんだろ?

今のところ、view を部分的に memcache に入れるような (TT Cache みたいなの) のを入れて、とりあえず警告はでなくなった。むずかしい…… 今はソート済みクエリをキャッシュしてないけど、これも expire つきで memcache に入れたほうがよさそうな気がする。

赤のリクエストが memcache にテンプレートキャッシュするようにしたときのリクエストで、一時的に memcache api も消費したので時間がかかってる。直後から api_cpu_ms が半減しているので、キャッシュの効果はあったようだ。だけど全体としての応答時間はまだまだ極めて遅い……

ちなみにユーザ情報を index つきで一発だけしかひいてない /help の応答時間は 100msec 以下になってる。

datastore はログを見ていると、割と timeout するので、ちゃんとエラー処理をすべきだろう。今はなんもしてないので 500 がでる。