yohei-y:weblog

XML と REST/Web サービス関連の話題が中心の weblog です

2007-12-14

WEB+DB PRESS Vol.42 と7周年記念イベント

来週 20 日に WEB+DB PRESS の7周年記念イベントが開催されます。 関係者枠で招待していただいたので、僕も参加します。 スピーカーがすごい面子で、楽しみですね。連載しててよかった。

ところで次回の WEB+DB PRESS には上記イベントのスピーカーの一人羽生章洋さんと、t-wada こと和田卓人さんと3人で REST に関して鼎談した内容をもとにした記事が特集として載る予定です。

もともとは、編集者さんから、t-wada さんが WEB+DB PRESS を読むときに僕の連載を一番最初に読むと言っていると教えてもらって、 僕の方も和田さんの TDD の記事でたくさん勉強させてもらったので(題材が REST だったし)、 ぜひ和田さんとお話したいと返信したら、話がどんどん大きくなって羽生さんを交えての鼎談になってしまったのでした。

ビデオ収録の鼎談なんて初めての経験だったのでかなり不安だったんですが、 自分の出来はともかくむちゃくちゃ楽しかったです。 鼎談の内容はニコニコ動画で公開されるらしいので、お楽しみに。

photo
WEB+DB PRESS Vol.42
WEB+DB PRESS編集部
技術評論社 2007-12-22

鼎談では URI を Universal Resource Identifier とか間違って喋っていて非常に恥ずかしいので(いつも Uniform か Universal かわからなくなる)、 あんまり DIS らないでください。もちろん記事の方は直っています。

それから和田さんが書いてくれた Restlet をベースに RESTful なシステムを実装する章は必見です。 Java じゃない人でも、実際に RESTful にリソースを設計するというのはどういうことかを学べるすばらしい記事になっていると思います。

ラベル: , ,

2007-09-08

REST の勝利宣言と良い XML の見分け方

ITpro Challenge 行ってきました。

豪華なメンバーでどの講演もとても面白かったですね。 江島さんの講演は、Web 上でサービスをやるとはどういうことなのかについてとても示唆に富んだ話だったし、 鵜飼さんのハッカーのソフト工学の話は職場的にすげータイムリーだったし、 なおやさんの話は同時代を生きてきた、生きている者としてとても共感できる内容だったし、 戀塚さんはこれぞハッカーという感じのすごい人でした。

僕は LT の最後に話をさせてもらったわけですが、 ネタを二つ持っていって聴衆のみなさんに選んでもらうことにしました。

結果は REST が勝ったので、当初の予告どおり REST の話をすることに。

結局お蔵入りになった XML の話ですが、もったいなかったので懇親会でお話させてもらいました。

プレゼン中で引用した Web ページはこちらです。

檜山さんの記事

Tim Bray の記事

リンクは重要ですよ。

ラベル: , ,

2006-08-20

XML の本当のメリットは拡張性を保証して構造化文書もマークアップできること

デジャビュを感じる

XMLの「本当のメリット」ってなに?

Matzにっき XML のメリット、デメリット

XML の仕様には歴史的・政治的理由でいろいろと不満な点があります。 これは XML をやればやるほど感じるものです。 しかし、拡張性を保証して構造化文書もマークアップしようとすると 選択肢は XML しかないのもまた事実です。

ということで、

  • 構造のあるデータが書けること(すずきひろのぶさん)

    別にS式でもYAMLでも書けますよね。拡張性のあるテキストのマークアップという意味(テキストが主、マークアップが従)ならSGMLの系譜を否定しませんが、データ記述や設定ファイルにまでとなると話は別です。

Matzにっき XML のメリット、デメリット(追記より)

結局はここに落ち着くのではないでしょうか。 XML というメタ言語の設計が構造化文書のマークアップに寄っているので、 データ記述や設定ファイルに使うとどうしても冗長性が鼻についてしまいます。 つまり用途によっては XML が最良の選択とはなりえないと僕も思います。 (参考: 檜山さんによる JSON と XML の比較)

あと「野良XML」のほとんどが名前空間を使っていない云々というのは 単なる印象っぽいので、どのくらいの割合で使っていないのか不明なんですが、 仮に名前空間を使っていない野良 XML であったとしても 将来的には名前空間を使って拡張することが可能になることは忘れてはいけないと思います(例: RSS 2.0)。

Open Data が叫ばれる昨今、Web 上を流通するデータフォーマットでは この拡張性というのは非常に重要な概念なのでやっぱりX重要

ラベル: , ,

2005-12-12

Atom で件数取得

なんか催促されちゃったみたいなので :-) 詳しく書いてみます。

はてなのブックマーク件数取得 API いいですね。 今さら xml-rpc かよ! というツッコミは置いておいて、 データ重要な世の中で有用なコンテンツ(メタデータ)にリーチする 方法が増えるのは喜ばしいことです。

そうそう、こういう API を AtomPP で実装するとしたらどんな感じなんだろう。そもそもうまくフィードで定義できるのか。教えて偉い人!

偉い人じゃないけど、結論からいえば、 Atom Publishing Protocol (APP) そのままじゃ無理です。 やってもいいけどどうしても無理が出てしまいそう。 そもそも目的が違うのだから、ここは野良 XML/プロトコルでいいのでは。 ただ、結果をフィードで取れるとそれなりに嬉しいかもしれない。

普通 REST で検索するときは query string を使った URI を GET することになる(検索結果リソースを GET する)んですが、 今回の場合のようにパラメータがたくさんあったり長かったりする場合は GET は現実的ではありません。 こういうときは問合せ文書(query document)を POST で投げます。

POST /atom/exist HTTP/1.1
Host: b.hatena.ne.jp
Content-Type: application/xml
Content-Length: xxx

