N2 ToolBox(跡地)

跡地です。引っ越しました。http://d.hatena.ne.jp/nosen

EasyMock vs jMock

2004-05-30 00:01:33 | 開発手法/方法論
昨日もちょっと書きましたが、どちらも動的にMockObjectを生成するタイプのツールであるEasyMockjMockを両方ちょっとだけ試してみました。
機能的には大差なくて、どちらも以下のような事ができます。
  • 動的プロキシの機構を使ったインターフェースのMockObject生成
  • cglibを使った拡張ライブラリによるクラスのMockObject生成
  • 予期されるメソッド呼び出しの設定と検証
  • 予期されるメソッド呼び出しに対する戻り値または例外の設定
予期されるメソッド呼び出しは複数回分を設定できますし、順番を指定することもできます。
違うのは、予期されるメソッド呼び出しの設定方法です。
EasyMockだと以下のようになります。

MockControl ctrl = MockControl.createControl(Foo.class);
//MockObjectの生成
Foo mockFoo = (Foo) ctrl.getMock();
Bar foo = new Bar(mockFoo);

String arg = "arg";
//予期されるメソッド呼び出しの設定
mockFoo.bar(arg);
ctrl.setReturnValue(1);
//テスト開始
ctrl.replay();
int rv = foo.doBar(arg);

jMockだと以下のようになります。
Mock mock = new Mock(Foo.class);
//MockObjectの生成
Foo mockFoo = (Foo) mock.proxy();
Bar foo = new Bar(mockFoo);

String arg = "arg";
//予期されるメソッド呼び出しの設定
mock.expects(once()).method("bar").with(same(arg))
.will(returnValue(1));
//テスト実行
int rv = foo.doBar(arg);

さあ、どちらがわかりやすいでしょうか?
EasyMockはMockObjectに対して予期されるメソッド呼び出しを"記録”するというアプローチです。jMockのやり方は細かいメソッドに分けて予期される動作を設定しており、一見分かりづらいのですが、JavaDocをよ~くながめると、「ふーんなるほど」と納得できます。これはこれでなかなか筋のとおったやり方です。
どっちがいいのか?と言われると難しいのですが、僕はjMockの方が好きですね。EasyMockはぱっと見はわかりやすいのですが、ちょっとややこしいことをやろうとするとすぐごちゃっとしたコードになってしまいそうな気がします。一方jMockは一見分かりづらいのですが、一度理解してしまうと、柔軟性も高いし、複雑な振る舞いもさくっと設定できそうです。そんなに使い込んでないんで、わからないですが。
ただ、ぱっと見のわかりやすさも実際の開発では結構大事なんですよねぇ。以前4人のXPプロジェクトを回したときに、ソースコードを生成するタイプのMockObjectツールを使ったのですが、僕も含めて全員が生成されたMockObjectの使い方が分からなくてハマったという苦い経験があります。
MockObjectというもの自体、うまく使えばテストの効率がすごく向上するけど、使いどころを間違えると大変なことになるものだという気がしています。基本的にはあんまり複雑なインターフェースには適用しない方がよさそうです。HttpServletRequestのMockObjectを作るよりは、素直にコンテナの中でテストしたほうが良いと思います。

EasyMock

2004-05-29 01:37:05 | 開発手法/方法論
なんのかんのいっても僕はMockObjectを使ってテストをすることが多いのですが、MockObjectのソースコードを生成するタイプのツールはちょっと面倒だな、と感じていました。
そんな中、最近見つけたのが、EasyMock。これはソースコードを生成するのでなく、JDK1.3から使える動的プロキシの仕組みを使って実行時にMockObjectを生成するタイプのツールらしいです。
さらに特徴的なのは、予想される引数や、戻り値、例外の設定方法。
従来型のMockObjectだと、addExpectedなんちゃらなどという難しい名前のメソッドを経由して予想される値を設定してあげないといけなかったのですが、EasyMockは違います。
あらかじめMockObjectに対して予想されるメソッド呼び出しを"記録"し、実際にテストを実行するときに以前記録した操作と、実際の操作の差異をMockObject側で比較し、異なる場合はAssertionFailedErrorを投げる、という仕組みらしい。
これは確かにシンプルで分かりやすいやり方のような気がします。

