メソッド抽出リファクタリングが 行われるメソッドの特徴調査 ○ 後藤 祥1,吉田 則裕2 ,藤原 賢二2 崔 恩瀞1 ,井上 克郎1 1大阪大学 2奈良先端科学技術大学院大学
研究概要 メソッド抽出が行われるメソッドの特徴を調査 一般的なメソッドの特徴と比較 オープンソースソフトウェアからメソッド抽出の履歴を収集 開発者がどのようなメソッドを対象としているか 一般的なメソッドの特徴と比較 メソッドのサイズ,凝集度に有意な差が存在した
リファクタリング プログラムの外的振る舞いを変化させずに,内部構造を整理すること [1] 保守性や可読性の向上を目的として行う 様々な種類のリファクタリングが存在する 保守性や可読性の向上を目的として行う [1] M. Fowler, “Refactoring : Improving the Design of Existing Code”, 1999.
メソッド抽出リファクタリング メソッドの一部を新たなメソッドとして抽出するリファクタリング 主な用途 長いメソッドを短いメソッドに分割する 複数の機能を持つメソッドを機能単位に分割する
メソッド抽出の例(1/2) 1-10までの成績を並び替えて表示するプログラム データの入力 ソート データの出力 int[] score = {9,4,8,2,3,10,7,1,6,5}; for(int i=0;i<score.length-1;i++){ for(int j=0;j<score.length-i-1;j++){ if(score[j] < score[j+1]){ int t = score[j]; score[j] = score[j+1]; score[j+1] = t; } for(int i=0;i<score.length;i++){ System.out.println(score[i]); データの入力 ソート データの出力
メソッド抽出の例(2/2) 1-10までの成績を並び替えて表示するプログラム ソート部分をメソッド抽出 int[] score = {9,4,8,2,3,10,7,1,6,5}; sort(score); for(int i=0;i<score.length;i++){ System.out.println(score[i]); } public void sort(int[] score){ for(int i=0;i<score.length-1;i++){ for(int j=0;j<score.length-i-1;j++){ if(score[j] < score[j+1]){ int t = score[j]; score[j] = score[j+1]; score[j+1] = t; } ソート部分がsortメソッドに置き換わり,プログラムの可読性が向上した. 機能単位に分割されたことで,バグ修正などの保守作業が容易になった.
リファクタリング支援の研究 開発履歴の調査と支援手法の提案 開発履歴の調査 調査結果に基づく 支援手法・ツールの提案 開発履歴 開発者 1 開発履歴の調査 開発履歴 開発者 調査結果に基づく 支援手法・ツールの提案 研究者 2
既存の調査研究 既存の調査の内容 [2] コードの特徴の定量的調査は行われていない どの種類のリファクタリングが行われているか? 開発者がどのようにツールを使っているか? コードの特徴の定量的調査は行われていない コードの特徴 ・・・ 行数,複雑度など リファクタリングされるコードの特徴を調べることで,リファクタリング対象の推薦ができる [2] E. Murphy-Hill et al., “How We Refactor, and How We Know It”, 2012
研究概要 メソッド抽出リファクタリングの定量的調査 調査する特徴:長さ,凝集度 メソッド抽出されたメソッドと一般的なメソッドの特徴を比較する 凝集度 ・・・ 機能的なまとまりを表す度合 抽出の対象となるのは長いメソッドや機能単位でまとまっていないメソッドと言われている [1] [1] M. Fowler, “Refactoring : Improving the Design of Existing Code”, 1999.
調査手順 メソッド抽出されたメソッドとリリースバージョンの全メソッドを比較 開発履歴 リファクタリング 抽出対象となったメソッドの特徴 Extracted 開発履歴 リファクタリング 検出ツール メソッド抽出事例 最新の リリースバージョン 全メソッドの特徴 All
メソッド抽出事例の検出 本研究では藤原らのツールを使用 メリット デメリット ・複数リビジョンから 一度に検出が可能 ・高速・高精度 ツール[3] ・対象はメソッド抽出 リファクタリングのみ Ref-Finder[4] UMLDiff[5] ・複数の種類のリファ クタリングを検出可能 ・一度に検出ができる のは2リビジョン間のみ [3] 藤原ら, “構文情報を付加したリポジトリによるメソッド抽出リファクタリングの検出”, 2013. [4] K. prete et al., “Template-based Reconstruction of Complex Refactorings”, 2010. [5] Z. Xing et al., “Refactoring Detection based on UMLDiff Change-Facts Queries”, 2006.
藤原らのツールの検出手順 リビジョン N リビジョン N + 1 条件1 : 行の追加および削除が行われた メソッドが存在する 削除された行 void printOwing(){ printBanner(); System.out.println("name: " + _name); System.out.println("amount: " + getOutstanding()); } リビジョン N + 1 条件1 : 行の追加および削除が行われた メソッドが存在する void printOwing(){ printBanner(); printDetails(getOutstanding()); } 削除された行 System.out.println("name: " + _name); System.out.println("amount: " + getOutstanding()); 条件3 : 新たに追加されたメソッドを 呼び出している 類似度が閾値(0.3)以上であれば メソッド抽出が行われたとする. void printDetails(double outstanding){ System.out.println("name: " + _name); System.out.println("amount: " + outstanding); } 条件2 : 新たに追加された メソッドが存在する
調査するメトリクス メソッドの長さと凝集度を表すメトリクス 長さを測るメトリクス1つ 凝集度を測るメトリクス3つ メソッド中の文数 (Number Of Statements : NOS) メソッドの長さ スライスベースの凝集度メトリクス Tightness, Coverage, Overlap メソッドの凝集度
凝集度メトリクス Tsantalisらの定義に従って計算する [7] スライスベースの凝集度メトリクス [6] プログラムスライスを用いて凝集度を計測する メソッドの出力変数に着目したメトリクス 0から1の範囲の実数値で値が高いほど凝集度が高い Tsantalisらの定義に従って計算する [7] 出力変数 ・・・ メソッド本体とスコープが一致する変数 出力変数が存在しないメソッドの凝集度は計算できない [6] M. Weiser, “Program slicing”, 1981. [7] N. Tsantalis et al., “Identification of extract method refactoring opportunities for the decomposition of methods”, 2011.
プログラム依存グラフ(PDG) プログラム中の依存関係を表したグラフ 頂点は文,辺は依存関係を表す 2 3 4 5 8 PDG 文 制御文 1 2 3 4 5 6 7 8 9 int factorial(int a){ int result = 1; int i; for(i = a;1 < i;i--){ result *= i; } return result; 4 文 制御文 5 データ依存辺 8 制御依存辺 PDG
プログラムスライス スライス基準(文と変数の組)と関連する文の集合 基準から後ろ向きに辺をたどって得られる集合を後ろ向きスライスという 3 2 5 8 4 1 2 3 4 5 6 7 8 9 int factorial(int a){ int result = 1; int i; for(i = a;1 < i;i--){ result *= i; } return result; スライシング基準 : <5, result> 後ろ向きスライス : {3,4,5}
全ての出力変数に関わる文がどの程度存在するか 凝集度の計算例 スライスの積集合 | SLi SLresult SLint 1 2 3 4 5 6 7 8 9 int factorial(int a){ int result = 1; int i; for(i = a;1 < i;i--){ result *= i; } return result; 出力変数の後ろ向き スライスを計算 出力変数のスライスが どの程度重複しているか 出力変数のスライスが どの程度メソッド全体に 広がっているか 全ての出力変数に関わる文がどの程度存在するか
調査対象のメソッド NOSの比較には全メソッドを使用 凝集度の比較には凝集度が計算できたメソッドのみを使用(表中の括弧内数) メソッド抽出事例数 比較用バージョン メソッド数 jEdit 490(286) 4.5.0 6275(2114) ArgoUML 659(302) 1.8.4 9123(2167) Apache Ant 704(322) 0.34 13840(4457)
NOS分布 抽出対象のメソッドはNOSが多い 有意水準0.05で有意差あり NOS リリース 抽出 リリース 抽出 リリース 抽出 jEdit Ant ArgoUML
凝集度の比較結果 3つの対象ソフトウェアで近い結果 メトリクスごとの結果について説明 抽出対象のメソッドは凝集度が低い Antに対する結果のみ
Tightness 分布 全てのソフトウェアで有意差ありの検定結果 抽出されるのは0.2以下の値のメソッドが多い 凝集度 リリース 抽出
Coverage 分布 jEditのみ有意差なしの検定結果 Tightnessに値の分布が近い 凝集度 リリース 抽出
Overlap 分布 全てのソフトウェアで有意差ありの検定結果 値の分布が広い 値が1となるメソッドが非常に多い 凝集度 リリース 抽出
調査結果のまとめ 抽出対象のメソッドはNOSが多く凝集度が低い 長く,機能的まとまりのないメソッドが対象になる 有意差 比較調査の結果 あり 抽出対象となるメソッドはNOSが多い Tightness 抽出対象となるメソッドは値が0.2以下のメソッドが多い Coverage jEditのみなし 差が小さく有意差がない場合もある Overlap 有意差はあるが値の分布が特徴的
まとめ 抽出対象となるメソッドの特徴を調査 抽出対象となるメソッドは文数が多く,凝集度が低い 3つのソフトウェアを対象に調査 リリース版に存在するメソッドと特徴を比較 抽出対象となるメソッドは文数が多く,凝集度が低い 検定によって有意な差がみられた
今後の課題 より大規模な調査の実施 メソッド抽出候補の推薦手法の提案 対象ソフトウェア,メトリクス(複雑度など)を追加した調査 調査した特徴の差異を利用する