ウェブアプリになってから、あまり画面そのものをモデリングする機会がありませんでした。スタンドアロンの GUI アプリでは画面のモデリングが必要となるケースが結構あった(複雑な画面を持つアプリケーションは画面上に配置されるコンポーネントを戦略的に管理しないと開発が成り立たなくなる)のですが、Kodougu を含めウェブアプリを作るようになってからあまり意識していませんでした。所詮画面のあるシステム、そうそう違いがあるとは思えないので、ためしに画面設計に関するモデリングを検討してみました。

続きを読む

Posted by あかさた
複雑な GUI を持つアプリケーションの設計について(Web アプリ編)を書いていたときに見ていた本は POSA 本だったのですが、以下のエントリでも同じようですね。

Flex2におけるアーキテクチャパターン @ 2007年08月 @ ratio - rational - irrational @ IDM

少なくともPACでいうAgentの開放/閉鎖は意識したほうがよさそうで、それだけでもイベントでワケワカになるのはかなり解消できます。


続報を強く期待します。Flex2 の固有事情とかもありそうです。

PAC で対処しやすい問題と対処しにくい問題があるから、その辺をどう考えるかですね。私はモデリングツールの開発経験が多いのですが、この種のアプリでは、構造ツリーとダイアグラムウィンドウという大きな枠組みがある場合が多いです。こういう大きな枠組みがあると、その単位で Agent を認識できるので、PAC の適用可能性が高く、スパゲティ対策に有効に働きます。

問題は、PAC が対応していない複雑性をどう制御するかでしょうか。たとえば、GUI アプリの状態やモードによって、中間レベル、下位レベルの Agent の枠を越えたアプリの制御を行わなくてはならなくなる場合があります。こういう場合、より上位の Agent に記述しますが、結局そのレベルの Agent の肥大化を招くことになります。これは、フォームやウィンドウのサブクラスを実装するタイプの開発スタイル(VB、Delphi 型)でよく遭遇します。

で、まだ整理されていないようですが、上記エントリに書かれているイベント翻訳(この言葉、知りませんでした。例外翻訳は聞いたことがありましたが。)や Command の適用などの話が出ていますから、その辺に対応策がありそうです。どういう解決策があるのか楽しみですね。