同様に動的にMockObjectを生成するアプローチのツールとして、jMockというものもあるらしいです。こっちも気になります。
テストを効率良く実施できるかどうかは、ソフトウェア開発にとって死活問題ですから、是非検証してみたいですね。

ブックレビュー:熊とワルツを

2004-05-28 00:19:45 | ブックレビュー
書名:熊とワルツを リスクを愉しむプロジェクト管理
著者:Tom DeMarco & Timothy Lister
訳者:伊豆原弓
発行:日経BP社

FDD関連の本を買おうと思って本屋さんに行って、なぜか衝動買いした本です。平積みになってたので、結構売れてるんじゃないでしょうか。

内容はタイトルから想像出来る通り、ソフトウェア開発プロジェクトにおけるリスク管理についてです。全体として平易な言葉で、理論と実例、たとえ話を降り混ぜながら親しみやすい語り口でリスク管理のいろはを語っており、読みやすい印象をうけました。3日で読み終わりました。ちなみに著者は「ピープルウェア」を書いた人だそうです。

まず、第1章の1ページ目からいきなり登場するリスクのないプロジェクトには手をつけるなとの言葉にはおもわず拍手しそうになりました。特に日本では「リスクをとる」ということができる会社はほとんどないのではないでしょうか?

ソフトウェア開発はなぜいつもこんなにツラいのか?というのはいつもみんなが不思議に思うことですが、本書ではそれは発注者もプロジェクトマネージャもソフトウェアプロジェクトについて回る不確定要素を認識せず、適当な基準で納期を決め、しかもそれを依怙地になって守らせようとするからだ、という話になってます。プロジェクトのリスクを正しく評価し、リスク移行の程度によって納期に幅があることを認めればみんなが幸せになれる、ということです。
この議論にかんしては僕も大いに共感できました。
プロジェクトの納期に幅を認めたくない人達の心配は、開発者に甘えを許すことだと思われますが、無駄な厳しさによって問題が解決するのなら僕は今すぐ、ムチとおもりの付けられる足枷と外から鍵のかけられる部屋を調達しますね。

よく発生するリスク(コア・リスク)については発生する確率のデータをとることで、プロジェクトのリスクをある程度定量的にはかれるようになる、ということもいわれていますが、それを実践できてる会社ってあるんですかね?あったら是非見学に行きたいです。
単なる数の遊びでなく、そのようなデータを現場に活かすのは、ものすごく難しいことのような気がするんですが。。。

インクリメンタルな開発手法は、リスク回避の方法として推奨されています。XPに関してはeXtream Programming Explaindなどの本が推薦図書としてあげられています。著者はXPをリスク回避戦略として高く評価しているようです。

なお、本書で紹介されているRiskologyという無料のツールを使うと、簡単なプロジェクトのリスクのシミュレーションができるそうです。

@ITの記事

2004-05-26 00:57:16 | その他
今日はちょいと気分を変えてWebWorkじゃない話を書きます。
すこし古い話になってしまうのですが、先週の@ITの記事にEJB3.0の話が出てましたね。
最近J2EEには全然興味が湧かなくて、新しい仕様とか全然チェックしてませんでした。それというのも、EJBなどの重量級の技術を使う局面が想像つかなかったからです。
サービス間連携をするならAxisとか使って普通のJavaBeansをWebサービスとして公開したほうが簡単だし、単にJavaで分散オブジェクトを実現したいならRMIの方が簡単だし、分散トランザクションなら素のJTAを使った方が簡単だし、CMPよりはHibernateとかの方がよさそうだし、というわけです。
一方、メソッド毎にトランザクション境界を設定したり、EJBのインスタンスをプーリングしたりといった機能が必要になることはめったになかったし、最近ではそれすらSpringとかSeaser等のIoCコンテナを使えば比較的簡単に似たようなことが実現できてしまうようになって、ますます僕の中で存在意義を無くしていきました。しかもJSPよりはVelocityの方が好きなので、もうサーブレットコンテナだけあればいいやと思ってる程です。
で上述の記事ですが、どうやら
EJB3.0=Spring+Hibernate
であるらしいことが判明。Annotation使ってるだけじゃん!
本当に最近のJava界はオープンソースコミュニティによって牽引されているなぁと感じました。まーそこが面白いところなのですが。
純粋に標準ライブラリの出来などは、Javaは.NETにかなわないですし。。。

