議事録 / 第07回


13章 Web Tire Design

数あるWebフレームワークの中でどれをつかうべきか?

技術的に優れている優れていないという観点ではなく、仕事として使えるかどうかで見ればStrutsとJSF以外に選択肢はない。
  • Tapestry
    • 良いところはあるが使われていない。
    • そのため開発者を集めることが難しい。
    • 癖が強い。
  • WebWork?
    • メインストリームから離れているので仕事で使うには裁量権がないと難しい。
  • Struts
    • 現時点では一番使いやすい。
  • JSF
    • メインストリームになるのは間違いない。
    • Craig自身が、Strutsの役割は終わり今後JSFが主流になると言っている。
  • Vendar独自のフレームワーク
    • たとえばTenArtni?のNinja-VA(オープンソース製品)。ViewだけでなくO/Rマッピングの機能もある。

Springとの連携について

  • ContextLoaderListener?
    • Springのフレームワークの中でWebのアプリケーションが立ち上がったときに自動的にSpringのコンテナを使えるようにするListener。
    • Servletでも同様のもの(ContextLoaderServlet?)が用意されている。
    • web.xmlの中でSpringの設定ファイルを指定するとこれらがContextLoadListener?経由でBeanFactory?となる。
    • ListenerとServletどちらを使うべきか
      • SeasarではServletを使っている。利点はブラウザからurlを指定することでコンテナのリロードや稼動確認をできること。
  • WebApplicationContextUtils?
    • ContextLoaderListener?で作ったWebApplicationContext?にアクセスするために使用される。
    • Springと連携するフレームワークがWebApplicationContextUtil?を使ってServletContext?からWebApplicationContext?を取り出す。これがSpring連携の実態。

Request-driven Web MVC Framework

Struts

  • ActionForm?で扱う値の型について
    • ActionForm?でStringとboolean以外の型を使うのは現実的ではない。バリデーションをかけたときに値が元に戻らないため。
  • どのようなものか?少なくとも日本では使われていなさそう。
  • BaseAction(p.379)
    • StrutsとSpring Frameworkをベタに連携させるとActionでコンテナからコンポーネントを取り出すコーディングとなる。
    • JPetStore?の初期バージョンで使用されていたようだ。
    • 現在のバージョンでは自動的にinjectionされるはず。
  • Struts Recap(p.381)
    • ActionForm?がcommandやmodelというのはおかしい。

WebWork2

  • WebWork?にはインターセプタなどのIoC的な機能があった。WebWork2になってIoC部分はXWorkに切り出された。
    • xxxAwareのクラスにinjectionが行われる。
    • インターセプタのStackが用意されている。
      • Seasar2ではインターセプタのStackに相当するものとしてInterceptorChain?というものが用意されている。
  • WebWork?のAction
    • WebWork?のActionはStrutsのActionとActionForm?を兼ねている。
    • 後続のビジネスロジックにはドメインオブジェクトに値をつめて渡すべき。Viewへの依存は少なくするために入力値と処理は別にするのが基本。
  • WebWork?はなぜ流行らなかったか?
    • すでにStrutsがあった。
    • 情報が少なかった。
    • マーケティングをしなかったのではないか。
      • 良いものをつくっても誰も使わなければ意味がない。
      • マーケティング重要。

SpringMVC

  • 利点
    • JSPでプレビューができる。
  • 欠点
    • Command Controllerの継承構造が深すぎる。
      • 継承構造の深さはBeanFactory?についても言える。
      • インタフェースの階層と実装の階層が合っていないのではないか。

Event-driven Web MVC Framework

Tapestry

  • 概略
    • HTMLのテンプレート:普通のHTMLにIDをつけたもの。
    • pageのspecification:HTMLのテンプレートにつけたIDがTapestryのどのコンポーネントに対応するのかを指定するもの。
    • pageクラス:あるHTMLに関連付けられているオブジェクトを受け取ったり、イベントを受け取ったりするもの。
    • Visit:HTTPSessionをラップしているようなもの。
    • Global:ServletContext?をラップしているようなもの。
  • 使いにくさ
    • HTMLのテンプレートとpageのsecificationを綺麗に分けると結構手間がかかる。間違いやすいし重複感がある。
    • Tapestryはステートレスを実現するための仕組みとして状態をデコードしてページに埋め込むなどの処理を行っている。このあたりの考え方に慣れるのが大変。
    • Tapestryでは画面に描画される順番にrequestを処理していくなど処理の順番がレイアウトに依存する。レイアウトに依存しないような別手段はあるが慣れが必要。
  • 画面から呼び出されるメソッドについて
    • WebWork?ではexecuteメソッドしか呼び出せないということを除けばTapestoryとWebWork?は似てると言える。Tapestryの影響があったかどうかわからないがWebWork?では任意のメソッドが呼び出させるように変更されている。
    • StrutsにもDispatchAction?というものがありexecute以外のメソッドも呼び出せるようになっている。