<uri-list xmlns="http://ns.hatena.ne.jp/uri-list">
  <uri>http://d.hatena.ne.jp/naoya/20051212</uri>
  <uri>http://yohei-y.blogspot.com</uri>
</uri-list>

結果はたとえば XML 形式で取れます。

HTTP/1.1 201 Credated
Host: b.hatena.ne.jp
Content-Type: application/xml
Content-Length: xxx
Location: http://b.hatena.ne.jp/atom/exist/1234567890abcdefg

<bookmark-list xmlns="http://ns.hatena.ne.jp/bookmark">
  <bookmark>
    <uri>http://d.hatena.ne.jp/naoya/20051212</uri>
    <count>5</count>
  </bookmark>
  <bookmark>
    <uri>http://yohei-y.blogspot.com</uri>
    <count>4</count>
  </bookmark>
</bookmark-list>

ここでのキモは Location ヘッダで検索結果リソースの URI を返しているところ。 この URI を GET すればいつでもこの検索結果(の最新版)が取得できると。

リクエストとレスポンスは野良 XML でもいいんですが、これくらいの情報なら JSON の方がプログラムから扱いやすくて便利ですよね。実際、グリモンとかから使うなら JSON の方がいいと僕も思います。

ただ、レスポンスの場合、野良 XML じゃなくて Atom フィードだと いいことありそうです。

HTTP/1.1 201 Created
Host: b.hatena.ne.jp
Content-Type: application/atom+xml
Content-Length: xxx
Location: http://b.hatena.ne.jp/atom/exist/1234567890abcdefg

<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>はてなブックマーク検索結果</title> 
  <link rel="self" type="application/atom+xml"
    href="http://b.hatena.ne.jp/atom/exist/1234567890abcdefg"/>
  <updated>2003-12-13T18:30:02Z</updated>
  <author><name>Hatena</name></author> 
  <id>urn:uuid:60a76c80-d399-11d9-b93C-0003939e0af6</id>

  <entry>
    <title>なおやのはてなダイアリー</title>
    <link href="http://d.hatena.ne.jp/naoya/20051212"/>
    <link rel="alternate" href="http://b.hatena.ne.jp/entry/http://d.hatena.ne.jp/naoya/20051212"/>
    <id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>
    <updated>2005-12-13T18:30:02Z</updated>
    <summary>5</summary>
    <content type="xhtml">
      <!-- リンク、キーワード、タグなんかをそのまま入れる -->
    </content>
  </entry>

  <entry>
    <title>yohei-y:weblog</title>
    <link href="http://yohei-y.blogspot.com"/>
    <link rel="alternate" href="http://b.hatena.ne.jp/entry/http://yohei-y.blogspot.com"/>
    <id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>
    <updated>2005-12-10T10:34:02Z</updated>
    <summary>4</summary>
    <content type="xhtml">
      <!-- リンク、キーワード、タグなんかをそのまま入れる -->
    </content>
  </entry>

</feed>

ブックマーク件数は summary に入れるの? とか(summary/content の中で microformats 的にやったほうがいいかもしれない)、いろいろツッコミどころはありますが、雰囲気は伝わるんじゃないでしょうか。

イメージとしては、現在の人間用はてなブックマーク一覧のページで、 表示するブックマークを一つ一つ指定できるようにした感じです。 今のブックマーク一覧ページで取れている情報をそのまま Atom フィードにしたものを想像してもらえればいいでしょう。 カテゴリなど、Atom で用意されている要素はそのまま使ってもよさそうだし、 足りない要素・属性があればはてなの名前空間で足せばいいだけ。

Atom フィードなんで、RSS リーダで購読すれば更新情報も取れます。 自分の気になる記事がどれくらいブックマークされてるかどうか気になる人には けっこう嬉しいんじゃないでしょうか。

まー、フィードは Atom じゃなくて RSS でもいいじゃん、 といわれちゃいそうだけど、RESTful に考えるとこんな風になるという参考までに。

追記: 例のレスポンスのステータスコードを 201 にしました。

ラベル: ,

2005-09-17

Javascript+HTML のデザインパターン

僕もご多分に漏れず Javascript で遊んだり調べたりしています。 いろいろなクールなサイトの生 Javascript を見て勉強しているのですが、 まず面白いなと思ったのがロールオーバーの実現方法です(JavaScript や HTML をわかってる人には当たり前の内容だと思うので、ツマラナイ話だと思いますが)。

WaSP の左上の画像のロールオーバーは

<img id="logo" src="/img/logo.gif" height="100" width="103"
  alt="Web Standards Project logo" />

生 HTML はこんなかんじで onmouseover/onmouseout 属性を記述せず、 JavaScript

function initRollOvers() {
 var logo;
 if (document.getElementById) {
  logo = document.getElementById('logo');
 } else {
  return false;
 }
 /*if (document.all) {*/
  logo.onmouseover = swapI;
  logo.onmouseout = swapI;
 /*} else {
  logo.addEventListener('mouseover',swapI,false);
  logo.addEventListener('mouseout',swapI,false);
 }*/
  return true;
}

function swapI(e) {
 e = (e) ? e : event;
 thisI = (e.srcElement) ? e.srcElement : e.target;
 if((thisI.status != 'a') &&
    (thisI.status != 'p')) {
  thisI.src = '/img/' + thisI.id + '_a.gif';
  thisI.status='a';
 } else if(thisI.status != 'p') {
  thisI.src='/img/'+thisI.id+'.gif';
  thisI.status='';
 }
}

こんな風にして id 属性に logo という画像を持つ img 要素の onmouseover と onmouseout をページ表示時に動的に変更することで実現していました。

