oldwaveの日記: Webアプリケーション設計と継続
Webアプリケーションの設計をするとき、Schemeでいう継続(continuation)の概念を理解しておくと非常に役に立つ。
継続の概念は、なかなか理解が難しい。概念として理解できても、それが何に役立つのかわからないという人も多いだろう。実際、僕も継続の有効活用についてわかるようになるまで、何年もかかったし、今でも十分に馴染んでいると自負できるまでには至っていない。
しかし、最近になって気付いたのだが、Webアプリケーションというものは、ちょっと見方を変えてみると、GOTO文とグローバル変数の塊なのだ。そして継続はこういった問題を制御するための武器になる。
セッションに値を格納するとき、それが不変の値であれば良いが、状態を持つ場合、それはまったくグローバル変数そのものである。しかもWebアプリケーションの場合、複数のURIにまたがる処理はブラウザの「戻る」ボタンやブックマークによって、プログラマーの意図しないポイントへGOTOしてくる可能性がある。利用者がプログラマーの意図した通りの操作をするとしても、個々のURIとURIの関係は「構造化」されてはいない。ちょうどKnuthのArt of Computer Programmingに書かれているプログラムのように、GOTO使いまくりの構造にならざるを得ないのである。
こういった問題に取り組むためには、もちろんセッションに格納する値の取り扱いについてきっちり文書化することが必要だ。また、各URIにおいてセッションの値、リクエストパラメータについて事前条件、事後条件を文書化しておくべきだ。そこまでは良いのだが、それが「適切・妥当な設計かどうか」をどのように評価すべきだろうか。
設計不在よりは設計がある方が良いが、やはり設計には良い設計もあれば悪い設計もある。だから設計を文書化したら評価しなければならない。試行錯誤なしにいきなり優れた設計を手に入れられると思うのは虫のいい話だ。
かくして設計の良し悪しを判定する視点が必要になる。そのとき、継続がわかっていると良いのだ。
継続とは、一連の処理のある時点において、以降の処理と以降の処理に必要な状態をパッケージ化したものだ。
継続をファーストクラスオブジェクトとして他の関数への引数にしたり、あるいはデータベースに永続化できたりすると、いろいろなことができるようになる。たとえば、一連の処理をある時点において中断し、他の処理を先に済ませてから、中断した処理を再開したりできる。例外処理が発生するような場合、例外処理の発生するブロックの直前で継続を取得しておけば、例外処理が発生したときにはその継続を評価すればブロックを脱出できることになる。
継続がわかるようになると、一連の処理のある時点において、以降の処理と以降の処理に必要な状態(つまり継続に含まれる情報)を見極められるようになる。Schemeでは継続の取得は処理系に任せることができるのだが、注意深く考えれば手作業で継続を取得することもできないわけではない(だからCommon Lispではマクロで継続を取得することができる)。
継続を手作業で取得できるようになると、Webアプリケーションにおける各URIの事前条件、事後条件を決定することができるようになるし、各URIの関係を関数と関数の関係にマッピングして、リファクタリングすることができるようになる。
こういうことができるとわかってみると、画面遷移図すら書かずにWebアプリケーションを書いていた頃のことを思い出して冷や汗が出る。フィーリングオンリーでGOTO文プログラムを書いていたのだ。たぶん、想定外のトラブルに遭うたびにアドホックなIF文を追加していたに違いない。
Webアプリケーションは、たぶん皆が思っているより、ずっと設計が難しい。Webアプリケーション設計の現場は、Dijkstraが構造化プログラミングを提唱する前の状態にあるのだ。
Webアプリケーション設計と継続 More ログイン