My favorites | Sign in
t-2
Project Home Downloads Wiki Issues Source
READ-ONLY: This project has been archived. For more information see this post.
Search
for
BestPractice  

ja, en
Updated Mar 24, 2011 by shinpei.ohtani@gmail.com

T2を使う上でのベストプラクティスをまとめてみました.

Programming

@DefaultをPageクラスに必ず1つつける

T2のプログラミングモデルでは、Pageクラスでいずれかのアクションメソッドが処理されるはずです. しかし、これらが処理されない場合に別のPageクラスを探索します. そのため、確実に特定のPageクラスで処理させる場合には、@Defaultをつけたデフォルトメソッドを作成しておきます.

以下のようなコードイメージになります.この例では、fugaメソッドとmogeメソッドの条件にマッチしない場合、indexメソッドが呼ばれます.

@Page("/hoge")
public class HogePage {

	@Default
	public Navigation index(WebContext context) {
		return Redirect.to("/jsp/add.jsp");
	}

	@POST
	@ActionParam
	public Navigation fuga(WebContext context) {
		...
	}

	@GET
	@ActionPath
	public Navigation moge(HttpServletRequest req) {
		...
	}

Pageクラスでオーバーロードメソッドは避ける

Pageクラスでオーバーロードメソッドは避けるべきです.T2ではアクションメソッドのオーバーロードメソッドは推奨していません. なぜならユーザからのリクエストの受け口であるアクションメソッドは出来る限り明示的でわかりやすくする必要があるからです.

そのため、オーバーロードメソッドで対応するのではなく、より適切なメソッド名をつけてください. このことが開発トータルで見たときの保守性はあげます.

Pageクラスの管理方法を統一する

Pageクラスを管理する方法は大きく分けて最初からDIコンテナに全て管理させる方法と、T2のeagerloadオプションを使って、 稼働時にDIコンテナに登録させる方法とがあります.最初からDIコンテナに登録させる方法は、例えばSpringを使う場合には、設定ファイルである applicationContext.xmlにT2のPageクラスを記述してしまうといった具合です. 一方eagerloadオプションを使えば、稼働した初期化時にT2の方からDIコンテナに登録にいくので、 設定を記述しておく必要がないので、開発時などには便利です.

どちらにせよ、アプリケーション全体でPageクラスを管理する方法は統一しておいてください. オススメはお使いのDIコンテナにきちんと記述して管理させる方法です.

@Formを使って変換する場合には、ErrorInfoも引数に記載する

@FormはT2が送信されてきたフォーム内容をPOJOに変換する機能です. しかし、このままだとT2がPOJOに変換した際にエラーが発生したかどうかを知ることが出来ません. そこで、ErrorInfoを併用すると、フレームワーク内部で変換したときにエラーが発生したかどうかを知ることが出来ます. @Formを使う場合、以下のようなコーディングを推奨します.

	@POST
	@ActionParam
	public Navigation addWithForm(@Form AddForm dto, ErrorInfo errorInfo) {
		......
	}

Configuration

適切なDIコンテナを使う

T2に限った話ではありませんが、DIコンテナは使う事を検討に値するフレームワークです. 特にT2ではDIコンテナ連携機能が準備されているため、ぜひ利用を検討してみてください. その際に、プロジェクトにより適したDIコンテナを使ってください. 例えば以下のような点を検討すると良いでしょう.

