このブログは、旧・はてなダイアリー「檜山正幸のキマイラ飼育記 メモ編」(http://d.hatena.ne.jp/m-hiyama-memo/)のデータを移行・保存したものであり、今後(2019年1月以降)更新の予定はありません。

今後の更新は、新しいブログ http://m-hiyama-memo.hatenablog.com/ で行います。

CatyのWeb処理: Webフィーチャとメタプログラミング

Catyのドキュメンテーションに含めるつもりの記事。

CatyのモットーはできるだけWeb処理をやらないことだ。Webフレームワークとか言いながらも、一般的な言語処理の機能内でついでにWeb処理をしてしまう形態を理想としている。「Web特有の機能を付けない」「Web特有の処理をしない」と言ってもいい。Webに適合するための機能性は「アクション」という概念だけに閉じ込めている。で、以下、アクション=Web処理の話。

[追記 date="2012-10-01"]「フィーチャ」って言葉を、ここで定義した意味で使うのはちょっと問題アリかもしれない。本来の用語では「モデル」。モデルってのも意味が広すぎてイヤなんだけど、フィーチャは「システムにインストール済みの機能」という意味で使いたい時がある。[/追記]

アクションの遂行処理

アクションも単なるコマンドに過ぎない、と僕は強調している。今後さらにアクションの特殊性を薄めていくつもりだ。アクションの特徴は次の3つ。

  1. プロファイルが固定されている。
  2. リモート起動が出来る。
  3. 遂行(perform)出来る。

アクションのプロファイルは、arg0も含めてお約束で決められている。これによりすべてのアクションを一律に扱える。だが、この特徴には何らの特殊性もない。どんなコマンドでもプロファイルを持つ。そのプロファイルがたまたま制約されているだけだ。

リモート起動は、外部からのリクエストにより実行(exec)できることだ。これが出来なきゃWeb処理に使えない。ただし、リモート起動(remote invocation)と直接起動(direct invocation)の違いはまったくない。アクション自体は、自分がリモート起動されたか直接起動されたかを一切区別することができない環境変数REQUEST_METHODなどがリモート起動時の情報を伝えるが、unclose構文で環境変数をセットできるので決め手にならない。これは、直接起動を使ってリモート起動を100%エミュレート出来ることを意味する。

遂行(perform)は、実行(exec)とは違う。その違いは次の絵で示せる。この絵全体でやっていることが「アクションの遂行」である。

遂行をCatyScriptのコードで書けば(catch {*=> ...} が今動かないが):


try --wall=superhard {
some-action
} |
catch {
normal => pass,
signal =>
try --wall=superhard {
map-signal
} |
catch {
normal => pass,
* => internal-server-error,
},
except =>
try --wall=superhard {
map-exception
} |
catch {
normal => pass,
* => internal-server-error,
},
}

単に実行するだけでなく、シグナルと例外を map-signal, map-exception に渡して面倒を見ることが遂行(perform)である。アクションを遂行するのはフレームワーク(Webシェル)の仕事だが、アクションを表現するクロージャ(closure-like object)を入力としてアクションを遂行するコマンド perform も提供される。また、ディスパッチャーコマンドとして lookup-and-perform ってのもある(単にexecするのは lookup-and-exec)。

Webフィーチャ

Webフィーチャとは、Web特有の機能性を実現するための、基本となる型とコマンドのセットである。

ちなみに、フィーチャとは、型、コマンド、ファシリティ、アセット(静的HTLM、画像、JavaScriptファイルなど)の一式をまとめた概念である。モジュールという単位でうまくマトマリがつかないときフィーチャという単位を使う。Webフィーチャも、必ずしもモジュールと1:1対応はしない。

[追記 date="2012-10-01"]「フィーチャ」の意味は上の説明のとおりだが、「Webフィーチャ」は不適切な気がしきた。冒頭の追記も参照。[/追記]

Webフィーチャの実体は2つの型と4つのコマンドである。フィーチャを構成する型/コマンドの名前とコマンドのプロファイルは完全に決まっている。

  1. 型 WebRaw
  2. 型 Response
  3. コマンド expand
  4. コマンド response
  5. コマンド map-signal
  6. コマンド map-exception

オプションと引数は省略して、入出力プロファイルだけを書くと:

  1. expand :: any -> WebRaw
  2. response :: WebRaw -> Response
  3. map-signal :: any -> Response
  4. map-exception :: Exception -> Response

anyとExceptionはCaty標準の型である。map-signal と map-exception は、先ほどのアクション遂行で出てきたアレである。歴史的な事情から、WebRawの別名としてWebInput、Responseの別名としてWebOutputが使われる。これらの型/コマンドの典型的な使用例は次のようになる。

上の絵の説明は節を改めてする。

Webフィーチャの使われ方

アクションは、その本質的な処理を行うセマンティック処理部と、Webへの出力の仲介をするWeb出力ラッパー(アダプター)の部分に別れる。Web出力ラッパーとして使ってよい基本コマンドは2つだけ、関係する型も2つである。

  1. 型 WebRaw : Webメッセージ(HTTPリクエストとレスポンス)のエンティティボディとなりうるデータの型
  2. 型 Response : エンティティボディをヘッダで包んだデータの型
  3. コマンド expand : テンプレートのパスを引数に取り、入力をWebRawデータに変換するコマンド
  4. コマンド response : エンティティボディからレスポンスを作り出すコマンド

頻繁に使われるprintコマンドは、expand | response と定義されるので基本コマンドではない

アクション内で発生したシグナルと例外は、map-signal, map-exception に渡される。上の絵に描いてないが、Web出力ラッパー内の expand, responsも例外を引き起こすリスクがある。map-signal, map-exception の例外に関しては最終的にフレームワーク(Webシェル)が面倒を見る。

アクション内で発生するシグナル/例外を予測することはまったく不可能だが、Web(HTTP仕様)で定義されたリダイレクトとクライアントエラー/サーバーエラーに関しては、事前に定義しておくことができる。


exception HttpError = {
"status": integer(minimum=400, maximum=599),
*: any?
};

type uri = common:uri;

@[register-public]
type HttpRedirect = @& {
"status": integer(minimum=300, maximum=399),
"location": uri,
*: any?
};

ステータス番号300番代のリダイレクトはシグナルで、ステータス番号400, 500番代のエラーは例外で知らせる。常識的に作られた map-signal, map-exception なら、これらのシグナル/例外を適切に処理する(HTTP仕様に従ったレスポンスを作る)だろう。

Webフィーチャの切り替え

デフォルトでは、Catyに組み込まれているWebフィーチャが使われる。これを標準Webフィーチャ(standard Web feature)と呼ぶ。標準以外のWebフィーチャは、非標準Webフィーチャ(non-standard Web feature)、または代替Webフィーチャalternative Web feature)と呼ばれる。

