谷本 心 in せろ部屋 このページをアンテナに追加 RSSフィード

2007-08-15

[]もうちょっと、Pageクラスについて。

Pageクラスについて考えてた時、ちょっと悩んだのがFormの扱い。

HTMLを、実直にPageクラスに置き換えて行くと

になるわけじゃないですか。

(まぁLoop系の話はおいといて)

f:id:cero-t:20070816002720g:image

複数フォームがあるHTMLなんかも踏まえると、

Pageクラスってこんな構造になるんじゃないかなと。


でも、そもそもPageクラスを作ろうという時に

Form云々を考えちゃいけないなー、と思ったので

前回のエントリーではFormについてカットしました。


やはり、1Page1Formが前提でしょう。


ちょっと例を挙げて話しましょうか。

たとえば、

  • 画面上に2つのフォームがある
  • それぞれのフォームが入力項目を持っている
  • ユーザが全ての入力項目に入力して、submitボタンを押した場合。

ここで、Pageクラスに、ユーザが「入力した全ての値」が反映されるかと言えば、No。

ユーザが「submitしたFormの値」だけしか反映されません。


そんな事を考えると、

やっぱり「Pageクラス」の考え方と「Form」って、いまいち合わない。

だったらいっそ、1Page1Formにしてしまえば良い。

f:id:cero-t:20070816232114g:image

(2007/08/16 画像を追加しました)

そして、こんな風に、Page内にフラットにコンポーネントを置いてやれば良い。


むしろ1Page1Formの方が、画面のコンポーネントレイヤー

動的に(JSAjaxで)書き換えたりする事に対応しやすいでしょう。


なので、

Form云々について考えたい場合は、Actionメソッドの引数にFormを渡す(Strutsライク)

Formを考えず自由にやりたいなら、1Page1FormでPageクラス(ASP.NETライク)

が良いのではないでしょうか。

2007-08-13

[]Pageクラスについて。

要は、PageクラスってHTMLJavaにしたものでしょ?

だから、そもそもPageクラスなんて手で作らず、

すべてHTMLから自動生成すべきだと言いたい。

もちろん、Dynamic Propertyと呼ばれているものも含めて。


つまり、

InputTextとかLabelとかみたいなクラスがFWに用意されていて、

public Label userId;
public InputText userName;
public InputPassword password;
public InputTextArea comment;

みたいな感じのプロパティ群で出来たPageクラスを、

HTMLから自動生成するわけです。


で、userName.valueで入力値を取り出したり、

userName.disabled = trueで使用禁止にしたりとか。


イベントは、そのPageクラスを継承したActionクラスで処理。

HTML側が書き換わっても、Pageクラスが書き換わるだけだから

GenerationGapパターンよろしくActionには影響なし。


あと、initActionの実行後はPageクラスをシリアライズして

クライアントのhiddenタグで保持しておいた方が良いでしょうか。

そうすれば、画面のイベント発生時に、initAction実行後の値を

そのまま利用することができます。


っていうか、どうみてもASP.NETです。

本当にありがとうございました。


そうなんですよね、

Pageクラスって、いったん行き着く所は.NETなんですよね。

.NETにないのは、Page → DTOの変換器(Dxo)ぐらいですか。


もしかして、

HTMLテンプレート系のフレームワークmayaaとか)と、

SwingライクなWebフレームワークWicketとかclickとか)を

組み合わせて、自動生成部分だけホゲっと作ってやれば、

こんな仕組みを実現できたります?


、、、なんて、そんな簡単なわけねーじゃん!

2007-08-01

[][]もうちょっとVerificationについて考えてみた。

S2JSFだったら、HTMLにValidationを書いて

Dtoアノテーションを書いてVerificationにすればOK。


でも、結局、両方に似たような事を書くことになるだろうから、

そのうち面倒くさくなってくるよね。(むら)


基本的にはVerificationの一部を切り出したものがValidationになるだろうから

(Validationの方がVerificationより厳しい事は、ないだろうから)

Validationもアノテーションに反応して行なえるようにしたい。


では、どのようなアノテーションにすれば、そんな事ができるのでしょうか。


■基本方針

Dtoプロパティに@Requiredとか@MaxLengthみたいなアノテーションをつけて、

Validator/Verifierがそれを見て反応。

アノテーションへの引数の渡し方なんかは、Teedaと同じノリで。


Verifier専用のメソッドは、public booleanなメソッドに

@Verifierというアノテーションを書く。


もしくは、StrutsのActionFormみたいに、Verifyメソッドを実装できる。


あるいは、クラスにアノテーションを付けて、

@VerifierMethod("verifyHoge") みたいに書いておくと

verifyHogeメソッドが呼び出されても良い。


