レベル: 中級 Dan Jemiolo (danjemiolo@us.ibm.com), Advisory Software Engineer, IBM
2007年 9月 11日 Project Zero 開発プラットフォームには使いやすいデータ・アクセス・ライブラリーが組み込まれているため、開発者は最小限の構成作業を行うだけで自分たちのアプリケーション・コードから SQL 文を実行できます。実際、データベースをセットアップして接続するのに必要なのは、たった 4 行の構成ファイルと基本的な SQL の知識だけです。そのどちらも、平均的な Web 開発者の負担になるはずがありません。しかし、これほど単純なデータベース駆動型の開発でも、データベース駆動型コンポーネントのパッケージ化に関しては十分に考慮しなければならない懸念事項がいくつかあります。設計が適切でないと Zero コンポーネントが依存関係を引きずるため、他の開発者たちが容認できない前提を生み出してしまうからです。この記事では、データベース駆動型コンポーネントを他の Zero 開発者たちが簡単に再利用できるように構成およびパッケージ化するためのベスト・プラクティスを説明します。
始める前に
この記事では、読者が Project Zero をダウンロード済みであること、そして初心者向けチュートリアル「Developing applications with Project Zero」の手順を完了しているか、または単純なアプリケーションを自分自身で作成した経験があることを前提とします。Zero のデータ・アクセス・ライブラリー (zero.data と呼ばれます) および Apache Ant について十分理解していることも必須です。また、開発には以下のデータベース製品のいずれかを使用していなければなりません。
詳細は、「参考文献」を参照してください。
はじめに
Zero コンポーネントを実動システム用にパッケージ化する際に最大の懸念事項となるのは、データベース構成です。設計が適切でないと、Zero コンポーネントが依存関係を引きずって他の開発者たちが容認できない前提を設定してしまいます。すべてのコンテンツを抽出して構成ファイルとスクリプトを操作しなければ Zero コンポーネントを使用できないとしたら、幅広い再利用は望めません。また、コードの変更がライセンスで許可されているとしても、サードパーティーのコードを変更する責任を敢えて負いたいという開発者はほとんどいないはずです。以降のセクションでは、Zero コンポーネントの構成ファイル、ライブラリー依存関係、テーブルの作成について検討します。この 3 つを最適化することで、コンシューマーが簡単に使える、データベースに依存しない Zero コンポーネントを実現できます。
構成ファイルの最適化
Zero 構成ファイルは、ドライバー名、データベース・ロケーション、認証情報など、コンポーネントのデータベース接続に関する詳細を指定する場所です。このファイルは、/config/zero.config 配下のアプリケーション・ディレクトリーにあります。リスト 1 に、Apache Derby データベースを使用するブログ・コンポーネントのサンプル zero.config ファイルを記載します。
リスト 1. データベース構成が設定されたサンプル zero.config ファイル
[/app/db/blog/config]
class=org.apache.derby.jdbc.ClientDataSource
serverName=localhost
portNumber=1527
databaseName=BlogDB
|
このようなコンポーネントの実装コードは、zero.data の Manager.create() メソッドを呼び出し、データベース構成の名前 (例えば、Manager.create("blog")) を渡してデータベースにアクセスします。
リスト 1 のファイルは初期段階の開発とテストには問題ありませんが、実のところ、この実装にはデータベース名とデータベース製品がハードコーディングされています。そのため、このコンポーネントを他の誰かがアプリケーションで再利用するには、既存のデータベースを再利用するのではなく、新しいデータベース・インスタンス ("blog") を作成せざるを得えません。さらに、選択されているデータベース製品をまだ使用していないとしたら、そのデータベース製品をインストールしてデプロイする必要もあります。たいていの実動環境では、どちらの要件も上手くいく見込みはありません。デプロイヤーがすべての Zero コンポーネントにそれぞれ固有のデータベースを設定する余裕があることも、たった 1 つのコンポーネントのためだけに別の製品システムをインストールして管理することもあり得ないからです。要するに、コンシューマーのデータベース環境に適用できるだけの柔軟性を備えた構成にしなければ、コードが再利用されることはないということです。そこで、このセクションでは上記の zero.config ファイルをもっと融通の利くものに変更します。
ハードコーディングされたデータベース名を削除する
柔軟性を実現するための最初の、しかも最も簡単なステップは、ハードコーディングされたデータベース名をデータベース関連のコードから削除することです。リスト 2 のスタンザは、ブログ・コンポーネントの dbKey プロパティーの値を設定しています。この値は、実行時に Zero の GlobalContext API を使って読み取ることができます。
リスト 2. データベース名の構成
このプロパティーを設定すれば、Manager.create("blog") の代わりに Manager.create(app.blog.dbKey) を使用するようにコードを変更できます。データベース名を外部化することで、コンシューマーがコードの隅から隅まで調べなくても簡単にデータベース名を変更できるようになります。
コードの改善はこれで終わったわけではありません。dbKey プロパティーの値はデータベースの名前にすることも、defaultDB にすることもできます。後者は特殊な値で、zero.data ライブラリーに対して、このライブラリー自体が含まれるアプリケーションのデータベース構成を使用するよう指示します。これこそが、目的とするところです。つまり、他の Zero 開発者が独自のアプリケーションにブログ・コンポーネントを追加する際に dbKey の値を defaultDB に設定すれば、そのアプリケーションの zero.config ファイル内で dbKey の値を再定義できるというわけです (リスト 3 を参照)。
リスト 3. データベース名の再定義
[/app/blog]
dbKey=defaultDB
|
これでバランスは完璧です。コンポーネントは開発とテストの段階では blog データベースを使用する一方、デプロイメントの段階ではコンシューマーが zero.config ファイル内でこのデータベース名をオーバーライドして固有のデータベース設定と一致させることができます。
動的データベース構成
データベース名は動的になりましたが、ブログ・コンポーネントの zero.config ファイルにはまだ、元のデータベース設定に固有の情報が残っています。リスト 1 には Apache Derby に極めて限定された設定が含まれていますが、このブログ・コンポーネントは IBM DB2 や MySQL で問題もなく動作するようなので、何もその正常な動作を犠牲にする必要はありません。
データベース構成を動的にするための最初のステップは、zero.config ファイルからこの構成を抜き出すことです。リスト 1 のテキストを data.config という別のファイルに挿入し、リスト 4 の構文を使って、このファイルを元の zero.config ファイルに組み込みます。
リスト 4. データベース構成の抽出
スタンドアロンのアプリケーションとして使用することのない小さなコンポーネントについては、ここで手順を終わりにできます。必要なデータベース構成はコンシューマーのアプリケーションによって提供されるという前提で、このコンポーネントを再配布用にパッケージ化する前に @include 行をコメント・アウトすれば完了です。
ただし、複雑なアプリケーションのビルディング・ブロックとして役立つと同時に、それ自体が完全なアプリケーションとして機能するようなコンポーネントも数多くあります。このブログ・コンポーネントがまさにその例で、ブログ作成だけの処理をする Web サイト (blogger.com など) が数多くある一方で、ブログ作成はユーザー・エクスペリエンスの一部でしかないという Web サイト (MySpace など) も数多く存在します。このようなコンポーネントは、コンシューマーがスタンドアロンのアプリケーションとして使用する場合、コンポーネント自体のデータベース構成を動的に設定する機能を備えていなければなりません。これにぴったりのシナリオは、コンシューマーが Zero コマンドライン・インターフェースを使ってコンポーネントのインストール・プロセスを開始すると、その一環としてコンポーネントが自動的にデータベース要件を構成するという場合です。
データベース情報はすでに別のファイルにあるので、動的データベース構成を追加するのは簡単です。それぞれの Zero コンポーネントには Zero コマンドライン・インターフェースを呼び出すために使用する Apache Ant ファイル (build.xml) があるので、このファイルを使ってカスタム・ビルドとデプロイメント・ロジックを追加することができます。次のステップは、コンシューマーのデータベース用に適切な data.config ファイルを生成することが可能な Ant ターゲットを追加することです。このブログ・コンポーネントの build.xml ファイルには、リスト 5 の Ant ターゲットを追加することができます。
リスト 5. Ant タスクによる data.config ファイルの生成
<property name="config-file" value="config/data.config"/>
<target name="create-derby">
<echo file="${config-file}">
[/app/db/blog/config]
class=org.apache.derby.jdbc.ClientDataSource
serverName=localhost
portNumber=1527
databaseName=BlogDB
</echo>
</target>
<target name="create-mysql">
<echo file="${config-file}">
[/app/db/blog/config]
class=com.mysql.jdbc.jdbc2.optional.MysqlDataSource
serverName=localhost
portNumber=3306
databaseName=BlogDB
</echo>
</target>
<target name="create-db2">
<echo file="${config-file}">
[/app/db/blog/config]
class=com.ibm.db2.jcc.DB2DataSource
serverName=localhost
portNumber=50000
databaseName=BlogDB
</echo>
</target> |
リスト 5 では、サポート対象の 3 つのデータベースそれぞれに 1 つのターゲットを追加しています。各ターゲットは、ベンダー固有の設定を使って data.config ファイルを作成します。このブログ・コンポーネントをダウンロードしたコンシューマーが Apache Derby でサポートされるスタンドアロン・アプリケーションとしてコンポーネントを実行する場合は、リスト 6 のコマンドを実行することになります。
リスト 6. Ant タスクの実行による Apache Derby 用 data.config の作成
$ zero resolve
$ zero create-derby
$ zero run
|
DB2 および MySQL のユーザーは、create-derby をそれぞれのターゲットに置き換えてください。
このように、データベース構成をできる限り柔軟にして潜在するコンシューマーのニーズに満たすことができるようにしました。次は、不要な依存関係という問題に目を向けます。
依存関係リストの最適化
データベース駆動型のコードを作成してテストするには、必要な JDBC ドライバーを提供するライブラリーをコンポーネントに追加しなければなりません。例えば、Apache Derby データベースをサポートしている場合に必要となるのは derbyclient.jar ファイルです。このファイルは、すべての Derby ディストリビューションに含まれています (このセクションでも引き続き Derby をサンプル・データベースとして使用しますが、ここでのアドバイスはすべてのデータベース製品に適用されます)。JDBC ドライバーが含まれる JAR ファイルは、コンポーネントの /lib ディレクトリーに配置することも、Apache Ivy によるビルド・プロセス中に検出することもできます。前者の場合、インストールは簡単で、JAR ファイルを該当するディレクトリーにコピーするだけです。後者の場合は、/config/ivy.xml にあるコンポーネントの Ivy ファイルにエントリーを追加する必要があります。このエントリーは、リスト 7 のようになります。
リスト 7. Apache Derby の JDBC ドライバー用 Ivy エントリー
<dependency name="derbyclient" org="org.apache.derby" rev="10.2+"/>
|
いずれの場合にしても、依存関係をコンポーネントに追加することでコンシューマーに影響を与えることになります。MySQL のユーザーにとって、アプリケーションに Derby ドライバーが組み込まれるのは望ましいことではありません。また、その逆も然りです。使用されない依存関係はアプリケーションの正確性には影響しないかもしれませんが、アプリケーションのサイズに影響し、ライセンスの問題も関係してくることは確かです。コンポーネントが「過剰に大きい」と思われることも、法的な問題が原因で却下されてしまうことも避けなければなりません。このような問題を回避するには、開発者側のニーズとコンシューマー側のニーズとを切り離す必要があります。
詳細はデプロイヤーに任せる
最初にサンプル zero.config ファイルの変更を開始した際に目的としたのは、構成をできるかぎりコンシューマーに任せ、コンシューマーが困らないようにすることでした。依存関係の管理についても同じように取り組むことにします。つまり、必要な JDBC ドライバーはビルドおよびテスト環境に組み込みますが、最終的な配布には組み込まないようにするということです。
この目標を達成するのに最も簡単な方法は、/lib ディレクトリーを利用して必要な JDBC ドライバーを追加し、配布成果物を作成するときにこれらの JDBC ドライバーを除外することです。Zero コマンドライン・インターフェースには、コンポーネントのディレクトリーに含まれるすべてのものを取得して ZIP ファイルに追加する package ターゲットがありますが、この package ターゲットについておそらく知られていないのは、特定のファイルとディレクトリーを除外できるオプションの excludes プロパティーがあることです。リスト 8 の Ant ターゲットは、excludes プロパティーを除外対象の JAR ファイルのリストに設定した上で、Zero の package ターゲットを呼び出しています。
リスト 8. コンポーネント・パッケージからのドライバーの削除
<target name="clean-package">
<property name="excludes" value="lib/derbyclient.jar"/>
<package/>
</target>
|
この Ant ターゲットは、リスト 5 のターゲットの場合と同じ方法でコンポーネントの build.xml ファイルに追加することができます。配布ファイルを作成する準備ができたら、後は通常の zero package の代わりに zero clean-package を実行するだけです。これで、コンポーネントは柔軟な構成が可能で、不要なファイルが一切ないデータベース駆動型になりました。
ベンダー固有のテーブル作成の最適化
残念ながら、すべてのプロジェクトが前の 2 つのセクションで説明したように整然と簡潔になるわけではありません。ロジックや構成の一部がベンダー固有になってしまうという事態は、どんなに避けようとしても避けようがないことがあります。ベンダーに依存しない SQL 文の作成については多くの記事が発表されているので、ここでそのアドバイスを繰り返す必要はないでしょう。代わりにこの記事では、ベンダー固有の SQL が避けられない場合、つまりデータベース・テーブルの作成に焦点を絞ります。この場合、コンポーネントのインストール中に実行したい SQL スクリプトがあっても、コンシューマーがどのデータベースを使用することになるのかは前もってわかりません。幸い、高度なソリューションは手の届く範囲にあります。
救いの手を (またもや) 差し伸べる Ant
リスト 5 では、インストール時にベンダー固有の構成ファイルを生成することができるベンダー固有の Ant タスクを作成しました。今度は、ベンダー固有の SQL を実行してデータベース・テーブルを作成することによる、これらのタスクへ追加を行います。すべての SQL スクリプトはデータベース製品にちなんだ名前のディレクトリー (/sql/derby、/sql/mysql など) 内に整理されているという前提です。ターゲットがこの規則を利用すれば、Ant の sql タスクを使って正しい SQL スクリプトを見つけ、実行することができます。リスト 9 を見ると、どのように create-derby ターゲットを変更して Derby 固有のプロパティーを設定するようにしたかがわかります。sql タスクはこれらのプロパティーを使用して正しいスクリプトを実行します。
リスト 9. SQL スクリプトを実行するための Ant タスクの増強
<property name="config-file" value="config/data.config"/>
<target name="create-derby" depends="init-derby, create-tables">
<echo file="${config-file}">
[/app/db/blog/config]
class=org.apache.derby.jdbc.ClientDataSource
serverName=localhost
portNumber=1527
databaseName=BlogDB
</echo>
</target>
<target name="init-derby">
<property name="db-name" value="derby"/>
<property name="db-driver" value="org.apache.derby.jdbc.ClientDriver"/>
<property name="db-jar" value="lib/derbyclient.jar"/>
<property name="db-url" value="jdbc:derby://localhost:1527/db/BlogDB"/>
</target>
<target name="create-tables">
<sql driver="${db-driver}"
classpath="${db-jar}"
url="${db-url}"
src="sql/${db-name}/create-blog-tables.sql"/>
</target>
|
これで、デプロイヤーが zero create-derby を実行すると、zero.config ファイルと併せて正しいデータベース・テーブルが作成されるようになりました。MySQL および DB2 ターゲットも、同等の init- ターゲットを追加すれば同じように増強することができます。このようにすることで、コンシューマーは確実に、自分たちの製品に適した構文によってコンポーネントのデータベース・テーブルを作成できるようになりますが、唯一の欠点はすべてのベンダー用の SQL スクリプトを配布しなければならないことです。けれどもこのスクリプトは比較的小さなテキストファイルでライセンスの問題も関与しないため、心配には及びません。
まとめ
Zero コンポーネントを他の開発者が再利用できるようにパッケージ化するとなると、検討しなければならない問題が多数出てきます。そのほとんどの原因は、データベース・アクセスです。この記事では、開発者が開発の段階で知らず知らずのうちにコンシューマーに対して作り出してしまう制約および問題を緩和、軽減する方法を説明しました。Apache Ant と Zero コマンドライン・ツールの助けを借りれば、データベース駆動型コンポーネントの公開に際して起こりがちな問題を一掃することができます。
参考文献 学ぶために
製品や技術を入手するために
議論するために
著者について  | 
|  | Dan Jemiolo は、ノースカロライナ州リサーチ・トライアングル・パークにある IBM Autonomic Computing チームの Advisory Software Engineer です。彼は Apache Muse 2.0 の設計および開発を指揮し、現在も引き続きこのプロジェクトに取り組んでいます。また、Dan は WS-RF TC に WS-ResourceMetadata 仕様のエディターとして参加しており、Web サービス標準の採用を促進する IBM の戦略に携わっています。彼はわずか 2 年前に、Rensselaer Polytechnic Institute で Computer Science を専攻し理学修士の学位を取得した後、IBM に入社しました。 |
記事の評価
|