JSF

  • JSFの今後
    • 一年後の新規開発でStrutsが使われることはほとんどないはず。
    • ただ、JSF1.1の仕様はまだ甘いため現在の素のJSFは使いにくい。今後JSF1.2、JSF2.0が出れば使いやすいものになる。
  • ツールを使った開発
    • ベーシックな開発にはベンダーのツールではなくオープンソースのツールが使われるようになるだろう。
    • JSF2.0の普及の仕方はオープンソースのツールのサポート度合いによって変わってくる。
  • JSFのコンポーネント
    • MyFaces?のコンポーネントが有名。
    • オープンソースのコンポーネントも高度な有償のコンポーネントもいずれ出てくるだろう。
    • WebSphere?のコンポーネントは移植性がない独自のJSF拡張。
  • HTML以外を出力するJSF
    • XMLやXULを生成するものがある。

その他のWeb MVC Framework

Portlets

  • 疑問
    • Webのフレームワークで行うことの意義は何なのか?
  • SpringはPortlets系の機能を盛り込もうとしている。Tapestryもサポートしている。
  • Portletsの仕様は良くない。
  • ポートレットをサポートするフレームワークは多いが、フレームワークを使ってもポータル系の案件は大変らしい。

ASP.NET

  • 特徴
    • code behindという考え方がある。画面で入力した値が裏側であるオブジェクトにマッピングされる。
    • 初期処理の仕組みが用意されている。ちなみに、JSFでは初期処理について仕様で規定されていない。
  • JSPでの開発と大きく違う点
    • FrontServlet?のようなrequestをまとめて受け付けるところがないのでJSPでの開発経験を元に取り組むと戸惑うかもしれない。

WebObjects?

  • Mac OS X TigerでEOFに似たCore Dataという機能が用意された。
    • EOFはサーバサイド(というか金融のような基幹系を扱うエンタープライズ)向けに作られたフレームワーク、Core DataはEOFを参考にして開発されたクライアント向けの実装
    • Core DataとEOFとの違い
  • 全然アップデートされない為、WebObjects?の存在意義がなくなりつつある。
  • WebObjects?はTigerでの対応がまだ発表されていない。
    対応されました
  • J2SE5.0の対応が発表されていない。

14章 Unit Testing and Testability


単体テストのゴール

  • 単体テストではクラスの「collaboration」(協調関係)のテストは必要だが同時に「collaborator」のテストはすべきではない。例えばAクラスからBクラスを呼び出しているときに、Aの単体テストでBを同時にテストすべきではない。ただ、AがBを呼び出しているということはテストすべき。
  • collaborationのテストも必要ないのではないか。たとえばDIコンテナを使っている場合、collaborationのテストはDIコンテナの設定があっているかどうかの確認にほぼ等しい。アトミックな機能を実現している末端のクラスのテストは必要だが、これを呼び出しているだけのクラス(例えばDAOを呼び出しているだけの業務ロジックのクラス)に対するテストは不要。等しくテストすると工数が爆発的に増える。いかにテストをしないですませるかを考えるべき。処理を委譲するだけのようなクラスのテストを行う必要はない。
    • この考えで行くと末端のクラスを主にテストすることになるのでほとんどMockを使う必要がない。
  • djUnitなどのツールを使うとカバレッジ100%にこだわりたくなるが、実際は70〜80%あれば十分だろう。

テスト容易性を保障する

  • ロッドはメソッドをシンプルにしろと言っているが、テストをしやすくするためには、これに加えてクラスを単機能単一責任にするという考えも意識する必要がある。たとえばひとつのクラスに100も200もメソッドがあるとテストがしにくい。

テストを困難にするもの

  • 誤ったSingleton
    • InitialContext?のこといっているのか?InitialContext?は毎回newして使用するが実装によっては毎回newすることにあまり意味がないように(同じ参照を見るように)作られている。だがInitialContext?そのものはSingletonとはいえないのでは。Namingを管理しているオブジェクトがSingletonになっていることがあるかもしれない。
    • Singletonをlookupに使用すると、DIを使用する場合と比較して置き換えが難しくなる。ただ、DIは置き換えを可能にすることだけを目的としているわけではない。
  • Static Facades
    • 関数のかたまり
  • 正しいstaticメソッドの使い方
    • Thread Localを使用する場合
      • Thread Loacalをユーザー要件を満たすためには使うことはないだろう。
      • コネクションなどのlookupのために使用することがある。methodで渡したくない場合など。Thread Localは一瞬だけ使える一種のグローバル変数と言える。