似たような手法は Nikon のサイトYamaha のサイトでも 利用されています(両方同じ業者さんみたい)。

もう一つ、今度は別のところで、これと似た手法を見ました。

del.icio.us では delete リンクをクリックしたときに ちょっとした工夫をしているのですが、 このちょっとした工夫は下記のように実現されています。

delete リンクの HTML ソースはこんなかんじ。

<a href="/yohei?delete=9d7b7c953b1e47a7d82e791848f43899"
  class="rm" rel="nofollow">delete</a>

onclick 属性がなく Javascript の影も形もありません。

どうなっているかというと、ヘッダでロードしている Javascript

function rmPostAddEvent() {
  var all = getElementsByClass(document.getElementById('posts'),'rm','a')
  for(var i = 0, o; o = all[i]; i++) o.onclick = function(){ return rmPost(this) }
}
function rmPost(o) {
  o.style.display = 'none'
  var s = document.createElement('span'); s.o = o
  s.innerHTML = '<span class="important">delete this post?</span> <a href="'+o.href+'">yes</a> / <a 

href="'+o.href.replace(/(\?|&)delete=[^&]*&?/,'$1')+'" 

onclick="this.parentNode.o.style.display=\'inline\';this.parentNode.parentNode.removeChild(this.parentNode);return 

false">no</a>'
  o.parentNode.insertBefore(s, o)
  return false
}

とやって、yes/no を追加しています。

ロールオーバーの例と del.icio.us の例で共通するのは、 静的なコンテンツ部分(HTML)と動的な UI の振る舞い制御部分(JavaScript)を 完全に別ファイルに分けているところです。 もちろんこうするためには class 属性や id 属性の値にコンベンションが必要となるのですが、 このようにアクションとコンテンツを分離することで、以下のようなメリットがありそうです。

コンテンツ生成プログラムの効率化
onmouseover などイベント系の属性を記述しないですむので、HTML 生成プログラムが効率化しそうです
メンテナンス性の向上
上の項目につながりますが、問題があるのがデータなのか、スクリプトなのかの区別がつきやすそうです
HTML サイズの縮小
要素毎に属性を記述しないですむので、ネットワーク転送量が減少します

さらに、class や id の値のコンベンションという意味で、microformats との相性もよさそうです。

さらに面白いと思ったのは、 この動的・静的がサーバから見たときと、クライアントから見たときにちょうど対称的になっているところです。 サーバから見ると、生成するデータ(ブックマーク一覧)こそが動的であり、 そこに yes/no リンクという振る舞いを与える JavaScript プログラムは静的です(del.icio.us の URL にも static とある)。 逆にクライアント(ブラウザ)から見ると、 HTML に入っているブックマーク一覧というデータは静的ですが、 JavaScript によってそれらを動的に変更しています。

こういうのってかなり抽象化できていて、正にデザインパターンと呼べそうな気がするのですが、 何か名前があるんでしょうか(NDO メソッド)。ちょっと探してみたけれど、見つけられませんでした。 勝手に behavior injection(振る舞いの注入) とか action injection (アクションの注入) と想像して検索してみたのだけれど。

ラベル: ,

2005-08-21

microformats などの設計についていろいろ

僕が提案した方法についておのひろきさんからツッコミが入りmicroformats を誤解しているマークアップする力の問題である、と批判されました。

まー実際、microformats を誤解しててマークアップする力もないかもしれないんだけど、 おのひろきさんの主張には賛成できないので、ここでまとめて反論しときます。

まず、「microformats についての誤解と,ぼくが理解している範囲」より。 前半の microformats の説明は特に異論はありません。 でもそれがなんでいきなり

それでさらに microformats であるなら,一度「意味付けと記述書式」を決め たら,それが他での使い回す事ができないと意味がありません.限定された問 題を解ければ良いとはいっても,特定の問題にしか対応できないほど限定して たら駄目なのです

ってなっちゃんでしょう?(強調筆者) ここがまずわからない点。

rel 属性値は profile で定義してそこで意味付けをします.上の例では a 要素で rel 属性値 hatenab とある場合は href が指す URI ははてなブックマークであるってことになるのかな?

元記事では、主題が別だったので詳細なプロファイルまで書いてませんが、 リンク形式 rel="hatenab" は、リンク先が元ページの著者のはてなブックマークへのリンク、という意味です。 目的は「自分が使っているサービスを宣言」するため。

profile を定義するということを意識していないから rel 属性値をどうするかというところで間違えるのではないでしょうか.profile を定義することと,その profile が他で応用できるようにするということを考えないとダメだと思うのです.

最後のここもいまだにわからないんですよね。 rel を拡張するなら profile (microformats なら XMDP) が必用、というのはわかってるつもりです。 でもそれと、「他で応用できる」ってどう関係があるんでしょうか? たとえば XFN は友人関係を記述する以外にどう「他で応用できる」んでしょうか?

続けて「マークアップする力」より。

檜山さんの記事を引用して

「邪悪マークアップは先進的マークアップか?」から引用すると:
これがまずい理由は、<田中>元気で行ってこい。</田中>や<ミヨ子>おみやげ、忘れないでねぇ</ミヨ子>のあいだに共通性があるのに、その共通性がマークアップにより表現されてないことです。
これと同じ事が rel="hatenab" と rel="delicious" にも言えると思うのです.

と書いていますが、同じとは言えないと思いますよ。

おのひろきさんは Semantic Web に詳しいようなので釈迦に説法かもしれませんが、 rel 属性と class 属性の仕様上の違いをまず再確認してください。 rel は「リンク形式(のリスト)」、 class は「クラス名(のリスト)」です。 リンク形式(link type)がリンクの関係性を表現するのに対し、 クラス名は (X)HTML 要素の分類に用いるものです。

