WWW (World Wide Web) はわずか 15 年の間に、研究者の実験から、現代世界を支える技術的柱の一つにまで成長しました。当初、人々が簡単に情報を公開し、情報にアクセスするために発明された Web も同じく、ソフトウェア・アプリケーションになくてはならないプラットフォームになっています。その一方で、アプリケーションがリッチ・アプリケーション・モデルを使用してパーソナライズされたコンテンツを生成することによって、一層実体験のようになるにつれ (没入型アプリケーション)、そのアーキテクチャーが Web のアーキテクチャー・スタイル、REST (Representational State Transfer) に違反することも多くなってきました。このような違反によって、アプリケーションのスケーラビリティーは損なわれ、システムがより複雑になる傾向があります。
新たに生まれた Ajax Web クライアント・アーキテクチャー・スタイルは、没入型 Web アプリケーションと REST アーキテクチャー・スタイルとの調和を実現します。Ajax アーキテクチャーによって、没入型 Web アプリケーションは REST の原則に違反した場合に被る好ましくない特性を排除すると同時に、REST 本来の特性を活用することができます。この記事では、Ajax と REST が共になって没入型 Web アプリケーションを成功させる方法とその理由について説明します。
WWW は何十年もの関連研究に基づいて構築されていますが、有効なものとして誕生したのは、1990 年 12 月、Tim Berners-Lee が Web の主要コンポーネントの実用プロトタイプ、URI (Unified Resource Identifiers)、HTTP、HTML、ブラウザー、そしてサーバーを完成させた時点です。Web の爆発的普及は、先駆者たちのすべての望みを越えたものでした。Roy Fielding は彼の有名な論文 (「参考文献」を参照) で当時の状況をこう語っています。
「インターネット開発者コミュニティーはその成功に高揚しつつも、Web の急速な普及は、初期 HTTP の不十分なネットワーク特性により、インターネット基盤のキャパシティーをすぐに追い越し、全般的な崩壊につながることを懸念するようになった。」
Fielding らは、大規模な普及に対応するため、Web のアーキテクチャーとその適合性を見直しました。この再検討が具体的な形となって表れたのは、URI や HTTP などの重要な標準に対する一連の更新です。一方、実体はないけれども有意義な結果となったのは、ハイパーメディア・アプリケーションの新しいアーキテクチャー・スタイルで、Fielding はこれを REST (Representational State Transfer) と名付けました。Fielding は、REST の設計制約に従って Web にデプロイされたコンポーネントは Web 本来の特性が生かされると主張し、逆に REST の原則からそれた Web コンポーネントは、これらの利益を活用できないと警告しています。
初期の頃は、Web サイトと単純な Web アプリケーションのほとんどは当然、REST の原則に従っていました。しかし、Web アプリケーションがより没入型になるにつれ、Web アプリケーションのアーキテクチャーは REST の原則から離れるようになり、それによって悪影響を被るようになりました。没入型のサーバー・サイド Web アーキテクチャーの問題を解剖するのは、少々困難です。それは、Web アプリケーション・アーキテクチャーのスタイルを十年にわたって使用するなかで、これらの問題がこのアーキテクチャーに本来備わっているものだという考えが出来上がってしまっているためです。でも、その考えは誤っています。問題の原因は明らかに、サーバー・サイド Web アプリケーションのアーキテクチャー・スタイルによるものです。偏見を打ち破るには、アーキテクチャーが現在のようになるまでの進化の過程を振り返ると参考になります。それでは、今まで認めていた多くの仮説はもはや有効ではなく、Ajax アプリケーションの作成が商業的に発展しうる理由をこれから説明しましょう。
Berners-Lee は、遠距離にいる研究者たちが文書を共有するため、そして文書間に単純なリンクを作成して知識と考えを素早く交換するための手段として Web を作成しました。しかし、URI 標準のアーキテクチャー特性により、すぐに静的文書の共有以上のことが可能になりました。
Web では当初、コンテンツは図 1 に示すように他の静的文書へのリンクを持つ静的 HTML 文書で構成されていました。
図 1. 静的文書を扱う Web サイト
REST では静的文書の取得が驚くほど効率的かつスケーラブルになります。それは、URI と最終変更日に基づいて静的文書を簡単にキャッシュできるためです。間もなく開発者たちは、静的文書だけでなく、動的コンテンツの処理をサポートすることを目指すようになりました。
Berners-Lee らが設計したのは、普遍的に固有のリソース識別をサポートすると同時に、Web クライアント (通常は Web ブラウザー) と Web サーバーとのネゴシエーションに応じてリソースの表現 (HTML、テキストなど) を変更することのできる URI 標準でした。URI はリソース識別とリソースの基礎となるストレージ・メカニズムを区別するため、Web 開発者は、URI の構文を検査し、事前定義 UI 要素と (リレーショナル・データベースなどから) 動的に取得したデータを組み合わせて即時に文書を生成するプログラムを作成することができました (図 2 を参照)。文書は生成されるものの、文書のキャッシング特性は静的ファイルのキャッシング特性とまったく同じです。
図 2. HTML テンプレート・コードに組み込まれたデータベース・レコードを扱う Web サイト
上記の初期アプリケーションの単純な例として、大学ディレクトリーの Web アプリケーションがあります。このアプリケーションは通常、以下のように機能します。
- ユーザーが Web フォームに名前 (例えば、Bill Higgins) を入力し、送信ボタンをクリックする。
- フォームが入力された名前に基づいて URI を作成し、この URI のコンテンツをサーバーに要求する (例えば、GET http://psu.edu/Directory/Bill+Higgins)。
- サーバーは URI を調べ、学生の電話番号と住所を表示する Web ページを生成する。
- サーバーが生成されたページをユーザーのブラウザーに戻す。
この対話の重要な特性は、べき等です。つまり、基礎となるリソースが変更されていない限り (例えば、Bill が電話番号を変更するなど)、要求が同じであれば出力も同じであるということです。これは、ブラウザーまたはプロキシー・サーバーが Bill Higgins 文書をローカル側でキャッシングし、基礎となるリソースが変更されていない場合は、リモート・サーバーからではなくローカル・キャッシュからリソースを取得できることを意味します。この手法により、ユーザーが知覚する応答性が改善され、システム全体の効率性とスケーラビリティーが向上します。このような初期の動的 Web アプリケーションは首尾よく機能し、ユーザーの簡単な操作で、大量の情報を得られるようになりました。
次の世代で Web アプリケーションが目的としたのは実体験感覚を高め、パーソナライズされたコンテンツとリッチ・アプリケーション・モデルを提供することでした。その後の十年間で、Web 開発者たちはそのような没入型アプリケーションの作成に成功しました。その典型的な一例は、Amazon.com の e-コマース・サイトです。ユーザー操作に従って、Amazon Web アプリケーションは特定の製品の推奨、閲覧履歴の表示、そしてユーザーのショッピング・カートに入れられた商品の価格表示を行う複雑なカスタム・ページを作成します。
没入型 Web アプリケーションは確かに便利ですが、サービス側の没入型 Web アプリケーション・スタイルは、REST のアーキテクチャー原則とは基本的に相容れないものです。具体的に言うと、これは主要な REST 制約に違反し、REST のもっとも重要な利点の一つを活用できないため、新たな一連の問題を引き起こします。
REST の「クライアント・ステートレス・サーバー」制約では、サーバーでのセッション状態を禁じています。この制約の範囲内で設計すれば、可視性、信頼性、およびスケーラビリティーというシステム特性は向上しますが、没入型のサーバー・サイド Web アプリケーションは、単一ユーザーに対して大幅なパーソナライゼーションを提供することを目的とするため、2 つの設計方法のいずれかを選択しなければなりません。その一つは、クライアント要求ごとに大量の状態情報を送信し、それぞれの要求のコンテキストを完全にして、サーバーがステートレス状態を維持できるようにするという方法です。これより表面的には単純なもう一つの方法はアプリケーション開発者とミドルウェア・ベンダーなどに好まれるソリューションで、単純なユーザー ID トークンを送信し、このトークンをサーバー側の「ユーザー・セッション」オブジェクトと関連付けることです (図 3 を参照)。この 2 番目の設計はただし、クライアント・ステートレス・サーバー制約に直接違反します。これによって目的のユーザー機能 (とくに、パーソナライゼーション) が有効になるのは確実ですが、アーキテクチャーには多大な負担がかかります。
図 3. サーバー側に大量のセッション状態が含まれる没入型のサーバー・サイド Web アプリケーション
この負担の一例は Java™ Servletの HttpSession API で、HttpSession ではセッション状態を特定のユーザーに関連付けることができます。この API は未熟な開発者には一見単純そうに見えます。いかにも、HttpSession にあらゆるオブジェクトを格納すれば、特別なルックアップ・ロジックをコーディングせずにオブジェクトを引き出せるように見えます。ただし、HttpSession に多くのオブジェクトを格納するにつれ、アプリケーション・サーバーが使用するメモリーと処理リソースの量が増えていくことに気付くはずです。そこで、増加し続けるリソースのニーズに対応するには、アプリケーションをクラスター化した環境にデプロイする必要があると判断するとします。次に気付くのは、HttpSession をクラスター化環境で機能させるためには、それぞれのオブジェクトが Java のシリアライズ可能なインターフェースを実装して、クラスター化環境のサーバー間でセッション・データの送信を可能にしなければならないということです。ここで判断しなければならないのは、アプリケーション・サーバーがシャットダウン/再起動サイクルの発生時にセッション・データを維持する必要があるかどうかです。そうこうするうちに、クライアント・ステートレス・サーバー制約に違反するのがそれほど名案なのかどうか、疑問になってくるはずです。(実際、多くの開発者はこの制約を意識していません。)
没入型のサーバー・サイド Web アプリケーションに伴う 2 つ目の深刻な結果は、REST が提供するリソース・キャッシングの優れたサポートを利用できないということです。Fielding の言葉を引用すると、以下のように説明できます。「キャッシュ制約を追加する利点は、これらの制約が一部の対話を部分的または完全に排除し、それによって一連の対話での平均的な待ち時間が削減され、効率性、スケーラビリティー、そしてユーザーが知覚するパフォーマンスが向上される可能性があるということである。ただし、その代償として、キャッシュ内の失効データが、要求をサーバーに直接送信した場合に取得されるデータと大幅に異なる場合は、キャッシュによって信頼性が損なわれるおそれがある」。
没入型 Web アプリケーションは、一種の生きているエンティティーとして見ることができます。該当するユーザーが提供する新しい入力、その他のユーザーが提供する新しい入力、そして新しいバックエンド・データに基づいて絶えず変化するからです。サーバーは複数のユーザーとアプリケーションとの対話に基づいて各ページを生成するため、事実上、同じ文書が生成されることは二度とありません。そのため、Web ブラウザーまたはプロキシー・サーバーはサーバー・リソースをキャッシングすることができません。
リソースのキャッシングが不可能であるという問題に対処するには、いくつかのソリューションがあります。その一つは、サーバー側にきめの細かいリソースのキャッシュを作成して、サーバーが基本要素 (HTML およびデータ) からではなく、事前に組み立てられたパーツから大まかなページを作成できるようにすることです。ただし、これには問題があります。要求ごとにかなりのサーバー処理が発生すること、スケーラビリティーが損なわれること、そしておそらくユーザーが知覚する応答時間が遅くなることです。
サーバーがリソースをキャッシュできないことによって生じるもう一つの結果は、各要求にはコストの高い処理が伴うため、極めて動的な Web アプリケーションでは、検索エンジンンやその他の「ロボット」による要求を明示的に禁止しなければならないことです。一方、REST に従ったアプリケーションでは、それぞれのロボットに一度リソースを提供すれば、その後ロボットがアクセスしたときには単純な「変更されていない」メッセージを送信することができます。
ここで疑問となるのは、理論的には処理とメモリーのニーズをクライアントに分散できるのに、なぜ負担の大きい単一のサーバーにそれほどのリソース消費を集中させるのかという点です。その簡単な答えは、従来の Web ブラウザー制約により実現可能でなかったためです (「Ajax を使用しないクライアント側の処理」を参照)。しかし、Ajax アーキテクチャー・スタイルを使用すれば、開発者は処理と状態の要件をクライアントに分散することが可能です。ここからは、Ajax スタイルのアーキテクチャーを選択すると、没入型アプリケーションがなぜ、REST との調和を取り戻してその利点を活用できるかを説明します。
これまで説明してきたように、従来のサーバー・サイド Web アプリケーションでは、サーバー上で表示と動的データ要素を組み合わせ、完全な形式にされた HTML 文書をブラウザーに戻します。Ajax アプリケーションとの違いは、Ajax アプリケーションではほとんどの UI とアプリケーション・ロジックがブラウザー内に常駐する点です。ブラウザー・ベースのアプリケーション・コードが必要に応じて新規サーバー・データをフェッチし、このデータを現行ページに組み入れます (Jesse James Garrett の Ajax に関する重要な記事については、「参考文献」を参照)。表示とデータをバインドするロケーションは、実装の詳細の話のように思えるかもしれませんが、この違いによってまったく異なるアーキテクチャー・スタイルになるのです。
Ajax アプリケーションは、クリックするたびにページの最新表示を一から実行する必要がない Web ページと説明されることがよくあります。これは正しい説明ですが、その根底にある動機は、完全なページ最新表示はユーザーの気をそらし、夢中になって没入できるユーザー・エクスペリエンスを損なうという点です。アーキテクチャーの観点から見ると、完全なページ最新表示はさらにやっかいです。それは完全なページ最新表示によって、クライアントにアプリケーションの状態を格納するというオプションが排除され、その結果、Web が持つ多くのアーキテクチャー設計の長所をアプリケーションがほとんど利用できないような設計になってしまうためです。
Ajax では、完全な最新表示を行わずにユーザーがサーバーと対話できるようにすることによって、ステートフルなクライアントというオプションを取り戻します。これは、動的な没入型 Web アプリケーションのアーキテクチャーが実現可能であることを示唆しています。アプリケーション・リソースとデータ・リソースのバインディングがクライアント側に移されるため、アプリケーションは没入型 Web アプリケーションの最大の長所である動的でパーソナライズされたユーザー・エクスペリエンスと、REST に従った アプリケーションの最大の長所である単純でスケーラブルなアーキテクチャーの両方を活用できることになります。
Amazon.com が真の Ajax アプリケーションとして完全に再実装されており、サーバーからすべてのデータを動的にフェッチする一つの Web ページであった場合を考えてみてください (Amazon はビジネス上の正当な理由から、このような形を望んでいませんが、それについては別の記事の題材になります)。ほとんどの UI とアプリケーション・ロジックはサーバーではなくクライアントで実行されるため、Garrett が説明するように、初期ページのロードには、Amaxon の Ajax「エンジン」のダウンロードが必要になります。このエンジンには、たくさんのアプリケーション・ロジック (JavaScript コードとして実装) と、後でサーバーから非同期でフェッチされるビジネス・データが入力される UI の基盤が含まれます (図 4 を参照)。
図 4. 没入型 Ajax アプリケーション
Ajax エンジンが持つ興味深い特性は、かなりの量のアプリケーション・ロジックおよび表示フレームワーク要素が含まれていながらも、正しく設計されていれば、ビジネス・データやパーソナライズされたコンテンツは含まれないということです。アプリケーションと表示はデプロイメント時に凍結されます。標準的な Web 環境では、アプリケーション・リソースが変更するのは 6 ヶ月に一度だけです。つまり、アプリケーション・リソースとデータ・リソースを分離する Ajax エンジンは、極めてキャッシングしやすいということです。
Dojo Toolkit はその代表的な例です (「参考文献」を参照)。Dojo が提供するビルド時のツールは、アプリケーションのロジック、表示、およびスタイルがすべて含まれる圧縮された JavaScript ファイルを作成します。このファイルは結局のところ、単なる一つのファイルでしかないため、Web ブラウザーはこれをキャッシングできます。したがって、次に Dojo 対応 Web アプリケーションにアクセスする際には、サーバーからではなく、ブラウザーのキャッシュから Ajax エンジンをロードする可能性が高くなります。これを、没入性の高いサーバー・サイド Web アプリケーションと比較してみてください。この場合、ブラウザーとネットワークの媒介は常に変化するリソースをキャッシングすることができないため、要求ごとに多大なサーバー処理が発生します。
Ajax アプリケーション・エンジンは単なるファイルであるため、プロキシーにも対応します。大規模な企業イントラネットでは、一人の従業員が特定バージョンのアプリケーションの Ajax エンジンをダウンロードするだけで、その他すべての従業員がイントラネット・ゲートウェイからキャッシングされたコピーを取得することができます。
アプリケーション・リソースに関して適切に設計された Ajax アプリケーション・エンジンは REST の原則に従っているため、サーバー・サイド Web アプリケーションと比べるとスケーラビリティーの点ではるかに有利です。
ユーザーは Ajax Web サイトをブラウズして、Ajax アプリケーション・エンジンをおそらくブラウザーのキャッシュから、そうでない場合はローカル・プロキシー・サーバーからロードします。それではビジネス・データについてはどうでしょう。アプリケーションのロジックと状態はブラウザー上に常駐し、ブラウザー上で実行されるため、アプリケーションとサーバーとの対話は従来の Web アプリケーションの場合とは大きく異なります。つまり、フェッチする必要があるのはコンテンツの併合ページではなく、単なるビジネス・データだけとなります。
Amazon.com の例をもう一度取り上げてみましょう。例えば、設計パターンに関する本についての情報を表示するリンクをクリックするとします。Amazon.com の現行アプリケーションでは、リンクのクリック操作によって、要求されたリソースを識別する各種の情報が送信されます。また、このクリック操作によって、サーバーが前のセッションの状態 (最近表示した項目など)、パーソナライゼーション情報 (「1999 年にこの本を購入しました」など)、そして実際のビジネス・リソース自体が含まれるページを新規に作成できるようにするための各種セッション状態の成果物も送信されます。アプリケーションは非常に動的で、極めてパーソナライズされていますが、(Amazon が説明するように、これらのアーキテクチャー上の問題は 100 万ドル規模の基盤設計で克服することができるとは言っても) キャッシングは不可能であり、そのまま拡張することもできません。今度は同じ操作を (仮想の) Ajax バージョンのアプリケーションに当てはめてみましょう。この場合、「最近表示した項目」に関して必要な処理はありません。これはページにすでに存在する単なる情報であり、リンクをクリックしても消えることはありません。設計パターンの本に関連するのは、おそらく以下の 2 つの要求です。
- /Books/0201633612 (ここで 0201633612 は設計パターンの本の ISBN 番号)
-
/PurchaseHistory/0201633612/bhiggins@us.ibm.com
最初に仮定した要求は、本についての情報 (著者、タイトル、説明など) を戻します。この情報にはユーザー固有のデータは含まれません。ユーザー固有のデータがないということは、同じリソースを要求するユーザーが増えるほど、これらのユーザーは送信元のサーバーではなくインターネットの中間ノードから、キャッシングされたバージョンのリソースを取得する可能性が高くなることを意味します。この特性により、サーバーとネットワーク全体の負荷が減ります。一方、2 番目の要求にはユーザー固有の情報 (Bill Higgins のこの本の購入履歴) が含まれます。このデータにはパーソナライズされた情報が組み込まれるため、この URL から正常にデータを取得してキャッシングできるのは一人のユーザーだけです。このパーソナライズされたデータには、パーソナライズされていないデータが持つスケーラビリティーはありませんが、重要な点は、この情報は個別の URL から取得されるため、キャッシングが可能なその他のアプリケーションやデータ・リソースのキャッシングを妨害しないというプラスの特性があるということです。
Ajax アーキテクチャー・スタイルのもう一つの利点は、サーバーの障害に簡単に対処できることです。前述したように、没入型ユーザー・エクスペリエンスを提供するサーバー・サイド Web アプリケーションは、大量のユーザー・セッション状態をサーバーに保持する傾向があります。サーバーが故障した場合、セッション状態は消えてなくなるため、ユーザーはホーム・ページに戻ったり、ショッピング・カートに入れた商品がなくなるなど、異常なブラウザー動作を体験することになります。ステートフル・クライアントとステートレス・サービスを備えた Ajax アプリケーションでは、サーバーのクラッシュ/再起動はユーザーにはまるで見えません。その理由は、ユーザーのブラウザーに存在するセッション状態はサーバーがクラッシュしても影響されないこと、そしてステートレス・サービスの動作はべき等であり、ユーザー要求のコンテンツによってのみ決定されるためです。
ここで没入型 Web アプリケーションと呼んでいる Web アプリケーションのクラスとして、適切に設計された Ajax/REST アプリケーションは、ユーザー・エクスペリエンス、応答性、そしてスケーラビリティーの点で従来のサーバー・サイド Web アプリケーションよりはるかに優れています。ただし、アーキテクチャー・スタイルのランタイム特性だけが、ソフトウェア・プロジェクトと Web アプリケーションの成功を決定する要因ではありません。Ajax/REST アプリケーションを作成する際には、大規模な JavaScript 開発の問題、文化的課題、そしてパッケージ化の問題をはじめ、ランタイム以外の難しい問題があります。文化的課題については、このシリーズの別の記事で説明しますが、その他の問題については Ajax の仲間に対応を任せることとします。
この記事について有益な技術的意見を提供してくれた同僚の Chris Mitchell 氏、Josh Staiger 氏、Pat Mueller 氏、Scott Rich 氏、そして Simon Archer 氏に感謝します。また、最初に RESR スタイルの Web サービスについての課題を投げかけてくれた Redmonk アナリスト・ファームの James Governor 氏および Steve O'Grady 氏にも感謝の言葉を述べます。
学ぶために
-
「Architectural Styles and the Design of Network-based Software Architectures」(Roy Fielding 著、カリフォルニア大学アービン校、2000 年): Fielding はこの博士論文で、REST のアーキテクチャー上の制約を説明しています。
-
Weaving the Web (Tim Berners-Lee 著、HarperCollins、2000 年): Berners-Lee が、WWW の設計と進化の過程を説明しています。
-
「Ajax: A New Approach to Web Applications」(Jesse James Garrett 著、Adaptive Path、2005 年 2 月): 「Ajax」という言葉を作った Garrett が、その基本的なアーキテクチャーとユーザー・エクスペリエンスの特性を説明しています。
-
All Things Distributed: Werner Vogels' weblog on building scalable and robust distributed systems(Werner Vogels 著、Amazon.com): Amazon の CTO のほうが著者よりスケーラビリティーに関して豊富な知識を持っていることは確かですが、Amazon の Web アプリケーションは、地球上でもっとも有名な没入型のサーバー・サイド Web アプリケーションの一つとなっているため、最適な例となります。
-
developerWorks の Architecture エリアで、アーキテクチャー分野でのスキルを伸ばすために必要な資料を入手してください。
-
著者のブログを読んでください。
-
Ajax Resource Center: developerWorks の Ajax に関するすべての記事が記載されています。
製品や技術を入手するために
-
The Dojo Toolkit: Dojo Toolkit は、より高レベルのプログラミング抽象化を提供し、ブラウザーの非互換性を標準化するオープン・ソースの Ajax フレームワークです。
議論するために
-
Ajax ディスカッション・フォーラム: Ajax 開発について疑問がある場合は、Jack Herrington が管理するこのフォーラムが答えを見つける手掛かりになります。

Bill Higgins は、IBM Rational Software 部門で、開発チームをサポートするツールに取り組んでいます。2000 年、ペンシルバニア州立大学を卒業した彼は、コンピューター・サイエンスの理学士号を取得しています。仕事以外での趣味は、夫人と 2 人の子供と一緒に過ごすこと、自分の developerWorks ブログに投稿すること、そして読書とバスケットボールです。