プログラムスライスを用いた アスペクト指向プログラムのデバッグ支援環境 石尾 隆,楠本 真二,井上 克郎 大阪大学大学院情報科学研究科 {t-isio,kusumoto,inoue}@ist.osaka-u.ac.jp
発表の概要 アスペクト指向プログラミング アスペクト指向プログラムの開発支援 ツールの実装 評価実験 今後の課題 オブジェクト指向プログラミング アスペクト指向の特徴 アスペクト指向の問題点 アスペクト指向プログラムの開発支援 アスペクト干渉の検出 プログラムスライシングの適用 ツールの実装 評価実験 今後の課題 この発表では,まず最初にアスペクト指向プログラミングの特徴と,その問題点について説明します.次に,この問題点に対して,有効な開発支援を行うためにアスペクト干渉の検出と,プログラム解析手法のひとつであるプログラムスライシングの適用について説明します.最後に,ツールの実装と評価実験,今後の課題について述べます.
オブジェクト指向モデル オブジェクトの相互通信でシステムをモデル化 横断要素: 複数のオブジェクトが関わる機能 システムの機能をオブジェクトが分担して担当 横断要素: 複数のオブジェクトが関わる機能 コードが分散,一貫性の維持が困難 →保守性の悪化 例:エラー処理 Database でエラーが発生したらユーザの指示に従う GUI, Database にエラー処理コードが分散 それではまず,アスペクト指向プログラミングについて説明する前準備として,オブジェクト指向プログラミングの特徴について,簡単に触れたいと思います.オブジェクト指向プログラミングでは,オブジェクトの相互通信という形でシステムをモデル化します.オブジェクトがシステムの機能を分担しますが,横断要素と呼ばれる複数のオブジェクトが関わる機能は,うまく取り扱うことができません.処理に参加するすべてのオブジェクトにコードが分散するため,一貫性の維持が難しく,保守性を悪化させる要因となっています. 例として,ここに簡単なオブジェクトのモデルを挙げています.Databaseでエラーが起きたら,GUIオブジェクトがユーザの指示を仰ぐという横断要素が存在しています. ユーザの入力を通知 Database GUI エラーを通知
アスペクト指向モデル アスペクト: 横断要素のモジュール化 アスペクト = (動作時点, 処理) の集合で定義 動作時点は,メッセージ送受信や例外の発生など 明示的な呼び出しが不要 Database GUI 2. Database の例外発生に 対応して,GUI を使って ユーザに通知 1. GUI の生成に応じて 参照を記憶 3. 結果を Databaseに反映 これに対して,アスペクト指向プログラミングでは,アスペクトという横断要素をモジュール化するための新しいモジュール単位を導入します. アスペクトは,メッセージ送受信や例外の発生といった,プログラム実行中のイベントに連動して動作する処理として記述されます.図に示しているエラー通知アスペクトは,Databaseでのエラー発生に連動し,ユーザへの通知を行い,ユーザからの指示をDatabaseに伝達します. 手続き呼び出し処理を呼び出す側に書くのではなく,動作する条件が呼び出される側に書いてある,という形式になります. エラー処理アスペクト
アスペクト指向の利点と問題点 利点:モジュール性の向上 問題点:プログラムの複雑化 保守性の向上 再利用性の向上 横断要素がアスペクトにまとまっているので,変更が容易 再利用性の向上 モジュール間の相互依存性の解消 横断要素とオブジェクトの独立した再利用 問題点:プログラムの複雑化 オブジェクトを見ただけでは動作がわからない アスペクトの干渉 アスペクトの動作順序で実行結果が変わる アスペクトの動作中に別のアスペクトが動作する アスペクト指向における利点は,モジュール性の向上という形で現れます. モジュール性の向上は,保守性と再利用性の向上につながります.横断要素に関する要求や仕様が変更された場合に,以前は関連したすべてのオブジェクトを変更していたのに対し,ひとつのアスペクトだけを変更すればよいことになります. また,横断要素を分離することで,オブジェクト間の相互依存性を抑えることができるほか,横断要素とオブジェクトをそれぞれ独立して再利用することができます. アスペクトの利点については,様々な報告がなされていますが,それと同時に,プログラムの複雑化が新たな問題となっています. アスペクトはオブジェクトから分離して記述されるため,オブジェクトを見ただけでは動作が分からない,という問題があります.また,複数のアスペクトが同時に実行される場合にその動作順序によって結果が変わったり,アスペクトの動作中に別のアスペクトが動作するなど,アスペクトの干渉と呼ばれる問題が発生します.これらは,いずれも,検出しにくい欠陥の原因となる恐れがあります.
本研究の目的 アスペクトを組み込んだプログラムに対する依存関係解析結果を用いた開発支援手法を提案する. 対象: AspectJ アスペクト干渉の検出 アスペクトを組み込む時点での支援 プログラムスライスの抽出 アスペクトを組み込んだ後のデバッグ支援 対象: AspectJ そこで,本研究では,アスペクトを組み込んだプログラムに対する,依存関係解析を用いた開発支援手法の提案を行います. アスペクトを組み込む際に発生する干渉の検出と,アスペクトを実際に組み込んだ後の依存関係解析によるデバッグ支援とを組み合わせて用います. 対象としては,最も使われている処理系であることから,AspectJを選びました.
アスペクト干渉の検出 アスペクトを組み込む段階での情報の提示 Aspect を含めた Call Graph の利用 頂点:クラス,アスペクトに含まれるメソッド(手続き)単位 辺:メソッドの呼び出し,アスペクトの呼び出し (呼び出し関係はソースコードから解析) ある時点でアスペクトが作動する=アスペクトを呼び出している 「Call Graphでアスペクトの頂点に到達可能」ならば「アスペクトの影響を受ける」 まず,アスペクトを組み込む段階で,アスペクトの干渉についての基本的な情報を開発者に提示します. アスペクトの干渉を検出するために,アスペクトを含めたCall Graphを作成します.具体的には,クラスやアスペクトに含まれたメソッドを頂点とし,メソッドの呼び出し,アスペクトの動作を辺とします.ある時点でアスペクトが動作する,ということを,アスペクトに対する一種のメソッド呼び出しとみなします.Call Graph上で,ある頂点から呼び出し辺を辿ってアスペクトの頂点に到達可能であれば,その頂点はアスペクトの影響を受けていると考えることができます.
Call Graph 例 凡例 Aspect Class 無限ループ call このグラフでは,ここにループが存在しており,実行すると無限ループに陥ってしまう可能性を示しています. プログラムの規模が大きくなるに従ってグラフのサイズも大きくなっていきますので,実際に開発者に提示するには,このグラフを直接与えるのではなく,ループ部分に対するマーキングや警告メッセージの出力など,開発者により理解しやすい形式での出力を行うことになります. Class call
プログラムスライシングの適用 プログラムスライシングとは プログラム解析手法のひとつ 開発者が注目する必要があるコードのみを抽出し,提示する技術 元々は手続き的プログラム用に開発され,オブジェクト指向プログラムに対して拡張されている 依存関係が複雑になるアスペクト指向プログラムに対して有効性が期待される 以上が,アスペクトを組み込む段階での情報の提示でした.Call Graphを用いることで,少なくとも無限ループに陥るような重大な干渉は除去されており,プログラムを実行できるという状態になります. 今度は,実行結果が正しくない場合,その原因を調べるための支援を行います.ここではプログラムスライシングと呼ばれるプログラム解析手法を利用します.プログラムスライシングは,プログラムの中に含まれるデータや制御の依存関係を解析し,開発者が注目する必要があるコードのみを抽出,提示するという手法です. 元々は手続き的プログラムに対して提案されたものですが,オブジェクト指向プログラムに対しても既に拡張され,その有効性が確認されています.モジュール間の依存関係が複雑化するアスペクト指向プログラムでも,その効果が期待されるため,Call Graphの場合と同様の発想で,手法を拡張します.
プログラムスライスの定義 プログラムのある文sのある変数v(スライス基点<s,v>)の値に“影響”を与えうる文の集合 影響 = 代入-参照 関係, if 文など制御関係 プログラム文を頂点,依存関係を辺としたグラフ探索 プログラマが扱う必要があるコードを提示 デバッグ作業の効率化 1: a = 5; 2: b = a + a; 3: if (b > 0) { 4: c = a; 5: } 6: d = b; 1: a = 5; 2: b = a + a; 3: if (b > 0) { 4: c = a; 5: } 6: d = b; a a 基点< 6, b > b 制御 b プログラムスライスがどういうものか,例を示して説明します.プログラムスライスは,プログラム文の中のある変数をスライス基点とし,その値に影響を与える文の集合のことを言います.ここで言う影響とは,変数の代入・参照関係,if文やwhile文による制御関係のことです. ここにプログラムの断片を示していますが,1行目で代入された変数aが2行目で参照されているので,1行目から2行目に依存関係がある,ということになります.同様に,2行目から,3行目と6行目へ依存関係があります.また,4行目が実行されるかどうかは3行目の条件判定によって決定されることから, 3行目から4行目に依存関係がある,ということになります. ここで,6行目の変数 b に注目して,この変数に対するプログラムスライスを計算すると,右側に示したものになります.この計算は,プログラムの各文を頂点とし,依存関係を有効辺としたグラフにおいて,その依存辺を逆向きに辿っていく探索問題として考えることができます. 求められたプログラムスライスを見ることで,開発者は,その値がどのように決まったかを知ることができます.たとえばデバッグ作業中,ある時点で変数の値がおかしくなっていることに気付いたとすると,その変数を基点にスライスを計算することで,無関係なコードをあらかじめ取り除くことができ,作業を効率的に進めることができます.
スライス計算に必要な情報 データ依存関係 制御依存関係 メソッド呼び出し関係 目的をデバッグに限定 ローカル変数の 代入 → 参照 フィールド(メンバ変数)の 代入 → 参照 制御依存関係 実行制御文の条件節 → 制御される文 メソッド呼び出し関係 メソッド呼び出し文 → 呼び出されるメソッドの文 メソッド呼び出し文の実引数 → 呼び出されるメソッドの仮引数 アスペクトの連動位置 → 動作するアスペクト アスペクトの連動位置 → アスペクトが参照する実行時点情報 目的をデバッグに限定 実行が失敗するテストケースが特定されている状態を想定 動的(実行時)情報 が利用可能 オブジェクトの区別,動的束縛の解決によってコード量を減らす プログラムスライスの計算を行うためには,データと制御,そしてメソッド呼び出しに関する依存関係を解析する必要があります. データ依存関係は,変数それぞれについて,ある代入文から,そこで代入された値を参照する文への依存関係として定義します. 制御依存関係は,if や while などの実行制御文から制御される文への依存関係です. メソッド呼び出しは,呼び出し文から呼び出されるメソッドへの制御の流れと,引数によるデータの流れの,二つの依存関係が基本となっています.これにアスペクトが起動される時点から動作するアスペクトへ,という依存関係を追加します.これは,Call Graphのときと同じ発想です.また,多くのアスペクト指向言語処理系では,アスペクトは,どの時点で実行されたかという,実行時情報にアクセスすることができます.これは,引数として実行時点の情報が渡されているものと考えます. 目的をデバッグに限定するため,実行が失敗するようなテストケースが特定されている状態を想定します.この特定のテストケースの実行経過を監視し,その情報,たとえばオブジェクトの区別,動的束縛の解決を反映することで,扱うコード量を減少させることができます.静的情報のみの場合は,
動的情報収集の実装 アスペクトとして動的解析処理を記述する 1つのモジュールにカプセル化可能 実現および実行時コストの軽減 可読性・保守性の向上 実現および実行時コストの軽減 実用上十分な情報が収集可能 Java を対象とした場合は十分に有効† → AspectJ で書かれたプログラム用に拡張 このような実行時情報の収集を実現するために,本研究では,その情報収集処理自体も,アスペクトを用いて記述します.メソッド呼び出しなどに対応して行う処理は,アスペクトを用いて作成すると,実現に必要なコストが非常に安く済ませられるだけでなく,実行時のオーバーヘッドについても小さくすることができます.これについては,Javaを対象とした実験結果が既に得られていますので,これをAspectJ用に拡張したものを使用します. † 石尾隆, 楠本真二, 井上克郎: “アスペクト指向プログラミングの動的スライス計算への応用”, 情報処理学会論文誌,Vol.44, No.7 (2003).
スライスツールの実装 統合開発環境 Eclipse への統合 コンパイル時にソースコード情報を収集 実行時情報が存在すれば読み込んで利用 プラグイン形式で機能を追加できる 開発者がエディタ上でそのまま利用できる コンパイル時にソースコード情報を収集 静的依存情報の収集 Call Graphの作成,無限ループ等の指摘 実行時情報が存在すれば読み込んで利用 動的解析モジュールを付加して実行しておく必要あり 実行時情報がなければ静的情報だけでスライス計算 開発者から利用しやすくするという観点から,スライスツールを統合開発環境に組み込む形で実装を行いました.オープンソースの統合開発環境Eclipseが持つ,プラグインによる拡張機構を利用しています.Java,AspectJを対象としたソースコード入力支援プラグインなどが既に提供されており,それにスライス計算機能を上乗せする形式になっています. プラグインは,コンパイルの実行開始,終了や失敗,ソースファイルの保存など,重要なイベントの通知をフレームワークから受け取ることができます.そこで,実装したスライスツールでは,コンパイル終了時に静的な情報をすべて収集し,Call Graphを構築します. また,動的解析モジュールを組み込んで実行することで情報を生成し,その情報をスライス計算に使用することができます.実行時情報がなければ,静的情報だけでスライス計算を行います.
プロトタイプのスクリーンショット 3. スライス計算実行を指示 2. スライス基点をエディタ上で選択 4. スライス結果を エディタ上に出力 ツールのスクリーンショットはこのようになっています. プログラムをコンパイルすると,静的な情報が収集され,スライス計算が可能な状態になります.スライス基準をエディタ上で範囲選択し,ツールバーからスライス計算を指示すると,結果がエディタ上に,ここでは青い波線として表示されています. コンパイル時に静的情報収集
実験(1) ツールの適用 適用対象 実験内容 AspectJ サンプルコード 5種類 プログラムの実行時情報解析アスペクト 各サンプルコードのサイズは平均500行 実験内容 サンプルコードを実行し,その結果に対してプログラムスライスを計算 従来のツールを用いた依存関係の追跡との定性的比較 AJDE: どこでアスペクトが動作するかをマーカーで表示する 作成したツールの評価と,スライスが開発作業に与える影響の評価を行うために,2つの実験を行いました. ここでは,まず,ツールの適用実験について説明します. 適用対象は,インターネット上で公開されているAspectJのサンプルコード5種類と,プログラムの実行時情報を解析するために作ったアスペクトの合計6種類です.各サンプルコードのサイズは平均500行となっています. サンプルコードを実行し,その結果に対してプログラムスライスの計算を行い,その有効性に関する定性的な評価を行いました.比較対象として,AJDEという,Eclipseプラグインのひとつで,どこでアスペクトが動作するかをオブジェクト側のソースコードにマーカーで表示するツールを用いました.
評価 プログラムスライシングの有用性 アスペクトがもたらす複雑さの軽減 「依存関係がなくなる」コードの発見が可能 アスペクトが増えた分,考慮すべき依存関係は増加 ファイルをまたいだ依存関係:手作業の追跡はコスト大 「依存関係がなくなる」コードの発見が可能 アスペクトの動作によって,実行されなくなるような文が発見できる 実験に関する評価は,次のとおりです. まず,アスペクト指向プログラムでは,横断要素だけがアスペクトというモジュールに分離された分,考慮すべき依存関係の数自体は増加しています.特に,複数のファイルにまたがる依存関係が多いため,手作業での追跡作業はコストが高くなります. また,プログラムスライシングを用いることで,アスペクトの動作によって実行されなくなる,依存関係がなくなるコードを発見できることが示されました.
「依存関係がなくなる」コードの例 開発者が意識する依存関係 実際のスライス結果 void f1() { x = f2(); : } : } int f2() { return doSomething(); int f3() { return doSomething2(); aspect redirectMethodCall { int around(): call(f2) { return f3(); 実際のスライス結果 void f1() { x = f2(); : } int f2() { return doSomething(); int f3() { return doSomething2(); aspect redirectMethodCall { int around(): call(f2) { return f3(); 依存関係がなくなるコードの例を示します.ここでは,メソッドf1の中でメソッドf2が呼び出されていますが,下にアスペクトがひとつ定義されており,f2への呼び出しに対して動作することがわかります.一見すると,色をつけた四箇所に依存関係がある,と考えられますが,このアスペクトは本来のメソッド呼び出しを完全に置き換えるアスペクトなので,元のf2への呼び出しは消えてしまい,実際のスライス結果は右側に示したものになります.従来のAJDEでは,アスペクトがどこで動作するか,という情報は示せましたが,このような依存関係がなくなるコードを明確に示すことができませんでした. このような,開発者が誤解しやすい点をサポートできることが,プログラムスライシングの利点だと言えます. メソッド呼び出しを 置き換えるアスペクト
計算コスト 時間コスト 空間コスト 静的情報の収集=コンパイラが構築した意味解析木に対する1パス処理 動的情報の収集(実行時情報を付加した状態での対象プログラムの実行時間)=実行するプログラムとテストデータに依存,過去の実験では通常の実行に比べて最大で10倍程度 空間コスト アスペクトの種類によってコストに大きな差 多数のクラスを横断して動作するアスペクトは,メモリ消費量が非常に大きくなることがある 約10000行のコードに,実行時情報解析アスペクト(1000行)を追加した結果,必要メモリが20MBから100MB以上に増加 AspectJ が生成した意味解析木の肥大化による,解析コストの増大 動作回数が多い分,アドバイス呼び出しの頂点と辺の数が増加 ここで,プログラムスライス計算に必要なコストについて説明します. まず時間コストについてですが,プログラムスライスの計算では,実際のグラフ探索よりも,プログラムの依存関係をグラフ化するのに必要な時間が大きな問題となります.静的情報と動的情報の二つがありますが,静的情報については,コンパイラが構築した意味解析木に対する1パス処理として実装しているため,構文木のサイズ,ソースコードの量に比例するものとなっています. 動的情報の収集については,実行するプログラムに依存しますが,過去の実験では,通常の実行に比べて最大で10倍程度となっていたので,バグを明確にする小さいテストケースを特定できれば,実用的な範囲で抑えられると考えます. 空間コストについては,アスペクトの種類によって大きな差が出ることが分かりました.多数のクラスを横断して動作するアスペクトは,依存関係の量を大きく増加させます.このようなアスペクトについては,何らかの特別な扱いをしなければ,より大規模なソフトウェアに対する適用は難しい,ということが分かりました.
実験(2) 開発への影響の評価 大学院の授業での利用 実験の手順 大学院生(修士課程) 12名 授業で Java 使用経験あり,AspectJ は使用経験なし 開発環境: Eclipse + AspectJ plug-in 実験の手順 Eclipse についての解説 Eclipse を用いた Javaプログラムのデバッグ演習(事前課題1) AspectJ についての解説 Eclipse を用いた AspectJ プログラミング演習(事前課題2) Eclipse を用いた AspectJ プログラムのデバッグ(実験) さて,ここから,プログラムスライシングが,デバッグ作業へどのように影響を与えるか評価するための実験について説明します. 実験は,大学院の授業において,14名の大学院生を対象としました.学生は,全員が過去の授業でJavaを使用した経験があり,AspectJを使うのはこの実験が初めてです.開発環境にはEclipseを用いました. 実験は,次のような手順で行いました.まず,Eclipseについての解説を行い,小規模なJavaプログラムのデバッグ演習を行って開発環境に慣れてもらいました.次に,AspectJ を用いたプログラミングの方法について説明し,簡単なアスペクトを記述するプログラミング演習を行い,最後に,実験の課題を与えました.
対象プログラムの概要 AspectJ プログラムのデバッグ演習 対象: 式評価プログラム 入出力例: (+ 4 3 (* 2 7 ) (* 2 7) ) 35 一部のノードは共有されていることがある アスペクトの干渉によって正しい結果が出力できないプログラム クラス5つ(式構造クラス),アスペクト4つ,合計340行 式評価経過の文字列出力,計算結果の共有,グラフのループ検出,評価が終了したグラフの接続解除 学生の半数 6名に,プログラムスライスを追加資料として提供 時間の都合上,印刷物として提供 誤った出力結果を格納している変数をスライス基点として設定 4つのアスペクトのうち,2つは関与していないことが明示されている この実験では,小規模な,複数のアスペクトを含んだ AspectJ のプログラムを対象として,アスペクトの干渉によって出力結果が正しく計算されないという問題に関するデバッグ作業を行いました.プログラムスライスの有効性を評価するために,学生の半数の6名に,ツールの使用方法などを訓練する時間がなかったため,プログラムの出力データを格納している変数をスライス基点として計算したプログラムスライスの情報を,印刷物の形で提供しました.
提供したスライスの一部 既に計算済みの場合は 計算を省略する 計算が完全に終了した 時点で,フラグをクリア この計算省略機能が, public aspect CachingAspect { // member of this Aspect static private Set workers = new HashSet(); // add a member to Worker class private boolean Worker.isAlreadyCalculated = false; pointcut work_call() : call(void Worker.work()); pointcut first_work_call() : work_call() && !cflowbelow(work_call()); void around(): work_call() { Worker w = (Worker)thisJoinPoint.getTarget(); if (w.isAlreadyCalculated) return; else { proceed(); w.isAlreadyCalculated = true; workers.add(w); } // clear the flag when calculation process is finished after(): first_work_call() { for (Iterator it = workers.iterator(); it.hasNext(); ) { Worker w = (Worker)it.next(); w.isAlreadyCalculated = false; workers.clear(); 既に計算済みの場合は 計算を省略する この計算省略機能が, 計算経過の文字列出力も 飛ばすことがバグの原因 計算が完全に終了した 時点で,フラグをクリア 提供したプログラムスライスの一部だけですが,このようになっています. 太字になっている部分がスライスです.このスライスでは,プログラムの出力に関係ない部分が取り除かれています.ここでは,対象プログラムに含まれていた4つのアスペクトのうちの1つしか挙げていませんが,残り3つのアスペクトのうち,2つにはまったくスライスが含まれておらず,プログラムが出力している誤った結果にはまったく関わっていないことが示されています. 出力結果には関係ないので スライスに含まれない
実験の提出物 提出物 (事前の2回の演習課題,実験用の演習) 提出した結果を分析 問題の原因 修正方針 変更したソースコード 作業に要した時間 スライスを使用した感想 提出した結果を分析 この実験と,事前準備として行ったJavaプログラムのデバッグの演習では,問題の原因,修正方針,修正したソースコード,作業に要した時間を提出してもらいました.また,スライスを使用した学生については,使用した感想についても報告してもらいました.これらを提出した12名,うちスライスを使用した学生は6名でしたが,その結果について,これから説明します.
実験結果 Javaプログラム課題の作業時間との順位相関 スライス使用の効果 グループ 事前課題1 (Java) 事前課題2 相関係数 r = 0.54 AspectJ プログラミングでは Java に関するプログラミング能力が重要な要素となる スライス使用の効果 スライス使用者のほうが値は多少良いが,統計的に有意な差は示せなかった 作業時間の平均 (単位: 分) グループ 事前課題1 (Java) 事前課題2 (AspectJ) 実験 1 150 186 200 2 210 190 (スライス使用) 評価は,バグの特定および修正を合わせた時間をベースに行いました.JavaとAspectJの課題において順位相関を取ると,0.5と正の相関があり,AspectJプログラミングの能力は,Javaプログラミングの能力の影響を受けていることが分かりました.実験でスライスを使用しなかった学生をグループ1,スライスを使用した学生をグループ2として,作業に要した時間の統計を取ったところ,この表のようになりました.スライスを使用した学生のほうが,平均的には好成績となりましたが,統計的に有意な差は示せませんでした.
考察 スライスを用いた学生の意見を分析した結果: バグの原因特定について バグの修正について 作業に取り掛かる段階で,コードを読む指針となる 「原因の候補」として目をつけた点に対して,その部分がスライスに含まれているかどうかで,候補を絞り込める バグの修正について 変更結果が他のアスペクトに影響を及ぼさないことを確認するには,他のアスペクトも読まないといけない スライスだけで,作業時間を短縮できるとは限らない 影響波及解析など他のデバッグ支援手法と組み合わせる プログラムスライスを用いた学生から意見を集めた結果,次のようなことが分かりました.まず,スライスを用いる利点として,プログラムと同時にスライスが与えられることで,作業の取り掛かりで,どのコードを読めばよいのか,という指針となります.また,原因の候補として目をつけた点が,スライスに含まれているかどうかで,候補を絞り込んでいくことができた,という報告がありました. しかし,同時に,バグを特定しても,修正が正しいかどうか,その変更が他のアスペクトに影響を及ぼしていないかどうかを確認するには,他のアスペクトも調べなければならず,結局,すべてのアスペクトを調べることになり,結果として作業時間が大幅に短縮されることはなかった,ということが分かりました. この結果から,プログラムスライスはバグの特定作業には役立ちますが,バグ修正においては影響波及解析など他のデバッグ支援手法との組み合わせることが重要であると考えられます.
まとめ アスペクト指向プログラムの開発支援 評価実験 今後の課題 Call Graphを用いた干渉の検出 プログラムスライシングの適用 アスペクトの動作を,メソッド呼び出しと等価とみなす ループ等,実行を不可能にするような重大な干渉の提示 プログラムスライシングの適用 従来手法に,「アスペクト呼び出し」を追加 静的情報,実行時情報を組み合わせた開発者の支援 評価実験 スライスツールの適用 アスペクトによる振る舞いの変化を示す 開発作業への影響の評価 バグの原因特定には有用 バグの修正支援には他の手法が必要 今後の課題 多数のオブジェクトを横断するアスペクトの効率的な扱い 影響波及解析など,他のデバッグ支援手法との連携 最後にまとめます. アスペクト指向プログラムに対する開発支援として,まず,Call Graphを用いたアスペクト干渉の検出を行いました.アスペクトの動作をメソッド呼び出しと同様に考えて呼び出し関係をグラフ化し,無限ループの発生のような,実行を不可能にするような重大な干渉を検出し,開発者に提示します. また,実行した結果が正しくないと判明した場合に対して,その原因の調査を支援するために,プログラムスライシングの適用を行います.プログラムスライシングは,依存関係を追跡して,開発者が調査すべきコードを抽出・提示する手法です.ソースコードの静的な情報と,実行時情報を組み合わせて,開発者の支援を行います. プログラムスライスの有効性を評価するために,プログラムスライス計算ツールの適用と,デバッグ作業への影響評価を行いました.この結果,プログラムスライスがアスペクトによる依存関係の変化を開発者に提示できるほか,バグの原因特定作業に対して効果があることが分かりました.ただし,バグの修正には他の手法が必要となります. 今後の課題として,多数のオブジェクトを横断したアスペクトの効率的な扱いによるスケーラビリティの実現,影響波及解析などの他のデバッグ支援手法との連携が挙げられます. /* アスペクト指向プログラミングの特徴は,横断要素のモジュール化にあります.複数のオブジェクトが関わる処理を単一のモジュールにまとめることで,保守性,再利用性を向上させることができます.しかし,ソースコードの見た目と実際の動作との間のギャップが拡大するという問題があります.*/
終
thisJoinPoint.getThis(); アスペクトを含んだプログラム依存グラフ 呼び出し データ依存 手続き内部頂点 around(): call (Foo.f1) の例 o, x を 代入したノード 呼び出し 引数: o, x around(): call(Foo.f1) データ o 元の o.f1(x); に対応 する頂点 thisJoinPoint.getThis(); 戻り値 o, x 本来の 呼び出し proceed(); 戻り値を代入する変数 戻り値 引数: x return 文 f1 メソッド本体
プログラムの概要 (1) “Worker” 階層オブジェクト それぞれ評価値を持つ Sumは加算ノード Prodは乗算ノード Literalは定数 ノードは共有可能 Worker.work() で評価値計算 Worker.getValue() で結果取得 17 SumWorker 9 5 ProdWorker Literal (5) 3 3 3 Literal (3)
プログラムの概要 (2) main.Main 4つのアスペクトを導入 Worker ツリー構築 → 計算 → 結果の出力 を実装 Worker ツリーの解体 (CleanupAspect) 式の構造 出力 (PrintTreeAspect) 先ほどのツリーの出力: (+ 5 3 (* 3 3 ) ) 共有ノードの再評価省略 (CachingAspect) 計算中のループ検出 (LoopDetectAspect)
オブジェクト/アスペクトのコード比較 一貫性の維持が難しい ・変更の反映を忘れる ・無関係な部分に実装を 追加してしまう aspect ErrorNotification { // Databaseでのエラートラップ after throwing(DBException e): call (* Database.*(..) ) { user_input = GUI.notifyError(e); // エラー処理 } // GUI に以下のコードを追加 public int GUI.notifyErorr(DBException e) { // ダイアログを表示 // ユーザの入力を戻り値とする return user_input; class GUI { public int notifyError(DBException e) { // ダイアログを生成してユーザに通知 database.processError(e, user_input); } class Database { private doSomething() { try { ... } catch (DBException e) { gui.notifyError(e); } private doSomething2() { try { ... } catch (DBException e) { gui.notifyError(e); } 一貫性の維持が難しい ・変更の反映を忘れる ・無関係な部分に実装を 追加してしまう DB内でのエラーが起きる場所 すべてで同じ処理が必要
その他のアスペクトの利用例 アスペクトによるトランザクションの実現† GoF デザインパターンのアスペクトによる書き換え‡ 種々のトランザクションメカニズムを利用したトランザクションのモジュール化 GoF デザインパターンのアスペクトによる書き換え‡ デザインパターン=オブジェクトの「連携のやりかた」のパターン 設計レベルでの再利用,使うときは個別のコードを書く パターンに関連するオブジェクトにコードは分散する いくつかのパターンは,単独のアスペクトに簡潔に記述することができる アスペクトとして再利用可能なコードになったパターンも存在 さて,他にも,いくつものアスペクトの利用が報告されています.たとえば,データベースなどに対するトランザクション処理や,オブジェクト指向でデザインパターンとして知られるオブジェクトの連携パターンをアスペクトで実装した例があります.特にデザインパターンのいくつかでは,オブジェクト指向による実現に比べて,分散したコードの局所化が達成されたものや,パターンを実装したコードの再利用可能性が達成されたものもあります.従来は,パターンはあくまでパターンであり,プログラマが個々の状況に合わせて実際のコードを書かなければならなかったのですが,それが再利用可能なモジュールとしての記述に成功した例も報告されています. † S. Soares, E. Laureano, P. Borba: `Implementing Distribution and Persistence Aspects with AspectJ'', OOPSLA 2002 ‡ J. Hannemann, G. Kiczales: ”Design Pattern Implementation in Java and AspectJ'‘, OOPSLA 2002
Architecture and Use Case of ADAS 1.edit program slice slice criteria 4.slice calculation Dynamic Analysis Aspect Java Source Slice Calculation Tool Static Analyzer Static Info. 2.compile This figure shows a use case of ADAS. Program slice calculation takes 4 steps. First, a programmer edits Java source codes. Second, a programmer compiles them. Current version of ADAS need to compile twice. One compilation is to extract static information and another is to generate java byte code with dynamic analysis. Third, a programmer execute byte codes on a Java Virtual Machine. The aspect collects dynamic information and outputs result to a file. Finally, a programmer select a slice criteria on the text editor and execute slice calculation. The tool calculates a slice from static and dynamic information, and shows it on the editor. Dynamic Info. Java VM AspectJ Java Bytecode 3.execute a test case
情報収集の従来の実現方法 「監視」処理は対象ソフトウェア全体に影響する Java を対象とした場合のその他の実現方法 単純な実装:対象ソフトウェアの各所でログを生成する → アスペクトでモジュール化するべき Java を対象とした場合のその他の実現方法 Java Virtual Machine (JVM)の改造 移植性がない,実現に必要なコストが高い JVMの持つ Profiler Interface の利用 実行時のコストが高い,バイトコード最適化で結果が変わる プリプロセッサによるソースコード変換 構文木の変換ルールが複雑,保守性が低い このような目的に対して,ソースコードからの情報収集は構文解析や意味解析を実行するだけでよいのですが,実行時の情報収集では,その実現方法が問題となってきます. プログラムの実行状態を監視する処理が必要となりますが,この監視処理そのものも,対象ソフトウェア全体に影響するものとなっています.単純な実装では,対象ソフトウェアの各所でログを生成するという形式ですが,これは,アスペクト指向において,アスペクトで実装すべき処理のひとつとなっています. 対象とするプログラム言語として Java を選んだ場合,他にも次の三つのような選択肢があります.Java の実行環境である Java Virtual Machine の改造,Java Virtual Machine が公開している Profiler Interface と呼ばれる性能計測インタフェースの利用,プリプロセッサによるソースコードの変換です. ひとつめの JVM の改造という方式は,改造元となる JVM のバージョンに依存してしまうこと,つまりバージョンアップに対応して毎回作り直す必要があること,実現に必要なコストが高いという問題があります. 二番目のProfiler interface の利用という方式は,元々性能計測用のインタフェースであるため,メモリの確保や解放,スレッドの利用などの粒度の細かい情報が得られますが,逆に,データ依存解析のようなフィールドの参照や代入,メソッドの呼び出しといった粗い粒度の情報を得ようとするには,オーバーヘッドが若干高めになってしまうこと,バイトコード最適化の影響で結果が変わってしまうことなど,いくつかの弱点が知られています. プリプロセッサによるソースコードの変換は,この三つの中では一番有望な選択肢ですが,構文木ベースでの変換ルールは記述の手間が多く,現状では再利用しにくい問題があります.アスペクトによる実装は,アスペクトを注意深く記述する必要はありますが,導入が容易で,実現に要するコストが小さいものとなっています.
アスペクトによる実装の利点 アスペクトとして動的解析処理を記述 1つのモジュールにカプセル化可能 実現および実行時に要するコストの軽減 可読性・保守性の向上 実現および実行時に要するコストの軽減 実用上十分な情報が収集可能 成果については論文投稿中† アスペクトによる実装の利点をまとめると,このようになります. まず,アスペクトとしてひとつのモジュールにカプセル化が可能となります.これは,可読性と保守性の向上をもたらします. 次に,実現に要するコストを低く抑えることができ,また,実行時に要するコストも,コンパイラの最適化などの恩恵を受けることができるため,抑えやすいものとなっています. また,オブジェクト指向プログラムに対して,アスペクトを付加して情報を収集することは既に実現しており,実用上十分な情報が収集できることが分かっています.これについては,成果を論文投稿中です. †: 石尾 隆,楠本 真二,井上 克郎: アスペクト指向プログラミングの 動的プログラムスライスへの応用,情報処理学会論文誌,投稿中
関連研究 AspectJ† IDE for JBuilder, Forte, Emacs ソースコードエディタで,オブジェクトのコード上にアスペクトの連動位置を表示する アスペクト干渉の検出は行わない アスペクト指向プログラムに対するプログラムスライス計算の提案‡ 提案だけ,有効性については評価されていない この分野で,現在までに行われている研究のうち,二つを紹介します.まず一つ目は,AspectJ IDE と呼ばれるものです.Javaのアスペクト指向拡張言語であるAspectJを対象に,JBuilder, Forte, Emacs といった開発環境のエディタ上で,どのアスペクトが連動するかを表示するというものです.アスペクトの存在を意識してコードを書くことができますが,アスペクト干渉などについては,開発者が手作業で調べるしかありません. もう一つは,アスペクト指向プログラムに対する,ソースコード情報を用いたプログラムスライス計算の提案です.これは,提案だけが成されているものの,実際にツールとして実装されているわけではなく,有効性についても評価されていない,というのが現状です. †: AspectJ Official Site: http://www.eclipse.org/aspectj/ ‡: Jianjun Zhao, “Slicing Aspect-Oriented Software”, In Proc. of the 10th IEEE International Workshop on Programming Comprehension, pp.251--260, 2002