最近のCatyは、Webフィーチャを切り替える機能を持っている。これは、汎用のモジュールローディング機能を利用しているのだが、その汎用機能はWebフィーチャの切り替えを目的に開発されたものである。メカニズムはどうでもよくて(つうか、あまり詮索して欲しくない^^;)、重要なことは、前もって準備された複数のWebフィーチャを切り替えて動作させることが出来るってこと。

Webフィーチャの切り替え機能を使うと、標準ではないWebフィーチャにより、Webの偽装(faking)が出来るのだ。アクションのコードは一切変えない。アクションは本物のWeb上で動作していると思っている。本番稼働と何一つ変わらない挙動を示す。この状態で我々は、好きなだけシステムを監視/調査/記録/テストできる。ニセ物のWebなので、普通では起こらないような現象を人工的に作り出すこともできる。高負荷状態やクラッキングのシミュレーションも出来る。もう、やりたい放題だ。ムフフ。

「自分で自分を苛め抜く」という意味のマゾ・テストも実行できる。あー、あこがれのマゾ・テスト。あー、虐めたい/虐められたーい。

代替Webフィーチャにより非標準のWebを作り出すにしても、システム自身のメタ情報(主に設計情報)にアクセスできないと全自動テストはできない。が、CatyのレイフィケーションAPIはかなり揃ってきたし、今後さらに精密なレイフィケーションが出来るようになる。メタプログラミングを駆使して代替Webフィーチャを作ることにより、今までとは次元が違うテストができだろうと期待している。

最後に一言注意しておくと; フィーチャを切り替えたり、コードトランスフォーム/コードシンセサイズを使ってテストをすることは、何もアクションに限らない。一般のコマンドセットに対しても同様の手法を使うことができる。関連するコマンド達を一連の“シナリオ”に沿って網羅的に実行する。全自動、無人、長時間の実行をする。