As Sloth As Possible

可能な限りナマケモノでありたい

カテゴリ: レポート・レビュー

あるいは、お遊びチーム2号は一体何をしていたのかについて

ISUCONという大変白熱した楽しいお祭を開催するにあたって、その前夜祭的な環境試験のためのチューニング祭が社内の有志数名で行われていて、そのときに色々学んだことをおまけとして書いておきます。

ISUCONて何?

下記参照。

要するに、「閲覧者視点での振る舞いさえ満たしてくれれば何をしようと構わんからWebアプリのレスポンスを改善しなさい」というお題で、誰が一番速くできるか競うイベント。

最初にある程度環境が整備されてるサーバ4台と、主催者側が用意した参考実装のアプリとテスト用データが渡される。このアプリってのはごくシンプルな個人ブログだと思ってもらえば良くて、最新記事10件が表示されるインデックスページと、記事全文が見られる詳細ページがあり、記事の投稿とコメントの投稿ができて即時反映される。全てのページには「最近コメントが付いた記事10件」が表示されるサイドバーがあり、ヘッダ画像、スタイルシート、JavaScriptが読み込まれる。テストデータにはそれなりに大量の記事データとコメントデータが入っている。フロントのWebサーバはApache、DBはMySQL、アプリはPerlとRubyとNode.jsのものが用意されている。

「お遊び組」って?

ISUCONは見学席が用意されていたのだけど、参加者以外はぶっちゃけ暇なので、空いたサーバ1チーム分を使って好きに遊んでいいことになっていた。で。そのお遊び用サーバで、事前に社内βで散々いじくり倒した俺とhidedenさんが空気読まずに自分のアプリで参加者達に対抗する、という大人気ないことをしていた。(すいません…)

一応ちゃんと言っておくと、中の人なので裏ルールや罠の存在についてある程度聞いていた上、6時間どころか2日3日費して試行錯誤していて、加えてhidedenさんに圧倒的な差を付けられた時は教えを乞うなどしていて、完全なるチートです。正直あの短時間でここまでやってくるって本当凄いな参加者のみなさん、と感動しっぱなしでした。勝手に熱くなって最後の方はムキになってたのは内緒です。

※ あ、でもでも、参加者の条件と対等じゃない「強くてニューゲーム」だった(会場に着くやいなや会社に行ってソース取って来た)という意味での「チート」で、コンテスト向けの実運用ではありえない実装にするとかはしてないです。なるべく突飛なことをせず普通にWAFを使い普通に配置するように心掛けてます。サーバのセットアップとかは手伝って貰ってるけど、アプリの実装は一人でやってるし、戦略そのものも自分で考えてます。

というわけで以下は俺のアプリで実際にやったこと。お遊び組ベストスコアを出した方とは別のアプリです。ちなみに使用言語はRuby。隣に座ったCTOと向かいに座った部長に「うちPerlの会社だからね?」とニヤニヤされながらも100%趣味全開のチョイス。「言語処理系の性能の違いが戦力の決定的差では無いということを教えてやる!」と赤くて速い人気取りで息巻いてみたものの、実際問題別な意味で全くその通りだった

糞クエリ対策とキャッシュ

殆どのチームがまずはクエリの見直しとDBのチューニングに手を付けてた様子。テーブル構造の見直しからMySQLのオプションやストレージエンジンの変更とかをやってたチームもあったみたいだけど、俺は必要なカラムにインデックスを貼る程度に留めて、データをガンガンキャッシュしてなるべくDBまで到達しないようにする戦略にすることにした。

まぁまずみんな真っ先に気付いてたところとしては、アプリ内に非常に残念なクエリがわざと仕込んであるということ。素晴しく分かりやすいお手本のような糞クエリだった。サイドバーのデータを取得するのが次のようなクエリ。

SELECT a.id, a.title
FROM comment c
LEFT JOIN article a ON c.article = a.id
GROUP BY a.id
ORDER BY MAX(c.created_at) DESC LIMIT 10;

記事が数千件、コメントが十数万件あるので、これは大分辛い。しかもサイドバーは全ページに表示されるので、全てのリクエストでこのクエリが発行されるという鬼畜さ。なので、次のように変更する。

  1. キャッシュからサイドバーに表示する記事IDのリスト取得を試みる
    1. なければ、commentテーブルから記事IDのみのリストを取得する
    2. キャッシュする
  2. 記事IDのリストを元に、キャッシュから記事データ10件のリスト取得を試みる
    1. それでも無かった数件をarticleテーブルからWHERE id INで取得する
    2. キャッシュする

あと、サイドバー・インデックスページ・記事詳細ページでそれぞれ必要なカラムだけを取って使ってたけど、これは逆にID・タイトル・本文・投稿日時全てを取得してIDをキーにキャッシュに突っ込むようにした。こうすることでサイドバーとインデックスと記事詳細でキャッシュを共有できるようになる上、コメントの投稿も記事の参照も新しい記事に偏っているので、サイドバーを読み込む時点では記事データはほぼ全てキャッシュに載っていることが期待できる。

commentテーブルから記事IDのリストを取得してるところはまだ重いと思うけど、当初のクエリよりは遥かに速いし、並行してコメントが投稿されたときの整合性の担保とかするのが地味に面倒だったので、とりあえず後回しにする。

コメントはコメントのIDではなく記事のIDでまとめてキャッシュするようにした。ページングや並べかえ、コメントの削除や編集などは仕様になく、コメントのパーマリンクなどもないので記事ページ以外では表示されないため、1回で全部取れるのがよかろうという判断。それらがあるようだったら、記事と同じようにコメントIDをキーにして「リストの順番や内容が変更されてもIDだけを取ってくるようにして、データ自体はキャッシュに載ってるものは使う」みたいにしたかもしれない。でもあんまりDBやmemcachedへのリクエストが増え過ぎるのはアレなので何らかのまとまりでキャッシュするかなぁ、とか色々考えてたけど、複雑になって余計悪化する、みたいなことにもなりかねないし、微妙に難しい。これもとりあえずこれでいいやってことにして後回し。

ノンブロッキングなフレームワーク

若干工夫してみたのは、フレームワークにはGoliathを選んだあたり。EventMachineベースのRubyのWebアプリケーションフレームワークおよびサーバで、これでI/Oを多重化して、同時接続数が増えてきても重いI/O処理でブロックしないで効率的に処理してくれることを期待する。まぁ、ぶっちゃけこれは実際にはそんなに効果なかった。

当初はPOSTのリクエストがばんばん飛んでくるとか、複数のテーブルに跨ってデータを取ってきて複雑な集約をするとか、画像アップロードみたいな長時間コネクション張り続けるようなリクエストがあるかなとか、そういう状況を想定してたんだけど、実際にはGETの比率のが圧倒的に高いしテーブル構造もシンプルで投稿はテキストのみ、みたいなパターンだったので「並列にI/O処理をする」ことがあまりなかった。

「遅延書き込みをするようにしてPOSTの際は即座にレスポンスを返してしまう」みたいなこともちょっとはやろうとしてたのだけど、「POSTリクエスト完了後1秒以内に表示に反映すること」ってルールにひっかかってテスト通らないことが頻繁にあったりして地味に嫌な感じになったので方針転換した。ここはむしろ同期処理にして「終わったら即書き込み即キャッシュ破棄」するようにして(実際には反映までにかかる時間に大差は無いはずなんだけど、こう振る舞った方がクライアント側からは速く反映されてるように見える)、POSTでは若干の時間をかけてしまってもいい、それよりもGETリクエストが来たときに既に準備が整ってるようにここで再取得再キャッシュまでやってしまう。

同時接続数の方はどうかというと、そもそもベンチマークスクリプトの並列数が最大10とかだったしコネクションも一瞬で切断されるし、じゃあワーカプロセスを10個立ち上げちゃえばいいじゃん、というオチが付いた。CPUもメモリもスッカスカでアプリサーバが遊んでたし、RubyやPythonみたいな言語を使う分には、1プロセス辺りの並列処理の効率化みたいなとこよりもUnicornの割り切りっぷりの方が現状理にかなってると思う。てことで言えばぶっちゃけ最初の素のSinatraで別に問題なかったような…どうしてもEventMachine使いたいならRainbows!Async Sinatraとかでも良かったような…まぁもう書いちゃったしいいか…。

余談だけどGoliath採用に併せて関連ライブラリも選び直すことになったので、MySQLクライアントにはMysql2を、mechachedクライアントにはremcachedを、ついでに趣味でテンプレートエンジンにSlimを使った。Mysql2やSlimは大分良かったので何か機会があれば使っていきたいところ。

Web「アプリ」って何?

とにかくもうDBに複雑なことさせたら負け、それ以前にDBに行ったら負け、と来たら次に来るのは「ていうかアプリに行ったら負け」。この段階ではフロントのWebサーバはアプリサーバ2台のロードバランサとしての仕事しかしていなくて、静的ファイルもアプリ側でファイル読んで返してたし、更新してないページも毎回アプリにリクエストが来ていた。バックエンドのアプリケーションサーバがどんなに速くなってもフロントエンドのWebサーバの処理速度とは文字通り桁が違うので、できればなるべくバックエンドに行って欲しくない。ならばということで、フロントエンドでページ丸ごとキャッシュしてGETリクエストは全部そっちで返してしまうことにする。

VCLの記述力やキャッシュ管理のしやすさ、ESI機能、あと名前のかっこよさなどが魅力的だったので、最初はVarnishを使ってみた。directorでアプリサーバ2台をまとめて、GET以外のリクエストは素通りするようにして、GETのレスポンスはページ単位でキャッシュするようにする。このままだと当然「投稿は1秒以内に反映されること」というルールが満たせないので、HTTPでパージできるように設定して、POSTのリクエストを処理したらアプリ側からVarnishにPURGEリクエストを送るようにした。

そうなると今度はキャッシュの破棄のタイミングが問題になってくる。記事の投稿はまぁいい。記事が投稿されて内容が更新されるのはインデックスページだけなので、1ページ破棄してやればいい。が、問題はコメントの方。コメントが投稿されるとまず記事ページが更新されて、「最近コメントが付いた記事10件」が表示されるサイドバーも更新される。が、このサイドバーは全てのページで表示されている。どこかの記事に1件コメントされる度に全ページのキャッシュが破棄されてたのでは殆どキャッシュの意味を為さない。なのでサイドバーは各ページのレンダリング時には生成せず、ESIでVarnishの段階でincludeさせるようにした。こうすれば、コメントが投稿されたときにパージするのは該当する記事ページとサイドバーだけになる。

そこまでやると最初の数回とPOST直後の数回以外は全部Varnishが返してくれるようになるので、アプリサーバの方は殆ど遊んでいる状態になる。前の段で「リソース余ってるからガンガンプロセス増やしちまおうぜ」って言えたのはこのおかげ。数万リクエスト処理しても数百とか数千くらいしか後ろに到達しなくて、さらにその後ろのDBまで行くのはもっと絞られてくる。この段階で初期状態から10倍くらいパフォーマンスが向上している。

ところがこの辺りで地味に嫌な罠を踏む。VarnishでESIを使うとContent-Lengthヘッダを返さなくなるので、Keep-Aliveで接続してるクライアントがいつレスポンスが終わったのかよくわからなくてタイムアウトするまで一部のクライアントできちんと扱えないのにKeep-Aliveのリクエストを送ってきたときにいつレスポンスが完了したのか判断できず、コネクションが切れるまで待ち続けてしまう。設定でどうにかできそうな気がするけど不慣れなVarnishに四苦八苦してなかなかうまくいかず、前段にもう一段Nginxを立ててリクエスト/レスポンスをいじってみたりするも今度は多段にしたのが祟ってそのオーバーヘッドで大分パフォーマンスが落ちてしまう。

結局Keep-Alive問題は真面目に対応するのをやめていかなる場合でも無効にしてしまおうかーとか考えてるあたりで、hidedenさんのNginx/SSI+SCGI構成にダブルスコアをつけられてしまって、NginxマジはえーほんとパネェつかVarnishってぶっちゃけNginxより遅いのに何で選んだの、みたいな声に負けてVarnishと戯れるのを放棄することにした。いや多分、俺のVarnish力の低さのせいで真の実力を発揮できてなかっただけでそこまでオワコンでは無いと信じたいのだけど、と一応擁護しておく。でもしばらくはNginx一択だけど。

ちなみに、ベンチマークスクリプトはそもそもKeep-Aliveに対応してないその「一部のクライアント」と同じ挙動をしていたわけではないので、この時点ではこの問題は割り切って無視するという選択肢もあった。が、本番当日の講評の際にkazeburoさんが恐しい罠を仕込んでたことを知らされる(っていうか社内では普通に話してたらしいけど聞いてなかった)。なんと、HTTP1.1じゃない持続的接続ができないのにそうできるかのように偽装してKeep-Aliveって付けた嫌がらせリクエストを3%程混ぜており、これに律儀に応えると、ベンチマークスクリプトはコネクション切れるまで待ち続けてしまって致命的に遅くなる、というもの。Nginxが素晴らしいのは周知の事実なので本番でも使ってくるチームが多いことを予想して、「Nginx(や、他の高速Webサーバやキャッシュサーバ)をチューニングせずにただ設置するとハマる罠」を仕掛けたんだとか。そうと知らずにそれを回避することに成功していて怪我の功名だった。本当運営の人達悪魔や…。

Nginxのチューニング

気を取り直してNginxの設定。まずNginxはWebサーバなので、餅は餅屋ということで静的なファイルはアプリサーバからフロントサーバに全部持ってきてNginxに返させてしまう。これでアプリから静的ファイルの配信機能を取っ払うのに成功して、本当に若干だけど無駄な処理を減らせる。リバースプロキシの設定は簡単なのでこれも普通に設定してしまう。それからVarinishのESI同様NginxでもSSIを有効にする。

それからキャッシュ。Nginxのキャッシュの方法はいくつかある。まず直感的なのはファイルキャッシュ。キャッシュファイルの置き場所を決めておいて、upstreamに飛ばすlocationのところでcacheを使うよって指定してあげれば、upstreamからのレスポンスを自動的にそこに貯めてってくれて、二回目以降は勝手にそのファイルから返すようにしてくれる。Varnishのときはキャッシュストレージにメモリキャッシュとファイルキャッシュが指定できて、ファイルの方を指定すると格段に遅くなるので、Nginxもそうなるんじゃないかと思ったけどこれが驚く程高速でびっくりする。むしろVarnishのメモリキャッシュの時より速いくらいだった気がする。ちゃんとは検証してない。ただ、このファイルキャッシュはuriをハッシュしてディレクトリに配置してしまうため、外からはどれが何のキャッシュなのか分からなくて、Varnishに比べるとキャッシュの管理が難しい、と思ってたら、ちゃんとこういうモジュール作ってる人がいた。これならVarnishのときに作ったHTTP越しのパージの仕組みがそのまま使える。