XWork用語集2

2004-05-25 00:53:00 | オープンソース
とりあえず続きです。

Package
Action,Result Type,Result ,Result Type,Interceptor,Stackをひとまとめにグループ化したものです。Packageは他のPackageを「拡張」することができるため、設定情報の再利用が容易になっています。

Value Stack
リクエスト毎に生成され、Interceptor,Action,Resultが互いにやりとりするデータを格納するコンテナとなるスタック実装です。InterceptorへのアクセスにはOGNLという式言語が使用されます。

Component
XWorkにおけるDependency Injectionパターンの適用です。Actionに対してComponentをInjectすることができます。

ここまで説明した内容を図示しておきます。
あまり自信がないので間違ってたらつっこんでください。

XWork用語集1

2004-05-24 03:06:26 | オープンソース
WebWorkを理解するためには、ベースとなっているXWorkを理解することが大切だと思います。そこでここでXWorkを理解するのに必要な用語を一通りおさらいしておきたいと思います。

Actions
Actionはリクエスト毎に呼び出されるクラスで、あるひとまとまりの処理を行った後、Resultを返します。Actionはフレームワークから呼び出されるエントリポイントとして最低限execute()メソッドを実装します。

ActionContext
ActionContextは実行環境へのアクセス手段を提供します。HttpServletRequestやHttpSession等のServlet特有のAPIをラップしているイメージで良いと思います。その他にもXWork特有の実行環境へのアクセスパスも提供してはいますが。ActionContextはリクエスト毎にインスタンス化されます。

Interceptor
InterceptorActionの呼び出しの前後に任意の処理を動的にはさみこむオブジェクトです。前にも書きましたが、ServletFilterと同じイメージです。複数のActionにまたがった共通の処理を定義するときに使用します。

Stack
Stackは複数のInterceptorの順序つきリストです。Interceptorをグループ化してまとめてActionに適用するときに使います。StackActionの設定時に名前で指定できます。

Result
ResultはActionが返す文字列定数です。標準的な定数としてlogin, error, input, none, success が定義されていますが、もちろん他のものを定義するのは自由です。

Result Type
Viewを生成するクラスです。WebWorkのデフォルト設定ファイルでは前もってdispatcher,redirect, velocity, chain, xsltが定義されています。
普通にJSPでViewを生成するときに使うのがdispacher、Velocityの時はvelocityなのですが、redirect, chain, xsltというのはちょっとまだ良く分かりません。興味津津です。

最小Webアプリ2

2004-05-21 02:14:52 | オープンソース
続きです。

xwork.xmlの作成
以下の通りXWorkの設定ファイルを作成します。

<xwork>

  <include file="webwork-default.xml"/>

  <package name="default" extends="webwork-default">

    <default-interceptor-ref name="defaultStack"/>

    <action name="Hello" class="wwstudy.HelloAction">
      <result name="success" type="velocity">
        <param name="location">/WEB-INF/vm/hello.vm</param>
      </result>
      <interceptor-ref name="defaultStack"/>
    </action>
  </package>
</xwork>

include要素で指定しているwebwork-default.xmlはWebWorkが提供するデフォルトのXWorkの設定ファイルで、WebWorkが提供するインターセプタなどが定義されております。XWorkではこのように他の設定ファイルを設定のベースラインにすることができます。
キモになるのはaction要素で、ここで自分で作ったActionの設定を行います。result要素のname属性は先程のActionのexecuteメソッドの戻り値と整合性がとれている必要があります。intercepter-ref要素で参照しているのはincludeしているWebWorkの設定で定義されているデフォルトのインターセプタスタックです。

