メソッド呼び出しパターンとして現れる横断的関心事の検出 大阪大学 三宅達也
研究概要 メソッド呼び出しパターン抽出手法を用いて横断的関心事を検出 横断的関心事と関連しているパターンがどの程度存在しているかの調査 横断的関心事とメソッド呼び出しパターンは同種の機能に関するコードが複数個所に出現するという点で類似している 横断的関心事と関連しているパターンがどの程度存在しているかの調査 メソッド呼び出しパターン 横断的 関心事 SIGSS研究会 2019/5/9
研究背景 横断的関心事 アスペクト指向プログラミング(AOP) メソッド呼び出しパターン SIGSS研究会 2019/5/9
横断的関心事 複数のモジュールにまたがって実装される機能 保守性,再利用性などを悪化させる クラス1 クラス2 ロギング ロギング 例外処理 SIGSS研究会 2019/5/9
横断的関心事の例 コンパイルエラー メソッドの開始時にメッセージを 表示するメソッド 本来はLoggingクラスにまとめてしまいたい Class cls1 { void method1 ( ) { logging.message(); } Class cls1 { void method1 ( ) { logging.message(“meth1”); } Class Logging { public void message(String s) { System.out.println(s); } Class Logging { public void message( ) { System.out.println(“start”); } ・・・ コンパイルエラー メソッドの開始時にメッセージを 表示するメソッド Class cls2 { void method2 ( ) { logging.message(“meth2”); } Class cls2 { void method2 ( ) { logging.message(); } ・・・ 本来はLoggingクラスにまとめてしまいたい SIGSS研究会 2019/5/9
新たなモジュール単位「アスペクト」を導入 アスペクトを利用し、より理想的なモジュール構造を実現 保守性、再利用性などが向上 アスペクト指向プログラミング(AOP) 新たなモジュール単位「アスペクト」を導入 アスペクトを利用し、より理想的なモジュール構造を実現 保守性、再利用性などが向上 クラス1 クラス2 アスペクト 例外処理 ロギング SIGSS研究会 2019/5/9
横断的関心事の種類 ~ Homogeneous と Heterogeneous ~ 均一性横断的関心事(homogeneous crosscutting concern) どの出現箇所でも関心事を実現するコードが均一 単一のメソッド呼び出し 複数のモジュールにまたがるコードクローン アスペクトにまとめるのが容易 非均一性横断的関心事(heterogeneous crosscutting concern) 出現箇所ごとに関心事を実現するコードが異なる アスペクトにまとめるのが困難 SIGSS研究会 2019/5/9
横断的関心事の種類の例 ~ Homogeneous と Heterogeneous ~ 均一性横断的関心事 非均一性横断的関心事 public void homogen1 ( ) { if ( isLog() ) { showLog ( ); } int r = ld.getRadius( ); res = Math.pow ( r,2 ); res = res * Math.PI; } public void heterogen1 ( ) { double res; LineData ld = input ( ); boolean c = ld.check( ); int h = ld.getHeight( ); int b = ld.getBottom( ); if ( c ) { res = b * h / 2; output ( res ); } } public void homogen2 ( ) { if ( isLog() ) { showLog ( ); } int h = ld.getHeight( ); int b = ld.getBottom( ); res = b * h / 2; } public void heterogen2 ( ) { double res; LineData ld = input ( ); Id.hoge(); boolean c = ld.check( ); if ( c ) { int r = ld.getRadius( ); res = Math.pow ( r,2 ); res = res * Math.PI; output ( res ); } } SIGSS研究会 2019/5/9
メソッド呼び出しパターン ソースコードに頻繁に出現する構造のよく似たメソッド呼び出し列 以下の情報を含んでいる 特定の機能を実現する定型的なコード 特定の制御構造を含む 以下の情報を含んでいる 実現したい処理に必要なメソッド呼び出し群 関連のあるメソッドの呼び出し順 メソッドの引数や返り値の扱い方 SIGSS研究会 2019/5/9
メソッド呼び出しパターンの例 input( ) LineData.check( ); if output; } Public void circle ( ) { double res; LineData ld = input ( ); boolean c = ld.check( ); if ( c ) { int r = ld.getRadius( ); res = Math.pow ( r,2 ); res = res * Math.PI; output ( res ); } } 辺の長さを 読み込む Public void triangle ( ) { double res; LineData ld = input ( ); boolean c = ld.check( ); int h = ld.getHeight( ); int b = ld.hetBottom( ); if ( c ) { res = b * h / 2; output ( res ); } } 長さの例外 チェック 求めた面積 を出力 メソッド呼び出しパターン input( ) LineData.check( ); if output; } SIGSS研究会 2019/5/9
本研究の目的 検出による効果 横断的関心事の検出 保守性・再利用性・拡張性などの向上 メソッド呼び出しパターンの抽出を応用 均一性横断的関心事と非均一性横断的関心事の両方を検出 検出による効果 保守性・再利用性・拡張性などの向上 横断的関心事のアスペクト化 横断的関心事の出現位置の管理 SIGSS研究会 2019/5/9
提案する検出手法 メソッド呼び出しパターン抽出手法を横断的関心事の検出に応用 横断的関心事 メソッド呼び出しパターン ≒ ≒ 特定の関心事に関するコード が複数個所に分散 メソッド呼び出しパターン 同種の機能を実現する コードが複数個所に出現 ≒ ≒ メソッド呼び出しパターン抽出手法を横断的関心事の検出に応用 横断的関心事に関連したメソッド呼び出しパターンが存在する SIGSS研究会 2019/5/9
メソッド呼び出しパターン抽出 既存の手法を採用[1] Javaで書かれたプログラムを対象としたツールを実装 特徴シーケンスの生成 Sequential pattern mining PrefixSpanアルゴリズムを採用 Javaで書かれたプログラムを対象としたツールを実装 [1] 中山崇,松下誠,井上克郎, ”ソースコードの差分を用いた関数呼び出しパターン抽出法の提 案”,情報処理学会研究報告,Vol.2006,No.35,2006-SE-151,pp.49–56,2006 SIGSS研究会 2019/5/9
特徴シーケンスの生成 ソースコードの特徴 特徴シーケンス メソッド呼び出し 条件文の開始・終了要素 繰り返し文の開始・終了要素 抽出されたコードの特徴を要素とするシーケンス 各メソッドごとに抽出 class Sample { A a; int i, k; void method1 (int arg ) { foo(); i = a.hoge(); if( i == 0 ) { k = arg; a.bar(); } void foo ( ) {・・・} Sample.method1()の 特徴シーケンス Sample.foo() A.hoge() if A.bar() } ソースコードの特徴 SIGSS研究会 2019/5/9
Sequential pattern mining(PrefixSpan) 特徴シーケンスに対し射影と呼ばれる操作を繰り返し行なうことでシーケンシャルパターンを抽出する 射影とは,全てのシーケンスに対して特定の要素からの接尾辞を取り出す操作 要素aによる射影 a c d c d 要素aの接尾辞 a b c b c c b a a a b a b SIGSS研究会 2019/5/9
PrefixSpanの例 各要素の 出現回数 ab,ac,を パターンとして出力 a,b,c,を パターンとして出力 最低出現回数2、最小要素数1 ab,ac,を パターンとして出力 a,b,c,を パターンとして出力 a:1 b:2 c:2 d:1 1. c d 2. b c 4. a b 2. c c:1 1. d d:1 1. a c d 2. a b c 3. c b a 4. a a b a:4 b:3 c:3 d:1 射影 2. c 3. a a:1 c:1 結果 a :4 ab:2 ac:2 b :3 c :3 a:1 b:1 d:1 1. d 1. b a 各要素の 出現回数 SIGSS研究会 2019/5/9
メソッド呼び出しの識別 メソッドを宣言しているクラスを区別する メソッドを呼び出しているクラスを区別しない Super メソッドを宣言しているクラスを区別する 継承元が同じであるメソッドは同一のメソッドとみなす メソッドを呼び出しているクラスを区別しない メソッド名のみを識別 Sample() Sub1 Sub2 Sample() Sample() 同一の特徴 A B C Sample() Sample() Sample() 同一の特徴 SIGSS研究会 2019/5/9
ツールのスクリーンショット クラス階層ツリーにおける 選択したパターンの 分散状況 抽出されたパターンの設定 抽出されたパターンの情報 ソースコード における 選択したパターンの分布状況 SIGSS研究会 2019/5/9
実験概要 実験対象 JHotDraw(図形描画アプリケーション) 総行数 : 約18000行、総メソッド数 : 約2900 抽出したパターン 総行数 : 約18000行、総メソッド数 : 約2900 抽出したパターン 出現回数 : 4回以上 パターンの要素数 : 4以上 メソッド呼び出しの識別方法 メソッドを宣言しているクラスを区別 メソッドを宣言しているクラスを無視 評価方法 抽出したパターンが横断的関心事と関連しているかどうかを評価 他の文献でアスペクト化すべきであるとされている横断的関心事を参考に評価 評価基準 パターンの出現回数 パターンが出現するクラス数 特定のキーワードの出現頻度 パターンの要素であるメソッド呼び出しの名前 パターンが出現するメソッドの名前 SIGSS研究会 2019/5/9
・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・ 抽出結果 メソッドを宣言しているクラスの違いを識別した場合 抽出されたパターン数 : 38種類 横断的関心事に関連しているもの : 22種類 横断的関心事に関連していないもの : 16種類 メソッドを宣言しているクラスの違いを無視した場合 抽出されたパターン数 : 55種類 パターンが関連する関心事 出現回数 出現するクラス数 横断的関心事 ループ処理のイディオム 54 31 × コマンドの取り消し 14 ○ コマンド取消用の情報保存 12 図形の選択解除 10 ・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・ ポリゴン処理 6 1 SIGSS研究会 2019/5/9
抽出されたメソッド呼び出しパターンの例 (横断的関心事に関連しているパターン1) 呼び出されているメソッドの名前に特定のキーワードが多数出現 AbstractCommand.setUndoActivity() AbstractCommand.getUndoActivity() Undoable.setAffectedFigures() Undoable.getAffectedFigures() 実行コマンド取消用の情報を 保存するためのパターン キーワードUndoが多数出現 SIGSS研究会 2019/5/9
抽出されたメソッド呼び出しパターンの例 (横断的関心事に関連しているパターン2) パターンが出現するメソッドの名前に特定のキーワードが多数出現 class ConnectionTool{ ・・・・・・・・・・・・ public void mouseUp{ ・・・・・・・・・ } MouseEvent.getX() MouseEvent.getY() マウス操作に関連するパターン 抽出 class PolygonTool{ ・・・・・・・・・・・・ public void mouseDown{ ・・・・・・・・ } 抽出 キーワードmouseが多数出現 抽出 class DrawingViewMouseListener{ ・・・・・・・・・・・・ public void mousePressed{ ・・・・・・・・ } SIGSS研究会 2019/5/9
抽出されたメソッド呼び出しパターンの例 (アプリケーションの機能に関連していないパターン) org.jhotdraw.standard.StandardDrawingView public void addAll(Collection figures) { FigureEnumeration fe = new FigureEnumerator(figures); while (fe.hasNextFigure()) { add(fe.nextFigure()); } } 集合がまだ要素を持っているかどうかチェック メソッド呼び出しパターン (出現回数59) FigureEnumeration.hasNextFigure() while FigureEnumeration.nextFigure() } org.jhotdraw.standard.CompositeFigure public FigureEnumeration figures(Rectangle viewRectangle) { if (_theQuadTree != null) { FigureEnumeration fe = _theQuadTree.getAllWithin(new Bounds(viewRectangle( List l2 = CollectionsFactory.current().createList(); while (fe.hasNextFigure()) { Figure f = fe.nextFigure(); //int z = fFigures.indexOf(f); l2.add(new OrderedFigureElement(f, f.getZValue())); } ・ } 繰り返しの制御に 関連するパターン (横断的関心事というよりはイディオム) 集合の 次の要素を取得 SIGSS研究会 2019/5/9
特定のクラス階層に出現するパターン 一部のサブクラスのみに出現するパターン 横断的関心事を管理する新たなクラス階層の提案 パターンが出現しないサブクラスは横断的関心事の実装し忘れの可能性 AbstractCommand Group UnGroup SelectAll Zoom Align Redo AbstractUndoable Align Zoom Redo Group UnGroup SelectAll パターンが出現するサブクラス パターンが出現しないサブクラス SIGSS研究会 2019/5/9
クラスを区別せずに抽出したパターンの例 setUndoActivity() createUndoActivity() org.jhotdraw.standard. DuplicateCommand public void execute() { super.execute(); setUndoActivity(createUndoActivity()); FigureSelection selection = view().getFigureSele・・・ // create duplicate figure(s) FigureEnumeration figures = (FigureEnumeration) ・・ getUndoActivity().setAffectedFigures(figures); view().clearSelection(); ・・・・・・・・・・・・・・・・・・・・・・・・・・・・・ } org.jhotdraw.figures.BorderTool public void action(Figure figure) { // Figure replaceFigure = drawing().replace(figur ・・ setUndoActivity(createUndoActivity()); List l = CollectionsFactory.current().createList(); l.add(figure); l.add(new BorderDecorator(figure)); getUndoActivity().setAffectedFigures(new Fig ・・ ((BorderTool.UndoActivity)getUndoActivity()).repl ・・ } AbstractTool のサブクラス AbstractCommand のサブクラス setUndoActivity() createUndoActivity() getUndoActivityI() setAffectedFigures() org.jhotdraw. standard.ResizeHandle public void invokeStart(int x, int y, DrawingView view) { setUndoActivity(createUndoActivity(view)); getUndoActivity().setAffectedFigures(new Sing ・・ ((ResizeHandle.UndoActivity)getUndoActivity()).se・・・ } AbstractHandle のサブクラス SIGSS研究会 2019/5/9
クラスを区別せずに抽出したパターン setUndoActivity() createUndoActivity() Abstract Command Abstract Handle Abstract Tool 11サブクラスに存在 6サブクラスに存在 9サブクラスに存在 AbstractCommand .setUndoActivity() EachSubClass .createUndoActivity() .getUndoActivityI() Undoable .setAffectedFigures() AbstractHandle .setUndoActivity() EachSubClass .createUndoActivity() .getUndoActivityI() Undoable .setAffectedFigures() AbstractTool .setUndoActivity() EachSubClass .createUndoActivity() .getUndoActivityI() Undoable .setAffectedFigures() setUndoActivity() createUndoActivity() getUndoActivityI() setAffectedFigures() クラスを識別しない場合のパターン SIGSS研究会 2019/5/9
考察 特定の関心事に関連しているパターンには関心事の内容を示すキーワードの出現頻度が高い 特定のクラス階層内のみに出現するパターンが存在 横断的関心事の実装し忘れのチェックに使用可能 一部のサブクラスのみに出現する場合、新たなクラス階層を提案 メソッドを宣言しているクラスを識別しないほうがより広範囲から抽出可能 横断的関心事に関連したメソッドには宣言が横断的なものもある 他の手法にも応用可能 SIGSS研究会 2019/5/9
関連研究 アスペクトマイニング オブジェクト指向プログラムからアスペクトの候補となる部分を抽出 既存手法 均一性横断的関心事が主な抽出対象 コードクローンをベースに抽出 モジュールを横断するコードクローンをアスペクト化 Fan-Inの大きいものを抽出 呼び出されている場所の数が多いメソッドは横断的である可能性が高い grepを用いた検索 横断的関心事に関連したキーワードで検索 SIGSS研究会 2019/5/9
関連研究との比較 コードクローンをベースにまとめる手法 Fan-Inを利用した手法 メソッド呼び出しパターンを利用した手法 コード記述が一致していないと検出できない Fan-Inを利用した手法 メソッドが個別に抽出されるので他のメソッドとの関連がわからない メソッド呼び出しパターンを利用した手法 コード記述の違いをある程度吸収できる 関連するメソッドをまとめて抽出することができ、その呼び出し順序もわかる ⇒AOPの目的は同一のコード記述を一箇所にまとめることではなく、同一の関心事を一箇所にまとめることであるので、コード記述の違いはある程度吸収できたほうが良い SIGSS研究会 2019/5/9
同一のメソッド呼び出しパターンを持つコード コードクローンベースの手法で抽出できるコード 既存手法との比較(抽出例) 同一のメソッド呼び出しパターンを持つコード org.jhotdraw.standard.CutCommand public void execute() { super.execute(); setUndoActivity(createUndoActivity()); FigureEnumeration fe = view().selection(); List affected = CollectionsFactory.current().createL・・・ Figure f; FigureEnumeration dfe; while (fe.hasNextFigure()) { f = fe.nextFigure(); affected.add(0, f); dfe = f.getDependendFigures(); ・・・・・・・・・・・・・・・・・・・・・ } fe = new FigureEnumerator(affected); getUndoActivity().setAffectedFigures(fe); UndoActivity ua = (UndoActivity) getUndoActivity(); ua.setSelectedFigures(view().selection()); copyFigures(ua.getSelectedFigures(), ua.getSele・・・・ deleteFigures(getUndoActivity().getAffectedFigures()); view().checkDamage(); } コードクローンベースの手法で抽出できるコード org.jhotdraw.fiures.GroupCommand public void execute() { super.execute(); setUndoActivity(createUndoActivity()); getUndoActivity().setAffectedFigures(view().selection()); ((GroupCommand.UndoActivity)getUndoActivity()).group・・・ view().checkDamage(); } org.jhotdraw.standard.AlignCommand public void execute() { super.execute(); setUndoActivity(createUndoActivity()); getUndoActivity().setAffectedFigures(view().selection()); ((AlignCommand.UndoActivity)getUndoActivity()).alignA・・・ view().checkDamage(); } SIGSS研究会 2019/5/9
まとめと今後の課題 メソッド呼び出しパターン抽出手法を用いて横断的関心事の検出 今後の課題 横断的関心事には特定のパターンを持つものが存在 コードの違いをある程度吸収できるため非均一性横断的関心事の一部も抽出可能 今後の課題 実験対象の拡大 本研究で得られた実験結果はJHotDraw特有の特徴から得られた結果である可能性がある 均一性横断的関心事と非均一性横断的関心事の識別 均一性横断的関心事はアスペクト候補として表示 非均一性横断的関心事は出現箇所を管理すべきコード片として表示 SIGSS研究会 2019/5/9