もう一つ、memcachedをまるでアプリサーバのように見立てて、pathをキーにしてmemcachedにあるデータをそのままレスポンスボディにして返してしまうという驚きのモジュールもある。こっちの利点は、アプリ側からもキャッシュが扱い易いということ。普通にアプリからmemcachedに繋いで、Nginxにレスポンスを返すときに同時にmemcachedにも書き込んでおくと、次はそっちから読んでくるようにしてくれる。破棄するのも普通にdeleteすればいい。HTTPリクエストを投げてパージするよりは分かりやすいし、memcachedプロトコルのがHTTPよりは速そうだ。が、問題は、前述のファイルキャッシュより遥かに遅いということ。これはmemcachedが遅いというよりmemcachedに毎回コネクションを張り直すコストがファイルキャッシュからの読み込み(これはおそらくかなり内部で最適化されているはず)のコストよりも高いせいらしい。ほぼ同じ状態でファイルキャッシュをmemcachedに切り換えたら、スコアが半分以下になってしまって絶望的な気分になった。仮にHTTP越しのパージよりもmemcachedのがアプリ側からは扱い易くてコストも低かったとしても、大半はNginxの段階で完結するキャッシュ済みGETリクエストなので、そっちのオーバーヘッドの方がもろに結果に影響する。ので最初はファイルキャッシュを採用した。

けど、hidedenさんの方はmemcachedを使っててそれでも俺のやつよりパフォーマンス出てるのでなんでだろうと聞いてみたら、upstreamとのコネクションを繋ぎっぱなしにしていたからだったらしい。試しにkeepaliveを設定してみたら、アプリ側何もせずに一気に3倍くらいのスコアになってhidedenさんのスコアに肉迫するレベルになった。同じことを当日もやらかした。hidedenさんが毎分11万リクエストというハイスコアを出した一方、前日まで大差はついてなかった俺の方は3万程度しか出てなくて焦ったのだけど、nginx.confを見直してkeepalive付け忘れに気付いて再起動したらちゃんと動いた。

で、結果はというと、ギリギリ100000req/minを越えるくらい。「お前はチートしてそれかよショボいな」と言われないくらいの結果は出せたと思うのでちょっとホッとした…。

この戦略の意味

POSTよりGETが圧倒的に多く、大半のリクエストが新しいデータに集中し、一度書き込まれた投稿はその後はあまり書き換えが起こらない、というのは、「大部分がほとんど書き換わらない動的コンテンツ」ではなくて「一部分が書き換わることがある静的コンテンツ」だと思っちゃえば少し話が簡単になる。

GETリクエストなんか静的なHTMLファイルを自動生成するためのトリガー、くらいに考えて、ただそれがファイル書き出しじゃなくてメモリ上のキャッシュに突っ込む方が扱い易いよねって発想で行けば、どんなミドルウェアが欲しいかとか、アプリは何をするべきなのかとか、どこで一番頑張るんだそうかフロントのWebサーバか、みたいなことでやることが決まる。てか、どっか1チームくらい本当にHTMLファイル書き出してデプロイしちゃうとこ無いかなーとか思いながら見てた。多分それはそれで速い。絶対面倒なのであまりやりたくは無いけど。

もっとぶっちゃけ話をすると、ライブドアブログの閲覧側チューニング戦略が(実現してる方法は違うけど)大体この形なので、ページのキャッシュと更新の局所化は最初からやる予定でいた。アプリエンジニアの性でついついアプリいじりに時間を割きたくなっちゃうとか、ミドルウェアやサーバ管理の知識経験が致命的に不足していたので時間ばっかり食ってしまったとか、ってのが「時間内には終わらなかったけど最終的には出来た」の実情だったりします。アプリエンジニアは常日頃からそういう知識をちゃんと収集しておけ、あとインフラチームと仲良くしておけ、色々捗るぞ、というお話でした。

上手く行かないケースと使い回せるテクニック

ブログ型の単純な表示系のリクエストが多いお題だったからWebサーバの性能が結果に直結してたけど、更新系のリクエストが多くて条件によって表示要素の個数や種類が大きく変わる、みたいな場合だと今度はアプリやDBの方に比重が移ってくる。例えばTwitterのサブセットみたいなのがお題だったらまた全然結果が違ったはず。

データのキャッシングやSSIみたいな仕組みはその場合でも有効だろうけど、「Nginx置いたらパフォーマンス20倍になったwwwwマジうめぇwwwwアプリ関係ないwwww」みたいなシンプルなことにはならないので、そっちの場合はアプリの実装力を鍛えてないと死ぬ。ISUCONに「部門別」とかあったら面白いかもねーとか思ったけど準備する側が死にそうなので軽々しく言うのはやめときます。僕お手伝いって名目なのに普通に遊んでただけでほんとごめんなさい。

反省点とか

DBロクに見てない。上位陣の方々見てるとMySQLバリバリチューニングしてるので、もっとちゃんといじればもう少し速度出るはず。一番効果が高いところを優先したと言えばそうだけど、あんま詳しくないところを放置しただけだったりもするので(アプリの全面書き直しとかマジで要らんかった)、ちゃんと勉強する。

みんなもやってみるといいよ

ISUCON運営チーム謹製のベンチマークツールと各言語の参考アプリは公開されてるので、是非触ってみてくだしあ。ゲーム感覚で楽しいし、各参考実装や意図的に仕込まれてる罠は、新人教育なんかにもうってつけだと思う。ええはい。自分の実力不足をガチで痛感した次第です。いや本当勉強しよう。ちゃんと。

「スマートフォンについて何か喋ってよ」というかなり大雑把なネタ振りをされたので、第五回ライブドア・テクニカルセミナーでこんな感じの話をしてきました。

あとで動画や資料は公開されるはずですが、大変申し訳ないことにテンパりまくって見るに耐えない感じになっちゃってると思うので、一応何を言いたかったのかを補足しておきます。

iOSとAndroidは違うものだという話

開発環境の違いについてはまぁいいとして、例えばアプリの設計思想。iOSでは「まずアプリケーションという大きなプログラムがあって、その中で画面を表示したり通信したりしてる」って感じの構成になってるのだけど、Androidの場合「画面とかデータ管理機能とかそういう独立した部品があって、それらをまとめたものに名前を付けてアプリケーションという風に見せる」という感じになっていて、後者の方が若干まどろっこしい感じはある。一方でアプリ間でのやりとりについて考えてみるとiOSでは「openURLで他のアプリを起動する」とか「Keychainだとかアルバムだとかを使って(限定的に)データを共有する」とかその程度に留まっているのだけど、Androidの場合はOSが提供する機能も同じアプリ内の機能も他のアプリの機能も全て「部品」という形になっているので、きちんと設計しさえすればデータや機能をシームレスに連携させられて大分可能性が広がる。この考えかたの違いはアプリの作り方の違いにモロに出てくる。

それから、デバイスの違い。iOSの場合はiPhone/iPod touch系とiPad系の二系統しかなく、どちらもApple一社が開発しているので、OSや周辺サービスも含めたプラットフォーム全体のコンセプトから良くも悪くも外れない。一方のAndroidはと言うと、Googleが主導してはいるものの、端末メーカー各社それぞれがOSにカスタマイズを加えてたり、独自のハードウェア(キーボードが付いてたり、先行してFeliCa対応してたり、裸眼立体視ディスプレイが付いてたり、そう言えばゲームのコントローラが付いてたりするようなのも出るんだっけ?)を搭載してたり、小さな画面のものがあったり、横固定だったり、多種多様だ。ハードウェアの違いがソフトウェアに影響を与えないわけが無く、「使い易いアプリって何?」って問いの答えはiOSとAndroidでは当然違うし、Android端末間でも異なってくることもある。

ここまでは技術者視点だけど、当然ビジネス的にも文化的にも異なる展開をするだろうね。と、いうことを考えたら、アプリの企画や開発をするのに「iOSとAndroidは違うもの」って認識は当然持っておく必要はあるだろう。

iOSアプリとAndroidアプリはどっちが作り易いか

率直に言うと、最初のとっつき易さに関して言えばAndroidの方が圧倒的に上。僕の元々のお仕事はPerlやRubyでWebアプリケーションを開発することで、今もアプリ作りのかたわらWebやってるのだけど、そういう人が、ObjCとXcode/IBでアプリを作りクローズドなプラットフォームでお仕事するのと、JavaやJVM上で動く言語とEclipse+ADTでアプリを作りオープンなプラットフォームでお仕事するのとで、どっちが大変かなんてのは言うまでもない。

で、だからAndroidのが素晴しいって話になるのかというとそれはそれで違うんだよってのが、無茶苦茶RTされまくってハッシュタグを埋めてしまった件のスライド(本当にすいませんでした!)の意図。「最初は薔薇色の世界に見えるAndroidも作り続けて行くと段々難しさに気付いていく」「最初はとても理解できないと思ったiOSも作り続けて行くと良さに気付いていく」「だからつまり、最初のとっつき易さだけでどっちかが圧倒的に優れていると言えるわけではない、最初のハードルを越えたら別の問題が見えてくる」っていうのを(一部の人には)視覚的に分かってもらえるように、と思ってあのイラストを入れたんだけど、前日にまどか☆マギカの8話を観て「正直やりすぎた」と反省はしました。あのスライドを見て「きっとこの人はAndroidよりiPhone派で、あと赤い子が好きなんだろう」ってコメントしてる人がいて、いやうん割とその通り(「杏子に『食うかい?』って言ってもらう」ことを願って白い獣と契約しかねないです)だけど、いくらなんでもアレに例えなきゃいけないほどAndroidを悪くは思ってない。Androidが孵す卵はもう少し夢のあるものだって信じてますし、iOSのあの林檎を輝かせ続けるために何が犠牲になってるかに思い至らないわけでもないですし。

魔法少女の話は置いといて、じゃあその「別の問題」ってなんなの、という話でいうと、まず一つはマルチデバイス/OS対応。Androidは自由度の高さが最大の売りだけど最大の欠点でもあって、Androidに取り組んでるところは軒並「端末やキャリアによってお約束事が違い戸惑う」とか「バージョンアップしない端末があってどのバージョンのOSを対象にするか迷う」とかそういうことに悩んでいる。正直、Android開発に関わってない人が想像してる以上にデバイスごとの差異が大きいし、今後収束するどころかもっと個性的なものが増える方向に進むだろう、だってそれが一番の売りなんだから。それに真面目に対応していくことの面倒臭さは、iOSアプリの最初の学習コストを上回ると思う。iOSだってもちろんiPhoneとiPadで両対応ってのは凄く大変だし、最近はケータイだと思って買っていくので家にパソコンも無くアップデートしないみたいな人も増えてると聞くので、その問題からは無縁じゃないんだけど、それでも現時点ではAndroidよりは幾分マシだ。

それから、パフォーマンスチューニング。いくらスマートだスマートだって言ったって所詮はモバイルデバイスなので、タイトなリソースをやりくりしていかなきゃいけない。今まで組み込み機器やローレイヤーなところの開発をしてた人からすれば「何を贅沢な」「ゆとりめ」と冷笑されそうな話だけどさ。スマートフォンアプリに求められる「リッチさ」はどんどん上がって行く一方だけど手持ちの戦力は高性能な戦闘機と言ったところで、その気になれば空母の艦隊を投入できるサーバサイドの開発とは全然違う。これに関して言えばiOSでもAndroidでも同じで、そういう段階に至ったらどっちにしてもそれなりに「難しい」。

クロスプラットフォーム開発に関して思うこと

きっと伊藤直也さんが肯定的な文脈で言及するに違いないと思って(実際してた)内心ビクビクしながら話してたんだけど、どうしても言わざるを得なかったので言ってしまった。一つのコードで両方のプラットフォームに対応するのは、現時点ではあまり現実的じゃないと思う

もちろんアリだろうと思ってる領域もあって、例えばゲームエンジンみたいなものは、凄く効果が高いと思う。最近は一般的な携帯ゲーム機向けのものと同じくらいのクオリティの高いゲームがどんどん増えてるけど、ああいうのは大概UIから自前で作ってしまうし、中のロジックもiPhoneだからAndroidだからということも無いだろうから、細かい差異はライブラリに吸収させちゃうのが定石だろう。それから、コアな部分をHTML5+JSで作って、ブラウザ上でできないことやパフォーマンスが必要なことをやらせるためにネイティブのUIでWebViewをラップする、というハイブリッド戦略も良いと思う。SNSとかブラウザゲームとかだと期間限定のイベントがあったり速いペースで機能改善していったりする必要があって、それで言うとアプリ開発して(iOSならAppleの審査を通して)ユーザにアップデートしてもらう、というプロセスを通すと遅すぎて全然上手くいかない。うちで作ってるアプリだとロケタッチとかは部分的にそんなアプローチをしてるし、今後そういうアプリも増えると思う。

懐疑的なのはトランスレータとかミドルウェアとかの話。Titaniumとかが盛り上がってるのはもちろん知ってるし追ってるけど、最近だと「一つのコードで両方のプラットフォームに対応」みたいな話より「iPhone(or Android)のアプリ開発を楽にする」って文脈で語られることのが多くなってきてるかなーという印象を受ける。まだまだ発展途上でどっちかのプラットフォームのサポートは手厚いけどもう片方は追いついてないだけで、今後は次第に改善していくだろう、ってところもあったりするんだけど、それとは別に個人的には「これだけ"違い"があるんだから、無理して同じ扱いをするよりそれぞれに合ったやりかたをした方がいいんじゃないか」って思ってる。特にツール系のアプリはそうで、それぞれにUIのお作法があるのでちゃんとそれぞれの特性を活かしたUIにした方がよくて、そうなったときに内部のロジックだって無理に同じにしておくより別プロジェクトにしておいた方がかえってメンテしやすかったりする。将来的にどうなるかは分かんないけども、今現在両方のアプリを作ってての実感としてはそんなところ。

というところまで書いて

そんな話が全然出来てなかった自分の話下手っぷりに絶望したのでもう少し練習しないとな、と思いました。あたしって、ほんとバカ。

謝辞

キュゥべえドロイドくんはSENさんに、杏子の林檎はニチロさんに描いてもらいました。素敵なイラストありがとうございました!