デプロイ
これらのファイルを必須ライブラリと共にWebアプリケーションの形にまとめます。ディレクトリ構造は以下の様になります。
`-- WEB-INF
    |-- classes
    |   |-- wwstudy
    |   |   `-- HelloAction.class
    |   `-- xwork.xml
    |-- lib
    |   |-- commons-logging-1.0.3.jar
    |   |-- ognl-2.6.3-modified.jar
    |   |-- oscore-2.2.1.jar
    |   |-- velocity-dep-1.3.1.jar
    |   |-- webwork-2.0.jar
    |   `-- xwork-1.0.jar
    |-- vm
    |   `-- hello.vm
    `-- web.xml


動かしてみる
さあ、それでは早速動かしてみましょう。今回は、jdk1.4.2_04とTomcat 5.0.24を使います。Tomcatを起動して、ブラウザで

http://localhost:8080/wwblog/Hello.action?name=Nose

を表示すると、ちゃんと

こんにちは! Nose さん.

と表示されます。

気になること
これでWebWorkを使ったWebアプリの概要は大体分かったのですが、細かい所がまだまだ不明です。検証や、型変換のときにエラーがおこったらどう処理するのでしょうか?セッションの扱いは?共通のデータ構造を複数のActionで使いたい時は?などなど。
これからはそういう細かい所をすこしづつ調べて行こうと思います。

あと、今回WebWorkの挙動で気になったのは、executeの戻り値の文字列がxwork.xmlの該当Actionの設定に存在しないと、ブラウザにレスポンスが永遠に戻ってこなくなることです。ログに警告ログははかれるのですがね。。。これって挙動としてはすこしおかしい気がします。
このへんについてももう少し突っ込んで原因をさぐっていきたいです。

ではまた。

最小Webアプリ1

2004-05-21 01:47:46 | オープンソース
さて、理屈はこれくらいでおいといて今日は実際にWebWorkを使って以下のような非常に簡単なWebアプリを作ってみます。

・リクエストパラメータ"name"から値をとってきて「こんにちは! xxさん」という挨拶を表示する

以下の手順で作業をすすめることにします。
1. Actionの作成
2. Velocityテンプレートの作成
3. web.xmlの作成
4. xwork.xmlの作成

Actionの作成
以下の通りActionインターフェースを実装したクラスを作成します。
package wwstudy;

import com.opensymphony.xwork.Action;

/**
 * Hello, World
 */
public class HelloAction implements Action {
    /**
     * Name
     */
    private String name;
    /**
     * Performs the simple action
     */
    public String execute() {
        return SUCCESS;
    }

    public void setName(String s) {
        name = s;
    }

    public String getName() {
        return name;
    }
}

リクエストパラメータ"name"を受け取るためにプロパティnameが定義されています。executeメソッドの戻り値は処理結果を表す任意の文字列で、XWorkはこの値と設定ファイル(xwork.xml)をもとにビューを選択します。StrutsのActionForwardと同等のものですね。SUCCESSというのはActionインターフェースで定義されている定数で、処理結果としてありがちなものとしてほかにERROR, INPUT, LOGIN, NONEが定義されています。

Velocityテンプレートの作成
今回は私の好みでビューにはVelocityを使いますが、もちろんJSPを使うこともできます。Velocityテンプレートは以下のようになります。
こんにちは! $name さん. 

$nameでActionのNameプロパティが参照できます。Velocityについてはこちらを参照願います。 JSPのかわりに使えるとても使いやすいテンプレートエンジンです。個人的にかなり好きです。

web.xmlの作成
web.xmlに以下の通りWebWork固有の記述を追加します。
    <servlet>
        <servlet-name>webwork</servlet-name>
        <servlet-class>com.opensymphony.webwork.dispatcher.ServletDispatcher</servlet-class>
    </servlet>
    <servlet>
        <servlet-name>velocity</servlet-name>
        <servlet-class>com.opensymphony.webwork.views.velocity.WebWorkVelocityServlet</servlet-class>
    </servlet>

    <servlet-mapping>
        <servlet-name>webwork</servlet-name>
        <url-pattern>*.action</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
        <servlet-name>velocity</servlet-name>
        <url-pattern>*.vm</url-pattern>
    </servlet-mapping>