標準ライブラリへの挑戦

  • JNDIのInitialContext?をスタブやモックに置き換える。
    • SpringにはJNDIからオブジェクトを取得するためのJndiObjectFactoryBean?が用意されている。モックのパッケージとしてorg.springframework.mock.jndiとorg.springframework.mock.webがある。
    • InitialContext?で取得するオブジェクトをモックで置き換えたいが、InitialContext?自体をモックに置き換える必要はないだろう。

テスト容易性を向上させる技術

  • TemplateパターンではなくStrategyパターンを使う
    • SpringではTemplate Methodだらけだが…。フレームワークでTemplateパターンを使うのは問題ない、らしい。
  • デメテルの法則
    • オブジェクトは直接の友達以外お話しちゃだめ,というルール
    • DIを使うとデメテルの法則が守れる。DIの世界では階層がなくフラットなので友達とだけしゃべればよくなる。
  • オーバーライド可能なメソッドにリファクタリングする
    • staticなメソッドやSingletonはテストしやすいようにリファクタリングすることができる。
    • ファウラーもblikiで言及している。

単体テストのテクニック

  • スタブとモック
    • 動的モックが一番コストがかからない。Seasar2のMockInterceptorJMock
    • いつスタブを使いいつモックを使うかの判断は非常に重要。
    • テストのコミュニティでもスタブが何を指すのは人によって意見が異なるので注意が必要。ファウラーがスタブとモックについて言及しているがこれがひとつの試金石と言えるのだろう。

効果的な単体テストを書く方法

  • 単体テストで設定ファイルを使うことの是非
    • コード量が減るならば設定ファイルを使っても問題ない。
    • テストの仕組みを意識する必要がないのであれば設定ファイルを使ってもよい。S2Unitのように外部ファイルの読み方を意識しないでテスト内容に集中できるようになっているべき。
    • CVSなどバージョン管理システムからとってきてそのまま使えるようになっているべき。絶対パスを使っているものなどはダメ。
  • テストコードのリファクタリングの是非
    • Without EJBや達人プログラマー3部作のUnit Testの章ではリファクタリングすべしと述べられている。
    • 日本ではテストケースのリファクタリングに反対な人が多い。そもそもテストケースのリファクタリングという言葉は正しくない。テストケースを変更した場合はその妥当性を確保できないため。

テスト駆動型開発

  • TDDとテストファーストの違い
    • TDDは必ずしもテストを先に書くとは限らない。TDDとはテストからフィードバックを受けて開発を進めることを指す。
    • インタフェースを先に決めてから進める開発をTDDと言えるのかな?
  • TDDのフィードバックについて(フィードバックにより設計が変更されるのか?)
    • アプリケーションの設計はユーザーの要求によって決まる。ユーザーの要求が変わらなければ設計は変わらないはず。ユーザーの要求で決まるインタフェースがTDDで行うことで変更されていくことはありえない。
    • 設計というより実装部分がTDDを行うことでよりシンプルに変更されていく。お客さんをまきこんでいけば設計部分も変更されていくことがあるかもしれない。
  • レビューについて
    • テストケース自体のレビューとテストケースのコードのレビューは別。テストケース自体のレビューを行いテストケースの漏れを防ぐ。ホワイトボックスのテストは実装者にまかせるのがいいのでは。
  • テストコードの書き方が開発者ごとに異なることについて
    • プロジェクトの初期にテストケース付きのリファレンス実装を用意するとテストコードも含めて品質が保てるだろう。開発者に真似させるということが重要。
    • 定量的にしばるにはJCoverageCheckstyleFindBugsなどを使う。けれど開発者を信じることも結構重要かも?
  • TDDのコスト
    • コーディングをしている時間はかかるがデバッグの時間が減らせる。デバッガを使うことはほとんどない。TDDは保守コストを下げるといっているが保守フェーズの前に元がとれる。
    • テストをしたほうがトータルのコストは間違いなく下がる。2回、3回テストすれば目視確認するよりコードを書くほうが安く済む。テストコードはトップダウンで書かせるべき。

TDDの実践

  • コンパイルエラーがあったとしてもテストの実行はできなければいけない。
  • 全体テストを実行するインターバルはプロジェクトそれぞれ。
  • ことなる粒度のテストをグループ分けして実行できる。TestNGというツールがある。