ニンテンドー3DSの体験会があるから行かないかと友達に誘われたので、今日は朝から幕張メッセまで行ってきた。恐しく混んでてろくに遊べないんじゃないかと不安だったんだけど、タイミングが良かったのか案外しっかり触ってこれた。体験したのはSTEEL DIVERとARゲームズとnintendogs+cats。ゼルダやMGSはまぁ、流石に長蛇の列で映像を見るだけに留めた。パルテナの鏡かパイロットウイングスかどっちかは試しておけばよかったなぁとちょっと後悔。んでまぁ、総合的な感想としては、予想してたより面白いデバイスで好感触。

裸眼立体視ディスプレイ

3DSというくらいなので目玉機能なわけだけど、思ったことは二つ。「かなりちゃんと3Dしてるし、綺麗」「んでもまぁ、面白い映像だなーっていうくらい」。

実はこないだ誘惑に負けてLYNX 3Dを買ってしまったんだけど、個人的にはこれよりも立体感あるなぁと思ったし、ディスプレイそのものも現行のDSより大きく綺麗になってるので映像は良かった。

一方で、3Dテレビや3D Androidのときも思ったんだけど、「おおすげー、3Dだ!…確かに凄いけど、凄いんだけど、それで?って感じだなぁ…」という印象は拭えなかった。面白い演出は出来るようになるんだろうけど、ゲームそのものには(今までとまるで違うというほどには)影響しなさそうというか。見え方にも個人差があるし(ガチャ目や乱視持ちにはちょいキツい)、結構目や脳にかかる負荷もあるし、映像展示の方で色々見てたらソフトによって大分差が出てたし、3Dオフにしてもちゃんとゲームできないといけないし、というわけで、まぁぶっちゃけオマケ感は否めない。本当に立体映像でゲームががらっと変わるとしたら、やっぱり本当に立体投影できるようになるまで待たないとなんだろうなぁと思った。

モーションセンサー、ジャイロセンサー

個人的におっと思ったのはこっちの方。STEEL DIVERの潜望鏡モードやARゲームズでは「3DS自体を動かす」というのがゲームの操作の一部になってて、これがかなり良かった。これとあとスライドパッド(アナログスティック)が追加されて、タッチパネルやフロント/リアカメラと合わせれば携帯ゲーム機としては「入力手段」がかなり多いデバイスになるので、それこそゲーム性にかなり影響してくると思う。

特にARゲームズ!twitterとかでも行ってる人が口を揃えて「ARゲームズ面白い!」って言ってたのが分かると思うけど、実際これが大分良かった。ゲーム自体は他愛のないもので、机の上に置いたマーカを3DSのカメラで認識すると、そこに的やらドラゴンやらが出てきてそれを撃ったりして遊ぶ(体験版なのでそれだけだったけど、実際にはもっと色んなミニゲームが入るとのこと)というものなのだけど、マーカを置いてる机ごとぼよんぼよん波打つのを上から横から狙いを付けるとか、ドラゴンの背後に回り込んで背中を攻撃するとか、「ゲームの演出として」ARとモーションセンサーをしっかり組み込んでて、拡張現実で遊ぶってのはこういうことだよなーと思わせるものだった。

ていうか、一応スマートフォンアプリの開発者のはしくれとしては、「何でこれをiPhoneやAndroidで先に"ちゃんと"やらなかったんだろう…」と大分反省した。モーションセンサーとカメラが付いててOpenCVやARToolKitを使えてある程度の処理性能があるデバイス、もうあるのに、ね。

ステージイベント

ゲームミュージックライブがとても良かった。ジャズアレンジのマリオやゼルダがすごく素敵で、もし明日明後日行く人がいたら、12:30からライブなのでそれに間に合うように行くことをおすすめする。並んで待ってる間に演奏を聴けたので、退屈せずに待ってられた。ちなみにステージイベントの様子はインターネット中継されてるようなので、ストIVやバイオのソフト紹介とかを見たい人は時間を確認して見てみるといいですよ。

全然関係ない話

隣でペット博をやってたらしく、会場付近にはそこかしこにnintendogsじゃない本物のdogsが走り回っていて、一旦外出て休憩してる間に凄く和んだ。うん、本当に全然関係ない話。

まぁなんだ、本来なら書くべきことは一杯あるんだけども、眠くてまとめてる時間が無かったので、これだけ書いておきますね。

eval(%w(eval(a="eval(%w(b=[35,35,35,
32,34,69   ,11   5,1   11,116,101,1,
14,105,9   9,  32,79   ,98,102,117,
115,99,9      7,116,   101,100,32,82
,117,98,   121,32,80   ,1        14,11
1,103,11   4,97,109,      109,1   05,
110,103,   34,32,105     ,115,3   2,103,
11   4,1   01,97,116   ,  33];p   uts
(b   .pa   ck('C*'))   ).        join)
;printf(\"eval(a=%p)\n\",a)")).join)

うん、あれだね、中途半端なのはよーく分かってるんだ。日本語で出したかったしちゃんと2回目以降も整形されたコード出すべきなんだけど、えーと、RubyKaigiが終わったら真面目にやろうとは思うんだ。衝撃を受けたって気持ちだけでも伝わるといいな。

表題通り日本Ruby会議2009に参加してました。一日目は参加できず、二日目の午後は途中から抜けなきゃいけなかったりでちょっと勿体なかったんですが、それでも本当に楽しかったのでつらつらと感想を。

まず何より先にスタッフに感謝です。今年もあの規模のイベントを回すのは本当に大変だったと思うんですが、どのスタッフの方もフレンドリーだし丁寧に対応してくれて、何よりみんな本当に楽しそうにしてたのが印象的でした。いいなー。本当にお疲れ様でした。

Reject懇親会

一日目は仕事で抜けられなかった&懇親会のチケットも買ってなかったので、Reject懇親会に参加。なんかみんな同年代な感じだったかな。RubyKaigiに集ってるのに「Scalaやろうぜ」「Objective-Cやろうぜ」とかそんな話したりしてたw

二日目以降も@repeatedlyや@kodukiたちと一緒に回ることが多かったけど、楽しかった!特に四国とか関西とかから来てる人達とは普段中々会うこともないので、貴重な機会に会えてよかったです。

Matz例外処理される

まつもとさんが遅刻して朝来なかった上、名札を忘れて受付で足止めくらうという事件に会場爆笑。Rubyに例外処理があって良かった、これで例外が捕捉されてなきゃRubyKaigi自体がセグフォで終了してたとこですね、わかります。

MacとRubyの話

三日目の午後は3会場のうち一つが、全部Mac絡みのセッションだったのでずっとそこにいたのだけど、予想以上に人多かった。RubyCocoa/MacRubyの注目度の高さに驚く。それと、iPhoneでRubyCocoaを使うセッションにいた人達のiPhone所有率が異常だった。会場のほとんどの人達が手を上げてるし。iPhoneのセッションだから当然ちゃ当然だけど。

MacRuby 0.5の話はとても面白かった。スピーカーのヴァンサンさんが言ってた通り、今0.5を使うのは「クレイジー」としか言いようがないんだけども、LLVMをバックエンドに使ってAOTコンパイラを持ってるとか、YARVをやめてVMを独自実装するとか、野心的な試みが多くて追ってると楽しい。まぁ、0.5俺の環境ではコンパイル通らなかったんだけどね…。

しかしこんだけ需要あるなら来年に向けてMacRubyネタでも用意しとこうかなぁ。実践MacRuby。

RejectKaigiに参加した

なんと勢いでRejectKaigiに参加してしまった。しかもネタはDT。去年は小さい方の会場で片付けが進む中2トラック同時進行、みたいなカオスな状態でやってた記憶があって、あれならなんとかいける、と思って参加したのだけど、今年はメイン会場でClosingの後そのままRejectに突入。うそん。すげーでかい会場なんですけど。なんかみんな全然帰らないんですけど。数百人いるよ、人。gkbr。

緊張のあまりうまくできた自信が無いけど、まぁ予定してたこと全部喋れたしそこそこ笑ってもらえたし、初舞台にしちゃ上出来でしょうか。うひー。みんなあれだぞ、あのプレゼンに対する賛辞の言葉は「これはひどい」だぞう。もっと罵声を浴せるべき。

ところで、終わったあとなんとyharaさんに声をかけられました。著者だ!著者の方が!せっかく面白い本なのにあんな形で使わせてもらってスイマセン!って気分でしたが、「あの本読んで自分で言語作ったって話、実はあんまり聞かないんですよねー」と。どうやら喜んでもらえてた様子。よかった…。「Rubyで作る奇妙なプログラミング言語 ~Esoteric Language~」、本当に面白いのでまだ読んでない人は買うと良いと思います。そんでオレオレ言語を作るといいと思います。俺でもできるんだから簡単です。

来年は

今年もとにかく楽しかったので、来年はもっとコミットできたらいいなと思った。それがスタッフなのか、またLTでもやるのかはわからないけど、お祭りは自分も中に飛び込んだ方がきっと楽しい。RubyKaigiだけじゃなくて、もっとRubyの中に踏み込んで行きたいなぁ、なんて思ったり思わなかったり思ったり。

昨日のネタではRackで簡単なアプリを作ってそれを複数立ち上げたThinで動かしつつ、表のApacheからmod_proxy_balancerで適当にプロキシしてやるって構成にした。Railsとかでもよくやるので慣れてるし、扱い易いので好きな構成だ。

ただ、今回の遊びでちょっとやってみたかったけことがある。何かというと、Passengerの導入。mod_railsとかmod_rackとか呼ばれてるアレ。スタンドアロンのサーバではなくてApacheやnginxに組み込んで使うタイプで、パフォーマンスもそれなりに良いし使い易いという話を聞いてたので気になってはいた。でもRails使わなくなってからなかなか試してみる機会がなかったので、この際ついでだ、とやってみることにした。

設定は簡単

インストールについてはPassengerのページでも見てもらうとします。別に何のことはない、gemからインストールできるし、俺が借りてるサーバ(OSはUbuntu 8.04)ではapt-getでさくっと入った。

んで。例えば、次のような構成のRackアプリができてたとする。もちろんこの状態でrackupすれば普通に動くのが前提。

/var/www/rackapp
         |
         +-- config.ru
         |
         +-- lib/
         |
         +-- view/

で、rackapp.example.orgってのでアクセスすると上のアプリに処理が移るようにしたいとする。まず、/var/www/rackapp以下にpublic、tmpってディレクトリを作る。publicはhtmlとかcssとかの静的ファイルを置く場所。tmpには、あとで説明するけど、restart.txtってのを置いておく。こうなる。

/var/www/rackapp
         |
         +-- config.ru
         |
         +-- lib/
         |
         +-- view/
         |
         +-- public/
         |
         +-- tmp/
              |
              +-- restart.txt

そこまで用意できたら次はApacheの設定。

<VirtualHost *:80>
ServerName rackapp.example.org
DocumentRoot /var/www/rackapp/public
RackBaseURI /
</VirtualHost>

これだけ。実にさっぱり。特に指定をしなければこれでRACK_ENV=productionでアプリが起動する。色々細かい指定はできるけど、まぁそれは必要になったときにいじればいいよねとりあえず。あと、アプリの修正をした場合はいちいちApacheを再起動しなくても、

$ touch tmp/restart.txt

とかやってrestart.txtのタイムスタンプを更新してやるとPassengerがアプリを再読み込みしてくれる。うわーいできた。なんだよマジ簡単じゃんよー、とか思ってたら甘かった。

な、何も出ないぞ…。

早速これでブラウザからアクセスしてみたら、全く何も表示されない。なんだこれ。config.ruでRack::Lintをuseしてるんだけど、ログ見たらそいつが何か警告出して処理を止めてる。うーん、だけど、全く見に覚えのない警告なので、困惑しつつRack::Lintを外してみる。案の定エラー出て落ちる。どうやら見てると、アプリのcallメソッドに渡されたenvからRack::Requestを作るときにこける様子。なになに、env['rack.input']にrewindメソッドが無い…?

色々調べてたら、Rack::RequestはrewindできるIOオブジェクトが必要なんだけど、PassengerはrewindできないIOを渡してくるらしい。Rackの開発グループでも議論になってる様子。これRackベースのWAFとか作ってると結構致命的だよなー。

rewindが無いと駄目なら、rewindできるオブジェクトにしちゃえ

とまぁつまりそういう話なわけですよ。Passengerが渡してくるIOオブジェクトがrewindできないなら、rewindできるIOオブジェクトに変換するなりラップするなりしてしまえばいいや、と。やっぱり同じこと考えてる人もいるみたいだし、そもそもその人が何を参考にしてるかというとRailsのActionControllerの実装だったりする。というわけで、それにならってとりあえずこんなミドルウェアを作ってみた。

# netakit/rewindable_input.rb
module NetaKit
  class RewindableInput
    def initialize(app)
      @app = app
    end
    def call(env)
      unless env['rack.input'].respond_to?(:rewind)
        env['rack.input'] = StringIO.new(env['rack.input'].read)
      end
      @app.call(env)
    end
  end
end
# config.ru
require 'netakit'
require 'netakit/rewindable_input'

use NetaKit::RewindableInput
use Rack::CommonLogger

map '/resource/kanojo' do
  run NetaKit::Resource::Kanojo.new
end

NetaKit、はfaultier.jpで動いてるアプリのnamespaceなので特に気にしない方向で。まぁこんな感じにしてやると、rack.inputがrewindできないIOだったときはStringIOに変換してからアプリに渡してくれるようになる。やってみたらこれでちゃんと動くようになった。まぁこのままだと入力を使う使わないに拘わらず(例えばRack::Responseを生成せずにenvを生で扱い、かつinputを読む必要のない処理だけをやるようなミドルウェアとかを通してるときにでも)毎回inputをreadしちゃってアレげなので、ちゃんとやろうと思ったら何かのオブジェクトでラップしてやって呼ばれたときに変換かけるようにする方がいいかも。例えばさっきのCloudKitだとこんな風に実装してるとか。まぁ、上に書いたのでも動くっちゃ動くのでお試し程度なら十分だけど。

お手軽感は確かに

というわけで意外に手間どったPassenger対応だったんだけど、rack.inputの問題を除けば簡単に設定できて中々良い。立ち上げるプロセス数の調整とかもApacheが勝手にやってくれるわけだし、静的ファイルはアプリ通さないで返すようにするのにも特に設定が要らないのも楽だ。動かすのがApacheだけなのも余計なこと考えないで済むしいいな。