いわゆる microformats ではこの二つをちゃんと使い分けていて、 rel 属性は (X)HTML の仕様どおり、リンクの関係性を表現しています。 そのリンク先がライセンス文書であると指定したりリンク先のコンテンツがリンク元とは関係ない(follow してない)と指定する、などです。

一方で class 属性は XHTML に vCard の構造を埋め込んだりiCalendar の構造を埋め込んだりするのに使います。 クラス名が構造情報と対応しているわけです。

ここまでで明かだと思いますが、 檜山さんの記事に出てくる「多重マークアップ」は class 属性の応用の話です。 対して、ここで議論しているのは rel 属性の値(リンク形式)をどうするか、という話です。檜山さんの例を引けば、

<寄せ書き>
 <ひとこと 誰="田中">元気で行ってこい。</ひとこと>
 <ひとこと 誰="ミヨ子">おみやげ、忘れないでねぇ</ひとこと>
 ...
</寄せ書き>

ここで言う 「誰」属性の値は「田中」がいいのか「id:tanaka」がいいのか 「上司」がいいのか「社員」がいいのか「男」がいいのか「日本人」がいいの か「人間」がいいのか「哺乳類」がいいのか「動物」がいいのか「生物」がいいのか… って話と同じですよ。

だから、

つまり rel="hatenab" と rel="delicious" の間に共通性があるのに,その共通性が表現されていないのです.それは,書き手の頭の中だけにあります.

これは勘違いではないですか。 上記のとおり、リンク形式に指定する値の粒度をどれくらいにするかというのを議論してるんです。 その値の定義は、おのひろきさん自身が言っているとおり「profile によって定義するっていう手」を使います。

profile によって定義するっていう手もありますが,そうすると似たようなサービス全てについて profile で定義を用意しなければなりません.そうではなくて rel 属性では共通性の部分を表現するべきでしょう.

別に「似たようなサービス全て」を定義しなくてもいいんじゃないでしょうか。 プロファイル策定者がはてなだったら hatenab, hatenaa, hatenai, hatenad,... と自社のサービスを定義すればとりあえず十分でしょう。 これで、あとは API さえあれば、今閲覧している Web ページの作者のはてなブックマークを自分のお気に入りに入れるブックマークレットとか、 その人が使っているはてなのサービス一覧を小綺麗に表示する greasemonkey スクリプトとかが作れそうです。

ただ、一利用者の感覚とすれば、hatenab じゃなくて del.icio.us も使いたいんですよね。 でも del.icio.us には inbox はあっても「お気に入り」はない。 こんなかんじで hatenab と delicious を区別したいニーズはあります。

これについておのひろきさんは

rel="hatenab" とある場合とない場合で,メタデータの抽出の仕方がどう変わるかを考えたら,あまりrel="hatenab"ってのは有効ではないのでは? hatenabにマッチングするか b.hatena.ne.jp にマッチングするかの違いだか ら.

という見解のようですが、 僕はまったく逆ですね。 URI でマッチングしなきゃいけないような設計は悪い設計の代表例だと思います。 何で悪いかの理由のひとつは shckor さんがいうとおり URI がやむを得ず変わる場合ですね。 REST とか、疎結合の文脈で言えば、クライアントとサーバのお約束が増えてしまうという意味で悪い設計です。 せっかく rel 属性があるのに、関係ないところで URI のコンベンションを作るのは余計な制限を増やすだけだと思います。

ちなみに、はてなや del.icio.us のドメイン名は安定してそうなのでまだいいですが、 たとえば、サーバインストール型の Web アプリケーションだったり、 社内向けサーバで、どうしてもドメイン名を変更しなければならなかったりしたらどうするんでしょうか。 たとえば pukiwiki にソーシャルブックマークプラグインができたとしたらどうしますか。

<link rel="onlineBookmark delicious" href="http://del.icio.us/onohiroki"/>
ってのも良くないと思います."delicious" ってのを profile で定義しなくちゃならないから.それなら "delicious" を与えるのは title 属性が良いと思うし,profile を定義しなくても良い class 属性のほうが rel 属性よりはまだ良いと思います.

上記のような理由から rel 属性の代わりに class 属性を安易に使うのは反対です。 rel には rel の意味があるのだから。

ここまで書いて、「class 属性を再発見」というエントリが追加されているのを発見したんで、 ついでにこちらにも若干コメントを。

最初に定義していなかったものを後から追加したくなったら,別 profile を作るのでしょうか? この問題をどう考えているのかはぜひ教えてほしいです.

同じプロファイルに新しいサービス名を追加してバージョンアップします。 もちろんこれは XML のスキーマのバージョンアップ問題と同じ話で、 いろいろと難しい問題を含んでいるのですが、 どこに追加される可能性があるのかはっきりさせる、 新しいものを追加しても問題が起きないようにクライアントを作る(知らないサービスは無視するか、知らないサービスとして扱う)、 追加するだけならバージョンを上げなくてもいい(プロファイルの URI を変更しない)、 といったような設計が 2005 年の現時点では理想的かつ現実的な設計でしょうね。

shckor さんや yohei さんが言っている事がちゃんと理解できたら title 属性とかぢゃなくて class 属性ってすぐに出てこないとおかしいですよね.いや,未だに shckor さんや yohei さんの主張でよく分からないところがあるけど.

僕は以前にも title 属性は助言情報なのだからコンテンツ作成者の自由にさせるべきという意見を書いたとおり、 title 属性の安易な濫用はお勧めしません。 上記のとおり rel から class への安易な鞍替えも同様です。

ラベル: , ,

2005-08-12

良い URI の設計

