「Webサービスを設計するための単純明快な方法」と「Webサービスの設計: ハイパーオブジェクトとトリガー」の続きをまだ書くつもりでいます。僕は、RPC(遠隔手続き呼び出し)スタイルを(「も」だけど)採用しようと思っています。こう言うと、脊髄反射で短絡的な反応をする人がいるかもしれない、と少し懸念されますので、このエントリーに前置きを書こうかと。
昨日はフローチャート礼賛のエントリーで、今日はRPCを擁護しようと。かつてサンザンに非難されて死にかけている概念や方法を拾い出してくるのが檜山の趣味か? そんなことではありません。マジョリティの評価に頓着もしないし、有り体に言って信用してません*1。白紙から考えて「いいもの」であれば「いい」と述べるだけ。
内容:
IDL仕様を実装プログラミング言語やトランスポート・プロトコルにマップすること
RPCスタイルでは、IDL(interface definition/description language)により“仕様としてのインターフェース”を書きます。それは、IDLコンパイラにより実装言語のソースコード雛形*2に変換されます。プログラマは、処理の実質的な部分さえ書けば(適当なライブラリやランタイムの支援のもとで)分散アプリケーションが出来上げるという寸法。
IDLをどのように実装言語にマップ(バインド)するかは、プログラミング言語ごとに決めます。ターゲット言語の機能や特性に応じて最適なマッピングを考えるのがマッピング設計者の腕の見せ所です。C言語にマップするなら、Cプログラマが違和感なく使えるマッピングを考えるべきだし、COBOL(知らんけど)にマップするならCOBOLプログラマに負担をかけないようにマップすべきなんです。
「ターゲットごとに最適なマッピング(バインディング)」という発想は、ターゲット・プログラミング言語だけではなくて、ターゲット・プロトコルについても同様です。HTTPトランスポートにRPCを乗せるなら、HTTPの機能と特性を最大限に活かしてマップするのは当然でしょう。「HTTPメソッドはPOSTだけ」とか「ステータスコードは200だけ」のようなマップは、HTTPの機能と特性をちっとも活かしてないですよね。
RPCが本質的にWebと相性が悪いという証拠はありません。出来の悪いHTTPバインディングが存在するという事実があるだけです。出来の悪い個別事例の存在から、原理原則や様式までも否定するのは飛躍してます。RPCに対して、もう少しマシなHTTPバインディングを考えればいいのではないでしょうか。
ハイパーリンクを徹底的に使う
WebのプロトコルはHTTPです。そしてWebのフォーマットはHTMLです。HTMLはハイパーリンク機能を持ちます。「ターゲットごとに最適なマッピング(バインディング)」のターゲットをWebとするなら、HTTPとHTMLをとことん利用したバインディングを考えねばなりません。言うまでもなく、ハイパーリンクを徹底的に使うのですね。
RPCがWebと相性が悪いと思われているのは次の点でしょう。
- 1回の呼び出しの粒度が小さい(例えば、整数値を戻り値とする)のは好ましくない。
- RPCサーバーとRPCクライアントのあいだの合意事項が多いのは好ましくない。
- インターフェースの変更に敏感すぎる(すぐに壊れる)のは好ましくない。
これらの問題点は、手続き呼出しの戻り値をハイパーリンクを含むHTML文書(Webページ)とすることにより解決できます。「ハイパーリンクを使うんだ!」という判断と態度があれば、弱点だ弊害だと言われていたことは自然に解消します。今まで弱点・弊害が実在したのは、Webに最適化したバインディングをしてなかったからです。
「ハイパーリンクを含んだHTML文書を返すって、それは単なるWebサイトじゃないのか?」 -- はい、そうです。「単なるWebサイト」こそが典型的かつ最重要なWebシステムですから、RPCベースのアプリケーションといえども、Webサイトと同じ形態になるのは当然で健全なことだと思いますが、なにか?
歪みがないWebバインディング
RPCベースであれ何であれ、システムはその応用固有のセマンティックスを持ちます。その機能や構造を、素材としてのHTTPとHTMLのセマンティクスのなかに、歪みがないように写像することがRPCのWebバインディングです。「歪みがない」ことがとても大事です。無理やりな暴力的なバインディングは使いにくいし、壊れやすいし、ロクなもんじゃありません。
例えば、システムが持つ手続き(RPCのP)は、バートランド・メイヤーに従って「問い合わせ」と「コマンド」に分類できます。問い合わせは副作用を持たない関数です。コマンドは副作用を目的とした手続きです。この区分はまさに、HTTPメソッドのGET(問い合わせ)とPOSTやPUT(コマンド)の区分に対応します。歪みがないバインディングということであれば、問い合わせ呼び出しはGETに乗せて、コマンド呼び出しはPOSTやPUTに乗せるのは当然です。
同様に、HTTPステータスコードやHTTPヘッダが、応用固有のセマンティックスと一致する定義を持っているなら、それをそのまま利用すればいいわけです。より詳細なエラーの分類やエラーレポーティングがしたいなら、エラーの大分類としてHTTPステータスコードを採用し、エンティティボディに詳細情報を詰め込めばいいでしょう。
郷(Web)に入っては郷(Web)に従え。
教義を盲信しないで
今までの話は、「RPCと言いながらRESTみたいだ」と思いましたか? そうです、RESTを考慮しています。「RPCはRESTと両立不可能」って定理を誰か証明してますか? 「RPCだからRESTを無視する」とかの言明を合理化する根拠を誰かお持ちですか?
「Webサービスを設計するための単純明快な方法」と「Webサービスの設計: ハイパーオブジェクトとトリガー」において:
今僕が言っていることは、REST後のRPC回帰と呼べるかもしれません(まー、レッテルはどうでもいいですけど)。
「手続き呼び出し」と聞くだけで顔をしかめる人もいるでしょうが、便利で分かりやすいなら、特定の宗派や党派に与する必要はありません。
「RPC vs REST」のような物言いは、人の興味を一時的に惹く効果はあるかもしれませんが、問題設定が幼稚過ぎてほぼナンセンスです。宗派や党派、教義や徳目は、思考の節約となります。各人が考える代わりに教義に従えばいいのですから。しかし一方、言葉に反応するだけで、現実や現象を見ず、根拠と推論を示せない人、見ない/考えない人を増やしてしまうかも知れません。
僕がフローチャートやRPCを取り上げるのは現実的な事情と理由からですが、ほんの少しだけ「字面だけに反応して何も考えない態度はやめようよ」という意図も入っています。
最後に、このエントリーのタイトルに対する僕の回答ですが; RPCとRESTを対立軸に置いて語るような時期はもはや過ぎ去ったと思います。相互補完的な手法として捉えるべきでしょう。もっとも、対立の構図からまだまだ成果物を得られるというなら、それもアリです -- 成果物があるのなら。僕自身は、協調の構図から何かを取り出そう、という方向を探ります。
*1:[追記]特にマスコミは信用するな、と父親が言い残しました。[/追記]