■ウィザード画面で、全バリデータが作動すると@Requiredで軒並みエラーが出るんですが

バリデーションをするのは、Dtoのフィールドに画面からの値を設定しようとした時。

だから画面から値が設定されないフィールドではバリデーションが起こらない。

もちろん、@Requiredなフィールドにnullとか空とか入れようとしたらエラー。


■複数フィールドバリデータは?

悩ましいけど、画面で一番下になる項目(年月日で言えば、日)に

アノテーションをつけるしかないかな。


■ボタンによってValidatorを分けたい時は?

えーっと、これは困る。

Dtoで画面のボタンまでは意識したくない、というのが本音。

だからアノテーションにボタンIDを書くというは、できれば避けたい。


いっそ、Actionのメソッドに引数を持たせるというアイデアでどうか。

もうS2JSFじゃ実現し得ないアイデアになっちゃうけど。

例えばHTML

<input id="param1" type="text" m:value="param1" />
<input type="button" m:action="doHoge" />
<input type="button" m:action="doFuga" />

って書いておいて、Actionに

publict String doHoge(FooDto fooDto);
publict String doFuga(BarDto barDto);

って書いておく。


doHogeのボタンを押したら、FooDto#setParam1にparam1を渡してdoHogeを呼び出す。

doFugaの方も同様。

それで、FooDto/BarDtoそれぞれのバリデーションを掛ける。

FooDtoもBarDtoも実装はほぼ全く同じになるだろうけど仕方ない。


■更新画面の場合、initialize()でどうやってparam1に値を入れるの?

えっと、、、ペ、、、ページクラス?

なんてやると、PageクラスとDtoでまた同じ値が被りますね。


まぁちょっとこの辺りで行き詰ったんですが、

もうちょっと考えれば答えは出せそうです。

2007-07-31

[][]ValidationとVerification

こないだのドン引き最終回でもチラっと出た、これ。


ValidationとVerification。

言葉的には「妥当性の確認」と「検証」なんだけど、

ここでは「画面入力のチェック」と「サービスの引数チェック」って事にしておく。


図にするとこんな感じ。

f:id:cero-t:20070731232453g:image


Webアプリケーションセキュリティでウダウダ言ってる問題って

実は、この2種類に分ければ、随分と上手く整理できそうなんですよね。


ときに、

フレームワーク使って開発してると、バリデーションの責務が増えがち。

だって、バリデータとロジックの双方でチェックなんてしたくないから。

だから複数フィールドバリデータとか、無理してキモい事やったり

バリデータからDBにアクセスしたり、おいおい、それ何てLogic? みたいな状況になる。


逆に、バリデータはソコソコに、ロジックできっちりチェックすると

決めてるプロジェクトも多いと思うんだけど、

そんな場合も、もし、hidden書き換え対策だー、とか言って

sessionにDtoを持たせてたりすると、

ロジックに到達した時点でDtoには値が反映されてるわけだから、これヤバい。

詳しくは書かないけど、ヤバい。チェックの意味があんまりない。


セッションは極力使わず、入力はhiddenを使って保持して、

値はロジックでもチェックする、多分これが一番安全。


さて、

ここで最初に書いた「Validation」と「Verification」に話を戻しましょう。


「入力値のチェック」っていうのを、何のために行なうかを考えると、

やはり「ユーザビリティ」のためでしょう。

最後のコミットする段階になって「ふつうにだめー」とかってDBに怒られると、

もう腹が立って仕方ないから入力段階でバリデーションを行なう。


ここで勘違いしちゃいけないのは、

このバリデーションはセキュリティのためじゃないってこと。


いくらバリデーションタグを使っても、hiddenタグは書きかえられちゃうし、

sessionの値も、結局、安全とは言えない。


セキュリティのために行なうのは、Verification。

つまり、サービスを呼び出し時の引数のチェック。


Dtoがリクエストスコープだったら、そのままサービスに渡して良いけど

Dtoセッションスコープで保持した場合は、ディープコピーを作ってから渡す。

それをService層でチェックする。


ほら、みんなWebサービスだったら同じことするでしょ?

それをWebアプリケーションでもやるだけ。


この原則を守ってさえいれば、

別に複数ウィンドウ対策とか、画面フローの制御とか行なわなくて良い。

そんな「変な」操作をして困るのは、操作した人だから。

システムには影響を与えないから。


ここで、サービスの引数となるDtoにはアノテーションを入れておいて、

Interceptorでチェックしてあげるのが、一番楽なのかな。


というのを形にすると、最初に見せた図の通りになる。

f:id:cero-t:20070731232453g:image

Validationは、HTMLに記述したValidatorで行なって