そういえば、一応参考程度にApache BenchでPassengerとThin+mod_proxy_balancerとのパフォーマンス比べてみたんだけど、ぶっちゃけ殆ど差はない。と言っても/resource/kanojoにひたすらGETリクエスト送っても殆ど静的なレスポンスを返すだけなので本当に参考程度。同時アクセス数を増やしてみたら若干数値が違ってたけど、Thinの立ち上げてるプロセス数次第で変わってくるだろうし、どうせ実運用になるとPassengerの場合でももう一段フロント立ててごにょごにょやるだろうからなぁ。RailsとかMerbとかでがちっとアプリ組んで、mongrel、lighttpd、WEBrick、fcgiとか色々試してみないと何とも言い難い。個人で作ったものくらいだったらPassengerのがやること少なくてお手軽かも、くらいには思った。あとまぁレンタルサーバだったら各自アプリケーションサーバ起動させるとか許さないだろうけど、Apacheに組み込めるんなら入れといてくれるところとかありそう。まぁ正直どっちでもいいな。とりあえずしばらくPassengerで運用してみよう。

あんま関係ないけど

rack.input問題調べてる最中に偶然辿り付いたCloudKitがちょっと気になる。面白そうだし、atomserver作るのに参考になりそう。あとでいじってみよう。

エンジニアの未来サミットというのに行ってきた。ちょっと前に色々ととある界隈を騒がせたいわゆる「10年泥」に対抗して、重鎮だか文鎮だかじゃなくて俺らギークがこんな風に働いてんだぜって学生達に見せてやろうぜ、ってひがやすをさんが言ったのがきっかけで企画されたイベント、ということだったのだけど、まぁその感想をぽろぽろと。

学生少なくねーか

予想はしてたんだけど、参加者の平均年齢が高い。20代後半から30代前半くらいの人達が半数以上を占めてて、学生も含む24歳以下(それだって多分社会人の方が学生より多かったんじゃないかと思う)は割合的には確か1/4かもっと少なかったように記憶してる。…まーね、多分ね、重鎮のお話を聞きにいくような層の学生達がひがさんや弾さんにどれだけ釣られるかというと、そりゃこないだろーなーとは思うけどねぇ。Ustでも流れてたので地方にいて来れない学生とかはもしかして見てたかもしれないけど、そもそもそういう連中は「IT業界は泥まみれだ」と思ってなさそうな気がするので、果たして「10年泥に対抗」できてたのかは微妙だなーと思わざるをえないかなぁ。

第一部で壇上にいた学生の他にはそれっぽい人をあんまり見かけられず、まぁ迎え打つアルファギークの方々が濃いのもあってか「学生とギークガチバトル!」みたいな状況にならなかったのが残念。俺は終ったら一緒に来てたid:poohtarouと飯を食って帰っちゃったので知らないんだけど、学生達と一緒に飲む機会はあったのかなぁ。あったのならいいけど、なかったのなら是非そういう機会を設けてあげて欲しい。ひがさんも定期的に飲み会を開くと言ってたし、パネラーの人達もそういうのを企画しても良いと言ってたので、学生はそういう機会に直接話を聞けばいいと思う。きっと面白い。そう言えば社会人になる直前に高井さんに説教してもらったなーとか思い出した。

IT業界(笑)は光も闇もあると言うことと、泥を被ること

学生がいようがテーマがなんだろうが相変わらず炸裂する弾節とか、それを黙らせてしまうよしおかさんの大人っぷりとか、ひがさんのタンクトップ姿とか、はてな人気すぎとか、にぽたんさんの「残糞感」とか、まぁ色々あったわけだけどその辺は誰かが書くと期待して華麗にスルー。今日の登壇者の人達が学生に伝えたかったメッセージって何だったのかなーと勝手にまとめてみたい。

  • 別に泥の中で不毛に藻掻いてるばかりがIT業界(笑)じゃない。俺達は好きで好きで仕方なくてこんな仕事してるぜ。
  • とは言えIT業界だからっていきなりスーパースターになれるわけじゃない。10年とか泥の中でとかはともかく、何であれ下積みの時代を経る必要はある。
  • 良い会社を選べなければ泥の世界なのは事実。また、自らを鍛えたり思い切って冒険したりする勇気が無ければ得られないのも事実。
  • それは「業界が悪い」じゃないだろ、自分の人生に責任を持つのは自分だろ。そこを履き違えちゃいけない。
  • まぁ、多重下請け構造とかそういう構造的な問題があるのもまた事実。自分達は「そうでない形」を模索してるし、そういう会社に人が流れることによって打破されるべき連中が淘汰されて欲しいと思い努力はしていく。

こんなところかなー。まぁ第一部のメンツを見たらわかると思うんだけど、途中で比較的マッチョなお話になってIRCとかでもすかさずつっこまれてたけど、たださ、「自らが動かなければ欲しい物が得られない」のはどの業界行ったって一緒じゃねーかな、とは思う。映画監督になりたい友人とかいるけど、そいつの話を聞くに俺なんかとは比べものにならない努力をしてる。じゃあ公務員なら誰がなっても安泰?金融業界なら誰が行っても金持ちになれる?違うよな、と。今日のパネラーの人達だって決して与えられた環境で安穏としてたわけじゃないし。で、彼らが何が見せたかったのかと思ったときに、きっと「自分がどうしたって絶望しか待ってない構造があるなら問題で、実際のところあるところにはあるけど、ないところもあるし、変えることもできる。だって俺らができたんだぜ、少くとも『不可能』ではないんだ」なんだろうと思う。当たり前の結論ではあるけど、それは知っておいて欲しいよな、と思う。

一応この世界に踏み込んだひよっこエンジニアの俺から言えるのは、「コード書くのが大好きな人にとっては絶望しか待ってない世界、なんかじゃないよ」ってこと。やろうと思えばやれる道はある。第一部が終わった後、うちのディレクターの人と弾さんとタバコ吸いながらちょっと話したんだけど、そんときに言ってた弾さんの言葉がちょっと印象的だった。IT業界は比較的若い業界だから、もしかして学生は明確なキャリアパスが見えないことが不安なんじゃないか、って話になって、それに対して弾さんは一言「無いから魅力的なんじゃないか」って。それは全くそうだと思う。第二部のラストでも「未来は作るもの、自分が作りたい未来を一緒に作ろう」的なことをgothedistanceさんとyoshioriさんが言ったけど、そう、作れるんだよ。用意されてんじゃなくて自分で作っていい。それって凄く魅力的なんだけどなぁ、俺にとっては。そうじゃない人がいるのも知ってるけど、さ。それを楽しめる人にとっては決して泥ばかりの世界じゃないよ。

あとは、自分で見てみればいい

もう一つ。学生にとってみれば「IT業界がどんなことやってるのかよくわからない」と言われ、企業側にしてみれば「どうやってうちのことを学生に伝えればいいかわからない」と言う。わかんないなら行ってみてこいよ、と思うのですよ。

比較的大きい会社ならインターンとかやってるわけだし、中小ベンチャーだってそこら中でアルバイトの求人出してるわけで、就職活動の時期になって始めて「IT業界って何してんの?教えて、エロい人!」なんて言うくらいならどこでもいいからどっかで働いてみればいいじゃんか。実際何個か回ると泥の臭いも少しは嗅ぎ分けられるようになるし、経験ある方が無いより有利だよ。採用時もそうだし入ってからも。学生の間なら泥につっこんじゃっても「辛いんで辞めます」って簡単に言えるし、うまいこと良い会社に潜り込んだらそのまま社員登用してくれるかもしれないし。企業側も積極的に学生呼べばいいじゃん。知って貰うには一緒に働くより効果の高い方法はないと思う。とまぁそんなことを思いました。以上。

関係ないけど

大変自重しないコメントしてたハチロクって俺じゃないからね。

livedoor クリップのadd/editの画面をちょっと変えました。既にコメントが付いてるページをクリップしようとすると、追加/編集画面でコメントが読めるようになります。

それはそれとして、画面の要素が変わったのでそれに何か手を入れるグリモンが動かなくなってるはず。とりあえず俺も愛用してるlivedoor clip cross postも動かなくなったので、ちょっといじってみた。

addForm : function(){
    var elem = document.getElementById('addclipsecondbox');
    var html = '<tr>'
             + '    <th>Cross Post</th>'
             + '    <td id="enableCrossPost"></td>'
             + '</tr>';
    var dummy = document.createElement('table');
    dummy.innerHTML = html;
    elem.appendChild(dummy.childNodes[0]);
},

こうなってるところを

addForm : function(){
    var elem = document.getElementById('AddClipsBox').childNodes[1];
    var html = '<dl class="NormalLIst">'
             + '<dt>Cross Post</dt>'
             + '<dd id="enableCrossPost"></dd>';
    var dummy = document.createElement('li');
    dummy.innerHTML = html;
    elem.appendChild(dummy);
}, 

こうすることで、動くようになります。クリップメインではてブやdel.icio.usにクロスポストしてて、「livedoor clip cross post動かなくなった!どうしてくれんだこのやろう!」って人はやってみて下さいな。

会社の同僚で、イケメンマークアップエンジニアのhamashunさんが本を出したそうな。そうな、と言うか出た。今日あたり書店に並んでたりするらしい。一冊貰ってきたのでどんな本なのかレビューを書くよ。

一週間でマスターするXHTML &amp; CSS for Windows

内容

テキストをXHTMLでマークアップして、CSSで見栄えを弄るところまでを実際のコードやスクリーンショットを交えつつ書いてあるチュートリアル。

誰に読んで欲しい本か

先に言っておくけど、タイトルからしてわかると思うけど、「MacRuby」だの「RSpec」だの「Objective-C 読書会」だののキーワードで検索してくるようなこのブログの読者が読む本では全く無い。

そうだなー、もし俺がこの本を誰かに勧めるとしたら、「(高校、大学の)情報リテラシの授業でホームページ製作の課題が出た後輩」とか「(IT系の業種じゃない会社で)ネットに詳しそうって理由でWebサイトの製作を頼まれちゃった友人」とか、そういう人かな。ああもちろん「Webデザイナになりたいけどまだ実際に作ったことがない人」は最初に読むべき本。リファレンス本を買うよりも、ネット上のHowTo記事を読むよりも、とりあえずまずこれを読んだほうが良いよ。

なんというか、例えると、「理屈はともかく猿でもジャイロボールが投げられる!」ではなく、「勝つためのスポーツ工学と野球理論」でもなく、「実践 ストレートを投げる為の練習法」ってところ。トリッキーなテクニックとか専門的理論的なことが書いてあるわけではないし、コピペするだけでOKな本でもないけど、順を追って読み進めて行くとそれなりにモダンで(内外共に)綺麗なWebサイトを作ることはできるようになると思う。

良いなーと思ったところ

とにかく「適当なこと」を書いてなくて良くまとまってる。「ただ書ける」じゃなくて「綺麗に書ける」ようになるように誘導してくれてる。斬新で奇抜なことが書いてあるとか、萌え路線で読み物として読めるとかではないので、内容や文体に関して「絶賛!これはすごい!こんなの見たことない!」とは言えないんだけど、わかりやすいし丁寧だ。デザインもシンプルで見やすい。

あと、要所要所に「検索ワード」が載っている。ある程度Webに馴染んでてわからなければ検索が身に付いてる人でも、「そもそも何を検索したらいいのかわからない」ってことはあると思うので、これはかなり親切だと思う。

微妙ーと思ったところ

あんまり無い。とにかく「ストレートを投げる為に必要なこと」がスッキリまとまってるので、目立つほど「アレ」なところが無い。hamashunさんらしいなぁと思う。

敢えて言うなら、リンクの説明が後半(金曜日)まで出てこないところ。CSSを書いてみよう、よりも、リンクを張ろう、とか、画像を入れよう、が後に来るのが気になる。うーん、まぁ、確かに見た目綺麗になるとモチベーション上がるので先に進みやすいんだけど、重要度としてはハイパーリンクやコンテンツの埋めこみの方が上だよなぁと。それから、相対/絶対パスの説明とかもしっかりやった方がいいんじゃないかな。杞憂かもしれないけど、8年前の自分がそこでハマった記憶あったので気になった。

あと、最後(日曜日)にlivedoor ブログの紹介がちょっと出てきて、これはすごくありがたいんだけど、「ブログテンプレートをカスタマイズしてみよう」はちょっとこの本の読者には荷が重いんじゃないかなーごにょごにょ。デフォルトのテンプレートでも結構複雑な上、ブログテンプレートとなるとHTML以外の知識も要求されるので、多分、これを読み終えたばかりの人には無理だと思う。俺でも未だに悩むもの、これ。いや、俺が言っちゃいけないセリフかもしれないけどごにょごにょ。

まとめ

ということで「Webサイトをきちんと作りたい人の最初の一歩」には「ストレートで、シンプルで、それでいていい加減じゃない」良い本だと思うので、勧めてあげてください。あと、読み終わりそうなころにリファレンス本やサイトを紹介してあげると良いと思います。ああそうそう、そういう「参考」みたいのは巻末にまとめておいて欲しかったかも。

あとhamashun先生は他にも書きたいことが一杯あるみたいだから期待して待つといいと思うよ!

今日は東工大で行なわれたSBM研究会に参加してきた。是非感想をmixiかブログに書いてくださいとのことだったので、感想と考えたことをまとめる。

とても新鮮だった

一番印象的だったのは、集まった人に結構いろんな立場の人がいたこと。SBM研究会には、大手SI企業の人、データマイニングやレコメンデーションの研究をしている研究者、Webサービスの開発者や運営者、技術好きな学生などなど。

これはとても新鮮だった。仕事柄というか趣味でというか、ここ最近技術系のカンファレンスや勉強会に何度か足を運んでいるのだけど、その雰囲気とはまるで違う。俺は興味の方向が基本的に「コンシューマ向けのWebサービス」に向いているので、普段はBtoBな業界の方や研究者の方と交流する機会は少ない。こうして同じ場に集まることで、視点の違い、空気の違いを感じられて刺激を受けることができて良かった。

印象に残った発表

どれも興味深い内容だったのだけど、専門的になるし内容も濃いので、具体的な話は発表者の方や他の参加者の方にお任せするとして、いくつか印象に残った発表についての雑感を。

ソーシャルメディアとマーケティング

発表者は学びing株式会社の横田さん。SBMの歴史をざっとなぞり、現状のソーシャルメディアはどういう状況に置かれていて、今後どう展開していくのが良いだろうかという提案だった。

まずSBM、というよりはオンラインブックマークというサービスを、del.icio.us以前の「ブレイク前」と以降の「ブレイク後」に分けて、その違いを考察。最大の違いは「ローカルのブックマークのバックアップ、ストレージであったものが、del.icio.us以降は日用のツールになった」ことだと指摘。また、評価の可視化、ブログの興隆による「パーマリンク」の増加、ソーシャルタギングなどの分類手法が「ブレイク前」とは異なる成功要因である、とも。