テストツール

  • テストケースジェネレーター
    • テスト作成者が何をテストすべきかを考えるべき。自動的テストに頼るべきではない。
    • 永続化層には使えるかもしれない。永続化層のテストケースは比較的単純なので。
    • Jtest
      • Design by Contractの機能が有用
      • 自動生成されるテストコードはあまりに大量
      • テスト漏れの有無を確認するなどあくまでプラスアルファとして使うもの
  • カバレッジツール
    • カバレッジをあげることだけを目的としてはいけない。コードがどのように振舞うかの観点のテストケースが重要。
  • ミューテーションテストツール
    • テストケース自体の有用性を検証するツール。研究段階のもの。
    • たとえば掛け算を実行するメソッドに2つの引数(2,2)のを渡すのは正しくない、足し算でも同じ結果になるため。ミューテーションテストツールはこういうことを検証してくれる。

その他

  • バグを直す前に単体テストを失敗させるべき
    • バグ報告をそのまま信じないで単体テストで確認すべき。
  • 依存について
    • ビジネスロジック層がPOJOであればそれ以外での層での依存をそれほどこだわる必要はない。
    • ただS2Daoを使っても依存は生まれない。インタフェースだけで実装クラスがないから。
  • 例外について
    • 現在は非チェック例外を使うのが主流。
    • どの非チェック例外が下位のクラスから飛んでくるのかすべて把握するのは難しい。アプリケーションだけでなく使用しているライブラリも非チェック例外を投げる可能性があるため。
    • 非チェック例外の捕捉はAOPで行うと楽。

15章 Performance and Scalability

クラスタリング

  • ハードウェアを増設すればクラスタリングは実現できるがセッションレプリケーションのコストはどのように考えるべきか
    • HttpSession?EventLisnter?でRDBに格納する方法が考えられるが格納する量が多ければ当然パフォーマンスが落ちる。
    • WebSphere6ではセッションレプリケーションについてきめ細かい制御ができるようになっている。
    • 画面の履歴をもつフレームワークがあるがセッションレプリケーションが大変。さらに履歴をもつフレームワークはメモリを非常に圧迫する。
  • リッチクライアント
    • リッチクライアントでは画面の履歴について考える必要がないのでセッションレプリケーションは問題にならない。
    • リッチクライアントはセッションを使わず、サーバーとの依存関係をもたない。
    • リッチクライアントはたとえ落ちたとしても簡単に状態を復元できる。

AOPのパフォーマンス

  • CGLIBは速いと言われているが実は遅い。環境にもよるが通常のJavaより20倍くらい遅い。
  • JDKのProxyは通常のJavaより6倍くらいおそい。
  • 現在のSeasar2のAOP実装では通常のJavaより6倍くらい遅い。速度的にはJDKのProxyとほぼいっしょ。
    • Seasar2のAOP実装がCGLIBのときはAOPの対象としていないメソッド呼び出しについてもパフォーマンスが遅くなっていた。
  • BEAはバイトコードレベルではなくVMレベルのAOPを実現しようとしているらしい。

パフォーマンスチューニング

  • パフォーマンスをあげる単純な方法は
    1. メモリを増設する。
    2. DBのチューニングをする。
      • クラスタリング環境下でprimary keyに連番を振るのはボトルネックになるので避けるべき。
      • KeyはIdentifireなのでユニークであればいい。
  • キャッシュ
    • DBにまかせるべき。DBの高度なキャッシュに勝るものをつくるのは無理。
    • アプリケーション層でキャッシュの仕組みを作っても苦労の割りにパフォーマンスはあがらない。
    • Hibernateの2次キャッシュなどは危険な問題を孕んでいる。
  • アプリケーションのチューニング
    • 不要であるべき。普通に書いてちゃんと動くことがアプリケーション層に求められている。
    • チューニングを実行する際は、プロファイルをとって遅いことを確認してからにする。
    • チューニングが必要ならばまずDBをチューニングすべき。

ベンチマークを行うためのツール

  • Microsoft Web Application Stress Tool(WAS)
    • 評判が高い。使いやすい。
  • Apache JMeter
    • 使いにくい。
    • Strutsのようなリクエストを受け付けるだけならば問題ないがhiddenのパラメータで実行プログラムを制御しているようなアプリには向いていない(コードを書けば対応できるが…)。
    • 物理的ネットワーク(ネットワークカード)の制限でストレスデータどおりのストレスをかけることができないことがあるので注意したい。
    • Argentとしても使うことができるらしい。
  • Sun Java Studtio Enterprise 7
    • ベンチマークの機能以外にも多くの機能がついている。安くておすすめ。

この議事録を読んで分からないことや、疑問に思ったこと、その他ご意見等がありましたら下記コメント欄にお願いします。匿名でも結構です。