« リーダーシップよりもメンバーシップ | トップページ | Kanasan.JS JavaScript第5版読書会#3 行ってきた »

2008/02/24

Webアプリのセッション管理はデスクトップアプリのメモリ管理と同じ

Webアプリ開発で必ずぶち当たる課題、Webアプリ特有の技術、アーキテクチャについて考えてみる。
古くから続く課題を知れば、次世代Webフレームワークがどのように解決しようとして、何を提示しようとしているか分かりやすくなるだろう。

#以下、セキュリティ関係などを除く。

Webアプリは、Ajaxが登場するまで、UIがブラウザで制限されているため、それほど難しい機能を実装できなかった歴史があった。
古くはPer/PHP、そしてJavaに至るまで、Webアプリはステートレスだったから、殆どの機能は閲覧機能とマスタメンテナンス機能にすぎなかった。
なぜなら、Webアプリでは、6時間以上もかかるようなバッチ処理を実装したとしても非現実的だから。

しかし、以前から知られているアーキテクチャ上の課題はあるし、Ajaxの出現によって更にその課題が複雑になった現状もある。

Webアプリを作る時はいつも、下記の問題をどのように解決するか、を潜り抜けなければならない。

・戻るボタン
・注文ボタンの2度押し
・F5(更新ボタン)連打
・マルチウィンドウで操作

しかし、ここでは、Webアプリ特有の技術に焦点を当ててみる。

1・リダイレクト
2・ポストバック
3・可変個数のパラメータをPOSTで送信する

※以下は殴り書き。後でロジカルにまとめる。

【1】リダイレクト

リダイレクトとは、フォワードを2回以上実行すること。
つまり、クライアントは次の画面に遷移しているように見えるが、サーバーサイドでは、2個以上の画面を経由して、最後にクライアントに画面表示する仕組み。

@ITの記事が分かりやすい。

リダイレクトとフォワードの違いを知る

リダイレクトを使う場面としては、ログインチェックが多いだろう。
つまり、ログイン完了した画面ではなく、注文画面だったり、会員修正画面のように、ログインチェック後、元の画面に戻るようにする。

あるいは、会員情報修正の画面フローで、住所登録や修正ができるとする。
普通は、住所修正が終わったら、会員情報修正完了画面に遷移するだろう。

しかし、注文の画面フローの途中で、「配送先住所を変えたい」「メールアドレスが間違ってた」などの理由で、途中で会員除法修正画面へ移るとする。
修正できたら、会員情報修正完了画面ではなく、元の注文の画面に戻らなくてはいけない。
このとき、画面遷移の分岐処理をフォワード処理でするか、あるいは、ViewにResponseからリダイレクトする処理を入れる。

他にも、他サブシステムへ画面遷移する時にも使う時が多い。

この手法は、JSP+ServletだけでなくASP.NETでも良く使われる枯れた技術。

【2】PostBack(ポストバック)

ASP.NETで出てくる。
@ITの記事が分かりやすい。

ポストバック処理

 従来型のプログラム開発の基本的な考え方は、ブラウザからの入力データの送信先を「次の画面を表示するプログラム」にするというもの。
例えば、Sturts。
ASP.NETでのポストバック処理とは、ユーザがクライアントブラウザ上で入力したデータを、次の別プログラムではなく同一プログラムに再送する処理のことを指す。

つまり、ポストバック機能とは、ViewStateを利用してブラウザ上で行われた操作をサーバ側で「再現」し、対応するメソッド(イベントハンドラ)を自動的に呼び出す機能である。
 ポストバックの仕組みにより、ASP.NETではポストしたデータを処理するのは、常にそのページ自身となる。そのため、ASP.NETのページには基本的に入力フォーム部分と処理結果の表示部分が同居することになる。
これによって、入力チェックエラーで元の画面を復元する場合、JSP+Servletのように難しく考える必要はない。

更に、ASP.NETフレームワークは、スケーラビリティを確保するためにページインスタンスを毎回破棄する。
つまり、初回リクエスト時とポストバック時に使われるインスタンスは別物になる。
このため、ページインスタンス上にデータ変数を用いてデータを残しておくことはできない。
だから、隣り合う画面ではない他画面を復元するには、ViewStateかセッションにデータを保持する必要がある。

【3】可変個数のパラメータをPOSTで送信する

この状況は、カート画面で、商品を複数の配送先にコピー又は分割したい場合が多いだろう。
良くある業務は、ギフト注文のように、1個の商品を複数の配送先に分けたい場合に相当する。

この操作は、以前は逐一サーバーに問い合わせてセッションを分割する手法が多かったが、Ajaxが登場して以来、DOMを生成する手法でクライアント上で簡単に実装できるようになった。

この問題は、POSTする商品リストの個数がSubumitされるまで可変なため、POSTする商品リストを動的に作る機構が必要なことだ。
業務アプリケーションでは入力項目数が可変であることが多いにも関わらず、WebアプリではPOSTする配列をダイナミックに生成する機構が最近まで存在しなかった。

以前は、Submitする時に、POSTする商品リストのサイズも合わせてPOSTするという原始的なやり方が主流だっただろう。

最近は、Javaの場合、Appche commons-collectionsのListUtils.lazyList()を使うと、遅延評価のように、リストをダイナミックに生成できる。
肝心のRailsの場合は知らない。

しかし、この問題はAjaxによって更に複雑化する。

フォワードした