次いで現状のSBMの置かれている状況について。「ブレイク後」とは言え、アンケート結果によると日本では7%強程度の「ユーザ」しかいないとの事実を指摘。まだまだSBMはいわゆる「キャズムを越えていない」ものだってのは共通認識ではあるんだけど、実際に数字を見せられると流石に愕然とする。7%って。いかに自分たちがいる界隈が「濃ゆい」集団かってことを再認識せざるを得ない。もちろんこれはSBMを「ツールとして」「意識的に、能動的に」使ってるユーザの話であって、それと気付かず検索結果などからSBMに辿りついたり、実態は領域特化型のSBMだけれどもSBMと呼ばれていないサービスを使っている人は含まれていない。とはいえ、はっきり言ってまだ「あまりにもパイが小さい」のは確か。

それを踏まえた上で、現状で無理に一般層へアプローチするのではなく、「閉鎖空間」をキーワードに、一度ターゲットを狭めて存在感を高めてからより汎用的なものを目指すべきではないか、との提案があった。例えば領域特化型のSBM、イントラSBM、モバイルSBM、など。実際にニッチなSBMやイントラSBMはちらほら存在感を増してきてはいるんだけど、モバイルSBMに関しては今のところまだ目立った成功例がないみたいだし、俺も個人的には懐疑的。理由として横田さんは「mixiやモバゲーなどのコミュニティがサイト内で出しているニュースや更新情報が、PCの文化に置けるSBMの情報配信の役割を果しているのではないか」と言っていたけど、多分、単純に「SBMにポストしづらい」のが最大の原因だと思う。ブックマークレットやアプリケーションを使えないし、URLをコピペしづらいし、それ以前にそもそも携帯端末でのブラウジング中に「URL」を意識する場面が非常に少ない。そういう障害が一気に打破されるような何かが出てこない限り、モバイル文化にSBMは定着しないのかなーと思う。

ちなみに、横田さんのプレゼンはとても面白かった。内容もさることながら飽きさせない話し方が良かった。影響力がもっとも強いのはやるおなのではないか。

Webの世界に「気付き」を集積するコモンズ・マーカー

発表者はコモンズ・メディアの星さん。先日リリースされたばかりのコモンズ・マーカーの紹介。何がどう凄いのかは実際に使ってみたりyuguiさんの記事を見たりしてもらう方が早いと思うので、敢えて解説はしない。

関心したのはそのUIへのこだわり。敢えて付箋のメタファーを捨て、いかにマークとコメントを効率良く閲覧できるかを追求した話は参考になった。そうだよなぁ、他にベターな解があるなら、別に「現実にある何か」に似せる必要はない。この辺はUIの設計の話になるのでまた別の機会につきつめて考えることにする。

あと、印象的だったのは、「引用部とコメントをセットにして一つのマーカー」にする、という見せ方。引用部とコメントが対になっていることで、単体でコンテンツたり得るということ。星さんはコモンズ・マーカーを「注釈を付けるサービスであると同時に、簡単にWeblogを記録できるサービス」だと言っていたけど、これはあれだ…Tumblrに似てるんだ。ページを軸にしてマーカーを並べると、「あるコンテンツに対しての注釈・解釈」に見えるのに、人を軸にして並べると、「その人が何を見てどう思ったのかが綴られた記録」に見える。それだけでその人の個性が出てくるし、それ自体が立派なコンテンツになる。これは面白い。

ただ、見ていて思ったのは、SBMに似てはいるけど、SBMとはまた少しベクトルの違うサービスかな、ということ。今SBMが担っている役割のうち、アノテーションに大きく重心を傾けたサービスのように思える。一応、タギングなども供えてはいるのだけど、評価や分類と言った要素はメインではないし、逆にそっちに重心を戻すとせっかく新しく生まれた魅力が減ってしまう気もする。今後コモンズ・マーカーがどう発展するのか、非常に気になるところ。

パネルディスカッション

パネラーのみずほ情報総研の吉川さんが紹介した、社内SBMの導入事例が面白かった。社内SBMを導入したことで、少なくともユーザ同士は同じ情報を見たという前提を共有できていることで、議論の前段の前提の確認のための時間が減って、よりコミュニケーションに集中できるようになった、とのこと。また、導入当初は一部署で始めて、その後ユーザ数を拡大した際に「ノイズが増えて情報共有のコストが上がる」ことが懸念されたが、「むしろ他部署の動向が知れて有益」と概ね好評でノイズの増加は起きなかった、とのこと。あと、社内文書もクリップできるようにしていたが、実際には社内文書のクリップは殆どされなかった、とも。面白い。うちだったら社内にもクリップしたいリソースは山程あるんだけどなー。

それから、社内SBMを導入したみずほ情報総研、コンシューマ向けにグループ単位のSBM「BuzzurlPlus」をリリースしたECナビが共に「コミュニティを志向し、コメントを付ける文化を求めた」ことも興味深い。ここは実はlivedoorクリップチームも同意見で、今後のSBMの展開にはキーになると思っている。

その他、全体的な印象

レコメンデーションという切り口でSBMに着目している人が多かった印象。確かに、社会学や情報工学の分野の研究材料としては大変面白いデータが集積されているし、マーケティングのツールとしてもレコメンデーションは重要な要素だ。だけど、「コンテンツの評価軸としてのSBM」や「コミュニティとしてのSBM」への言及が少なかったことが気になる。これについては後述する。

あと、まぁ分かり切ってたことだけど、はてブ人気すぎ。ほぼ全プレゼン中で言及されてnaoyaさんがニヤニヤしたり苦笑したりしてるのが面白かった。ただ、まぁ、一応SBMサービスの提供者として言っておくと、「はてブの長所・欠点」をそのまま「SBMの長所・欠点」みたいに語るのはもう少し慎重になって欲しいなと思った。そこ、クリップなら違うことやってんだけど、やっぱ見てないかー、とか何度か言いたくなった。ちょっと残念。まだ努力が必要だなー。

研究会に対して不満に思ったこと

とりあえずこれだけは書かないわけには行かないと思ってたので書く。

なんでmixi?

今回のSBM研究会は、mixiイベントを使って告知され、mixiイベント上で参加者の管理が為された。また、感想もmixiで書くよう勧められ、(参加者は全員mixiのユーザーであるのが前提なので)是非mixi上で交流を持ちましょう、とも言われた。mixiがサービスとして良いか悪いかは話がそれるのでここでは語る気はないが、言いたいのは、SBM研究会という会を運営するにあたってその方法は適切だったのか、ということ。

(追記: 6月末にブログ告知とメール応募もしてたのは知ってたけど、4月時点での告知、5月末のTechTalk.jpでの告知には気付いてなかった。うわー、これは恥かしい。俺の勘違いですね、すいません。まぁでもそれでもmixiイベントでの運用と、感想をmixiに書くように勧めるたことは微妙だなーと思うので、ここの記述は残しておきます。あとTechTalk.jpは素敵すぎる。ちゃんとチェックしとこう。)

mixiは規模こそ巨大ではあるものの、「閲覧にも書き込みにもアカウントが必要なクローズドなコミュニティ」であることに変わりはない。である以上、その中の情報に検索で到達することができないし、SBMを使って周知することもできない。本来ならリーチし得たはずのSBMに関心があり有益な情報を持っている人が、この研究会の存在を知ることができなかったり、知っていても参加できなかったりした可能性がある。

はっきり言う。「SBMの」研究会なのに「SBMがカバーしていない」場所で行なわれる意味が、全くわからない。最初からブログで告知して、メールで参加者を募るなりして、感想はブログに書いてSBMでブックマークすること、という方法の方が適切ではなかったのだろうか。俺だって、Twitterでたまたまこの話を聞かなければそもそも存在すら知らなかった、いや、「知れなかった」。それから、今回の参加者のブログ記事は情報の共有がしやすいように「SBM研究会」タグを付けてください、とまで指示が出ているにも関わらず、一方でmixiアカウントが無ければ閲覧すらできない場所に感想を書くことを推奨するとはどういうことなんだろう。何か理由があるのなら是非教えて欲しいし、そうでないのなら次回以降は違う方法を検討して欲しい。

サービス提供者の視点で語ってくれる人が欲しかった

それから、若干気になったのは、発表内容がビジネスと学術に偏り気味だったこと。例えば、レコメンデーションやフォークソノミーの研究対象として見た場合に、SBMはデータの集合として捉えられる場合が多い。だけどそれだと、ユーザ同士のコミュニティが作る文化や、元のコンテンツに付加されたコメントが生み出す価値や、UIによるユーザ動向の変化など、SBMという「サービス」に重要な要素が出てこない。

もちろん、学術的な研究対象としては非常に扱い辛いものであることも、ビジネスの観点では優先順位として低いことも、十分にわかる。それから、吉川さんや宇佐美さんの話はその辺にも触れたし、コモンズ・マーカーの紹介もあったわけで、それはそれで大変参考になった。だけど、1セッション使ってその辺を掘り下げてたり一般化したりした話があってもいいくらいのテーマなのに、それが無かったのが残念だ。

最後に

いくつか不満は挙げたけども、各発表は興味深いものばかりだったし、この研究会を通じて知り合えた方々からもすごく刺激を受けた。全体としては本当に有益な時間でした。運営の方、発表者の方、休憩時間や解散した後の飲み会でお話させてもらった方、本当にみなさんありがとうございました。

ブログネタ
Objective-C に参加中!

詳解Objective-C 2.0読書会に参加してきた。読書会というのに参加したのは初めてだけど、皆で同じ本を読んで、読んだ部分に対して「ここがわからない」「いやそれは実はこういうことで…」というやりとりは中々面白かった。一人で読んでるとスルーしがちなところも拾ってみると勉強になるなぁ。

それより何より、Objective-Cなんていうマニアックな言語の、読書会なんていうストイックな催しに、24人も集まったのが凄い。これもiPhone効果かーなんて思ったけど、現時点ではiPhoneを買うと表明した人が少なかったのも印象深かった。いや俺も買わないけど。とは言えなんだかんだで衝動買いしかねないけど。どっちだよ。

今日はCHAPTER2とCHAPTER3の途中までを読んだ。CHAPTER2はObjective-Cの基本的な特徴や構文、CHAPTER3がクラス定義と継承だった。内容に関しては詳解Objective-C 2.0を読んでもらうとして、以下は読書会中に挙がった話の補足。

[[Hoge alloc] init]について

ObjCでクラスからオブジェクトを作る場合のイディオムについての話。「allocの後に続けて初期化処理を書かないといけないと言われたことがあるが、それは何故か、どう危険なのか、またそれが必須ならなぜ一纏めにしないのか」との質問が挙がった。

allocの後にinitもしくはinit...で始まるメッセージを続ける理由は、呼び出し側でそれを分けて使うことがまず無いから。別に、

id obj = [Hoge alloc];
/* なんか別な処理 */
[obj init];

としたところで文法上は問題無いんだけど、NSObjectのクラスメソッドであるところのallocは単にメモリを割り当ててオブジェクトを生成しただけで、それがオブジェクトとして振る舞うためには最初にNSObjectのインスタンスメソッドのinitが呼び出されていなければならず、上のコードの変数objは「なんか別な処理」をしている最中には、「何もできないか、何かさせようとすると異常な挙動をする」。詳しくは見てないけど、NSObjectのinitは結構色々やってるはず。そんな不安定な状態のものを放っておくメリットはよっぽど特殊なケースでないと皆無なので、allocと初期化処理は同時にやってしまうようにしましょうと言う話。

じゃあ何でメモリ割り当てと初期化が別なんだ、一緒でいいだろ、と言われるとちょっと勉強不足で即答できないんだけど、内部的には未初期化のオブジェクトが効果的に使われてるところがあるのかもしれない。そういう設計思想だからじゃないか、としかわかんないなー。

ちなみに、「allocしてinitしたオブジェクトを返すクラスメソッド」はある。NSObjectにnewってメソッドが定義されてるので、上記のイディオムの代わりに、

id obj = [Hoge new];

って書いても同じ意味になる。ただこれだと引数なしのinitを呼び出すだけなので、引数付きで同等のことをやりたかったらそういうことをするクラスメソッドを定義してやる必要がある。あと、Cocoaのクラスでも初期化で色々ややこしいことしてるやつは、そういうクラスメソッドが用意されている。例えばNSArrayのarrayWithObjects:とか。ちなみに、Fooクラスのクラスメソッドの「fooWithHoge:」と、Fooクラスのインスタンスメソッドの「initWithHoge:」は対応させるのが慣習になっているようだ。

初期化処理のイディオム

詳解Objective-C 2.0には、初期化処理は通常次のようにする、と書かれている。

- (id)init
{
    self = [super init];
    if (self != nil)
    {
        /* 何らかの初期化処理 */
    }
    return self;
}

これは実は、次のように書いても大抵の場合問題ない。

- (id)init
{
    [super init];
    /* 何らかの初期化処理 */
    return self;
}

スーパークラスの初期化処理を明示的に呼び出すことと、returnを省略できないのは変わらないんだけど、明示的なselfへの代入とnilチェックはしなくても処理できる。スーパークラスの初期化処理を辿ってNSObjectのinitが呼び出されると自動的にselfへオブジェクトが代入されるし、仮にselfがnilでも「nilに対するメッセージ送信は単に無視される」。まぁインスタンス変数の扱いとかは危ういけど。

じゃあ何でわざわざselfへの代入を明示的にするのかと言えば、「selfに自分自身じゃないオブジェクトを代入してもいい」上に「スーパークラスのinitの返り値が自分自身とは限らない」から。そういうトリッキーな実装も可能なので(例えばNSStringとかは実は結構トリッキーなことをやってる。その話が出てくるのは大分先だけど)、何か特殊なことをするのでない時は上のイディオムで書いた方がいい。てかselfが自分自身じゃなくてもいいって凄いな。お前は誰だ。

superの意味

selfが単にオブジェクトだったのに対し、superは変数に代入したり付け替えたりはできない。多分予約語なんだよな。superは何かと言うと、「自分より上位の継承関係を辿って行って最初に見つけたクラスの実装を使って、自分のコンテキストでその処理を実行する」という構文。難しいね。

基本的には一つ上のスーパークラスを見て、なければさらに上へ…を繰り返して最終的にはNSObjectまで行く。ここで「一つ上からじゃなくて、スキップしていくつか上のクラスのメソッドを呼び出せるか」という話で盛り上がった。聞いて驚いたんだけど、実はすごくごちゃくごちゃしたコードを書けばできるらしい。けど、実行時に既存のクラスの書き換えまでやってのけるObjective-Cにおいて、コード上の継承関係を元にややこしい処理を行なうのは危険すぎる。最終的には「できるかできないかより、そんなことをしなきゃならないような設計の方が問題だよね」というオチがついた。そりゃそうだ。

