ObjectSquare [2000 年 12 月号]

[レポート]




梅澤 真史のOOPSLA’2000レポート



1.はじめに

始めましてUmejavaです。動的言語が好きな野望の人です。
この度OOPSLA’2000に行ってきましたので、あれこれレポートしたいと思います。
こんな記事を書く暇があったらHappySqueaking!!を書け!と言われそうですが、それはそれ。会社の施策ですから、お許しください。

さて、今年のOOPSLA、ミネソタ州は、Minneapolisで行われました。10/15-19の5日間です。
私達(hirasawaさんとペアでした)は、前日から米国に入り、明日からのカンファレンスについて綿密に計画を練ることにしました。

まず、カンファレンスで寝てしまわないように時差を直すことが非常に重要でしたので、軽く観光にいってきました。(^^;
Minneapolis といえばSt. Paulの存在を無視するわけにはいきません。この2都市はTwin City(双子都市)として昔から発展してきたのです。伝統を重んじるSt. Paulに対し、多少革新的なMinneapolis。双方の対比が面白く、実は行く前から個人的興味がありました。

OOPSLAが行われるのはMinneapolisのほうで、5日間は滞在し続けることになるため、観光はSt Paulを重視しました。といっても基本的に観光地ではないので、半日もあれば十分です。
通常の観光スポット(St. Paul大聖堂など)はあっという間に見終わり、White Bear Lake(ホワイトベア湖)に行くことにしました。
Fitzgeraldの珠玉の短編”Winter Dreams”の舞台となった湖です(小説ではBlack Bear Lakeなのですが)。
ついてみると、何の変哲もないただの湖でした。たまに犬の散歩をさせている人を見かけるくらいで、実にうらぶれていました。

White Bear Lake湖の写真

White Bear Lake

が、私にとっては一生ものの印象に残る風景となりました。小説に書かれた1920年代のきらびやかな描写がオーバーラップして来て、一人でニヤニヤしていました。皆さんも”Winter Dreams”読んでみましょう。今はWebで読めます
グサリと心に突き刺さる、いい感じの小説です。
Extreme なSEを目指すのならば、こういうものも必要ですよね。多分。




2.10/15日

さて、White Bear Lakeにも行ったことですし、これで私的な興味の大半は失われたのですが、そこは社会人。OOPSLAにもきちんと参加しています。

初日は、まだ慣らしといった感じで、メインのセッションである”Technical Program”が始まっていません。入門者向けの”Tutorial”と、濃厚な人向けの”Workshop”が開催されています。

私は”Improving Design and Source Code Modularity Using AspectJ”という、一日がかりのチュートリアルセッションに参加しました。

2.1 Using AspectJ

2.1.1 AspectJとは?

AspectJ とは「アスペクト指向プログラミング(AOP)」のJavaによる実装です。
アスペクトとは、その名の通りシステムの様相(aspect)です。
世の中にはオブジェクト指向プログラミングでは十分に対処しがたいシステムの様相というものが、確かに存在します。
具体的にはスレッド処理や、例外処理、ロギング、トランザクション管理などです。

こうしたものは、通常のオブジェクト指向で、分析、設計、実装したとしても、コードのあちこちに処理が分散してしまいがちです。
例外処理のtry/catchや、デバッグ用のSystem.out.println()、トランザクションのstart/commitがばら撒かれた「オブジェクト指向」によるコード、皆さんも何度かご覧になったことがあるのではないでしょうか。

もちろんデザインパターンなどを駆使すれば、これらをある程度一箇所にまとめあげていくことも可能です。しかしそうするためには大量の設計用のクラスが必要となり、非常に手間がかかることになります。OOAでの綺麗なオブジェクトモデルの骨格がOOD、OOPに向かうに従い、設計/実装クラスに埋もれて見えにくくなってしまうのは、ある程度仕方ないとしても、最小限にとどめたいものです。こうしたOOのモデリングとは直行して存在する、システムの並行性、永続性、分散性などに関わる部分を様相(aspect)として分離して、別個にプログラミングできるようにしてしまえば、より事態をシンプルに解決できるはずです。

アスペクト指向では、weaving(織り込み)という言葉を使います。主に論理的、機能的な観点からとらえたオブジェクト群と、非機能的な様相を表現するアスペクト群を、ちょうど繊維の縦糸と横糸を組み合わせるようにして、一つのシステムとしてビルドするという考えをとります。

図にすると以下のようなイメージとなります。

図1: Aspect Weaver概念図

図1: Aspect Weaver概念図

このような「織り込み」を行う環境をAspect Weaverといいます。AspectJはJava用のAspect Weaverの実装なのです。

AspectJ自体は1998年からあり、今回のOOPSLAで特別デビューというものではありません。ですが、2年前に比べてどう進化したのか、興味があったので参加してみることにしました。

2.1.2 AspectJクイックガイド

丸一日に渡るセッションを詳細に解説していくことは紙面の都合上無理があるので、かいつまんでおいしいところを説明します。

AspectJでは、Aspectが織り込まれることによるオブジェトの変化を”join point”に対するフックという形で実現します。”join point”とは、オブジェクトがメッセージを受け取って、対応するメソッドを起動し、そのメソッド内部でさらに別のオブジェクトに対するメッセージを送信するという流れの「継ぎ目」を表現したものです。

図にすると以下のようになります。

join pointのイメージ

図2: join pointのイメージ

こうした「継ぎ目」にさまざまな仕掛けをフックとしてweaving時に組み込んでいくことで、もとのソースコード(機能的要求実現に専念している)に一切の変更を加えずに、非機能的要求としてのロギングやトランザクション管理を実現していくことが可能になるのです。

例を示してみましょう。セッションで使われた例を更に単純化することとします。

以下のようなクラスがあったとします。オブジェクト指向の入門講座などでよく出てくる銀行口座クラスです。

class BankAccount {

      protected int balance = 0;

      public int deposit(int money){
            balance = balance + money;
            return balance;
      }

      public int withdraw(int money){
            balance = balance - money;
            return balance;
      }
}

デバッグ目的でこのクラスのdeposit()、withdraw()が呼ばれるたびに、標準出力に起動されるメソッド名を出力したいと考えたとします。

通常であれば以下のような形になるでしょう。

class BankAccount {
      protected int balance = 0;

      public int deposit(int money){
            System.out.println(“deposit”);
            balance = balance + money;
            return balance;
      }

      public int withdraw(int money){
            System.out.println(“withdraw”);
            balance = balance - money;
            return balance;
      }
}

この例ではメソッドがたかだか2つしかありませんので、コードの変更は少しで済みます。それほど手間にも感じられないでしょう。しかし実際のアプリケーションでは、もっと多くのメソッドが存在するはずです。それらの全てに対してこの”System.out.println(…)”といちいち書かねばならないとすると、多少面倒に思えてきます。また、デバッグが終わったならば、今度は変更した部分を、ログを出さないように元に戻していかなければなりません。

こうした「ログをとる」という本来の銀行業務とは無関係な要求に対し、アスペクト指向では、以下のような「ログをとるアスペクト」を定義することで対処します。
これによりBankAccountには一切の変更を加えず、純粋なドメインオブジェクトとして無傷に保つことができます。

aspect AccountLogging of eachobject(instanceof(BankAccount)){

      pointcut balanceChanges ():
            receptions (int deposit(int)) || receptions (int withdraw(int));

      after() : balanceChanges (){
            System.out.println("balance changed > " + thisJoinPoint.methodName );
      }
}

通常のJavaでは見慣れないキーワードが出てきます。実際のセッションではきちんとした説明がありましたが、ここでは個々の言語要素の詳細に立ち入るのは避け、かいつまんで見ていくことにします。

pointcut”とは、join pointの選択をするために定義されるものです。
この例では、「deposit()またはwithdraw()を受け取ったとき」という条件を指定し、それに合致するjoin point群をbalanceChanges()という名前で定義しています。

after”は、balanceChanges()というpointcutに対するアクションの規定です。

これによりdeposit()、withdraw()メソッドが起動された後で、内部に書かれたコードが実行されることになります。

他にも”before”などを指定することもできます。これらのアクションはadviceと呼ばれます。

thisJoinPoint”は、現在実行されているjoin pointのコンテキスト情報を取り出すための特殊な変数です。ここから起動されているメソッド名や、パラメータなどの情報を得ることができます。

pointcutやadvice群を要素として持つ親がaspectということになります。この例では示されませんが、aspectは通常のクラスのように属性や操作を定義したり、継承させていくことも可能です。

AspectJでは、ajcというAspect Weaverが用意されています。
これを使い、BankAccount.javaとAccountLogging.javaをコンパイルするとweavingが行われます。

Weaving後にできたBankAccountクラスは通常のBankAccountクラスと全く同じように使うことができます。

      public static void main(String[] args){
            BankAccount acc = new BankAccount();
            acc.deposit(100);
            acc.withdraw(20);
      }

これを実行すると、標準出力には以下のようなロギングが行われます。

balance changed > deposit
balance changed > withdraw

pointcutに、複数のadviceをつけることも可能です。例えば、adviceとして

before(BankAccount acc): instanceof(acc) && balanceChanges() {
            System.out.println(thisJoinPoint.methodName );
            System.out.println(acc.balance);
}
after(BankAccount acc): instanceof(acc) && balanceChanges() {
            System.out.println(acc.balance);
}

と書けば、以下のように、起動前と起動後でのbalanceの値が表示されることになります。

deposit
0
100
withdraw
100
80

aspectという言語要素がなければ、これらの処理は全てドメインオブジェクトであるBankAccountに書かれることになってしまいます。起動前と起動後でのbalanceの値表示となると…通常のやり方ではちょっと面倒に思えてきますよね。

この例ではLoggingのみですが、そのほか不正なクライアントからの起動でないか、セキュリティのチェックを行わせるaspectや、マルチスレッドで問題なく動作するよう排他制御を行うaspectなどを、BankAccountにかぶせていくといった応用が考えられます。

2.1.3 AspectJへのコメント

以上のような感じでセッションはつつがなく続いていきました。
以前のAspectJでは、アスペクト記述用の特別な言語を使うといった向きもあったのですが(例えばスレッド制御記述言語COOLなど)、今回見たものでは、もともとのJavaにほとんど変更を加えずに、aspectを記述できるようになっていたところが特徴だったと思います。ユーザにとっては新たな言語を覚えるよりもAOPの世界に入っていきやすくなっているところがメリットでしょう。反面、特定のアスペクトの記述に関しては、Javaよりももっと効率よく書ける、そのアスペクト記述に特化した言語というものもあっていいはずで、ここは悩みどころだと思いました。

また、AspectJではAspectの付与、削除は全てリンク時に行われます。実行時にAspectを入れ替えたりといったことが現状ではできません。動的OO言語が好きな私としては、実行時にログ機能をつけはずしできなければ、まだまだ(甘い)、と感じてしまいました。
セッションの発表者はGregor Kiczalesさん。この方は究極の動的OO言語、CLOSの開発者として有名ですので、将来的には何かやってくれるかもしれません。期待しています。

2.1.4 OOPからAOP?

さて、AspectJセッションの紹介をしてきました。チュートリアルとは言えなかなか内容は充実しており、有意義だったと思います。AspectJに代表されるAOP、そろそろブレイクの時期が近づいてきている予感がします。

アスペクト指向は、オブジェクト指向に取って代わるものではありません。ナイーブなオブジェクト指向では捕らえ難かったシステムの様相を、デザインパターンなどでなんとか対処するというよりは、言語レベルでそのまま表現してしまおうというアプローチです。いわばオブジェクト指向の弱かった部分を補い、発展させていくものと考えることができます。

実際アスペクト指向の考え方は、はっきりと大上段に「アスペクト指向」とは言われないものの、オブジェクト指向による開発に徐々に浸透しつつあります。
例えば古典的なものとしては、CORBAがあります。CORBAでは分散オブジェクトのインターフェース記述用の言語(IDL)と実装用の言語(C++、Java、Smalltalkなど)を分離する立場をとっています。
IDLコンパイラは、Weaverと呼ぶにはちょっと機能が貧弱ですが、これも、CORBA Component Modelなどで定義されているように、コンポーネントの実装コードまでも生成するようになってくると、よりWeaverに近づいてきます。

また、EJBの世界では、アプリケーション配置(deployment)に関する情報を、Javaコードとは独立したdeployment descriptorとしてXMLで記述します。
EJBの開発環境により、JavaとXMLのWeavingが行われ、トランザクション管理やセキュリティ方針などが埋め込まれた適切な実装コードが出来上がり、動きだすというわけです。

このように考えると、AOP-likeな環境はすでに一般に広まっていると言え、私達は特別に意識しない形でアスペクト指向に入っていくのかもしれません。

しかし非OO言語でOOP-likeな実装をするのが大変なように、単なるOO言語でAOPをしていくのもそれなりに手間がかかってしまうものです。

AspectJのようにAOPを明示的にサポートできる言語がもっと出てくれば、アスペクト指向の考えもより広がりを見せていくのではないでしょうか。(さらに言えばAspectJも所詮はPure JavaによるJavaのAOP拡張にすぎませんから、「最初からAOP対応」という言語が出てくると面白いと思います。)
OOPからボトムアップ的にOOA/Dが生まれてきたように、AOP用言語から、AOA/Dが生まれてくるかもしれません。

21世紀にはAOA/D/Pと、トータルに開発をサポートできる時代が来るのでしょうか?
私ではなんともわかりませんが、そこは皆さんの感覚で掴み取っていただくとして、まずはAOPに触れてみることをお勧めします。
AspectJ、ここからダウンロードできます




3 終わりに

すみません。時間切れです。結局初日のみのレポートになってしまいました。残る4日分は、またの機会ということで。ペアプログラミングのパートナーからお呼びがかかっていますので。これにて失礼します。

次回をお楽しみに。


© 2000 OGIS-RI Co., Ltd.
HOME HOME TOP オブジェクトの広場 TOP