Strutsとの違い2

2004-05-20 00:36:03 | オープンソース
引続き、Strutsとの違いです。

3. ActionFormが、ない
WebWork/XWorkには、StrutsでいうところのActionFormにあたるものがありません。では、HTTPリクエストのパラメータをどうやって受け取るのかというと、昨日の話の通りActionがリクエスト毎にインスタンス化されるというのがミソで、Actionのプロパティに設定されてしまいます。なので、ActionFormにあたるものがない、というよりもActionFormとActionが一体化しているというほうがしっくりきますね。

4. 前処理/後処理
StrutsではActionに対して共通の前処理、後処理を設定しようとすると、Actionのクラス階層を形成して共通処理をスーパークラスにもっていく必要がありました。
これに対してWebWork/XWorkではServletFilterのようなChain Of Responsibilityの形をとる"Intercepter"というコンポーネントによってActionの前処理、後処理を行います。Interceptorのチェーンの構成は設定によってActionごとに変更することができるので、とても便利です。WebWork/XWorkではリクエストパラメータの検証やActionのプロパティへの設定もInterceptorとして実装されています。

細かいことをいえばいろいろあるのでしょうが、ざっと目についた違いはこんなところでしょうか。こういう風に書くと、なにかStrutsに恨みでもあるのかと思われそうですが、そんなことはありません。単に私がStrutsと比較しながら勉強した方が分かりやすかっただけなので、誤解なきようお願いします。
まあWebWorkの方が後発なのですし、きれいな作りになっているのは当然といえば当然ですよね。。。それもこれもStrutsという偉大な先輩あっての成果なのではないでしょうか。
なお、昨日と今日かいた内容は以下のページを参考にしています。

WebWork vs Struts

そろそろ実際にWebWorkを使って、何か動くコードを書いて行きたいと思います。

Strutsとの違い1

2004-05-19 01:23:04 | オープンソース
WebWorkとStrutsはよく似たフレームワークです。以下の機能は両者に共通するものです。

・リクエストされたURIと設定ファイルに基づいて適切なActionに処理を転送する。
・HTTPリクエストパラメータを利用しやすい形のオブジェクトに変換してActionに引き渡す。
・必要に応じてHTTPリクエストパラメータの検証を行う。

一方、以下の点ではWebWorkはStrutsと異なっており、独自の特色を打ち出しています。

1.ServletAPIへの依存性が低い
WebWorkはXWorkという汎用的なコマンドパターンのフレームワークをベースにしています。StrutsでのActionクラスにあたる部分は完全にXWorkの中になります。XWorkはServletのAPIに依存していません。WebWorkというのは、大雑把にいうとこのXWorkをServlet経由で呼び出せるようにしたものです。

2.Actionクラスのライフサイクル
WebWork(正確にはXWork)にもStrutsのAcitonクラスに相当するActionインターフェースというのが存在しますが、これはリクエスト毎にインスタンス化されます。StrutsでActionクラスのインスタンスが使い回されているのは主にパフォーマンス上の理由だと思われますが、これに対してWebWorkは、どうせServletコンテナはリクエスト毎に山のように一時オブジェクトを作るのだから、もう一個余計に作ったところでどうってことねぇよというスタンスをとっているようです。この割り切りによって、StrutsのようにActionが必要とするデータの全てを引数として受け取る必要がなくなり、Actionインターフェースは以下の通り随分シンプルな作りになっています。
public interface Action extends Serializable {
     String execute() throws Exception;
}

別に話を簡単にするためにメソッドを省いている訳ではなく、本当にこれだけなのです。あとは便宜的に定数がいくつか定義されているだけです。引数が4つもあるStrutsのexecuteメソッドとは対象的ですよね?

眠くなったので、続きはまた明日。