メッセージセレクタ

「メソッドを呼び出す際に引数をつけるときには最後に:を付ける、複数の引数があるときは"keyword:"を並べる」というのを読んで、「第二引数以降にキーワードを付けるのは分かったけど、第一引数の前にはメソッド名があるだけでキーワードが無いけど、付ける方法はないのか」というの質問が上がった。ここはちょっと誤解しやすいポイントかも。多分、メソッド名とかメッセージキーワードとかいう語彙が悪い。

例えば、

[obj setValue:@"hoge" forKey:@"name"];

こういうときの「メッセージセレクタ」は「setValue:forKey:」のひとまとまりであって、その際に:や後ろのキーワードも含む。ちょっと無理矢理にRuby風に書くと、以下のようなイメージ。

# Rubyではメソッド名に:は使えないけど、仮に使えるとしたら
obj.setValue:forKey:("hoge", "name")
# もっと言うと、こういうイメージかも
# この方が「メッセージパッシング」っぽいし、
# 実際こういうメソッド呼び出しの方法はObjCにもある、
# というか内部的にはCの関数でこういうことをしている
obj.__send__(:setValue:forKey:, "hoge", "name")

なので、「最初の一個目がメソッド名で、二個目以降がキーワード」というのは誤り。一見分かれてるようだけど「全部くっつけたもの = メソッド名」だと思った方がいいし、セレクタ(SEL)を使って上のRubyの__send__みたいなことをやるときは正に、

SEL sel = @selector(setValue:forKey:);

などとして「メソッド名を生成」する。

ちなみに、最初の「一個目の引数の説明はどこに書くのか」に対しては、「何の引数を取るのかわかるメソッド名にする」が一応答えかな。Cocoaだと一個の引数を取るメソッドは例えば、

id url = [NSURL URLWithString:@"http://www.apple.com"];

のように、何の引数を取るか分かるように命名するのが慣習になっている。さっきのsetValue:forKey:も、「最初が値になるオブジェクトで、次がキーになるオブジェクト」ってのが分かるようになってるね。

ところで、ちょっと違う話になるけど、

# これはさっきの偽Ruby
obj.setValue:forKey:("hoge", "name")

これ何か見覚えあるなぁと思ったら、

# これはRubyCocoa
obj.setValue_forKey("hoge", "name")

RubyCocoaでOSX::NSObjectを継承したクラスのメソッドを呼び出すときとほぼ一緒(まぁ、そういう風に作ってあるのだけども)。RubyCocoaからMacアプリの世界に入った人は案外、ObjCのメソッド送信がすんなり分かるかもしれない。でもそれ以前にCocoaを知らないとRubyCocoaは分かりづらいって話はあるけど。ジレンマ。

詳解Objective-C 2.0読書会の今後

今日はとりあえず「音読して、途中途中で質疑応答タイムを設ける」っていう形式だったけど、今後は色々試行錯誤していくとのこと。あと、今回は休日だったけど、2時間程度であれば別に平日でも良いのでは?との意見から次回は試しに平日にしてみることになった。多分今月中にもう一回ぐらい開催されることになりそうなので、興味ある人はメーリングリストに参加してみるといいよ!

今週いろいろと忙しかったせいで「あとで書くと言ったまま書かないメソッド」が発動してしまって大分出遅れた感があるんだけど、RubyKaigi 2008に行ってきたの続き。

拡張ライブラリの書き方講座(artonさん)

RubyをCで拡張する方法の解説。朝からマニアックなセッションやるなぁ、と思ったら「朝のうちにマニアックなものをやっておく」という運営側の戦略だったらしい。朝一でつくばまでやって来てる人程マニアックな層なので、この戦略は当たりかもしれない。

Rubyの拡張ライブラリは結構簡単に書けるらしい。面白そうなので今度Cの勉強も兼ねて書いてみようかな。ruby拡張を書いてみるテスツ - 大学6年生のhogelogでサンプルがあがってるけど、これはちょっと面白そうだ。

あと個人的に興味深かったのは、artonさんがサンプルプログラムが上手く動かなくてその場でデバッグしはじめたとき。artonさんがあれこれ書き換えてる後ろで流されてるIRCのログに、みんなで「ここをこうすればいいんじゃないか」「arton、うしろうしろー!」などと協力してて面白かった。ペアプロならぬテラプロって誰が言ったんだっけ。

さらに仕事で使うRuby(ごとけんさん)

仕事で使うツールやその運用方法などの紹介。HikiとかRedMineとか。RedMine今回色んなセッションで紹介されてたし、Ruby本体のissue trackingにも使われてるらしい。今度使ってみようかな。

あとなんとオープンソース版Fastladderを紹介していただいた。日曜、月曜とFastladderのダウンロード数が増えてたのは間違いなくごとけんさんのお陰だろうと思う。

でもその後twitterで「Fastladderってでも最近全然開発してないよね。飽きちゃったのかな」とか言われてるのを見て焦った。いやいやいやいや、本当すいません、飽きてないですちゃんとやります。中の人二名(二人ともRubyKaigiに行ってました)が中々手が空かず放置気味になってしまってたのだけど、俺の今季の個人目標にはちゃんと「Fastladderの開発」が入ってますので!Googleグループの方にも反応できてなくて本当に申し訳ないんですが、バグレポートや要望など挙げてもらえたら頑張って対応します。

The future of Ruby in Mac OS X(Laurentさん)

RubyCocoaとMacRubyの紹介をApple社員のLaurent Sansonettiさんから。大変wktkする内容だったんだけど、それにしてもあの盛り上がりようはRubyistのマカー率の高さを示してるのかな。

前半はRubyCocoaの紹介で、後半はRubyCocoaが抱える問題点をMacRubyというアプローチで解決していこうとしている、という話。具体的なところは以前書いた記事をご覧下さい。要は「ブリッジではなくObjective-CでRuby処理系を実装することで、ラッパーを介する際のオーバーヘッドや複雑さを避ける」というのが要旨。当然ながら処理速度が飛躍的に早くなるよってところで歓声が上がってた。

RubyCocoa使いとしては「NSObjectが基底クラス」ってところが一番の目玉に感じたんだけど、Rubyist視点として興味深いのは、なるべく綺麗にObjective-Cのメッセージパッシングを実現するためにキーワード付き引き数を導入してること。MacRubyは今1.9ベースだけど、この機能は1.9にも無い。これが洗練されてくればMRIにも取り入れられるかもしれないってことで今後に期待。

あと、ちなみにMacRubyはiPhoneで動かすことは当分できないそうだ。メモリ管理にRubyのGCではなくObjC 2.0のGCを使っているので、GCサポートが無いiPhoneのランタイム向けにコンパイルできないらしい。これはちょっと残念。

それから質疑応答の光景が中々面白かった。Laurentさんはフランス語が母語?だったようで、込み入った質問になると「日本語で質問→フランス語で通訳→英語で回答→日本語で通訳」とかになってた。マルチリンガル!

Real-World Enterprise Ruby(大場さん、高井さん)

企業向けの開発でRubyを導入するにあたってのノウハウを伊藤忠テクノソリューションズの二人から。内容的には非常に真面目な話な上、二人ともスーツでステージに立ってたにもかかわらず、IRCでは「スーツがコスプレにしか見えなくなってきた」「漫才が始まった」などと盛り上がっていたのでなんだろうと思って行ってみたら、確かに面白いことやってた。なんでそんなことになったのかは高井さん大場さんのキャラクターから推してしるべし。

ちなみに内容はSI業界の人にはかなり参考になったんじゃないかと思う。yuguiさんの「わかっとらんやつは黙ってろ」とは対照的な、上司や顧客にRuby導入を承認させる方法とその効用についてがよくわかるセッションだった。

最後に

仕事柄大変Perl充な日々を送っているのだけど、久々に2日間丸々Rubyまみれな時間を過させてもらって本当に楽しかった。RubyKaigiスタッフの方々、スピーカーの方々、会場でご一緒させてもらった方々に心からの感謝を。

それから車を出してくれたsotarok、家に泊めてくれたdaftbeats、俺が頼まれてたyuguiさんのサイン入り初めてのRubyを代わりに確保してくれたfrom_kyushu、本当に助かりました。ありがとう!ハチロク世代++。

追記

あと俺何気にRubyConfのTシャツやらJRubyのTシャツやらを着てた。初めてのRuby片手にPHPTシャツを着たsotarokと、Sunと何の繋りもないのにJRubyTシャツを着てた俺が連れだって歩いてる光景は中々妙な感じだったんだけど誰にもつっこまれなかったのは、ツッコミ待ちなのがバレてたんだろうか。

表題通り、RubyKaigiに行ってきました。大変に楽しかったし会場中にRuby愛が満ちていて充実した二日間だった。全体のレポートは既にそこかしこであがってると思うし、動画もUPされてるようなのでそちらを観てもらうとして、興味深かったセッションや出来事をいくつか。

基調講演(まつもとさん)

Rubyは梁山泊になりつつあるんじゃないか、という趣旨の話。が、それよりも印象に残ったのは「Rubyをキメるとキモチいい」。ええ。キモチいいですね。うふふ。

Ruby M17N(成瀬ゆいさん、Martin J. Dürstさん)

Ruby1.9からは多言語対応のため文字列の扱いが大きく変わっている。唯一の内部エンコーディングを持たず、内部で変換をかけたりもしない、Stringオブジェクト自体がエンコーディングを持つ、とか。話には聞いてたけど1.9はまだあんまり弄れてないので興味深かった。

個人的には「内部エンコーディングを持たずソースコードやStringオブジェクトの単位でエンコーディングが決まってしまうとなると、例えば日本語を処理するライブラリなどを書くときに上手く実装するのが大変になるのではないか」っていう話が気になった。多分、受けとった文字列のエンコーディングを記憶しておいて一旦変換し、処理が終わったら最初のエンコーディングに戻して返す、とか、マルチバイトの文字列を返すメソッドはオプションでエンコーディングを取る、みたいなのが基本になると思うけど、若干前より泥臭くなってる印象もなきにしもあらず。

RSpecによるRailsアプリケーションBDD事例報告(yuguiさん)

最初サブセッションの方にいたんだけど、なんかメインの方で俺のID(faultier)が連呼されててびっくりして行ったら、案の定以前一緒に仕事してた会社での事例だった。うひー。妙な汗かいた。

で、肝心のBDDですが、これは確かに実績を上げてました。RSpecとSeleniumを使うようになって格段にバグも減ったし、「何をやってるか知りたければまずSpecを見ろ」っていう習慣も自然に浸透したし、LLに不慣れなベテランプログラマや新人プログラマを含む混成部隊でもペアプロのお陰で開発速度を維持できたし全体の技術水準も上がりました。

あと余談だけど、「Specのないコードを書くときは上長に申請書を提出させる」とか「ペアプロ時にはナビゲータはピコピコハンマー装備」とか、今回の名言「わかんないやつは黙ってろ」とか、本当にやっちゃう人ですからねyuguiさんは。実際に。そこに痺れる憧れる。

Rubyで快適に連投する11の方法(ujihisa)

ujihisaの集客力は異常。

1日目終了後

ハチロク世代+α、つくばクラスタ、懇親会難民だったTAKESAKOさん、が合流して会場付近の魚民でYet Another 懇親会。幹事を努めてくれたdaftbeats、はるばる九州からきてくれたfrom_kyushu、お疲れ様!

楽しく飲んだ後はdaftbeats家におじゃまさせてもらった。hacktour組に対抗して夜通しRubyプログラミング、の予定だったけどIRCボットと戯れてるうちに夜が更けてた。何してんだ俺。

続きはあとで

長くなりそうなので2日目のことは後でまた書きます。

昨日の夜からハチロク世代の開発合宿に参加している。千葉の笹川で二十余名、いつものメンバーもいれば始めましての人もいて、上野氏がいたりamachangさんやnishioさんがいたりと面白い面子。

遠いわ!

まず、宿泊地の笹川、遠いよ。仕事が終ってから行ったので一人で夜に向かったんだけど、赤坂から軽く2、3時間、目的地が近付くにつれ周囲に街灯もなくなってきて非常に心細かった。着いたら何にもないし、怖いので駅からそう遠くないと聞いてたけどタクシーで旅館まで。タクシーの運ちゃんに「ハチロク世代の人?」と聞かれて、なんだなんだハチロクはこんなとこまで名が知れわたるようになったか、と一瞬思ったんだけど、旅館の前に「ハチロク世代開発合宿様」と書かれていて思わず笑ってしまった。そりゃ、何の集団かと思うよな。

御飯旨い

御飯にボリュームがあるところは素敵です。飯時でもプログラミングの話か上野氏の話しかしてないとか、変態集団だな。

「あのテンプレートのせいで、私の印象が一人歩きしている」(上野氏)

そんなこと言うからまたネタにされるという。彼は面白いなぁ。

開発中

とりあえず合宿中にCocoaでPICSのAPIを叩くフレームワークと、できればそれを使ったデモアプリくらいは作ろうと思ってるんだけど、これは順調に進んでいる。Objective-Cを使う奇特な人はやっぱり俺だけっぽいけど、CとかAtomAPIとかで困っても周囲にいくらでも聞ける人がいるってのは心強いな。開発合宿なるものに参加するのは始めてだけど、これは良い。

あとHashがRubyCocoaをやると言うので、隣の席陣取ってちょくちょくお節介してる。ちょっかい出したくてうずうずしてるのでハマったらもっと声掛けてくれるといいよ!

「家に帰ってレポートをブログに上げ(た上で野望の会の名声を各所に轟かせ)るまでが新年会です」と言われたので、中程度の酩酊とスイマーに襲われながらエントリーを上げるよ。

野望の会って何?

「いずれにせよITで世界征服制服」をする組織であるとのこと。

最初野鳥の会と空目したのだけど、実はあながち間違いじゃないらしい。そう言えば最近の紅白では野鳥の会は出動してないみたいですよ。全く関係ない話だけど。

「詳しくはpinkmacさんに聞けって言っとけばいいよ」ってことなので、みんなid:pinkmacさんに聞くといいよ。

謎よ、もっと深まれ。

非常に刺激になりました

各分野の専門家、特に大学や大学院などで研究をされてる方や未踏のスーパークリエータな人が多くいらしてたし、ハチロクの人が参加者の三分の一程度を占めて軽くジャック状態になってたし、あとゆーすけべーさんと話せたしで、かなり楽しかった。

