このブログの更新は Twitterアカウント @m_hiyama で通知されます。
Follow @m_hiyama

メールでのご連絡は hiyama{at}chimaira{dot}org まで。

はじめてのメールはスパムと判定されることがあります。最初は、信頼されているドメインから差し障りのない文面を送っていただけると、スパムと判定されにくいと思います。

参照用 記事

いかにして合意と伝達の負担を減らすか: URLを例として

昨日「URLに関する議論 -- なぜ僕はクエリパラメータを擁護、ときに推奨するのか」という記事を書きました。そこで出した簡単な事例は、足し算を要求するのに、/calc/add/2/3 みたいなURLを使うのはやめて /calc/add?x=2&y=3 とか /calc/?op=add&arg1=2&arg2=3 にしようぜ、というものです。

実際には、URLのパス部分が既に存在する実体を指すことを強要すると、PUTメソッドでファイルを作りたいときはどうすんだ? といった問題もあります。が、個別の問題を議論する前に、クエリーパラメータや拡張子を擁護する背景をもうちょい説明します。

内容:

  1. 合意と伝達は大変
  2. XMLを使ってエンコードする方法
  3. URLにエンコードする方法
  4. とにかく手間を減らすには
  5. 名前やパスに情報を含ませること
  6. まとめ

合意と伝達は大変

僕は「合意と伝達」の問題に強い関心を持っています。複数の人間が協力してソフトウェアシステムを作るとき、仕様に関して合意する必要があります。合意形成の過程で、また合意事項を全員に伝達し周知させるために、コミュニケーションが必要になります。このような「決めて、みんなで守る」過程はけっこうな負担となります。特に、複数のメンバーが地理的に離れていたり、ミーティングのスケジュールを合わせにくい場合はなおさらです。

よって、合意すべき事項は少ないほうがいいことになります。また、合意に基づく実作業も少ないほうがいいのも当然です。

XMLを使ってエンコードする方法

冒頭の算術計算のサービスを例題にするとして、例えば、算術計算の要求を次のようなXMLデータで送るとしましょう。

<call xmlns="http://xmlns.example.com/api/calc">
 <operationName>add</operationName>
 <arguments>
  <number>2</number>
  <number>3</number>
 </arguments>
</call>

エントリーポイントURLとHTTPメソッド(POSTに固定でしょう)はいいとしても、リクエストのためのXMLフォーマットを決めなくてはなりません。タグの名前?、要素の名前?、どんな構造にするか? …… と。正確さを求めるなら、スキーマ定義が必要となるでしょう。

算術演算とその引数をXMLシリアライズ(マーシャリング)するために、クライアント側プログラムが必要になります。そしてサーバー側でそれらを分解して取り出す(パージング、デシリアライズ/アンマーシャリング)プログラムも作成しなくてはなりません。

計算結果を返すレスポンスに関しても同様に「決めて、作る」作業があります。既存の仕様、例えばXML-RPCをベースにして、そのライブラリを使うとかすれば負担は軽減します。しかし、「XMLフォーマットを決める」こと、「クライアント側とサーバー側で、付加的プログラムを作る」ことを省略はできません。

「合意すべき事項は少ないほうがいい」、「合意に基づく実作業も少ないほうがいい」という観点からはマズイ方法となります。

URLにエンコードする方法

それに比べると、「2 + 3」の要求を /calc/add/2/3 にエンコードする方法にはメリットがあります。

  1. エンコードのルールが簡単。
  2. HTTP GETを使うなら、クライアントはブラウザのアドレスバーで済んでしまう。
  3. サーバー側もパス文字列をスラッシュ区切りで分割するだけでデコードできる。

しかし、エンコードのルールはローカルルールとなります。第三者に説明するときに常識に訴えたり、他の仕様を参照することはできません。ローカルルールを詳細まで曖昧性なく説明する作業は、意外と手間です。

例えば、スラッシュで区切ったオシリ2つを演算の引数と思えばいいのでしょうか? /calc/add/2/3/1 はエラーでしょうか? それとも「2 + 3 + 1」の要求でしょうか? /calc/minus/3 は「3の符号反転である -3」なのか、それとも引き算の引数が足りないのか?

算術演算とその引数達を、どのように単一パスにエンコード/デコードするかに、準拠すべきこれといった標準はありません。「ルールは簡単」とはいえ、「決めて、みんなで守る」ことはそれなりの負担です。

とにかく手間を減らすには

/calc/add/2/3 の代わりに /calc/add?x=2&y=3 を使うと、演算子部分と引数(パラメータ)部分の区切りは極めて明白です。「算術演算の“パラメータ”を、クエリー“パラメータ”にエンコードする」のは常識的な感覚としても自然です。パラメータ部分のデコード方法も、ありものライブラリの挙動で問題はないでしょう。

とはいえ、パラメータの名前や個数の合意はローカルに取り決める必要があります。この手間も軽減できないでしょうか?

ここで、先に「マズイ方法」といったXMLによるエンコードの方法を思い起こします。XML-RPCは、XMLベースRPCの一般的デメリット(メンドクサイとか)を持ちますが、メリットもあります; 関数やメソッドのインタフェース定義があれば、そこからエンコード方法が決まってしまうことは大きなメリットです。

例えば、JavaScriptの関数風な次の宣言があったとします。

function add(x, y) {/** 足し算 */};
function mult(x, y) {/** 掛け算 */};
function minus(x) {/** 符号反転 */};

この宣言と、「関数のパラメータはそのままクエリーパラメータに対応させる」ルールを組み合わせると、決めた内容を伝達し周知させる負担はだいぶ軽くなります。

名前やパスに情報を含ませること

ついでに、拡張子が「伝達の負担」を減らすことにも触れておきましょう。

次の文面を考えます。

  • 最新版を http:/www.chimaira.org/hiyama/latest-version に置きました。

この文だけから、最新版ファイルの内容がなんであるかはまったく推測できません。次はどうでしょう。

  • 最新版を http:/www.chimaira.org/hiyama/latest-version.txt に置きました。
  • 最新版を http:/www.chimaira.org/hiyama/latest-version.pdf に置きました。
  • 最新版を http:/www.chimaira.org/hiyama/latest-version.java に置きました。

もちろん、拡張子がなくても、日本語で丁寧な説明を付ければ情報は伝わります。

  • まだドラフトですが記事原稿テキストの最新版を http:/www.chimaira.org/hiyama/latest-version に置きました。
  • 完成したレポートのPDF文書の最新版を http:/www.chimaira.org/hiyama/latest-version に置きました。
  • サンプルのJavaプログラムの最新版を http:/www.chimaira.org/hiyama/latest-version に置きました。

日本語の説明には劣るものの、拡張子を付けるだけで情報量が増えることは明らかでしょう。

まとめ

個別の説明を要するローカルルールをできるだけ排除して、広く受け入れられている常識や習慣、そしてメジャーな標準(スタンダード)を採用すれば、合意と伝達の手間を減らせます。

また、ひとつの仕様(たとえば、関数/メソッド群のインタフェース定義)から、他の仕様を自動的かつ一意的に導出できるようにしておけば、合意事項を少なくでき、不整合も起こらず、記憶や伝達の負担を減らせます。