所詮さじ加減といわれるとそれまでですが・・・。(^^;

Posted by あかさた
以下のようなエントリを見つけました。非常に良い問題意識です。そう、GUI プログラミングは泣けるほど面倒くさいのです。

subtech - Pink Blossom Diary - AS3/Flex2 を使い始めて約半年より

まずイベントドリブンなプログラミングに慣れてないのが一つで。Flex のイベントや自前イベントやをただ単に投げまくってると、とりあえずは動くけど後からメンテし辛いスパゲッティコードができあがる。このスパゲッティコードは goto 文が乱立するコードよりも酷く、goto だったら割と行き先は把握できるけど、イベントを投げまくってるだけだと、どこでどのオブジェクトがこのイベントを受け取るかが解らない。解りづらい。いちいちソースコード grep ですね、おめでたいですね。あのイベントが発生してから、そのイベントが終了したら発生するイベントが終了したらウィンドウ閉じて、その間は別のイベントはブロックして/発生しないようにして、とかもうわけわかんない。これも GUI プログラミングをしたこと無いからのような気もしなくもないけど。


もう、このエントリは素敵すぎです。GUI のいやらしさをよく表現しています。しかし、残念ながら、C# + Windows.Forms を使おうが、Java + Swing を使おうが、Delphi + VCL を使おうが、そのスパゲティから逃れることはできません。

なぜ、C# や Java でもこの問題から逃れることができないのか、考えて見ましょう。確かに、Form や Window を継承したクラスにイベントハンドラを追加していくスタイルは、一見すると、わかりやすくて簡単です。でも、何の指針もなく開発を進めていくと、イベントハンドラに、UI の状態管理、アプリの処理、UI の見た目管理などの処理が混ざることになり、結局、Form や Window を継承したクラスはスパゲティになります。

言い換えると、Web アプリは、MVC2 を採用したフレームワークにしたがって書けば、関心ごとがそこそこ分離され、わりと綺麗に書けます。でも、GUI プログラミングの場合、フレームワークに従っても、複数の関心ごとを分離してはくれません。開発者は自衛する必要があります。また、関心ごとの分離という意味では、JavaScript でも、スタンドアロンアプリでも本質的に同じ問題を抱えています。

では、どうすれば、このいやらしさから逃れられるか考えて見ましょう。

(0) 前提

複雑な GUI アプリの場合のアイディアを書きます。一応、Web(Ajax とか Comet とか絡みそうなもの)を前提にしています。

(1) UI の状態は抽象化しよう

UI の状態を抽象化します。vi みたいにモードを作ってもいいです。

GUI アプリでは、特定の作業をしているときに、特定の入力を排除するようなことがあります。保存中に全ての入力を排除するとかですね。どの状態(モード)のときに、どの View 部品が、どのイベント(キーとかマウスとか)を受け付けるか、わかりやすく定義できるような抽象化が望ましいです。View 部品は構造化しておくと、粒度に応じた管理が出来るようになります。

また、UI の状態遷移図を書いて整理して、状態遷移を実現するフレームワークを書いて抽象化してもいいでしょう。State パターンですかね。サーバと通信があるなら、それも考慮した状態管理を行いましょう。

Kodougu ではこの辺の手を抜いていて、関係線の作成中に Del キーを押したりするとちょっと変な動作をします。

(2) イベントハンドラは UI の状態管理だけを行おう

イベントハンドラにアプリの処理を書かないようにしようということです。画面描画に関わるような処理も書かないようにして、UI の状態管理に徹させることです。イベントハンドラは UI の状態に応じて、別のクラスか関数に書いたアプリの処理を呼び出しましょう。

(3) 必要ならアプリの処理と UI の変更処理は分離しよう

ここで言う UI の変更処理とは、たとえば、チャットの場合、ユーザーの発言を受信したら画面を書き換えたりするようなことです。特定の UI の状態で、ボタンを disabled にするような処理は別です。そういう処理は、状態管理で考えてください。

アプリの処理とは、チャットなら、クライアントで発言ログやログインユーザを管理したりするような処理です。

以下のケースなら、アプリの処理と UI の変更処理の分離を検討した方がいいです。当てはまらない場合は行う必要はありません。
1. アプリの処理と UI の変更処理が一対一でない場合
2. アプリの処理と UI の変更処理が同一のイベントで処理できない場合(画面への反映はサーバの応答待ちとか)
3. サーバの処理とクライアントの処理の境界があいまいな場合(Web なら、HTML の組み立てをサーバでやるか、JavaScript でやるかあいまいなとき)

(4) 必要ならアプリのモデルを定義しよう

Web アプリの場合、サーバにはしっかりとしたモデルクラス(社員クラスとかね)があるかもしれませんが、JavaScript にはそれはないかもしれません。サーバとは異なるモデルかもしれませんが、クライアントにモデルが必要になら、ちゃんと定義しましょう。Kodougu(Web 上で動作するモデリングツール) は、クライアントにもモデルを定義しています。

(5) アプリ処理、画面変更、サーバとの通信の順序を決めよう

そのままです。機能ごとに上記の順序が変わるとわかりにくいので、決めた方がいいです。

とりあえず、こんな感じかなと思います。私はまだまだ、JavaScript については経験不足です。Kodougu も JS の部分は、2000 行位しかなく、小さなものしか作ったことがありません。

■ 追記(2007/8/14 4:53)
GUIプログラミングのパターンが知りたい : akiyan.com

イベントドリブンでステートフルなGUIプログラミングには、いわゆるWebサーバーアプリーケーションでの抽象化経験は全然役に立ってる気がしません。むしろ余計に感じたりします。


無駄になるということは無いと思います。要は関心ごとの分離ですから。ただ、フレームワークを「使う」Web アプリ開発と異なり、複雑な GUI アプリはフレームワークを「作る」ことになるという違いはあります。たしかに、Rails アプリを作るように、複雑な GUI アプリを作ったら自滅しますね。そういう意味では、上記の余計に感じるという表現は非常に示唆に富んだものだと思います。

Posted by あかさた