大人数開発を支える技術

変態アドベントカレンダーに登録してみたので書きます。

変態アドベントカレンダー

昨日の記事は[twitter:@Kuchitama]さんの「ジャッジメントですの変換を作ってみる」ですの。


私は全然変態ではないので、そもそも変態ってなんなんだろうーと思って辞書を引いてみました。

変態の意味
http://dic.yahoo.co.jp/dsearch/0/0na/16683500/

今回は2の意味がいいのかな。
2 普通の状態と違うこと。異常な、または病的な状態。

ということで、開発をしているとたまに見かける異常な大人数開発でJavaEEがどのように役に立つのかを3つほど語りたいと思います。

想定

以下の様なプロジェクトを想定しています。

いやー、聴くのも嫌になるぐらい異常ですね。
でもよくある気がするのはなぜだろう!

大人数開発でありがちな3つの状況

結合テストしようと思ったらDB定義がずれていた!

画面の方は会社Aが作っていてバッチは会社Bが作っていたという状況。

A社とB社に渡していたDB定義が間違っていて結合しようとしたけれども、動かなかった!
しかも設計書が間違っていたことを盾に取られて修正まで時間がかかる!
しかし今日中に結合テスト終わらせないと納期に間に合わない!
自分でアプリを直してしまいたいけれども責任範囲という言葉で直せない!

ありがちなこんな状況ですが、JavaEEで作っていたら何とか出来ます。

JavaEEでは通常DBのマッピングJPAを使い、エンティティに対してアノテーションを使ってDBへのマッピングを行います。

Entityの例

@Entity
@Table(name = "projects")
@NamedQueries({@NamedQuery(name = "project.getAll", query = "select p from Project as p"),
        @NamedQuery(name = "project.getAllOpen", query = "select p from Project as p where p.endDate is null"),
        @NamedQuery(name = "project.countByName", query = "select count(p) from Project as p where p.name = :name and not(p = :currentProject)"),
        @NamedQuery(name = "project.new.countByName", query = "select count(p) from Project as p where p.name = :name")})
public class Project extends AbstractEntity implements Serializable {
    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator="PROJECT_ID")
    @SequenceGenerator(name="PROJECT_ID")
    private Long id;
    @Column(nullable = false, unique = true)
    @NotNull
    @Size(min=0, max=8)
    private String name;
・
・
・

こちらのほうが便利なのですが、実は旧来のようにXMLによるマッピングを行うこともできます。

XML定義の例(orm.xml)

<?xml version="1.0" encoding="UTF-8" ?>
<entity-mappings xmlns="http://java.sun.com/xml/ns/persistence/orm"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence/orm ;  
http://java.sun.com/xml/ns/persistence/orm_1_0.xsd"
version="1.0">
<description>My First JPA XML Application</description>
<package>entity</package>
<entity class="entity.Employee" name="Employee">       
<table name="PROJECT"/>
<attributes>
<id name="id">
<generated-value strategy="TABLE"/>
</id>
<basic name="name">
<column name="EMP_NAME" length="20"/>
</basic>
<basic name="column">
</basic>
</attributes>
</entity>
</entity-mappings>

かつ、こちらでエンティティにアノテーションで定義したものの上書きが可能です。
なので、A社が作ったものだから自分では直せないといった場合もA社の責任範囲に踏み込む必要がなくアプリケーションの動作を修正することが可能になります。

これで修正を待たなくても結合テストができますね!

ログ出力忘れてた!

業務処理が呼ばれるたびにログ出力をコーディングするように規約を定めていたのに、ログ出力がされていなかった!
協力会社さんが作っていたので自分じゃ触れないけれども結合テストは今日中に終わらせないといけない!
もう帰ってしまってすぐには直せないよ!

こんな状態でもどうにかできるかもしれません。
JavaEEでは業務処理は通常EJBに記載します。

EJBの例

@javax.ejb.Stateless
public class SomeService
{
        public ReturnObject doSomething(Argment arg)
        {
                //業務処理
        }

JavaEEではInterceptorという機能があって、EJBが呼び出される前処理、後処理を画一的(もしくは個別)に行うことができます。
いわゆるAOPと呼ばれているもので、昔はAspectJとか使ってやっていたことですね。
JavaEE5から標準機能に取り込まれました。

Interceptorの例

public class SomeInterceptor
{
        @Inject
        Logger logger;

        @AroundInvoke
        public Object log(InvocationContext ctx) throws Exception
        {
                logger.log(toLogFormat(ctx));
                return ctx.proceed(); //EJBの処理を呼び出す
        }
・
・
・

こちらに関してもアノテーションで呼び出すことも出来るのですが、責任範囲の問題があるのでXMLで記載して協力会社さんが作ったソースには手を加えません。

XML定義の例(ejb-jar.xml)

<assembly-descriptor>
<interceptor-binding>
<ejb-name>*</ejb-name>
<interceptor-class>megascus.SomeInterceptor</interceptor-class>
</interceptor-binding>
・
・
・
</assembly-descriptor>

これで修正を待たなくても(以下略)

まあ、最初から業務処理の中にロギングとか個別で書かせるなという意見もあります。
アーキテクト仕事しろ。

そもそも品質悪すぎて使えないよ!

協力会社さんが作ってくれたけれども(以下自粛)

それでも修正できないといった場合はよくあります。
その場合でも、責任範囲を超えることなく(以下略)

JavaEE5でも出来る方法として一番簡単なのは先と同様にInterceptorを使用する方法でしょうか。

Interceptorの例

public class SomeInterceptor
{
        @Inject
        Logger logger;

        @AroundInvoke
        public Object log(InvocationContext ctx) throws Exception
        {
                logger.log(toLogFormat(ctx));
                //return ctx.proceed(); //EJBの処理を呼び出さないようにコメントアウト
                return doProcess();
        }
・
・
・

これで協力会社さんが作った処理をすべて呼び出さずに自分で作った処理で動かすことができます。
元のソースには一行も変更を加えていません。

これはEJBの例ですが、JavaEE6だとCDIという機能を使っている場合にも(別の名前ですが)同じように前処理、後処理を入れることができます。
もうちょっと簡単な方法もありますが、今回はこんなのでもいいでしょう。

これで修(以下略)

まとめ

いかがでしたでしょうか。JavaEEのパワフルな機能を使えば、多人数開発でも開発を成功させる可能性が増やせます。
色々な所でコンテナが間に入ってくれているのでいざとなった時に自由に結合を変えられるのがミソですね。

なお、これらの機能は正しく使うと保守をしやすくすることができますが、今回のような例だと動いたとしても改修できないシステムとなりますのでご注意下さい。

このような下策が必要な開発現場が一つでも減ってくれるといいですね!

Beginning Java EE 6~GlassFish 3で始めるエンタープライズJava (Programmer's SELECTION)

Beginning Java EE 6~GlassFish 3で始めるエンタープライズJava (Programmer's SELECTION)

Enterprise JavaBeans 3.1 第6版

Enterprise JavaBeans 3.1 第6版