アプリケーションのアーキテクチャをJavaフレームワークで構築する
Javaは強力なオブジェクト指向言語で、複雑でありながらも保守と機能強化が容易なアプリケーションを開発するのに多くの企業が使用しています。しかしJavaベースのウェブ・アプリケーション開発に着手する前に明確にしておかなければならないことが1つあります。Javaベースのウェブ・アプリケーション開発には、データベースへのアクセス、ユーザー・インタフェース、UIとビジネス・ロジックの間の調停からログ機能、単体テスト機能、レポート機能に至るまでいろいろな角度からの設計上の懸念事項を解くための戦略が必要となります。
Javaはウェブ・アプリケーション開発のためだけに設計されているわけではありません。にもかかわらず、ウェブ・アプリケーションの開発をサポートするための拡張機能が継続的に追加されています。Javaの優れている点は、SunやIBMやOracleだけではなく誰でも言語拡張を構築できるという点です。言語拡張の多くがオープン・ソースのJavaフレームワークとして利用可能になっています。Wikipediaによればフレームワークとは「他のソフトウェア・プロジェクトを計画し、開発することができる、定義されたサポート構造。フレームワークにはサポート・プログラム、コード・ライブラリ、スクリプト言語、ソフトウェア・プロジェクトのさまざまなコンポーネントを開発したり、結合したりするのに役立つその他のソフトウェアが含まれる。」となっています。
多数のさまざまなフレームワークからアプリケーション・フレームワークを構築することができます。難しいのは、自分のアプリケーションにうまく適合するフレームワーク群を選択することです。当然のことですが、自分のアプリケーションの設計上の懸念事項を解決するためにカスタム・ソリューションを記述することもできますが、高度でしかも使いやすいソリューションが既にオープン・ソースのフレームワークとして提供されています。さらに、私の信条は「記述するコードが少ないほどバグが少ない」というものなのです。何十というフレームワークが利用可能ですが、本稿では私自身が個人的に使用した経験のあるフレームワークについて説明します。本稿ではフレームワークを以下の8つのカテゴリに分けました。
- アプリケーション・コンテナ
- オブジェクト関係マッピング
- ユーザー・インタフェース
- モデル-ビュー-コントローラ(MVC)
- ログ機能
- テスト機能
- Ajax
- レポート機能
アプリケーション・コンテナ
Javaアプリケーション開発に初めて着手しようとしている組織にとって上記の8つのカテゴリの中で一番理解しづらいのがコンテナです。要するに我々はレガシー・アプリケーション用のコンテナについては議論してこなかったのです。OS/400の作業管理機能がコンテナに必要なサービスを提供していましたから・・・。ウェブ・アプリケーションでは、トランザクション制御、セキュリティ規則の設置、HTTPリクエスト処理、サービスの調停(たとえばデータベース接続)などといった同様のサービスを用意する必要があります。すべてのウェブ・アプリケーション・サーバー(たとえば、Apache Tomcat、WebSphereなど)は、HTTPリクエスト処理サービスを提供していますが、それを利用するにはJ2EE完全互換のウェブ・アプリケーション・サーバーを使用してバンドルされているすべてのサービスを導入しなければなりません。WebSphere Application Server (WAS) V6.0 ExpressはJ2EEコンテナ・サービスを一式全て提供していますが、WAS V5.1 Expressはそうではありません。コンテナ・サービスを提供しているウェブ・アプリケーション・サーバーは管理実行環境を有しているといわれており、提供していないウェブ・アプリケーション・サーバーは管理されていない実行環境を提供していると言われています。
管理環境を使用すると、セキュリティとトランザクション制御を宣言文の形で使用することができます。データベースの完全性を提供するには、トランザクション境界を定義する必要があります。トランザクションを起動すると、必要なinsert、update、delete操作などをすべて完了し、コミットするかもしくはエラーが発生すればロールバックします。管理環境がないと、トランザクション制御機能を提供するコードを記述しなければなりません。管理環境においては、トランザクション制御の構成をXMLドキュメントで記述することができ、コードは一切記述する必要がありません。これを宣言型トランザクション制御と呼びます。また管理環境においては宣言型セキュリティも利用でき、アプリケーションのコードを複雑にすることなくXMLドキュメントでセキュリティの制御を定義できます。セキュリティ制御やトランザクション制御に関する問題はさまざまなソフトウェア・コンポーネントに影響するので、トランザクションやセキュリティ用のコードを追加してコード全体を複雑にするべきではありません。
「記述するコードが少ないほどバグが少ない」という私の信条に従っていただけるのであれば、サービスをXMLで宣言的に構成できるサービスを提供しているコンテナを使用したほうが良いでしょう。ただし、WebSphereのJ2EE互換コンテナ・サービスを使用する必要はありません。オープンソースのコンテナが利用可能です。WebSphereのコンテナ・サービスを使用したとしても、Spring社が提供している有用なサービスの使用を検討してみてください。そのようなサービスのうちの代表的なものに、アスペクト指向プログラミング(AOP: Aspect-Oriented Programming)と依存性注入(制御の反転、IoC: Inversion of Controlとも呼ばれています)があります。AOPは複雑さという意味では「すでにあるもの」ですが、依存性注入はあらゆるアプリケーション・アーキテクチャにとって非常に有用なものです。 IoCの最も一般的な使用方法はコネクション・プールの割り当てとデータ・アクセス・オブジェクト(DAO)のビジネス・コンポーネントへの実装です。
Springは軽量のコンテナであると言われています。つまり、重量級のJ2EE互換のコンテナよりもシステム資源を消費せず、使用方法や構成方法も簡単なコンテナです。Springはアプリケーションを構成する他のフレームワークを管理したり統合したりすることを可能にするための重要な機能を提供しています。
オブジェクト関係マッピング
オブジェクト関係マッピング(ORM)の必要性を説明する前に、もう1つの変わった用語を説明しなければなりません。それはインピーダンス・ミスマッチです。インピーダンス・ミスマッチとは、関係データとオブジェクト指向言語を統合しようとするときに発生する悩ましい問題です。何らかの理由でデータベース・レコードの値をJavaオブジェクトに取り込み、そのオブジェクトに含まれる情報に対してユーザーが更新した値をデータベースに反映させる必要が生じたとしましょう。
このインピーダンス・ミスマッチの問題を解くために1999年にJ2EE Enterprise JavaBeans (EJB)が誕生しました。しかし私を含む多くの(あえてほとんどのと言いますが)開発者はEJB Entity Beansは扱いにくく使いづらいものだといくことがわかり、独自のORMツールを作成しました。何十というORMがオープン・ソースのORMフレームワークとしてリリースされました。
ORMはリレーショナル・データをJavaのオブジェクトに対してXMLでマッピングさせるための戦略を提供します。図2のPEOPLEテーブルを図3のJava Personクラスにマッピングしている様子を図1に示します。1点重要な点を指摘するとすれば、PersonクラスはPlain Old Java Object (POJO)であるということです。POJOは基本的にはデータ構造です。つまり、POJO自体にはビジネス・ロジックはありません。ORMはSQL風のクエリーでPOJOにデータを提供するためのAPIを提供しています。その上で追加のORMメソッドを使用してデータベースに永続しているPOJOを追加、修正、削除することができます。
何十というORMが利用可能な中で、私はHibernate (hibernate.org)、ApacheのObject Relational Bridge (OJB - db.apache.org/ojb)、iBatis (ibatis.apache.org)を使っています。OJBはJava Data Objects (JDO) 仕様 JSR 12 (jcp.org/en/jsr/detail?id=12)を実装している数少ないORMフレームワークの1つです。もちろん、業界標準のAPIを実装しているORMを使用することは良いことのように思えますが、JDOの実装ごとに一長一短があるということも知っておいてください。ただし、業界標準といっても2種類あるということを覚えておいてください。1つは特定の組織によって規定されたもので、もう1つは業界から圧倒的に受け入れられて標準になったものです。特定の組織が標準化したAPIは、EJB 1やEJB 2の例もあるように、必ずしも価値のあるものではありません。
もっと最近になって制定されたORM標準はJava Persistence APIで、JSR 220 Enterprise JavaBeans (jcp.org/en/jsr/detail?id=220)のサブ仕様になっています。JSR 220の仕様作成担当者によれば、Hibernateの実装はEJB 3.0 (Hibernateの創業者ガビン・キング氏はJSR 220作成チームの一員)に大きな影響を与えたとのことです。Hibernate 3.2はJPAとHibernateという2種類のAPIを提供しています。HibernateのAPIはJPAのスーパーセットとなっています。J2EE EJBのコンテナを構成してHibernate 3.2を使えるようにすることができます。
今日現在、EJB 3.0はそのバージョン1.0および2.0で失った業界の信頼を取り戻し始めました。その主な理由は3.0がPOJO開発をサポートするようになったからです。残念なことに、EJB 3.0を実行するにはWAS 6.1が必要となるため、ほとんどのi5使用者にとってはEJB 3.0は選択肢とはならないでしょう。
HibernateはORMに関して圧倒的な強さで業界をリードしています。2007年3月現在、Hibernateのバーション3は130万回ダウンロードされており、数十冊の書籍、100を越える記事、さまざまなトレーニング・コースが利用可能になっています。 Hibernate、OJBおよびその他のほとんどのORMフレームワークはSQLのselect、insert、update、delete文を動的に生成します。iBatisだけが例外なのは注目に値します。 HibernateとOJBはSQL文を自動的に生成できるので、SQLを大規模に修正することなくさまざまなデータベースをサポートできます。ただし、アプリケーション中のSQLをすべて包括するような必要があるとお感じならiBatisが適切なORMフレームワークでしょう。iBatisではSQLを自分で記述します(図4)。SQLに関するiBatisの要件は両刃の刃です。つまり、iBatisを使用すればレガシーのデータベースをサポートでき、ストアード・プロシージャを呼び出せ、SQLでパフォーマンスのチューニングができますが、データベースの変更に伴って設定作業やSQLの微調整がより大変になります。私の場合、Hibernateでレガシー・データベースを使用する方法をなんとか探し出すことができましたが、頻繁に変更があるデータベースのレイアウトをHibernateで使用するのはiBatisで使用するのに比べていろいろ調べる手間が多いようです。つまり、iBatisに比べてHibernateの方がいろいろ設定できて機能も豊富ですが、使用方法をマスターするまでの時間はiBatisの方が短くてすみます。
ユーザー・インタフェース
Javaベースのウェブ・アプリケーション開発は、アクション・ベースとコンポーネント・ベースの2種類に分かれます。この2つの種類の違いを一言で言うと、アクション・ベースのアプリケーションはJava Server Pages (JSP)を使用し、コンポーネント・ベースのアプリケーションはJava Server Faces (JSF)を使用するということです。アクション・ベースはHTMLのフォーム・タグのアクション属性を使用してフォームのサブミット処理を行なうサーバー・プロセスを規定します。
< form action="/remittanceWorkSheet.do" >
サーバー・プロセスは、この例の場合remittanceWorkSheetという名前ですが、検証、データ層とビジネス・ロジックとの間の通信、HTMLレスポンスの構築などの処理を行ないます。一方、コンポーネント・ベースのJSFアプリケーションでは、ページの開発者はソフトウェア・コンポーネント(JSF HTMLページ)を使ってJavaオブジェクト属性への入力をバインドしたり、UIイベントをサーバー・プロセスにマッピングしたり、フォーマッティングと検証を統合したりできます。つまり、GUIコンポーネントのメタファーを真似するにはJSPのタグを使用するよりJSFのタグを使用するほうがずっとうまくいくのです。
JSFで私が経験した大きな問題の1つはどのJSF実装を選択するかということでした(JSFはJSPとServlet API上に構築されているという点に注意してください)。JSFの主な実装はIBM、Sun、Apacheの3つです。IBMのJSF実装はWebSphere 5.1から6.0で劇的に変わり、IBM JSFをWAS 5.1から6.0へ移行するにはいくつか問題があります。現在WebSphere 5.1を導入している場合は、SunかApacheのJSFを使用することをお勧めします。私はMyFaces (myfaces.apache.org)と呼ばれているApacheのJSFを好んで使います。その理由は単に私のオープン・ソースApache製品の使用経験がいつも優れたものであったというだけです。
アクション・ベースで開発するにしてもコンポーネント・ベースを採用するにしても、タグ・ライブラリ拡張を検討しなければならないことには変わりはありません。アクション・ベースの方法を採用した場合、Struts (struts.apache.org)のタグ・ライブラリを検討してみてください。Strutsのタグ・ライブラリはMVCにStrutsを使用していなくても使えます。コンポーネント・ベースを採用した場合は、Tomahawk(myfaces.apache.org/tomahawk)とAjax4JSF(labs.jboss.com/portal/jbossajax4jsf)をお勧めします。
アクション・ベースのUIとコンポーネント・ベースのUIを比較した場合の私の考えをまとめると次のようになります。私はたった今6ヶ月のJSFプロジェクトを終えたばかりですが、JSFのエキスパートになって他のメンバーにもそれを教えられるようになるまでに必要な時間は会社(そして私自身)にとって効率的な時間の使い方とはいえません。しかし、UI戦略が一旦決まってしまえば豊富なJSFのタグを使用することでパネルや機能を追加するのは容易です。ただし、JSFを使用するプロジェクトではJSFのエキスパートがいることが必須です。
ウェブ・アプリケーション・フレームワーク
コンテナであるORMとアクション・ベースまたはコンポーネント・ベースのUIを選択したら、ウェブ・アプリケーション・フレームワークを選択しなければなりません。このフレームワークはUI処理、セッション管理、ビジネス・ロジック、データベースへのアクセスを調整します。ほとんどのウェブ・アプリケーション・フレームワークはMVCデザイン・パターンの実装です。Strutsが群を抜いて有名なアプリケーション・フレームワークです。Strutsについては私もいくつか記事を書き、何十回と講演をしましたし、数々の実運用アプリケーション用のアプリケーション・フレームワークとしてStrutsを使ってきましたが、私はさらに先へ進みます。Strutsが役に立たないものになったという訳ではないのですが、古女房になったという感じです。業界の注目を集め始めている新しいフレームワークがいくつかあります。その1つがStruts 2です。Struts 2はStruts 1ともう1つの新興MVCであるWebWorkを結合したものです。この他にもJSF、Shale、Spring MVCなどがあります。
JSF自体は基本的なコントローラー・ロジックを提供していますので、コントローラー・ベースのUIを採用するのであれば、ほとんどのウェブ・アプリケーションでJSFの統合MVCがうまくいくでしょう。しかし、複雑なウェブ・アプリケーションの場合、ApacheのShaleの採用を検討したほうが良いかもしれません。ShaleはStruts 1の一部の開発者(Strutsの開発者でもありSunのプロジェクトであるJSFをもリードしているクレイグ・マクラナハン氏もその1人)が特にJSF用に開発したMVCフレームワークです。
私が使用したことのあるアクション・ベースのフレームワークはStruts 2とSpring MVCです(Spring MVCはSpringコンテナにバンドルされていました)。Struts 1に比べてこの両フレームワークが技術的に優れている主な理由は、(1) POJO開発をサポートしていること、(2)強力なテスト機能を提供していること、(3)拡張が可能であること、の3点です。Struts 1では、開発中のアプリケーションに同じ属性を含んだPOJOが既にあっても、ページごとに「ビュー・ビーン」を作成しなければなりませんでした。また、Strutsコード(つまりアクション)のテストはウェブ層でしか行なえませんが、これはウェブ・ページをカタコトと繰り返しクリックしてテストを実行することになります。新しいフレームワークではMVCのサービスをウェブ層ではなくバッチ処理として単体テストすることができます。またこの2つのフレームワークはシンプルで容易に拡張可能なアーキテクチャになっていますので、カスタム機能を追加することもできます。
私は他の上級Java開発者と同様でSpring MVCが好きです。Spring MVCにはばかばかしいほどシンプルな戦略から強力ではあるものの複雑な戦略までいくつかの戦略があります。私は通常は基本的なSpring MVC戦略を使用しますが、それでも強化されたテスト機能とPOJOサポートがアプリケーションに恩恵をもたらしています。またSpring MVCはJSP/JSTL、Tiles、Velocity、FreeMarker、Excel、XSL、PDFなど多数のUIオプションとうまく統合できます。一方Spring MVCは設定が多数あり、柔軟性が高すぎるといえるほどで、1つの問題を解決するのにさまざまなオプションを調べる必要がある場合もあります。
さてどのウェブ・アプリケーション・フレームワークをお勧めしたらよいのでしょうか。Struts 1は優れたフレームワークですので、しばらくはレガシーのStruts 1のコードが残るでしょう。また、Struts 1については多数の書籍、セミナー、求人需要、才能のある人があり、WDScもStruts 1のウィザードとGUIを提供しています。ただし、IBMはStrutsのツールをこれ以上強化せず最終的にはStruts 1を撤退させると思われる点に注意してください。IBMの企業戦略は「JSFでStrutsを戦略的に置き換える」というものです。ではJSFを採用すれば良いのでしょうか。私もJSFアプリケーションをいくつか開発してみましたが、まだJSFを採用すれば良いと自信を持って言えるところまでは来ていません。JSFを採用するのであれば、JSFのエキスパートをチームメンバーに必ず加えてください。
Struts 2はアーキテクチャの観点でいえば明らかにStrutsよりも優っていますが、最近リリースされたばかりです。WDScにはStruts 2用のウィザードがありませんが、ほとんどの開発者はそもそもStruts 1のウィザードを使っていないようです。私はアクション・ベースのUIの場合はSpring MVC、コンポーネント・ベースのUIの場合はJSFの統合MVCを使用しています。
ログ機能
アプリケーションの開発を始める際にフレームワークとして選択して使用しなければならないものにさらにログ機能とテスト機能の2つがあります。ログ機能のフレームワークの主なものはApacheのLog4jとJDK 1.4のログ機能APIの2つです。最良の選択肢は言語に統合できるログ機能の戦略を選択することのように思えますが、ほとんどのJava開発者はそうは考えていません。ApacheのLog4jはJDKのログ機能に優る機能を備えています。その機能の中にはさまざまな出力デバイス(たとえばJava Message Service、Java Mail、JDBCなど)やローリング・ファイルなどといったテキスト・ファイル・オプションへのメッセージを記述する機能があります。
Log4jでなければApacheのJakarta Common Loggingを使用する手もあります。Jakarta Common Loggingはご自分が選択したログ機能へのプラグ・インとして使用することができます。ただし、Jakarta Common Logging のAPIはLog4jの部分集合なので、Log4jの有用なログ機能のいくつかをあきらめなければなりません。
テスト機能
テストについては「JUnit Test Infected: Programmers Love Writing Tests」という本(junit.sourceforge.net/doc/testinfected/testing.htm)でも指摘されている通り、プログラマの生き様でもあります。テストにはまってしまったプログラマの信条は「まずテストしてからコードを書く」というものです。アプリケーション開発の最初から単体テスト機能を使用し始めなければなりません。テスト用のフレームワークとして代表的なものとしてJUnit、DbUnit、jMock、HttpUnitがあります。私はJUnitで単体テストを作成することがすべてのJavaアプリケーション開発における標準になるべきだと思います。WDScではJUnitのウィザードが提供されていて、単体テストの作成と実行が容易になっています。
DbUnit (www.dbunit.org)はJUnitを拡張したもので、JUnitのテストを実行する前にデータベースを既知の状態に容易にすることができます。jMock (jmock.org)もJUnitを拡張したもので、Java APIの機能を模擬するオブジェクトを作成します。jMockを使用するとアプリケーションのある層をテストしながら他の層の実装を模擬する(スタブとして機能する)ことができます。こうすることで、多層からなるウェブ・アプリケーションをテスト中に分離することができます。各層を分離してテストすることで、問題を含んだコードの部分を検知したり、書き上がったコードを他のモジュールを実装する前にテストしたりするのが容易になります。Springのコンテナは非常に有用なjMockの拡張やServlet APIを模擬するクラスを多数提供しています。これらのクラスはウェブ層のコードのテストをウェブ・ブラウザやウェブ・アプリケーション・サーバーを使わずに自動的にテストできるので大変便利です。HttpUnit(httpunit.sourceforge.net)はウェブ層のコードのテストを自動化することでJavaScriptのコードとブラウザの動作を検証することができるようにしています。
私はほとんどのビジネス・クラスについてJUnitでテストを記述します。DbUnitは使い始めたばかりです(単体テストを実行する前にデータを複製する時間を無駄にしたくはないのですが、SQLのスクリプトを用いて複製することは可能です)。たまにjMockを使用してビジネス・ロジックをスタブ化してテスト対象を特定のモジュールに分離させます。Springのモック・オブジェクトをいつも使用して、信用できないサーバーのコードをテストします。自分が書いたコードがうまく動作しないときにまず私が行なうのは単体テストを修正してテスト環境でそれを再現させることです。そして次に、コードの修正と強化された単体テストの実行を、誤った動作が修正されるまで繰り返します。HttpUnitを使用するのは、Struts 1や自製のMVCを使用しているなどといったサーバー・コードを単体テストすることができない場合です。
Ajax
Ajaxは豊富なクライアント・インタフェースを提供しているので今後のウェブ・アプリケーションはすべてAjaxを使用すべきです。アクション・ベースのUIではAjaxフレームワーク(Prototype、Scriptaculaousなど)は取り上げません。
コンポーネント・ベースのUIでは、Ajax4jsfを選択するのが良いでしょう。HTTPリクエストとレスポンスのサイクルのすべてのフェーズを引き受けるJSFの方法が特殊であるため、JSFフレームワークのいずれかを使用してJSFアプリケーションでAjaxを実装しようとするのには問題があります。一方、AjaxをAjax4jsfで実装するのは簡単です。それはAjax4jsfではJavaScriptを一切書かなくて良いからです。その代わりに、JSFアプリケーションのライフ・サイクルに統合するタグ集合を使用します。
i5/OSでAjax4jsfを実行する際に1つだけ問題に遭遇しました。Ajax4jsfには画像を動的に生成する機能があります。この機能を使用するにはAbstract Windowing Toolkitが必要で、i5/OSではこの機能がデフォルトでは有効になっていないのです(i5/OSはネイティブGUIを持っていないため)。この問題は、java.awt.headlessまたはos400.awt.nativeというJDKプロパティをtrueに設定すれば解決できます。私の場合は画像の表示をAjax4jsfのコード・ベース(オープン・ソースのプロジェクトではいつもそうですが、コード・ベースはいつでも利用可能です)で単にコメント・アウトしました。
レポート機能
アプリケーションでPDFを生成させる必要がある場合は、JasperReports (sourceforge.net/projects/jasperreports)とBIRT(eclipse.org/birt)という2つのフレームワークを検討してみてください。JasperReportsはリリースされてから数年が経過しており、良い評価を受けているフレームワークです。しかし、時間をかけてJasperReportsを勉強しようなどと思わないでください。PDFの生成はBIRT (Business Intelligence and Reporting Toolsの略語)なら簡単だからです。BIRTはJasperReportsを使用していますので、JasperReportsを除け者にしようとしているわけではありませが、BIRTはEclipseベースのGUIを提供しています。ある日BIRTをダウンロードしてインストールし、設定してPDFを大量に生成してみました。実運用しているBIRTのレポート・ツール自体がウェブ・アプリケーション中で実行されるので、報告書を書く必要が生じるまではBIRTの実行を止めておいた方が良いでしょう。
正しいオプションを選択する
アプリケーション・アーキテクチャの選択肢として3つのオプションをご紹介しました。(1) 最も人気のあるフレームワークを自分で調べる、(2) IBMの企業戦略に従ってJ2EEにバンドルされているフレームワークを使用する、(3) Springを使用してSpringとうまく統合できるフレームワークだけを使用する。1つ目のオプションは職業を選択するのとほぼ同じです。私は記事やセミナーや営業活動などにかかる膨大な時間をそれに当てることができるのでなんとかなります。2番目のオプションは、トレーニングにたくさん時間をかけなければならず、WDSc Advanced Edition (1人あたり4,000ドル)、WebSphere Application Server Base (1プロセッサあたり10,000ドル)、そしておそらくIBM Global Servicesの支援も受けなければならないので、非常にコストがかかります。また、純粋なJ2EEを選択する場合はEJB 3.0を使用することを強くお勧めします。
3番目のオプションがもっとも現実的なソリューションでしょう。Springは大変人気があり、ドキュメント、チュートリアル、書籍、ウェブサイト、セミナーなども豊富です。無数にあるSpringのサンプル・アプリケーションの中からいくつかをダウンロードしてWDSc上にインストールし、実行してみて、そのアーキテクチャを評価してからプロトタイプを作成してみることをお勧めします。どのオプションを選択すべきかを決めるのに役に立つ情報源の一覧については後述の「Find Out More」を参照してください。