  • 実際に使った経験のあるDIコンテナは何か
  • 開発の規模や開発者のスキルセットとして適切なDIコンテナは何か
  • 今後の継続性を見た場合にどのコンテナが最も適しているか

T2とDIコンテナの連携の仕方は、フレームワーク連携を参照してください.

Debugging

ログに出力された情報をよく見る

T2では以下のような手順でPageインスタンスのアクションメソッドを探索し、実行します.

+ 送信されてきたURLから該当のPageインスタンス候補を探し、1つづつ試していきます. + Pageインスタンスの中から、対象となるアクションメソッドを探し出します. + アクションメソッドを実行し、その結果をNavigationのインスタンスでもらいます.

このようなポイントのところは、ログで全て出力するようにしています. まずは、上記のポイントが自分の想定どおり動いているかを確認してみましょう.

ログは下記のようになっています(適宜見やすいように改行いれています).

23:37:11.731 [HttpProcessor:init0] INFO  o.t.t2.action.impl.ActionInvokerImpl
  - リクエストを処理するPageクラスを検出しました。(Pageクラス名:HelloPage, IndexPage).
23:37:11 [HttpProcessor:init0] INFO  o.t.t2.action.impl.ActionInvokerImpl
 - リクエストを処理するPageクラスを検出しました。(Pageクラス名:HelloPage, IndexPage).
23:37:11.732 [HttpProcessor:init0] DEBUG o.t.t.a.impl.ActionInvokerFilterImpl org.t2framework.t2.lifecycle
 - URL(/t2-samples/hello)に対して、アクションメソッド(HelloPage#index(org.t2framework.t2.contexts.impl.RequestImpl@775121))を実行します.
23:37:11 [HttpProcessor:init0] DEBUG o.t.t.a.impl.ActionInvokerFilterImpl
 - URL(/t2-samples/hello)に対して、アクションメソッド(HelloPage#index(org.t2framework.t2.contexts.impl.RequestImpl@775121))を実行します.
23:37:11.732 [HttpProcessor:init0] DEBUG o.t.t.a.impl.ActionInvokerFilterImpl org.t2framework.t2.lifecycle
 - URL(/t2-samples/hello)に対して、アクションメソッド(HelloPage#index(org.t2framework.t2.contexts.impl.RequestImpl@775121))を実行しました.
23:37:11 [HttpProcessor:init0] DEBUG o.t.t.a.impl.ActionInvokerFilterImpl
 - URL(/t2-samples/hello)に対して、アクションメソッド(HelloPage#index(org.t2framework.t2.contexts.impl.RequestImpl@775121))を実行しました.
23:37:11.733 [HttpProcessor:init0] DEBUG org.t2framework.t2.filter.T2Filter org.t2framework.t2.lifecycle
 - Navigation(org.t2framework.t2.navigation.Forward@16f70a4)が見つかりました.
23:37:11 [HttpProcessor:init0] DEBUG org.t2framework.t2.filter.T2Filter
 - Navigation(org.t2framework.t2.navigation.Forward@16f70a4)が見つかりました.

この例では、以下のようなことがわかります.

  1. Pageクラスの候補として、HelloPageとIndexPageが見つかりました
  2. /t2-samples/helloに対して、それを処理するアクションメソッドとして、HelloPage#index(org.t2framework.t2.contexts.impl.RequestImpl)を実行しました.
  3. 実行結果として、org.t2framework.t2.navigation.Forwardのインスタンスが返されました.

大きな動きはこのようにデバッグしやすくなっています.

ログ出力を細かく制御する

T2のロギングはコアライブラリとして、slf4j/logbackというライブラリを使用しています. このライブラリはログ出力を細かく制御する仕組みがあり、それをマーカと言います.

T2の重要なログはこのマーカを使って制御する事が可能です. T2のマーカは下記のように定義されています.

マーカ名 キー名 説明
DESIGN org.t2framework.t2.design プラグインやアドインなどの拡張ポイントにつけるマーカーです.
BOUNDARY org.t2framework.t2.boundary 外部オブジェクトのインジェクトポイントなどの境界につけるマーカーです
LIFECYCLE org.t2framework.t2.lifecycle T2フレームワークのライフサイクルが明記できるポイントにつけるマーカーです
DETAIL org.t2framework.t2.detail T2フレームワークの内部詳細を明らかにするポイントにつけるマーカーです
PROFILE org.t2framework.t2.profile T2フレームワークのパフォーマンス測定のためにつけるマーカーです

マーカの制御には、slf4j/logbackロギングの設定ファイルで指定します. 例えば以下の例では、T2のDESIGN関連のログを出力するようにしています.

	<turboFilter class="ch.qos.logback.classic.turbo.MarkerFilter">
		<Marker>org.t2framework.t2.design</Marker>
		<OnMatch>ACCEPT</OnMatch>
	</turboFilter>

T2のデフォルトの設定はt2-filters.xmlとしてjarファイルに同梱されているので、以下のようにincludeして使う事が可能です.

<configuration debug="true">
	<include resource="t2-filters.xml" />
	......

t2-filters.xmlは下記のようになっています.

<included>
	<turboFilter class="ch.qos.logback.classic.turbo.MarkerFilter">
		<Marker>org.t2framework.t2</Marker>
		<OnMatch>ACCEPT</OnMatch>
	</turboFilter>
	<turboFilter class="ch.qos.logback.classic.turbo.MarkerFilter">
		<Marker>org.t2framework.t2.design</Marker>
		<OnMatch>ACCEPT</OnMatch>
	</turboFilter>
	<turboFilter class="ch.qos.logback.classic.turbo.MarkerFilter">
		<Marker>org.t2framework.t2.boundary</Marker>
		<OnMatch>ACCEPT</OnMatch>
	</turboFilter>
	<turboFilter class="ch.qos.logback.classic.turbo.MarkerFilter">
		<Marker>org.t2framework.t2.lifecycle</Marker>
		<OnMatch>ACCEPT</OnMatch>
	</turboFilter>
	<turboFilter class="ch.qos.logback.classic.turbo.MarkerFilter">
		<Marker>org.t2framework.t2.detail</Marker>
		<OnMatch>DENY</OnMatch>
	</turboFilter>
	<turboFilter class="ch.qos.logback.classic.turbo.MarkerFilter">
		<Marker>org.t2framework.t2.profile</Marker>
		<OnMatch>DENY</OnMatch>
	</turboFilter>
</included>	

TOPに戻る

Powered by Google Project Hosting