正直なところ、割と「俺野望の実現に大して貢献しないよ、場違いかもよ」と思いつつ参加してたんだけど、案外需要あるかもしんない。スキマ産業的な意味で。

Objective-Cスキーは貴重っぽい

ハード寄り、ビジネス寄り、学術寄り、Win32/.NETエンジニア、LLスキーは居るんだけど、Objective-Cに造詣が深いって人は案外いないのかもしれない。マカーはいるのにねぇ。Cocoaを使ったMacネイティブアプリの話とかもしかしたら需要あるかもしれない。それが「ITで世界征服」に役立つかは知らんけど。ObjCかわいいよObjC。

ネットコミュニティに関する研究をしてる人がいる

まがりなりにもブログやらSNSやらを主たる事業としてる会社の末席にいる身としては、その手の研究は非常に興味ある。個人的にも一番やりたい分野だし。なんか面白い研究をしてるんだけど実装する場がない、ってことがもしあれば協力したいなぁ。言うだけで俺自身にはそんな権限があるわけでもないのだけど、今後何かに生かせるかもしれないし。各種コミュニティサービスの統合インターフェースとか、ねぇ。

LDの宣伝しといた

livedoor Blog使ってくだしあ。はてダ使ってる俺が言うのもアレですが。

その他

秋葉原でうろちょろしてるよって事前予告してみたものの、やっぱり誰も来なかった。一人で優雅に飯食う、等身大ハルヒを見つめてたらメイドさんの集団に絡まれるなどしてた。あとせっかく教えてもらったリナカフェ、Intelのイベントやってたせいで入ることもままならず、ようやくイベント終わったと思ったら閉まってしまいましたよ。Intelめ。ボールペンもらったから怒らないけども。

その後id:yuyarinid:suztomoid:gomi-boxらと合流してハチロク世代の皆様と初顔合わせを果たしたのだけど、よく考えたらみんなT大なのか。T大クラスタめ。別に何の恨みもないけども。あとサイトウサンのポストカードもらえたので凄く嬉しかったのだけども。アレいいな。コンプしたい。

とまぁ、そんな感じで凄く楽しかったです。野望の会。次は魅惑のiPod touch LTを用意して参加します。よろしく。

シンプルな共有BTSってところかな。出たばかりなのとコンセプト上機能を大分絞ってあるのとあって、BTSとしてはちょっと寂しいし、かといってソーシャル機能が強いとか個人タスク管理に向いてるとか、そういうわけでもない。livedoorのサービスだけどlivedoor IDでのログインじゃないから、特に他サービスとも連携してない。まぁ本格的にタスク管理したいならRTMとか使えばいいんだろうなぁ。

ただ、とっつきやすいので気軽に使える感じがいい。実際すごいぬるーいプロジェクトがぽこぽこ立てられたりしててネタで使えるし、オフ会のタスク管理とか趣味で作ってる小さいフリーソフトのBTSとかにもちょうどいいかも。自前でBTS立てるとか、関係者全員にRTM覚えさせるとか、流石にそれは大掛りだよなってときにはコレだな。

というわけで早速RubyCocoaを極めるに参加してみた。なんか作る。なんか作るのだそろそろ。

どう書く?.orgのお題に取り組み始めてからObjective-Cでいろいろ書いてて、久しぶりにCocoaのリファレンスを読んだりしてるんだけど、いやハマるハマる。二重の意味で。Objective-C熱が出てますよ。二重の意味で。昨日はファイル更新監視のツールに挑戦してたんだけど、随分とスットコドッコイなものを作ってました。CUIのツールなのにGUIのAPI叩いてたりとか、アホかと。それでも書くのが楽しくて時間を忘れたくらい面白かった。いいなぁObjective-C。マカーなプログラマはもっとCocoaに触れてみるといいのにな。Cocoa-Javaサポートも外れた?ことだしJavaJavaしてる場合じゃないですよ。いや、JavaはJavaで好きだけど。

どう書く?.orgに挑戦してて思ったこと