カート画面を表示

クライアント上でDOM操作で商品リストを追加ないし削除して、商品リストの個数をフォワード時と変える

POSTする

Servletが処理して次画面を表示
でもやっぱり、一つ前に戻るとしよう

戻る場合は、DOM操作して個数が変わった後の画面を再表示する。
一つ前のアクションを呼ぶのではない。
セッションに放り込んだデータを再表示する。

入力エラーの場合も同じ。
 Strutsでは、Servletに渡る前にActionFormでValidatorが動いてしまうと、一つ前のActionが呼ばれてしまう。
 DOM操作して個数が変わった後の画面が表示されない。
 普通は、ActionFormのValidatorはコメントアウトし、ServletでValidatorを実行するようにする
 しかし、余計なロジックが入り、複雑化する。

【4】クッキーログイン
半ログインとも言われる。
クッキーにログイン情報が残っていれば、ログインした状態で商品検索できる。
注文する時、カード情報を入力する時、半ログイン状態ならログイン画面で入力させる。
Amazonなどのように、半ログインであたかもログインしているかのようにクライアントに思わせる。
Webアプリがクライアントに優しくなるための一つの手法。

つまり、Webアプリでは、会員の状態は下記3つがある。

・ログオフ
・半ログイン
・ログイン(実ログイン)

以上の技術を見ても、Webアプリで何度もぶち当たる問題は、詰まる所、セッション管理に行き着く。
デブサミでyoshioriさんは「セッション管理の問題は昔辿ったプログラミングの歴史と同じ。詰まる所メモリ管理と同じでしょ?」と言っていた。

思い出して見よう。
書いてるWebプログラムはステートレスが多い。
つまり、手続き型プログラミング。
 全然オブジェクト指向じゃない。
 画面の状態を保持するオブジェクトがプログラムで存在しない。
  画面の状態は、セッションに保持するのが普通。
  Viewに残すのはセキュリティ上やばい。
   クレジットカード番号だけでなく、会員IDすらViewに残すのは危険。
  セッションへ保存するのは、ハッシュに詰めるのと同じ
  タイプセーフでない。
  何故、オブジェクトでセッションに保存できない?

  セッションに入れるデータの一覧表をExcelで管理していた。
  DRY原則に反する。
   何故ソースで管理しない?

【RailsとAjax】
【1】Railsがもたらしたもの

デブサミでyosihoriさんは「Ruby on Railsは究極のWebフレームワークだ」と言った。
Strutsの究極の進化系がRails。

Webアプリのアーキテクチャは、MVC2モデルで既に確立されている。
業務システムの殆どは、RDB→SQL→Controller→View というアーキテクチャ。
もっと簡単なシステムであるWikiなどは、テキストor XML→正規表現→Controller→View というアーキテクチャ。

Railsが最も生かしやすいターゲット。
しかし、Wicketは別方向に進もうとしている。

画面の状態をどこで保持し破棄するか?
画面の状態をどのようなライフサイクルで管理するか?

つまり、それはデスクトップアプリ開発で悩んでいたメモリ管理と同じ。
Webフレームワークは、それをどのように解決しようとしているか?

Railsは、クッキーへ画面情報を持たせようとしている。
更に、URLで指し示すHTMLかXMLに情報を持たせる。
いわゆるREST思想。

Wicketは、セッションへ画面情報を持たせようとしている。

継続フレームワークは、画面操作の手続きをスタックで保持する。

おそらく今後数年で、上記の問題を解決するフレームワークが出るだろう。

【2】Ajaxがもたらしたもの

Ajaxによって、Webアプリはクライアントに優しいUIを持てるようになった。
つまり、サーバーと非同期通信することによって、クライアント操作の待ち時間が減る。

 その仕組みは、Viewを生成するロジックはサーバーではなくクライアントに置く。
 サーバーからView生成用データを送ってもらい、クライアント上ではJavaScriptでDOM生成によってViewを生成する。

 RESTの概念とは、リソースに全てのデータがある。そのリソースはサーバーにある。
 View表示ロジックはサーバーにない。

 サーバーからデータをもらえば、View生成のために逐一サーバーに問い合わせる必要はない。
 ステートレスWebアプリを作る現在の主流の方法にすごくマッチしている。

 Railsが持つRJS、GWT(Google Web Toolkit)は、サーバーからViewを返す時に、Ajaxを埋め込んで、クライアント上で自由自在にDOMを生成できるように自動生成する機構を持つ。
 この手法ならば、クライアントのUIもサーバーサイドから制御できる。


Webアプリプログラミングは、デスクトップアプリに比べると開発途上と言える。
「画面の状態をどこで持つか?」。
セッション管理のように、未だにメモリ管理の機構をプログラマが逐一考えないといけない。

車輪の再発明を未だに繰り返すWebアプリ開発。
そろそろキラーアプリが出ても良い予感。

|

« リーダーシップよりもメンバーシップ | トップページ | Kanasan.JS JavaScript第5版読書会#3 行ってきた »

モデリング」カテゴリの記事

コメント

コメントを書く



(ウェブ上には掲載しません)


コメントは記事投稿者が公開するまで表示されません。



トラックバック


この記事へのトラックバック一覧です: Webアプリのセッション管理はデスクトップアプリのメモリ管理と同じ:

« リーダーシップよりもメンバーシップ | トップページ | Kanasan.JS JavaScript第5版読書会#3 行ってきた »