Verificationは、Formに記述したアノテーションに反応して行なう。

もちろんVerificationは複数フィールドの相関チェックにも対応するし、

Daoアクセスなんかも可能、という位置づけで。


ただ、これでも、二重サブミットと、CSRFは防げないから、

ワンタイムトークンの発行だけは必須。

確認画面の表示時にでもワンタイムトークンを渡してあげて、

それでコミットを行なえば良い。


これでどう?

2007-06-29

[][]コンポーネント化する単位

S2JSFを使いながら、頑張って複数フィールドバリデータを作ったり、

時には、複数フィールドコンバータみたいなものを作ろうとしたり、

そんな風にして、無理やり、複数フィールドの値をDTOに詰めてきました。


でもよくよく考えると、そうやって「複数○○」したい単位こそ

コンポーネント化すべき単位じゃん、って、今さら気付いた。


つまり、日付入力を実現するのは、年、月、日のテキストフィールドではなく、

カレンダーって、3つのテキストフィールドを持つ、コンポーネント

もちろんDTOの型は、DateもしくはCalendar。


それがあるべき姿だよね。


でもぶっちゃけ、

JSFって(そもそもJSPって?)カスタムコンポーネント作るの面倒くさいねん!!


じゃー、どんなFWなら、カスタムコンポーネントを作りやすいんだろう?

それが宿題。


[]やっぱStruts様はエラい。

Strutsを使ったフレームワーク(共通基盤。APアーキテクチャとプロセスとライブラリ群)よりも、

S2JSFを使ったフレームワークの方が、作り難いな、と思うことがあります。


理由は、S2JSF(JSF)が素直じゃないから。


コンポーネントツリーがセッションにいるから、、、なんて嘆いても、せん無きこと。

他にも、素のリクエストが見えにくいとか、ライフサイクルがあるせいで、

使い難いと思うことがあります。


時々、JSFのコンバータに頼るよりも、

RequestをMap<String, String>か、Map<String, String[]>で受け取れて、

自前でDtoに変換できる(Dxoを提供する)方が、随分とありがたいんじゃないか、って思います。


時々、JSFのバリデータに頼るよりも、

全部Stringで構成されたDtoを作って、それを自前のValidatorで検証できる方が、

随分と楽なんじゃないか、って思います。


当然、「だったらStruts使えよ」って流れになります。


Webの常識に従った「Request = 文字列」が前提の開発なら、

JSFを使うよりも、Strutsを使ってる方が楽なことも多いでしょう。

Web開発者の頭にあるイメージそのままでしょうから。

特に、自分がFWを開発する側になると、それを感じることが多いです。


さて、少し話は変わりますが、

Teedaでは、ドロップダウンリストで選択した「値」と「ラベル」の両方を

次の画面に送るための機能があると、id:szk-takanoriさんから聞きました。


これはキモい!

数年来、Perl/CGIでWebやってきた人間にとっては、ほんとキモい!

そんな、JavaScriptでラベルを渡すなんて、Webの常識外でしょう!!


なのですが、

実は、それこそが、FWに求められてる所なのかな、と思うわけです。


旧来のWebの常識の中で生まれた育ったのがStrutsだとしたら、

その常識に捉われない、「こう使いたい」「こうなって欲しい」という

夢が溢れるような使い方をできるFWこそ、いま作るべきものでしょう。


そういうものを作りたい時に、

JSFの「素直でないトコロ」が引っかかるんですよね。


だから、Teeda + S2JSF - JSFっていう考えが出てきたのかな、と思います。


[]素直さと優しさ

  • リクエストをMap<String, String[]>で扱う、超基礎的FW
  • その上に、DataExchangeObject / DataValidateObject、もちろんデフォルト変換/検証機能つき
  • あとは、コンポーネント化しやすい仕組み

なんて辺りが、欲しいんですよ。


ユーザーが使いやすいものほど、その仕組みは複雑になっている、

というのはよく言われること。


要は両方欲しいんですよね。

シンプルなFWと、それに積み重なった優しいFWが。


たとえば、↓こんなものもFWの仕事だと思います。

  • サーブレットフィルタでの認証
  • トランザクショントークン
  • 画面遷移フローに従わないアクセスの制限
  • 二重サブミット禁止
  • 二重サブミット時、ニ発目スルー(一発目と同じ結果が表示される)
  • 諸々のセキュリティ
  • 独自スコープ
  • 開発環境(プラグイン)
  • アプリケーションアーキテクチャ
  • 開発プロセス

なんか、下の方は随分と既存のFWからは外れる気がしますが、

これらも求められるのですよね、実際。


その点で、マスカットなんかは、開発プロセスと開発環境を

最初に打ち出している辺りがイイな、、、と思いました。