Wicketを使う際、イベントなんかはonSubmit()をオーバーライドしたら実現できるけど、でもコレって自分にとっては非常に嫌な感じがする。無名クラスでってのは簡単でいいけど、無名クラスのメソッドをフックするポイントができないので、Wicketを基幹業務にバリバリ使わせるように提案するときには結構気を使うんじゃないかと最近考えていた。
イベントなどが行われる際に、よくログを取ったりイベントの後に色々と処理を行うなどイベントをフックしたいときが良くあると思います。例えば、ボタンのイベントの場合だと更新系のイベントが起こったらデータベースにログを出力するなんて仕様があったりとか、お客様合意の共通仕様なんかにだけイベントの前、後でログを取ったりするとか書いてあるとか。
この場合、Wicketではいくつか方法が考えられるけど自分はこんな感じになるのかなと考えた。
イベント内でプログラマが共通関数を呼び出すパターン。下記の例では無名クラスの中で処理を書いているけど、WebPageクラス内のメソッドに委譲する場合でも内容は同じです。
Button b = new Button("ok"){ public void onSubmit(){ // イベントの処理 ... 省略 // NOTICE 共通仕様(ログ出力) Util.addLog("ok", "OKボタン処理"); } };
この場合、先の共通仕様にだけ処理内容を書いているパターンだとプログラマが設計書の行間を読む作業が入ります。そのため、処理を入れ忘れることも考えられます。
2.ボタンを継承した独自のボタンを使わせる。
プロジェクト内では拡張したボタンなどを提供してプログラマに使わせるって手です。例えばこんなボタンを提供します。
public abstract class HogeButton extends Button { public final void onSubmit(){ try{ // 処理を委譲 onHogeSumit(); } catch(exception e){ // エラー処理 return; } // ログに出力 Util.addLog(...); } // override this method public abstract void onHogeSubmit(); }
これで、イベントの際には前処理、後処理が追加できるようにまります。
3.WebPageだけ独自のクラスにする
WebPageを継承した新しい独自ページクラスを作って、イベントの前、後処理をオーバーライドする。こんなWebPageを作ればいいんじゃないかい?
public class MyPage extends WebPage { public void beforeCallComponent( final Component component, final RequestListenerInterface listener){ // ここにイベントが呼び出される前の処理 } public void afterCallComponent( final Component component, final RequestListenerInterface listener){ // TOTICE 共通仕様(ログに出力) Util.addLog(...); } }
一応、これでプログラマが意識しなくとも処理が行われるようになると思います。
以下は自分がこのエントリを書いた理由ですので、Wicketとは関係ありません。読みたくない方は飛ばして結構です。
先の共通仕様に書いているパターンなどの場合はお気軽なマネージャーはこんな事を言うと思います「共通関数作ってコーディング規約に書いたらいい。」それでコーディング規約に追加される一文がこれ。
更新系イベントの際、次のメソッドを呼び出し、ログを出力すること。 Util.addLog(String name, String log); 第一引数:ボタン等の名前 第二引数:ログ文字列
これが上記1のパターンになります。自分からすればコレは思考が停止したのか?と言いたくなります。コーディング規約は縛りが弱いためにプログラマ任せになってしまう。それを確認するのがUTだろと反論する方やプログラマを信用しないでどうするのと言う方もいるが、フレームワークのお作法内でクラス設計やコンパイル時に静的に解決できるかどうかぐらいは検討したほうが良いと考えます。
そのためプログラマに責任を転嫁する仕組み(規約)を作るのではなく、必ずこうなるって仕組みを提供するのが吉だと自分は考えている。別にそれはプログラマを信用しないとか言う意味ではなく単に仕様をシステマチックに楽に解決できないかと考えているだけのこと。(人間はミスをするのでなるべくミスをしない仕組みを作る)
なので、なるたけコーディング規約にはこう書いて提供したい。
プログラマは画面クラスにこのクラスを継承する*だけ*で共通仕様は実現される。
そんな気持ちからこのエントリを書いています。そう考えた場合Wicketは無名クラスを多用するので、プログラマがサクサクとイベントの中身を制御して書くぶんにはいいけど、後々の拡張性、プログラマの書いたコードの制御などを考慮したいと思うと辛いなぁと感じた。単に自分はまだWicketのWを知ったぐらいなので色々方法はあると思いますが。
未来の仕様は分かりはしない。だけど変更に強いものは作る事ができる。変更に強いってのは変更仕様を実現しやすいってのもだけど、業務処理をシステムからみて変更後も統一性があるってのも重要なことだと思う。そういった意味で。
人によってはそれを「同じようなコードになる」って勘違いする人も出てきたり、「思い上がるな!オレはこうやりたいんだ!」って主張するプログラマも出てきたり、POJOだよPOJO、いまどき継承は流行らないよとか批判だけして去っていく人もいるけど、保守を中心に考える自分みたいな単なる業務プログラマは製造の一瞬よりも長い保守期間を考えたい。
上記2の場合では、プログラマがあまり共通仕様を意識しなくとも提供したボタンを使用すれば実現できるようになりますが、でもこの場合の欠点は
- この独自コンポーネントを使うかどうかは最終的にはプログラマ任せになる
- 改修時に新たに使うWicketコンポーネントがあった場合、新たな独自コンポーネントを追加しなくてはならなくなる場合もある
- 開発初期に提供するべきコンポーネント以外に使うものが出てきた場合にうっかり提供し忘れると、もしかすると1期にはこのコンポーネント、2期以後にはこのコンポーネントも存在する・・・なんてパターンができますが、コードに統一性が無くて嫌です。
こんな感じで、まだまだ考える余地があるなぁと感じます。でもコーディング規約はこんな感じで済みます。
ボタン処理はHogeButtonを使うと共通仕様は実現されます。 リンク処理は... ・・・その他の独自コンポーネント
上記3の場合だとプログラマはあまり共通仕様を意識することなく実現できるのでコーディング規約はこんな感じになります。
プログラマは画面クラスにこのクラスを継承する*だけ*で共通仕様は実現される。
結局、最終的に作ってもらう方には普通にWicket的にButtonを使って・・・って言うのがベストだと思う。プロジェクト独自で提供できるコンポーネントが少なければ少ないほど、「そのフレームワークを知っていればいいよ」って言うことができるので頼むほうも頼まれるほうも楽かと思う。
Web2.0的なサービスであれば、ササっと作って公開して適宜使い易くするためにどんどん変更を加えて、リファクタリングなんかもするんであれば、自分の書いたことはどうでもいいことかもしれない。でも、基幹業務のように一度作ったコードが修正したくとも修正できなくなる状況がある場合については、作る前に時間がある限り考えたいなと思う。