URI は綺麗であるべき、と常々思っているんですが、よいページを発見しました。 Michael Eakesこのエントリです。 Tanya Rabournリストアップしている文献一覧からエッセンスをまとめてくれています。 曰く、よく設計された URI とは

  • 変らない(don't change)
  • 人間が推測可能(are human guessable)
  • 論理的(ファイルシステムを反映する必用がない) (are logical (no need to mirror a filesystem))
  • サイト構造をビジュアライズするのに役立つ(help visualize the site structure)
  • 短い(are short)
  • 小文字を使う(use lowercase)
  • 予期されない記号を使わない(don't use unexpected punctuation)
  • 問合せパラメータなし(lack query parameters)
  • 公開リンクを許す(allow public linking)
  • ステートレス(are stateless)
  • 技術を丸出しにしない(dont expose technology)

だそうです。 彼のエントリにはそのほかにも Flickr の URI が良い設計例として載っています。

典型的な悪い例はこんな感じかな。

http://test1.example.com/Test/getDocList.cgi?folder-name=abc&user_name=yohei&sessionId=123

直すとこうなる。

http://www.example.com/yohei/abc

最後の項目の悪い例は /home.pl とか /login.do とか /index.jsp とか /hitobito.nsf とかですかね。 とりあえずは mod_rewrite を使って解決するんでしょうけど、本質的にはフレームワークが解決した方がよさげ。

ラベル: ,

2005-07-31

Web らしく URI で連携する方向

前のエントリで触れた ID だけのディスカバリの問題点ですが、 他にもこんなのもあります。

僕が自分のブログにはてな ID を埋め込んだとして期待するのは、 ブログを訪れた人が自分のブックマークやアンテナを見に来てくれたり、投げ銭してくれたりすることです。 でも僕がはてなで何を使っているかは僕にしかわかりません。 僕の場合はてブはてアは使ってるけど、 はてダは更新を止めちゃった、はてフは知らん、という状況です。 もしかしたらアサマシは嫌いだから投げ銭してほしくない、という人もいるかもしれない。

これって「はてなID」の埋め込みだけでは実現できません。 自分ははてなのこのサービスを使っているよ、という主張をできないからです。

ではどうするか。 自分ははてなのこのサービスを使っているから見に行ってね、という宣言をしたらどうでしょう。 head 内で宣言するんだったらこんな感じ。

<link rel="hatenab" href="http://b.hatena.ne.jp/yohei" />
<link rel="hatenaa" href="http://a.hatena.ne.jp/yohei" />

body 内部で a タグに書くのであればこんな感じ。

<a rel="hatenab" href="http://b.hatena.ne.jp/yohei" >はてぶ</a>
<a rel="hatenaa" href="http://a.hatena.ne.jp/yohei" >はてあ</a>

ここまでくると、別にはてなに限らないでもいいのではないかという気がしてきます。 たとえば僕の場合、使っていると宣言したいサービスは

  • hatenab
  • hatenaa
  • flickr
  • bloglines
  • delicious
  • mixi
  • blogger

なので、head はこうなります。

<head>
  <link rel="hatenab" href="http://b.hatena.ne.jp/yohei" />
  <link rel="hatenaa" href="http://a.hatena.ne.jp/yohei" />
  <link rel="bloglines" href="http://www.bloglines.com/public/yamamotoyohei" />
  <link rel="flickr" href="http://www.flickr.com/photos/60043209@N00/" />
  <link rel="delicious" href="http://del.icio.us/yohei" />
  <link rel="mixi" href="http://mixi.jp/show_friend.pl?id=173690" />
  <link rel="blogger" href="http://yohei-y.blogspot.com" />
</head>

a タグだったらこうなります。

<a rel="hatenab" href="http://b.hatena.ne.jp/yohei">僕のブックマーク</a>です。
<a rel="mixi" href="http://mixi.jp/view_profile.pl?">mixi</a>も使ってるよ。
<a rel="payment hatenagesen" href="http://nagesen.hatena.ne.jp/yohei">投げ銭</a>よろしく。

この rel= はいわゆる microformats ですね。 link タグなら Atom feed にも同じように入れられます。

rel 属性の値が各サービスごとに違うのがいいのか、 もっと別の値がいいのか、そもそもこんなことがやりたいのか、やっていいのか、という話はありますが (^^; URI で繋がるという方向性もある、ということを認知してもらえたらと思います。

ラベル: , , ,

そもそも ID を見つけるだけで十分なのだろうか

なんか複雑な方向になってきたなーと思っていたところで風邪を引いてしまって寝込んでいたので、なんだか浦島太郎状態ですが、思うところを。

今の暫定仕様は僕にとってはちょっと違う方向のように感じるんですね。アカウントの ID だけを渡すというのは、関数のパラメータの一引数を渡すというのに繋がる気がするからです。

そもそも naoya さんがやりたかったこと

まずそもそも僕が考えた仕様は...という前にまず何をしたいかを明確にしないとですね。僕がしたいのは、はてなダイアリーを含めたインターネット上のウェブページ (Permalink) から、そのページを作った人の「はてなのID」を探し出したい、ということです。

ですが、では ID を探し出して具体的に何をするんでしょうか。 もちろん、はてなのサービスの中の人はいいと思います。 HTML や RSS/Atom を取ってきて、その中にはてなIDがあれば、その ID からユーザを特定していろいろできる。 でも Web 2.0 的に考えるなら、はてな外の Remix する人の事も考えてほしい。

そんな Web 2.0 的な Hatena ID Auto Dicovery の応用に、 吉松さんが触れていました

僕は「投げ銭」に特化しないほうがいいなあ、と思ってます。例えばツールバーに「この人のはてダに移動」とか「このひとのはてブお気にを一覧」とかいうボタン作るのに役立ちそうだな、と思うもので。

なるほど。確かに便利そう。 とある Web の記事や RSS/Atom フィードを表示すると、 はてなツールバーや Greasemonkey スクリプトでその人のはてなブックマークへのリンクがポップアップしたら楽しい。 実際のコード(の断片)は例えばこんな感じかな。

var hatenaid = getIdFromRdfFoaf("http://www.hatena.ne.jp/");
document.write("<a href='http://b.hatena.ne.jp/" + hatenaid + "'>?B</a>");

うーん、嫌だ。

嫌な点の一つ目は "http://b.hatena.ne.jp/" という文字列をクライアント側で持っていて、ユーザ名と組み合わせている点。 これをやってしまうと、b.hatena.ne.jp を変えたり、URL の構造を変えたとたんに 途方もない数の全クライアントを一斉に変更しなければならなくなってしまう。 いわゆる密結合の一番悪いパターンですね。

もちろんはてなのドメイン名や URI の構造がそんなに簡単に変化するとは思いませんが、 一般的にはやらない方がいいことです。

それからもうひとつ嫌なのは JavaScript で getIdFromRdfFoaf() を作るのが大変そうなところ。 コメントアウトされた RDF/FOAF の文字列を「わざわざ」探し出して、さらにそれをパースして、RDF のトリプルにして…、 とやるのは想像するだけで鳥肌が立つ(のは僕だけかな)。

HTML に ID を埋め込む、というのは一見するとすごく汎用的で何にでも使えそうなんだけど、 汎用的であるが故に何をやるにも中途半端になってしまう危険性があります。 もう少し実用的な使い方をいくつか模索したり組み合わせたりして、 その中で汎用的に使える部分を探すという方がいいのではないかと思います。

では具体的には何なのだ、という話は次のエントリで。

ラベル: ,

2005-07-23

Hatena ID Auto-Discovery について

昨日は SIGMOD-J の大会に行った後にアルファギークなお二人と食事をしてきました。

大会ではやはり naoya さんの Web 2.0 についての話が一番面白かったです。 周りにいた人の反応も一緒でした。

ちなみに僕は naoya さんは初対面。 食事に途中参加の高林君とはちょうど4年ぶりだったことが今判明。オリンピックみたいだ:-)。

naoya さんは普段から blog やブックマークを見ているので、ぜんぜん初対面な気がしなかったんですが、 僕としては REST だの Folksonomy だの microformats だのといった単語をガンガン喋ったり聞いたりするのが新鮮かつエキサイティングでした。 やっぱり直接会って話すのは大切だと実感です。

以下本題です。僕は話題に出遅れてしまったんですが Hatena ID Auto-Discovery について。 naoya さんには直接喋ったんだけど、 酔っ払っててよくわからなかったと思うので、 もう一回ここに書いておきます。

まず、現状の仕様はこうですね。

<link rel="schema.DC" href="http://purl.org/dc/elements/1.1/" />
<link rel="DC.creator" title="id:naoya"
  href="http://www.hatena.ne.jp/user?userid=naoya" />

で、僕が提案するのはこれ。

<link rel="schema.DC" href="http://purl.org/dc/elements/1.1/" />
<link rel="DC.creator" href="http://www.hatena.ne.jp/user/naoya" />

二点提案があります。

最初は title 属性について。 例では title="id:naoya" となっていますが、 別にこれはなくてもいいのではないでしょうか。 DC の creator は href 属性で指定される URI で識別されるのであって、title 属性はあくまでも便宜上の助言的情報。 ならば、title 属性の内容はコンテンツ作成者に委ねた方が自由度が上がる、と考えられます。 もちろん id 記法が好きな人は title="id:yohei" としていいし、 そうじゃなくて title="YAMAMOTO Yohei" としてもいいし、 title="このページの作者のはてなIDです" とかしてもいいわけです。

次に href でリンクする先の URI についてです。 ひとつは ?userid=naoya というように、query string を使うのはどうだろう、という話。 もうひとつはこの URI が適切なのか、という話です。

こういう ID としての URI に query string が入っているとちょっとクールじゃないですね。 文字列長も長くなっちゃうし、何より query string はクライアント側でいじれる所がいかにも密結合的です。 ま、このケースはそんなに気にすることはないんですが、 僕のこれまでの感覚だと、はてなは URI がいつも綺麗だという印象があります。 はてならしさを維持するためにも、ここは query string を使わないほうがいいのではないでしょうか。

あとはリンク先の妥当性です。 はてなダイアリーの id 記法でリンクする先はそのユーザのダイアリーですよね。 その観点から id 記法との整合を考えると、ダイアリーを持っているユーザの場合は、 ダイアリーにリンクするのが最も適切ではないでしょうか。 ダイアリーを使っていないユーザはどうするのかという問題が残りますが、 それも id 記法でのリンク先にあわせるのがいいのではないでしょうか。

ということで、最終的には以下のような形になりました。

<link rel="schema.DC" href="http://purl.org/dc/elements/1.1/" />
<link rel="DC.creator" href="http://d.hatena.ne.jp/naoya" />

ラベル: ,

2005-05-23

疎結合と XML

疎結合(loosely-coupled)って何でしょう?

僕自身、適当に疎結合という言葉を使ってしまいがちですが、 ちゃんとした説明なり定義なりが必用だと感じています(自分のために)。 いいかげんな定義で話をはじめると、 各人の方向性がずれまくって議論ができないですよね。 Web サービスしかり、 SOA しかり、REST しかり。 ということで今回は僕なりに疎結合ってこんなもの、 というのを考えてみます。

ものすごく一般化してしまうと、 疎結合というのは複数のコンポーネント間の結び付きが ゆるいことを指すんでしょうね。 たぶん、ここまでは誰でも同意してくれるはず。 ただこれだけでは議論ができなくて、 このコンポーネントに何をもってくるかを決めて、 はじめて具体的な話ができます。

僕がここで話したいのは Web サービスの文脈での「疎結合」ですから、 コンポーネントは Web サービスになります。 コンポーネントがオブジェクトだとかもっと細かいレベルの話もあると思いますけど、 ここではしません。

あ、Web サービスという言葉も危いですね。 ここでは Web 上で機械(プログラム)可読なフォーマットで情報を提供するもの、 だとします(実際、僕の Web サース感はこれに近い)。 SOAP インターフェースの株価サービスかもしれないし、 AtomAPI のはてなブックマークかもしれない。 RSS フィードも含みます。

ところで、この「疎結合」をもろに扱った本があります。 タイトルがずばり「疎結合」です。 SOAP よりの Web サービスの文脈での疎結合を扱っている本です。 この本は10章で疎結合とは何かを解説しているんですが、 そこにはこんなことが書いてあります。

(前略) 多くの人々が「疎結合」という言葉を口にしますが、 その意味を正確に説明できる人はほとんどいません。 これは、疎結合が方法論もしくは作法であり、 確立された規則や仕様ではないからです。

疎結合は、俊敏性(アジリティ)、すなわち変化に適応する能力を重要視する 分散アプリケーション設計へのアプローチの一種です。 (後略)

つまり疎結合というのは分散アプリケーションの作り方、 設計の仕方に関する考え方のひとつであり、 特に決った規則や仕様はないってことです。 これは逆の意味でしっくりきました(僕には)。 これだけ曖昧な定義なら、議論の方向性が定まらないのも仕方ないですね。

僕が今考える疎結合システムのイメージはこんな感じです。

まず、サービス(コンポーネント)間のインターフェースは統一し、 半永久的に変更しません。 サービスのインターフェースに少しでも修正が入ると、 旧インターフェースを利用していたクライアントを修正しなければならないからです。

インターフェースを統一して不変にしたときに、 ではいったいどこでサービス同士の機能を差別化するのか。 それはサービス間でやり取りするデータで行います。 データ形式を思いっきり自由に拡張可能にして、 どんな種類のデータでも統一インターフェースで受け渡し可能にします。 オブジェクトだとこの拡張性が厳しいのですが、 XML と名前空間の組み合わせならぜんぜん問題ありません(ちょっと言い過ぎか)。

XML が拡張可能ということは、自分が知らない要素や属性が出てくる可能性があるということです。 でも、そんな拡張された未知のデータでもエラーにせずに、使えなければなりません。 そのために、知らない要素は無視する、という動作をデフォルトで行わなければならないのです。 SOAP の mustUnderstand 属性がデフォルトで false なのは、こういう理由からではないかと思います、たぶん。

で、このデフォルトで無視という動作は、 吉松さんがこのポストで言っている 「無邪気なまでにデータの読み手に解釈をゆだねる姿勢」 のデータの読み手側の一番簡単な実践なんだと思うのです。 本当はさらに吉松さんのポストのコメントで萩原正義さん(らしき人)が言っている「semantics を重視した…」 というのも直感的にわかりそうなのだけれど、今の僕には残念ながら理解しきれません。 だからとりあえず、 XPath なりで知ってる要素と属性をパターンマッチして知らないやつは無視、からやってみるしかないんだな、 というなんだか当たり前の結論になっちゃったなあ。

ラベル: , , , ,

2005-03-09

Restifying excite 翻訳

今日は excite 翻訳の REST インターフェースを考えた。

まずは簡単な翻訳

POST /translation HTTP/1.1
Host: rest.excite.co.jp
Content-Type: application/xml

<?xml version="1.0"?>
<input xmlns="http://ns.excite.co.jp/translation"
    xml:lang="en" out="ja">
REST stands for REpresentational State Transfer.
</input>
HTTP/1.1 OK
Content-Type: application/xml

<?xml version="1.0"?>
<output xmlns="http://ns.excite.co.jp/translation" xml:lang="ja">
REST は REpresentational State Transfer の略です。
</output>

これは以下のようにする案もある。

POST /translation?i=ja&o=en HTTP/1.1
Host: rest.excite.co.jp
Content-Type: text/plain

REST stands for REpresentational State Transfer.
HTTP/1.1 OK
Content-Type: text/xml; charset=utf-8

REST は REpresentational State Transfer の略です。

今度は Web ページ翻訳の例。

POST /translation HTTP/1.1
Host: rest.excite.co.jp
Content-Type: application/xml

<?xml version="1.0"?>
<input xmlns="http://ns.excite.co.jp/translation"
    xml:lang="en" out="ja" type="url">
http://rest.blueoxen.net/cgi-bin/wiki.pl
</input>
HTTP/1.1 OK
Content-Type: application/xml

<?xml version="1.0"?>
<output xmlns="http://ns.excite.co.jp/translation" xml:lang="ja">
  <html xmlns="http://www.w3.org/1999/xhtml">
    <!-- 翻訳したもの -->
  </html>
</output>

これも以下のほうが使いやすいかもしれない

POST /translation?i=ja&o=en HTTP/1.1
Host: rest.excite.co.jp
Content-Type: text/plain

http://rest.blueoxen.net/cgi-bin/wiki.pl

http:// で始まるので Content-Type などから類推する。

HTTP/1.1 OK
Content-Type: text/html; charset=Shift_JIS

<HTML>
  <!-- 翻訳結果 -->
</HTML>

REST の雰囲気わかるかな?

ラベル: ,

2005-03-08

RESTful 英辞郎

英辞郎の REST インターフェースを考えてみた。非常にもっともらしい URL やホスト名や名前空間を使ってますが、完全にフィクションなのでそこのところをよろしく。

restful という単語を検索

GET /?word=restful HTTP/1.1
Host: rest.alc.co.jp

結果は一つ

HTTP/1.1 OK
Content-Type: application/xml

<?xml version="1.0"?>
<result-list xmlns="http://ns.alc.co.jp/eijiro">
  <word>restful</word>
  <count>12</count>
  <result>
    <pronounciation>レストゥフル</pronounciation>
    <pronounciation>レストフル</pronounciation>
    <basic-block><block>rest</block><block>ful</block></basic-block>
    <acceptation type="adjective">休息を与える</acceptation >
    <acceptation type="adjective">安らかな </acceptation>
  </result>
  <result>
  ...
</result-list>

rest という単語を検索

GET /?word=rest HTTP/1.1
Host: rest.alc.co.jp

結果はたくさん

HTTP/1.1 OK
Content-Type: application/xml

<?xml version="1.0"?>
<result-list xmlns="http://ns.alc.co.jp/eijiro">
  <word>restful</word>
  <count>3293</count>
  <result>
    <level>2</level>
    <pronounciation>re'st</pronounciation>
    <pronounciation type="kana">レスト</pronounciation>
    <inflections type="verb">rests resting rested</inflections>
    <item type="noun">
      <acceptation>休息</acceptation >
      <acceptation>睡眠</acceptation >
      <acceptation>眠り</acceptation >
      <acceptation>休養</acceptation >
      <acceptation>静養</acceptation >
      <acceptation>保養</acceptation >
      <example>
        <en>Get a good night's rest.</en>
        <ja>ゆっくりお休みなさい。</ja>
      </example>
      <example>
        <en>I think you'll need some rest.</en>
        <ja>君には少し休息が必要だ。</ja>
      </example>
    </item>
    <item type="intransitive verb">
      <acceptation>休む</acceptation>
      <acceptation>休息する</acceptation>
      <acceptation>休憩する</acceptation>
      <acceptation>休養する</acceptation>
      <acceptation>眠る</acceptation>
    </item>
    <item type="intransitive verb">
      <acceptation>静止する</acceptation>
    </item>
    <item type="intransitive verb">
      <acceptation>(物がある場所{ばしょ}に)ある</acceptation>
      <acceptation>置かれている</acceptation>
      <example>
        <en>Swans rest elegantly on the water.</en>
        <ja>水面には白鳥が優雅にたたずんでいる。</ja>
      </example>
    </item>
    <item type="intransitive verb">
      <acceptation>~次第である</acceptation>
    </item>
    ...
  </result>
  ...
  <next>http://rest.alc.co.jp/?word=rest&offset=50</next>
</result-list>

rest を検索で offset を 50 に指定

GET /?word=rest&offset=50 HTTP/1.1
Host: rest.alc.co.jp

結果が変わる

HTTP/1.1 OK
Content-Type: application/xml

<?xml version="1.0"?>
<result-list xmlns="http://ns.alc.co.jp/eijiro">
  <word>restful</word>
  <count>3293</count>
  <offset>50</offset>
  <result>
    ...
  </result>
  ...
  <next>http://rest.alc.co.jp/?word=rest&offset=100</next>
</result-list>

日本語の検索の例

GET http://rest.alc.co.jp/?word=レスト&ie=utf-8 HTTP/1.1

結果は面倒なので省略

ラベル: ,

2005-01-12

RESTful ツールキット

昨年11月に Amazon Web Service から Simple Queue Service がリリースされた。

このサービスの持つインパクトについては江島健太郎氏の blog が最もよく記述されている。

いわく、エンタープライズ市場で醸成されてきたキューイング技術がAmazon によって非対称ポーリングモデルという形でパーソナルユースに取り込まれることにより、B2C ならずとも B2B の世界にも大きなインパクトをもたらすであろう、ということだ。この考察は素晴しいと思う。トラックバックを見ると、そのように感じた人も多いようだ。

Amazon のこのサービスがアルファギークの興味とうまく連携してこれまで想像もつかなかった応用を生めば、確かにとても面白い。

ところで Amazon Web Service の常だが、この Simple Queue Service も二つの API を持っている。一つは SOAP/WSDL であり、もうひとつが REST API だ。ただし、この REST API は肝心の REST 陣営からは評判が悪い。

BitWorking の Joe Gregorio が xml.com で SQS REST API の批判記事を書いている。

SQS REST API の最大の問題点は、オペレーション名を URI に埋め込んでおり、全ての操作を HTTP GET で実現しているところだ。REST では HTTP の GET オペレーションはリソースの状態変更してはならないのだが、SQS ではキューの削除まで GET でできてしまう。

ただし、Amazon 側からしてみると、そんなことは百も承知で全てのメソッドを HTTP GET で実現しているのだろう。彼らが GET を採用している本当の理由は、それが一番クライアントを作りやすいからだと思う。

GET ならブラウザさえあれば簡単に試すことができる。XSLT/XPath の document() 関数も URI を GET してくれる。wget を使えばコマンドラインからでもできる。ある URL を簡単に GET するための仕組みはすでに十分用意されているのだ。perl も ruby も python も知らないけど、おそらく GET が一番簡単だろう。

REST の概念は美しいし、共感するけれど、いざ実装となるととたんに難しい。それは現状で用意されているツール、ライブラリ、フレームワークのしがらみや制約からくるものだ。では、そこをサポートするツールがあったらどうだろう。具体的には任意の XML やバイナリを任意の URI に GET, POST, DELETE, PUT できる簡易ブラウザのようなイメージである。

RESTful なサーバ側フレームワークも重要だが、クライアントライブラリも同じように重要だと思う。

ラベル: ,