水曜日 9 27, 2006
水曜日 9 27, 2006
トム・デマルコ本の2冊目を読みました。本書の主題は「実際のところ、ソフトウェア開発上の問題の多くは、技術的というより社会学的なものである」であり、全ての章に渡って、人間同士の関係のあり方がプロジェクトの成功に影響を与え得ることを説いています。内容的には多くの部分が「デッドライン」と通ずるものがあります。
オフィス環境(騒音、電話、広さなど)、残業時間、チームの結束、達成感、満足感がソフトウェアの生産性と品質に与える影響に関する考察は、PMというロールを担う人だけでなく、組織の管理職の立場となる人にも考えさせられる内容となっています。
ソフトウェア開発の現場では、諸刃の剣と考えられる開発プロセスの標準化に関しても、役に立たない作業規定やドキュメント、変化に対する抵抗などが作業のやる気をそぐことになり、生産性と品質を高めることを目的としたはずなのに逆に悪い方向に向かうことがあり得ることに注意しなければいけません。
29章にも述べられていますが、「プロセス改善はいいことだけれど、(押し付けられた)プロセス改善プログラムはよくないか、少なくともよくないことが多い」ということです。プロセス改善は結束したチームの内部から自然発生的に起こる状態が理想的なプロジェクトであると再認識しました。
金曜日 9 08, 2006
EJB 3.0仕様は、EJB 2.xとの相互運用性に配慮して注意深く仕様化されました。EJB 3.0準拠のコンテナはEJB 2.xとEJB 3.0との関係において上位互換と下位互換の両方を維持しています。具体的には以下のことが実現できます。
EJB 2.xとEJB 3.0のインターオペラビリティが確保されているということは非常に重要です。アプリケーション開発において、既存のEJB 2.xモジュールの資産が何らかの理由でEJB 3.0形式に作り直すことができなくても、Java EE 5の採用を断念する必要はありません。新たに機能拡張する部分だけEJB 3.0で開発し、既存のEJB 2.x資産と連係するように設計することができます。
もちろん、既存のEJBモジュールも3.0ベースで作り直した方が全体の構成がシンプルにできるのは確かですが、開発工数との兼ね合いからそうもいかない場合があると思います。ただし、EJB 2.x/3.0混合システムの実現は、従来のEJB 2.xの複雑さに伴う痛みを伴いますので、必ずしも既存の資産を流用した分だけ、開発工数が相殺できるわけではありません。全てをEJB 3.0に書き換えるか、EJB 2.x/3.0混合システムとするかは、よく検討して判断して下さい。
以下では、EJB 2.x/3.0連係の具体例を紹介します。
EJB 3.0モジュール(あるいは、Java EE 5仕様に基づくWARモジュールまたはクライアント・モジュール)からEJB 2.xを呼び出す方法は比較的簡単です。アノーテーション@EJBはEJB3参照だけでなく、EJB 2.xのホーム・インタフェースをインジェクションすることができます。もし、既存のEJB 2.xモジュールを連係するEJB 3.0モジュールと同じSJS AppServer 9 (glassfish)にデプロイすることが可能であれば、EJB 3.0からEJB 2.xへのメソッド呼出しは以下のように非常にシンプルです。
package com.example.modern;
import javax.ejb.Stateless;
import javax.ejb.Remote;
/**
* EJB 3.0仕様のセッション・ビーン
*/
@Stateless
@Remote(Modern.class)
public class ModernBean implements Modern {
@EJB RegacyRemoteHome home; // EJB 2.xのホームをインジェクション
public String sayHelloToEJB_2_x(String name) {
try {
// EJB 2.x参照の取得
RegacyRemote bean = home.create();
return bean.sayHello(name);
} catch (Exception e) {
....
}
}
}
glassfishでは、EJB 2.xモジュールにおけるデフォルトのJNDI物理名はリモート・ホーム・インタフェース名になります。そのため、EJB 2.xモジュール内のMETA-INF/sun-ejb-jar.xmlを削除して、このデフォルトルールに従うようにすれば、上記のように@EJBにパラメータを設定する必要はありません。
もし、EJB 2.xモジュール内のMETA-INF/sun-ejb-jar.xmlでJNDI物理名を変更しているのであれば、EJB 3.0モジュール側では以下のいずれかの方法で参照するEJBのJNDI物理名を明示します。
@EJB(mappedName="example/RegacyBean") RegacyRemoteHome home;
<ejb-ref>
<ejb-ref-name>com.example.modern.ModernBean/home</ejb-ref-name>
<ejb-ref-type>Session</ejb-ref-type>
<home>com.example.regacy.RegacyRemoteHome</home>
<remote>com.example.regacy.RegacyRemote</remote>
<mapped-name>example/RegacyBean</mapped-name>
</ejb-ref>
<ejb-ref>
<ejb-ref-name>com.example.modern.ModernBean/home</ejb-ref-name>
<jndi-name>example/RegacyBean</jndi-name>
</ejb-ref>
なお、(1)と(2)の方法はAppServerのベンダによってはサポートされない可能性があることに注意して下さい。また、(3)の方法はAppServerのベンダによって設定方法が異なることに注意して下さい。
場合によっては、何らかの事情でEJB 2.xモジュールをJava EE 5コンテナに移すことができない場合があると思います。例えば、EJB 2.xモジュールは従来のSJS AppServer 8で動かし、EJB 3.0モジュールはSJS AppServer 9(glassfish)で動作させ、それらを連係したい場合があります。この場合は、参照するEJBのJNDI物理名にcorbaname:iiop:host:port#global-nameの形式で指定することで、適切にEJB参照を取得することができます。ここでhostはJ2EE 1.4サーバ(ex. SJS AppServer 8)が動作しているホスト名またはIPアドレスで、portはJ2EE 1.4サーバのORBポート番号です。以下は、@EJB.mappedName要素にcorbaname形式のJNDI名を設定した場合の例です。
@EJB(mappedName="corbaname:iiop:host:port#example/RegacyBean")
RegacyRemoteHome home;
上記とは逆に、EJB 2.xモジュール(あるいは、J2EE 1.4仕様に基づくWARモジュールまたはクライアント・モジュール)からEJB 3.0のメソッドを呼び出すこともできます。この場合、EJB 2.xモジュールが連係するEJB 3.0モジュールと同じglassfishサーバにデプロイできるのであれば、呼び出すEJB 3.0モジュールのJNDI物理名を指定してJNDIルックアップを行なえば、そのEJB 3.0のビジネス・インタフェースを直接取得することができます([1])。
package com.example.regacy;
import com.example.modern.Modern;
import javax.ejb.SessionBean;
import javax.naming.InitialContext;
import javax.naming.NamingException;
/**
* EJB 2.x仕様のセッション・ビーン
*/
public class RegacyBean implements SessionBean {
:
public String sayHelloToEJB_3_0(String name) {
try {
InitialContext ctx = new InitialContext();
// 物理名によるEJB3ビジネス・インタフェースの取得
Modern bean = (Modern)ctx.lookup("com.example.modern.Modern");
return bean.sayHello(name);
} catch (NamingException e) {
...
}
}
}
しかし、この方法は2つの点において好ましくありません。1つはJNDI物理名を明示的に使用しているため、ポータビリティがないということです。物理名の代わりにjava:comp/envで始まる環境コンテキスト名を用いることもできますが、この場合は<ejb-ref>要素で<home>要素を省略できるEJB 3.0のスキーマに基づいたejb-jar.xmlに変更できることが条件になります。2つ目は、上記の方法は、InitialContextからEJBのビジネス・インタフェースが直接取得できるJava EE 5コンテナの機能に頼っているため、EJB 2.xモジュールをJ2EE 1.4サーバで動作させなければならない場合には適用できないためです。
クライアント側がJ2EE 1.4 APIのみを使用し、J2EE 1.4環境からEJB 3.0モジュールにアクセス可能にするためには、EJB 3.0のビーンをEJB 3.0/2.xハイブリッド形式で作成することです。そのためには、従来のEJB 2.x仕様に基づくホーム・インタフェースとEJBインタフェースを別途用意することになります。以下の図にハイブリッド形式のセッション・ビーンの構成を示します。
EJB 2.x向けに追加で用意するホーム・インタフェースとリモート・インタフェースは、純粋にEJB 2.xのスペックに従ったものです。以下にそれらのサンプル・コードを示します。
// ModernRemoteHome.java:EJB 2.x用リモート・ホーム・インタフェース
package com.example.modern;
import java.rmi.RemoteException;
import javax.ejb.CreateException;
import javax.ejb.EJBHome;
public interface ModernRemoteHome extends EJBHome {
ModernRemote create() throws CreateException, RemoteException;
}
// ModernRemote.java:EJB 2.x用リモート・インタフェース
package com.example.modern;
import java.rmi.RemoteException;
import javax.ejb.EJBObject;
public interface ModernRemote extends EJBObject {
String sayHello(String name) throws RemoteException;
}
EJB 3.0のビーン本体側では、アノーテーション@RemoteHome(ローカルの場合は@LocalHome)を用いて、ホーム・インタフェースとの関連づけを宣言します。
package com.example.modern;
import javax.ejb.Stateless;
import javax.ejb.Remote;
import javax.ejb.RemoteHome;
/**
* EJB 3.0/2.xハイブリッド形式のセッション・ビーン
*/
@Stateless(mappedName="example/ModernBean")
@Remote(Modern.class) // EJB 3.0用ビジネス・インタフェース
@RemoteHome(ModernRemoteHome.class) // EJB 2.x用ホーム・インタフェース
public class ModernBean implements Modern {
public String sayHello(String name) {
return "Hello, " + name +"! I'm an EJB3.";
}
}
なお、glassfishでは、EJBに@RemoteHomeを付与するとデフォルトのJNDI物理名が付与されなくなるようなので、EJBに付与すべきJNDI物理名を明示しなければなりません。上記では@Stateless.mappedName要素で明示的にJNDI物理名を指定しています。以上の作業により、その対象のEJBコンポーネントはJava EE 5環境からもJ2EE 1.4環境からも呼び出すことができるようになります。
上記のようにして作成された、EJB 3.0/2.xハイブリッド形式のセッション・ビーンは、J2EE 1.4環境のモジュールから従来のクラシカルな方法でEJB参照を取得することができます。
public String sayHelloToEJB_3_0(String name) {
try {
// J2EE 1.4環境からのEJB参照の取得
InitialContext ctx = new InitialContext();
Object ref = ctx.lookup("java:comp/env/ejb/ModernBean");
ModernRemoteHome home = (ModernRemoteHome)
PortableRemoteObject.narrow(ref, ModernRemoteHome.class);
ModernRemote bean = home.create();
return bean.sayHello(name);
} catch (Exception e) {
...
}
}
上記の例ではアロケートするEJBのJNDI名に環境コンテキスト名を用いているため、J2EE 1.4標準のDDファイル(ejb-jar.xmlなど)に<ejb-ref>要素の定義と、ベンダ独自DDファイル(sun-ejb-jar.xmlなど)に参照するEJBの環境コンテキスト名とJNDI物理名のマッピング定義も必要になります。もし、J2EE 1.4サーバとJava EE 5サーバが物理的に別れているなら、先ほどと同じように参照するEJBのJNDI物理名にはcorbanameで始まるURI形式のアドレスを指定します。
<ejb-ref>
<ejb-ref-name>ejb/ModernBean</ejb-ref-name>
<jndi-name>corbaname:iiop:host:port#example/ModernBean</jndi-name>
</ejb-ref>
以上のように、EJB 3.0を含むJava EE 5環境から既存のEJB 2.xモジュールを利用するのは比較的用意ですが、逆にJ2EE 1.4環境からEJB 3.0モジュールを利用可能にするのはかなり厄介な作業になります。
[1] JBoss Seamはまさにこの方法を使っています。現在のJBoss 4.0.4サーバはJ2EE 1.4仕様であり、EJBコンテナのみEJB 3.0仕様のアドインを行なうことによってSeamを動作可能にしています。しかし、WebコンテナはServlet 2.4仕様のままであるため、Web層のSeamランタイムはJNDI物理名を使ってセッション・ビーンのビジネス・インタフェース参照を内部でアロケートしています。
同僚の勧めで読み始めました。プロジェクト管理の指南書というよりは、普通に小説として楽しめます。
主人公のウエブスター・トムキンスは転職講習会で謎の女性ラークサー・フーリハンに拉致され、モロビアの国家的ソフトウェア開発プロジェクトの管理者となります。そこで直面する様々な問題を解決しながら、ウエブスターは様々な発見し、日記にそれらを綴っていきます。以下は、その中の一つです。
トムキンスの日記より。
病んだ政治(再び)