なんかお題がないと「それPRagg(ry」なものを再発明しては悦に入る程度のことしかしないので始めたのだけど、やり始めたらいろいろ再認識することが多くて凄く楽しかった。そもそもなんでObjective-Cで書いてんのかというと、今ならObjective-Cで書いてると目立てるんじゃね程度の中二病的短絡思考に過ぎないのだけども、図らずも仕事でも趣味でもやってこなかった種類のプログラミングだったのでものすごく勉強になる。

言語ごとの向き不向きを肌で感じる

どう書く?.orgのコンセプトや投稿してるユーザ層を考えるとそういうもんかなとも思うんだけど、CUIでOS非依存のテキスト処理とかリスト操作のお題が多い感じがする。で、それらをObjective-CというかCocoaで書こうとして再認識したのは、その手の処理をLLで書くのがいかに楽かってこと。もともとそのためのスクリプト言語だったりするし、文字列の検索・置換だとか配列のならべかえとかがびっくりするほど簡潔に書ける。最近はWebアプリを書くのに多用されることもあってHTTP経由のリソースの扱いも言語組み込みあるいは標準のライブラリで簡単。いかにシンプルに手早く書けるかという点においてだけ言えば、もともとネイティブアプリのフレームワークであるCocoaでやろうとしたってまず敵わない。

一方でCとかLispの「何でもできるぜ」っぷりも物凄い。そりゃあ理屈で言えば、コンピュータの処理として記述できるものは(簡単か難しいかの差こそあれど)どんな言語でも記述できるとはいえ、その汎用性は流石としか言いようがない。定石も多いし。それから関数系の言語のエレガントさも惚れぼれする。いいなぁ。ああいうのをさらっと書けるようになると脳味噌の中身もすっきり整理されそうだな。

あと、秀丸マクロとかPowerShellとかの投稿が予想外に多いのが面白かった。というかObjective-Cが秀丸マクロに負けてるのはなんか意味もなく悔しいな。ユーザ数で言ったら秀丸マクロより下なんでしょうか、Objective-C。もっと頑張れObjective-C。君はやれば出来る子なんだから*1

何故かCの勉強になる

Objective-Cは見た目はアレだけど実態はCの拡張なので、素のCコードと混在できる。GUIアプリだと大分様相が変わってくるんだけど、CUIのツールを作ろうとすると、制御方法とかアルゴリズムとかはCの例を参考にすることになる。そんなこんなで、Objective-Cを書いてるつもりが気がつくとCのライブラリ探したりmanで関数の使いかた読んだりしてた。

それから、アプリケーションフレームワークであるところのCocoaはObjective-Cで書いてあるけど、それより下のレイヤーのCore FoundationライブラリはCで書いてある。なのでランタイムAPI叩いてリフレクションとか、もっと低水準で細かく制御したいとか、そういうこと考え始めると必然的にCでゴリゴリになる。まぁ、俺はまだそんなレベルでは全然無いんだけど、Cocoaのリファレンスとか読み漁ってるうちに気がつくとCでランタイムいじるような内容を読んでたりすることはままあった。

あと、C++だとありがちな話だけど、Objective-Cでも拡張子は.mだけど良く見るとまるっきりC、みたいなコードが書ける。どう書くのお題をやろうとしたときは、Cとの差別化をしないとなと思ってわざわざNSStringとかNSArrayとかに変換して処理してみたけど、正直「これCで書いた方が楽じゃね」って時々思ってしまった。もちろん本格的なアプリケーションの中でOSの機能をバリバリ使うとなったらどう考えてもCocoaのが強力で楽で保守性も上がる、はず。でも、当り前のことだけど、一個の関数の処理をラップしただけみたいな小さなツールで、かつOS非依存の処理だったりすると、わざわざCocoaで書く意味はあんまり無い。つかCどころかRubyでいい。むしろシェルスクリプトでいい。

そんなわけでCの勉強をかなりした(気分になった)。

そもそも根本的なところが弱過ぎるぞ俺

自覚してはいたけど、アルゴリズムとかデータ構造とか実行効率とかエラーハンドリングとか、土台の部分が脆弱過ぎる。他の人がやってるのを見ればなんとか、「こういう風に処理すると効率がいい」とか「これだとこんな理由でダメなんだな」とかいうのは想像できるんだけど、自分でそれを発想するに至ってない。高水準言語でWebアプリ開発ってのに慣れきってるのもそうなんだけど、そもそも勉強不足。いくらスクリプト言語が、ライブラリや処理系が裏で良きにはからってくれるとと言ったって、中で何やってるのか分かってる上であえて意識しないというスタンスでいないとロクなものは作れない。そりゃ「最近のLLかぶれの若造は使えねえ」と言われるわ。

いや、LLの凄い人だって下のレイヤーのことも良く知っているし基本的な考えかたを理解しててLLで書いてるから凄いんであって、LLだとかそうじゃないとかの問題じゃない。それなりに作れるかなと思い始めた*2ミユビナマケモノがより高みを目指すには、一度きちんと基本に立ち返る必要があるのを再確認というか痛感した。おっかしいな。Cのソートアルゴリズムとかバイナリサーチとかリスト構造とかを始めて見たときは感動してたんだけどな。所詮ナマケモノ、あのときの情熱が自分の能力の向上に繋がってねぇ。

TODO

  • iPod touchでタイトなリソースで動くプログラムを作る
  • 一瞬でも落ちたら大量の嫌がらせメールが俺の携帯に届くようなサーバアプリを作る

もっと緊張感を必要とするプログラミングをしてみようかと思いました。そうじゃないとずっと「それなりに動くが、それなりでしかない」ものを作り続けてしまいそう。

  • どう書く?.orgでもRubyやObjective-Cだけじゃなくて他言語のコードも読む
  • 仕事中の待機時間に他のプロジェクトのコードを読む、Sledgeのソースを読む
  • オープンソースのコードを読む

読んで理解できるということは自分でも書けないわけじゃないんだよなぁ、多分。きっと。もっと大量にInputすれば多少はOutputのセンスが磨かれるかなぁと。あとさりげなくどう書く?.orgにObjective-Cのコードをばんばん上げ始めてくれたPsychsさんに多謝。読みまくったる。

*1:余談だけど、俺高校時代に「faultierってやればできるのに絶対やらない子だよね」って言われた。多分、全く褒められてない

*2:勘違いともいう

以前iPod touchをJailbreakした際にRubyをインストールしたものの、irbは起動しないし添付ライブラリを読みこんだだけで落ちてしまって、全く使いものにならなかった。その原因が気になっていたので今日はそいつを追っかけてみた。てっきりarm-darwin版のRubyが何かバグを抱えているもんだとばかり思って愚痴ってたのだけども、結論から先に言うとどうもそうではないようだ。で、タイトルのようなことになるのだけども。

とりあえずエラーを吐いてる箇所を探す

エラーを吐いてる、と言うのは正しくない。どのライブラリでも関係なく、requireした時点で[BUG]とだけ言ってAbort trapしてしまうツンツンぶりで、まったくとりあってもらえないというのが現状。数は多くないけど、日本でもarm-darwin版rubyに泣かされてる人は何人かいるみたいだ。

っても、インタープリタのコードもライブラリのコードも読んだことないし、arm-darwinのバイナリを作る開発環境もないしで、インタープリタのバグだったりしたらお手上げだったりするんだけど。まぁ、とりあえず小さそうなところで、URIライブラリを選んでみる。

bash-2.3# ruby -e "require 'uri'"
/opt/iphone/lib/ruby/1.8/uri/generic.rb:1121 : [BUG] terminated node (0x21294c)
ruby 1.8.6 (2007-03-13) [arm-darwin]

Abort trap

ぐ。ここまでは既に何度も経験したので、この程度のツンツン加減じゃへこたれないからね。しかしgeneric.rbの時点で落ちるとはどういうことだ。1121行目に一体何があるのか見てみるべくuri/generic.rbを開いてみる。

1106     def inspect
1107       sprintf("#<%s:%#0x URL:%s>", self.class.to_s, self.object_id, self.to_s)
1108     end
1109 
1110     def coerce(oth)
1111       case oth
1112       when String
1113         oth = URI.parse(oth)
1114       else
1115         super
1116       end
1117 
1118       return oth, self
1119     end
1120   end
1121 end

endやん。さらっと見てみたけど当然のことながらおかしなところは何もない。他のRubyライブラリか、あるいはもっとローレベルな機能に依存してるとこはないかとも思ったけど、どう見てもごく普通のRubyコード。一応、まさかsprintfが?とか裏切りのcase式か?とか一通り自分で書いて試してみたけど、別に問題なく通る。というか、ここModuleやClassの定義の箇所だし、そもそも実行すらされてないはず。何なんだ一体。

行けるとこまで行かせてみる

何箇所かコメントアウトしてみたりしたら、一応generic.rbは読み込めたりするんだけど、今度は他のライブラリで止まるし、ひっかかる箇所を見比べても共通点が見えてこない。仕方ないのでライブラリのソースにdebug printを仕掛けつつ、上から順番に地道に読みすすめていくことにする。

まずはuri.rbからrequireしてるものをgeneric.rb以外全部コメントアウトして、generic.rbの方では__END__で後ろの処理を無効にして実行してみると、その段階では問題なく読み込める。徐々に読み込む範囲を広げていったら、ついに「そこから先は必ずAbort trapする」行を見つけた。

 914     def route_from(oth)
 915       # you can modify `rel', but can not `oth'.
 916       begin
 917         oth, rel = route_from0(oth)
 918       rescue
 919         raise $!.class, $!.message
 920       end
 921       if oth == rel
 922         return rel
 923       end
 924       
 925       rel.set_path(route_from_path(oth.path, self.path))
 926       if rel.path == './' && self.query
 927         # "./?foo" -> "?foo"
 928         rel.set_path('')
 929       end
 930 
 931       return rel
 932     end
 933         
 934     alias - route_from

これの925行目の後、return relより前に何かの式を入れるとそこで必ずAbort trapする。ついに、ついに見つけたぜこの野郎。

…待て。うん、この箇所も全然おかしくない。何の変哲もないif文。試しに色々なif文を書いてみる。全部ダメ。unlessもwhileもbegin-rescueもダメ。putsは…ダメ。じゃあ、1。あ、これは通るのか。1+1は…な、なんだって、これも通らないだと?…なんか、すごく嫌な予感がする。手に負えないバグを見つけるよりもよっぽど嫌な予感が。

さて。どうも926行目に書いてあることが原因じゃないようだ。ふむ。じゃあ、コードの順番を入れかえてみたり、前後のコードを減らしたり増やしたりしてみたらどうだろう。

…あはは。コードを減らすと通るんだ。それも、どの箇所かに関係なく。

vim*1を閉じて、おもむろにtop、と打ちこんでみた。うふふふふふ。そういうこと。そういうことなんだ。

メモリが全然なかった。なんでか知らんがhttpd*2起動してるし。誰だそんなふざけたものをiPodに入れたやつは。俺か。俺だよなぁ。

100MBのメモリでできること

結局、iPod touchがあまりに貧弱なため、インタープリタがrequireしたコードを解析中にメモリを使い切ってしまい、どうしようもなくなって[BUG]と断末魔を残して死んでたんだろう、ということだった。だから、コードをあれこれいじってたときに、条件分岐が複雑なコードやオブジェクトを余計に生成するコードが即座に息の根を止めてたんだな。ちょっと考えればわかりそうなもんで、多分携帯電話とかで開発してる人だったら、そんなリソース馬鹿食いしそうなRubyなんかがモバイル端末でまともに動くわけないじゃん、って言いそうだ。あるいは、いやいや、数年落ちのビンテージ環境でもRuby自体は動くわい、それはiPod touchが貧弱なんじゃい、っていう声も違う方から聞こえてきそう。

でもさ。iPhone/iPod touchが携帯電話とも骨董PCとも違うのは、あれは高機能なGUI環境なんだってことなんだよな。サブセットとは言えdarwinが、いやMacOSXが載ってるわけで、だからこそモバイル端末にあるまじき過剰な期待をしてしまうし、(皮肉にも)それが故に骨董PCでもできるようなことが出来なかったりする。確かにiPod touchのインターフェースレベルの層を排してdarwinだけにすれば、Rubyくらいは平気で動くと思うけど、それって何の意味があるんだろう。かと言ってあんなにスムーズに動くUIがあって、音楽・動画が再生できて、ネットワークにも繋がるのに、ハードの制約でいじれる部分が少ないというのも切ない話。

やっぱりObjective-Cで書いて最適化しまくってなんぼって世界か、あるいはWidget程度の小さなアプリがせいぜいってところなのか。Cocoaは好きなんでそれはそれでいいんだけどさ。折角RubyやPerl*3があるのにまともに使えないのは残念過ぎる。まぁ、最初からAppleが言うようにWebアプリで作ればいいじゃんって話だが*4

*1:最初vimがあることに気付かなくて、しばらくviを使ってた。いや、だって入ってないと思ってたし。会社のサーバだってviしか入ってないんだぜ。

*2:以前ネタで入れたApacheがlauchd経由で自動起動するように設定されてたらしい。使いみちもないし、即座に消した。

*3:もしかしたらPerlならRubyよりまともに動くかもしれないけど、CPANフル活用してバリバリ、というわけにもいかないだろうからどっちみち期待はできない

*4:しかしSafariのJSはそれはそれでなんだかなって代物だけど。未だに。

表題通り。恵比寿にあるドリコム東京本社に行ってRails勉強会に参加してきました。体調不良でえらい豪華なメンバーのランチには参加できなかったし、それどころか恵比寿についてから迷って遅刻ギリギリになるし、まぁいろいろとアレだったけども。うん、そう、ここのところ頭痛いなぁとか思ってたら、体が熱っぽいくて意識が遠くなって、そうかこれ風邪ひいてんじゃね?とか気が付いたのは帰り道。馬鹿は風邪ひかないんじゃなくてひいたことに気が付かないとは名言だなーとか思いながらよれよれと帰ってきました。それはそれとして、勉強会は非常に楽しかったです。以下、自分で後で見返すためにも軽くまとめ。

Rails 2.0は案外普通だな

前半のセッションでは「Rails 2.0を読む」と題してRails 1.2から2.0になって変わったところをざっとさらい、該当箇所のソースを読んで、どんなことやってんだろうなどと話した。Rails 2.0。Railsの仕事から離れてからRails周辺の話題を追いきれてなくて、実はまだ試してなかったんだけど、ちょっと面白そうなことになってるみたい。これは後で試してみないとなぁ。

相違点をざっと。

RESTfulなRails

SOAP関連のサポートが省かれてREST関連の機能が強化されてるよ、って話。これは前々から聞いてたのでふむふむなるほどと言った程度。RESTfulなクライアントサイドを書くための仕組みだけでなく、RESTfulなサーバサイドのAPIも作りやすくなってるらしい。

MultiView

respond_toを拡張。面白いなぁと思ったのは、従来ならviewの拡張子がhoge.rhtmlとなるところがhoge.html.erbとかになる話。一個目の拡張子(変な言い方だ)でファイルの種類を、二個目の拡張子で何で処理するかを判別するらしい。

セキュリティの強化

デフォルト設定だとURLに自動的にトークンが入ってCSRF攻撃対策を取るとか。えーとこれなんだっけと思いながらメモ見たら「あとで調べる」とだけ書いてある。コラ。しっかりしてくれ自分。

Record identification

URLの規約をより簡素にして、モデルからURLを特定する仕組み。redirect_toやlink_to、form_forなどで使う。具体的にどういうことかというと、例えばRubyistモデルの情報を参照するページのURLが /[モデル名(複数形)]/:idという規約に従っていれば、userがRubyistクラスだったとしてlink_to(user)とかやると"/rubyists/#{rubyist.id}"なURLが自動生成されるということらしい。

HTTP Loving

Basic認証がデフォルトでサポートされるらしい。ところでなんでLoveなんだろう。

Queryキャッシュ

ARがQueryキャッシュするらしい。肥大化してものすごいメモリ食うんじゃねってとこを不安視する声が上がって、ソース読みながらキャッシュの生成・破棄のタイミングを調べたりしたのだけれど、どうもそんなに本格的なものではない様子。メモリリソースが気になるような状況では使わない、本格的にDB負荷や速度を考えるならどのみち違う方法でのキャッシングを考える。要検証。

Sexy Migration

マイグレーションの見栄えがよくなるよという話。

create_table :rubyists do |t|
  t.column :full_name, :string
  t.column :handle_name, :string
  t.column :age, :integer
  t.column :created_at, :timestamp
  t.column :updated_at, :timestamp
end

とかだったのが、

create_table :rubyists do |t|
  t.string    :full_name, :handle_name
  t.integer  :age
  t.timestamps
end

と書けるようになると。誰かが言ってたけど「Cの変数宣言みたい」。なるほどねぇ。ちなみに1.2系でもプラグインで同等の機能があるらしい。belongs_toとかもMigrationで書けるんだって話だったか。この変聞き逃してて記憶が定かでない。

あと、「(上のコードの)tはいらない」という情報がでて、それって凄いんじゃない?てかどうやって実装してるの?という話になって、終盤はMigrationまわりのソースを読んだ。結局それらしいコードは見つからず、もしかしてガセだったんじゃないかというところでに落ちついた。

Railsのプロファイリングあれこれ

後半のセッションはRailsアプリのプロファイリングノウハウについて。これ、凄く聞きたかった。Railsの欠点でもあり俺個人の弱点でもあるパフォーマンスとそのチューニング、そのためにもまず上手なプロファイリングが必要だよねと。

Railsのprofiler

Seattle.rbがいろいろと面白いものを作ってるらしく、いくつかのProfilerをセッションオーナーの瀧内さんが紹介してくれた。

中でも面白かったのがProduction Log Analyzer。これは実行中のプログラム自体の動作を測定するのではなく、ログを解析してRailsのパフォーマンスを測定するというもの。プログラムに組みこまないので「測定することによる影響」が無くてすむし、動作も重くならないし、既に稼働中のシステムを測定することもできる。これはなかなか素敵だった。

ただ、SyslogLoggerで吐いたログじゃなきゃダメらしい。なんでだろう。とりあえずSeattle.rbはSyslog大好き?ってことにしておいた。

Rubyレベルのprofiler

RubyProfは必須だそうです。標準のprofilerより速いのか。実際にRailsに仕込んでプロファイルさせてみるところまで実演。ちなみにRails 2.0を使用。試行錯誤してる内にRailsのここが変わった、RubyProfの最新版はここが違う、なんて話も出たりして、苦労してプロファイル結果を表示したときには拍手が上がった。うん、大変だった。なんか凄く大変だった。

ついでにdebugger

プロファイリングしたらデバッグしてみよう、ということで、2.0の新機能のdebuggerも試してみることに。script/serverのdebuggerオプションというのがあって、これを付けるとdebuggerが有効になるらしい。Ruby本体のバグ修正にともなって使えなくなったことで有名なbreakpointに変わって、ruby-debugを使ったものになっているとか。が、やってみたところlighttpdでは無視され、WEBrickでは何らかのエラーで起動できず、結局試してみることができなかった。流石にpreview版、まだまだ不安定というところか。ちなみにscript/profilerは全然メンテされてないらしく、一応2.0にも標準添付されてるくせに全く使えなかった。

作ってみるのがいい

後半のセッションはとにかく作ってみて試してみてあれこれ話しあったのだけど、これが非常に勉強になったし楽しかった。聞くところによると他のセッションでも掲示板作ったり、初心者セッションではScaffoldでとりあえず組んでみたりしてたらしい。まさにRailsならではだよなぁ。

まとめ

ようと思ったけどいい具合に意識が遠のいて来たのでとりあえずここまで。薬飲んで寝る。明日に備えて。そう明日もAkasaka.rbのJRuby勉強会に行くんだった。RubyばっかりじゃなくてPerlとかJavascriptも勉強してこいって言われそうだなぁ。

と、言うわけで、とりあえずiPod touchでちょこっと遊んでみたので雑感を。


流石の「触れる」インターフェース

iPod touchを語るにはまずインターフェースからだと思うので、早速べたべた触ってみる。

面白い。うん、すごく面白い。とにかくこれに触れてみたくて買ったようなものなのだけど、やっぱりこのタッチパネル式のインターフェースは凄い、としか言いようがないね。スクロールも実に滑らかだし、二本指で触ると動作が変わるのも余計なボタンや遷移が入らないで済むので素敵。

特にフォトライブラリをいじるのが楽しかった。パラパラと「めくるように」見られるのは操作と実際の挙動のギャップが少なくて本当にわかりやすい。二本指で開いたり閉じたり、縦にしたり横にしたり、とiPhoneの紹介動画みたいなこともやってみました。こーれは楽しい。写真撮りたくなってきた。ライブラリ充実させるためだけに。うは、本末転倒。

ただ、iPhone出たとき「直感的!誰でもわかる!」って絶賛されてたけど、それほどでもない、かな。例のごとく説明書は非常に簡素だけど、しばらく触ってみないとわかんないこと多い。ところどころ、「えっ、こここんな動きすんの?」ってのはあるし、設定とか「これを設定するとどーなるんだっけ?」ってのも結構あるし。あとキーボードは非常に使いづらい。俺は別に指が太い方じゃないと思うけど、それでもあちこち触れてしまってミスタイプしまくるので、平均的な成人男性なら確実にストレスが溜ります。でも日本語変換はそこそこ使える。MOSAIC.WAVが予測変換できた上、読みがなまで出てきたのには笑っちゃったけど。多分、ライブラリに入ってる曲名とかアーティスト名とかが予測変換のリストに自動で入るんだろうな。

あとAppleが大好きなカバーフロー、あれは素敵でした。タッチパネルと相性良いし、クリック(っていうかタッチか)すると曲リストとアルバム情報が出てそっから選べて、まさに棚からジャケットを頼りにアルバムを選ぶ感覚。ただ、プレイリスト再生中だろうがアルバム指定してようがどっから入っても、全アルバムのアートワークがでちゃうのはどうにかなんないかな。そこはちょっと不満。

iPod the Movie

動画再生に関しては、文句なしです。画面が大分でかくなったので今までよりずっと楽しめる。これまでのiPodで字幕スーパーの洋画は流石に厳しかったけど、あの画面サイズと解像度なら問題なく観られそう。サイズといえば、今までは圧倒的に画面サイズで勝ってたPSPに並ぶくらいにはなってるね(まだ若干PSPのが大きいけど)。iTunesと同期してるiPodの画面サイズがここまでになった以上、「メモリースティックの容量小さい・動画を管理するのが面倒・しかもかさばる」PSPはもう今後動画再生端末としては使うことはないだろうなぁ。いや、今までもPSPを動画再生端末としては使ってなかったけどさ。

ただ、動画再生機能が素敵すぎるだけに余計に容量の少なさが気になる。画面サイズがでかくなった分だけ画質の良い動画入れたいし、沢山入れておきたいんだけど、16GBじゃそれはちょっと厳しい。やっぱりその倍は欲しいよなぁ。

iTunes Storeは…ねぇ…

正直そんなに使い勝手はよくない。まず曲を探すのが面倒だし、検索するのにも件のすげー使いづらいキーボードで打たなきゃなのでストレスフル。しかも、日本でそんなに公衆無線LAN普及してないので、Wi-Fi機能を使うのが自宅だったり会社だったり、じゃあ何もiPodで買わんでもパソコンで買えばいいじゃんって話。日本のiTMSの品揃えはさほどでもないので「街で聞いて気になった曲があったから、その場でiPodで購入」ってわけにもいかないしなぁ。良い機能だとは思うけど、個人的にはあんまり使わなそう。

フルアーマーiPod touchに期待

最後に、周辺機器やグッズについて。

まず、全面タッチパネルのものを携帯や家の鍵と一緒にポケットに入れるのは流石にアレなので、袋を買ってきた。そう待たずとも専用のケースやカバーが出るだろうけど、さしあたってDS Lite用のシンプルなポーチのサイズが丁度よさそうだったので980円で購入。これならキズつく心配はないし袋ごとポケットに入る。touchに同梱のメガネふきみたいなやつも一緒に入れておける。値段も安いので急場しのぎにはオススメ。当分はコレで過ごすけど、今まで腰から下げるスタイルだったのでその手の専用ケースが出て欲しいところかな。

あと、家にあった5G iPod用のスタンド兼スピーカー(Princeton製)、これはそのまま使えた。Dockコネクタなので多分Macとの同期用にも使えるはず。夜間の充電用や卓上スピーカーとしては便利なんだけど、難点は縦置きなので動画再生には使えないこと。うーん、まぁ、固定してゆっくり観られる状況なら普通にMacなりPCなりで観ればいい話なのでそんなに需要はないと思うけど、touch専用スピーカー作るとしたら横にした状態でカチっとはめ込むタイプにしないとだなぁ。

なにはともあれハックしたい

とりあえず雑感はこんな感じ。Safariはまだ試してないので、これからじっくり試そうと思います。

あとは、早いとこ誰かハックして勝手アプリ作れる環境にならないかな。そしたらアレやコレやいじくり倒したいのですよ。ふふふ。

↑このページのトップヘ