コードクローンを対象とした リファクタリングの有効性に関する調査
DESCRIPTION
コードクローンを対象とした リファクタリングの有効性に関する調査. 肥後 芳樹,楠本 真二,井上 克郎 大阪大学 大学院情報科学研究科 {y-higo, kusumoto, inoue}@ist.osaka-u.ac.jp. コードクローン. コードクローンとは ソースコード中に存在する一致または類似したコード片 コピーアンドペーストなどのさまざまな理由により生成される ソフトウェアの保守を困難にする あるコード片にバグがあると,そのコードクローン全てについて修正の検討を行う必要がある 機能を追加する場合も同様のことがいえる. コピーアンドペースト. - PowerPoint PPT PresentationTRANSCRIPT
1Software Engineering Laboratory, Department of Computer Science, Graduate School of Information Science and Technology, Osaka University
コードクローンを対象としたリファクタリングの有効性に関する
調査肥後 芳樹,楠本 真二,井上 克郎
大阪大学 大学院情報科学研究科{y-higo, kusumoto, inoue}@ist.osaka-u.ac.jp
2Software Engineering Laboratory, Department of Computer Science, Graduate School of Information Science and Technology, Osaka University
コードクローン コードクローンとは
ソースコード中に存在する一致または類似したコード片コピーアンドペーストなどのさまざまな理由により生成
される
ソフトウェアの保守を困難にするあるコード片にバグがあると,そのコードクローン全て
について修正の検討を行う必要がある機能を追加する場合も同様のことがいえる
コピーアンドペーストコピーアンドペー
スト
3Software Engineering Laboratory, Department of Computer Science, Graduate School of Information Science and Technology, Osaka University
リファクタリング ソフトウェアの外部的な振る舞いを保ったままで,
内部構造を改善していくこと リファクタリングを行うことでソフトウェアの保守
性が増し,後の保守作業効率が向上する
これまでに多くのリファクタリングすべきコードのパターン( Bad Smell )とその対処法( Refactoring Pattern )が提案されている [1][2]
コードクローンは最も優先してリファクタリングを行うべきものの1つとされているしかし,具体的な評価事例はほとんど報告されていな
い[1] M. Fowler: Refactoring: Improving the Design of Existing Code, Addison-Wesley, 1999.
[2] Refactoring Home Page: http://www.refactoring.com/
4Software Engineering Laboratory, Department of Computer Science, Graduate School of Information Science and Technology, Osaka University
研究の目的と概要 コードクローンに対するリファクタリングのコスト
と効果を調査し,その有効性を評価する 実験対象は複数バージョンのソースコードが公開さ
れているオープンソースソフトウェア最初のバージョンに対してコードクローン検出 & リ
ファクタリングリファクタリングのコストとして以下のものを用い
たソースコード修正と回帰テストに要した時間
リファクタリングの効果として以下のものを用いたCK メトリクス値の変化総行数の増減集約箇所の後のバージョンでの修正回数
5Software Engineering Laboratory, Department of Computer Science, Graduate School of Information Science and Technology, Osaka University
CK メトリクス Chidamber と Kemerer が提案したオブジェクト指向ソフトウェ
アの複雑度を測定するメトリクス [3] であり,広く用いられている 各メトリクスは,クラス単位で計測される
WMC(Weighted Methods per Class): そのクラスに定義されているメソッドに重み付けをして足し合わせた値
DIT(Depth of Inheritance Tree): クラス階層における継承の深さ
NOC(Number of Children): サブクラスの数CBO(Coupling Between Objects): 関係しているクラスの数RFC(Response For a Class): そのクラスのオブジェクトに
メッセージが送られた結果,実行されうるすべてのメソッドの数を表す
LCOM(Lack of Cohesion Of Methods): そのクラスのメソッドがお互いに関連している程度を表す
[3] Chidamber S. R. and Kemerer C. F.: “A Metrics Suite for Object Oriented Design”, IEEE Transaction on Software Engineering, Vol. 20, No. 6, pp. 476-493 (1994).
6Software Engineering Laboratory, Department of Computer Science, Graduate School of Information Science and Technology, Osaka University
コードクローンに対するリファクタリング コードクローンは最も優先してリファクタリングを
行うべきコード(のパターン)の1つとされている
どのようにリファクタリングを行うかは,コードクローン間の関係によって異なる [1]
同一クラス内の複数個所が重複している場合兄弟クラス間で重複コードが見られる場合まったく関係のないクラス間で重複コードが見られる
場合
[1] M. Fowler: Refactoring: Improving the Design of Existing Code, Addison-Wesley, 1999.
7Software Engineering Laboratory, Department of Computer Science, Graduate School of Information Science and Technology, Osaka University
コードクローンに対するリファクタリング:同一クラス内の複数箇所が重複している場合 Extract Method を適用して,各メソッドの内部から
コードクローンを抽出し,新たなメソッドとして定義する.
抽出箇所は,そのメソッドの呼び出し文に変更する.void printTaxi(int amount){
String name = getTaxiName();
System.out.println(“ name:” + name);System.out.println(“ amount:” + amount);
}
void printBus(int amount){String name = getBusName();
System.out.println(“ name:” + name);System.out.println(“ amount:” + amount);
}
void printTaxi(int amount){String name = getTaxiName();print(name, amount);
}
void printBus(int amount){String name = getBusName();print(name, amount);
}
void print(String name, int amount){System.out.println(“ name:” + name);System.out.println(“ amount:” + amount);
}
void printTaxi(int amount){String name = getTaxiName();
System.out.println(“ name:” + name);System.out.println(“ amount:” + amount);
}
void printBus(int amount){String name = getBusName();
System.out.println(“ name:” + name);System.out.println(“ amount:” + amount);
}
void printTaxi(int amount){String name = getTaxiName();print(name, amount);
}
void printBus(int amount){String name = getBusName();print(name, amount);
}
void print(String name, int amount){System.out.println(“ name:” + name);System.out.println(“ amount:” + amount);
}
8Software Engineering Laboratory, Department of Computer Science, Graduate School of Information Science and Technology, Osaka University
コードクローンに対するリファクタリング兄弟クラス間で重複コードを共有している場合 各クラスに対して Extract Method を行い,次に Pull
Up Field や Pull Up Method を適用すれば解決する 場合によっては, Form Template Method などを適用
する場合もありうる
Employee
Salesman Engineer
getName() getName()
Employee
getName()
Salesman Engineer
Employee
Salesman Engineer
getName() getName()
Employee
getName()
Salesman Engineer
9Software Engineering Laboratory, Department of Computer Science, Graduate School of Information Science and Technology, Osaka University
コードクローンに対するリファクタリングまったく関係のないクラス間で重複コードが見られる場合 Extract Class を適用し,古いクラスから新しいク
ラスへと処理を委譲するように変更を行う
Person
nameofficeAreaCodeofficeNumber
Company
getTelephoneNumber()
addressofficeAreaCodeofficeNumber
getTelephoneNumber()
Person
name
getTelephoneNumber()
Company
address
getTelephoneNumber()
Telephon Number
areaCodenumber
getTelephoneNumber()
1
1 1
1
Person
nameofficeAreaCodeofficeNumber
Company
getTelephoneNumber()
addressofficeAreaCodeofficeNumber
getTelephoneNumber()
Person
name
getTelephoneNumber()
Company
address
getTelephoneNumber()
Telephon Number
areaCodenumber
getTelephoneNumber()
1
1 1
1
Person
nameofficeAreaCodeofficeNumber
Company
getTelephoneNumber()
addressofficeAreaCodeofficeNumber
getTelephoneNumber()
Person
name
getTelephoneNumber()
Company
address
getTelephoneNumber()
Telephon Number
areaCodenumber
getTelephoneNumber()
1
1 1
1
10Software Engineering Laboratory, Department of Computer Science, Graduate School of Information Science and Technology, Osaka University
本研究で扱うコードクローン コードクローンの一般的な定義はない
これまでにいくつかのコードクローン検出手法が提案されているが,それらはどれも異なった定義を持つ
リファクタリング可能なコードクローンを検出したいコードクローン検出に CCFinder[3] と CCShaper[4]
を用いる[3] T. Kamiya, S. Kusumoto, and K. Inoue, CCFinder: A multi-linguistic token-based code clone detec
tion system for large scale source code, IEEE Transactions on Software Engineering, vol. 28, no. 7, pp. 654-670, Jul. 2002.
[4] 肥後 芳樹,植田 泰士,神谷 年洋,楠本 真二,井上 克郎:コードクローン解析に基づくリファクタリングの試み,情報処理学会論文誌 , Vol.45, No.5, pp1357-1366, 2004-5
11Software Engineering Laboratory, Department of Computer Science, Graduate School of Information Science and Technology, Osaka University
クローンペアとクローンセット クローンペア
互いに一致または類似しているコード片の対(ペア)
クローンセット互いに一致または類似しているコード片の集合(セ
ット)C1
C2
C3
C4
C5
クローンペア
クローンセット
(C1, C2) {C1, C2, C4}
(C1, C4) {C3, C5}
(C2, C4)
(C3, C5)
12Software Engineering Laboratory, Department of Computer Science, Graduate School of Information Science and Technology, Osaka University
コードクローン検出ツール: CCFinder概要 ソースコードをトークン単位で直接比較することによ
り,コードクローンを検出する
より実用的なコードクローンを見つけることができるように設計されているユーザ定義名の置き換えテーブル初期化部分の取り除きモジュールの区切りの認識
検出結果はテキスト形式で出力
数百万行単位のソフトウェアからでも数十分で検出可能
13Software Engineering Laboratory, Department of Computer Science, Graduate School of Information Science and Technology, Osaka University
コードクローン抽出ツール:CCShaper概要 CCFinder が検出したコードクローンに含まれるプログラ
ミング言語の構造的なまとまりの部分を抽出コードクローン情報をリファクタリングに用いる場合に便
利CCFinder が検出するコードクローンはトークンの並びであ
り , 必ずしもリファクタリングの適用が容易なまとまりにはなっていない
現在は Java 言語のみに対応抽出するコードクローンの単位は以下の 12 個
宣言:クラス,インターフェース関数:メソッド,コンストラクタ,スタティックイニシャラ
イザ文: do, for, if, switch, synchronized, try, while,
14Software Engineering Laboratory, Department of Computer Science, Graduate School of Information Science and Technology, Osaka University
609: reset();610: grammar = g;611: // Lookup make-switch threshold in the grammar generic options612: if (grammar.hasOption("codeGenMakeSwitchThreshold")) {613: try {614: makeSwitchThreshold = grammar.getIntegerOption("codeGenMakeSwitchThreshold");615: //System.out.println("setting codeGenMakeSwitchThreshold to " + makeSwitchThreshold);616: } catch (NumberFormatException e) {617: tool.error(618: "option 'codeGenMakeSwitchThreshold' must be an integer",619: grammar.getClassName(),620: grammar.getOption("codeGenMakeSwitchThreshold").getLine()621: );622: }623: }624:625: // Lookup bitset-test threshold in the grammar generic options626: if (grammar.hasOption("codeGenBitsetTestThreshold")) {627: try {628: bitsetTestThreshold = grammar.getIntegerOption("codeGenBitsetTestThreshold");
623: }624:625: // Lookup bitset-test threshold in the grammar generic options626: if (grammar.hasOption("codeGenBitsetTestThreshold")) {627: try {628: bitsetTestThreshold = grammar.getIntegerOption("codeGenBitsetTestThreshold");629: //System.out.println("setting codeGenBitsetTestThreshold to " + bitsetTestThreshold);630: } catch (NumberFormatException e) {631: tool.error(632: "option 'codeGenBitsetTestThreshold' must be an integer",633: grammar.getClassName(),634: grammar.getOption("codeGenBitsetTestThreshold").getLine()635: );636: }637: }638:639: // Lookup debug code-gen in the grammar generic options640: if (grammar.hasOption("codeGenDebug")) {641: Token t = grammar.getOption("codeGenDebug");642: if (t.getText().equals("true")) {
コード片1
コード片2
CCFinder が検出するクローン
CCShaper が抽出するクローン
15Software Engineering Laboratory, Department of Computer Science, Graduate School of Information Science and Technology, Osaka University
1527: if ( inputState.guessing==0 ) {1528: t=a.getText();1529: }1530: {1531: _loop84:1532: do {1533: if ((LA(1)==COMMA)) {1534: match(COMMA);1535: id();1536: if ( inputState.guessing==0 ) {1537: t+=","+b.getText();1538: }1539: }
1007: if ( inputState.guessing==0 ) {1008: buf.append(a.getText());1009: } 1010: {1011: _loop144:1012: do {1013: if ((LA(1)==WILDCARD)) {1014: match(WILDCARD);1015: a=id();1016: if ( inputState.guessing==0 ) {1017: buf.append('.'); buf.append(a.getText());1018: }1019: }
コード片3 コード片4
CCFinder が検出するクローンペア
16Software Engineering Laboratory, Department of Computer Science, Graduate School of Information Science and Technology, Osaka University
実験:概要 実験対象はオープンソースソフトウェア Ant
記述言語 : Java 15 バージョンのソースコードを用いた
バージョン番号: 1.1, 1.2, 1.3, 1.4, 1.5, 1.5.1, 1.5.2, 1.5.3, 1.5.4, 1.6.0, 1.6.1, 1.6.2, 1.6.3, 1.6.4, 1.6.5
最も古いバージョン (1.1) からコードクローン検出を行い,検出された全てのコードクローンに対してリファクタリングを試みた
リファクタリングのコストとして以下のものを用いた ソースコード修正と回帰テストに要した時間
リファクタリングの効果として以下のものを用いた CK メトリクス値の変化 総行数の増減 集約箇所の後のバージョンでの修正回数
17Software Engineering Laboratory, Department of Computer Science, Graduate School of Information Science and Technology, Osaka University
実験:バージョン 1.1 に対するリファクタリング コードクローンのリファクタリングを行うために
CCFinder と CCShaper を用いて 50 トークン以上のコードクローンを検出
バージョン 1.1 の規模ソースファイル数: 83総行数: 19,986検出時間は約1分
7 個のクローンセットを検出そのうちの6つが実際にリファクタリングすることができたソースコード修正後,付属のテストケースを用いて回帰テストを行っ
た
その後の修正回数を調査するために バージョン 1.2 ~ 1.6.5 の該当箇所を調査
前のバージョンから修正を加わっているかどうかを diff で調査クローンセットになっているかを CCFinder と CCShaper を用いて
調査
18Software Engineering Laboratory, Department of Computer Science, Graduate School of Information Science and Technology, Osaka University
実験:検出されたコードクローン 以下は検出されたコードクローンの概要である
実際はもっと回帰テストに時間がかかる付属のユニットテストしか行っていない,結合テストなども行
うべき
ID コード片数
単位 分類 時間
S0 2 メソッド 単一クラス内 7 分S1 6 メソッド 単一クラス内 19 分S2 2 メソッド 単一クラス内 -
S3 2 メソッド 単一クラス内 15 分S4 2 If 文 兄弟クラス間 14 分S5 2 メソッド 兄弟クラス間 5 分S6 2 メソッド 関係のないクラ
ス間17 分
19Software Engineering Laboratory, Department of Computer Science, Graduate School of Information Science and Technology, Osaka University
実験:CK メトリクス値の変化 (1/3) S0 の CK メトリクス値の変化
S1 の CK メトリクス値の変化
S3 の CK メトリクス値の変化
クラス名 WMC DIT NOC CBO RFC LCOM
DirectoryScanner 21(+1) 1 0 0 47(+1) 158(+20)
クラス名 WMC DIT NOC CBO RFC LCOM
DirectoryScanner 21(+1) 1 0 0 47(+1) 158(+20)
クラス名 WMC DIT NOC CBO RFC LCOM
Task 17(+1) 1 23 4 24(+6) 98(+16)
$NestedElementHandler 4 2 0 4 14(-3) 0
$TaskHandler 4 2 0 7(-2) 21(-7) 0
リファクタリング前に比べてメトリクス値が悪化
リファクタリング前に比べてメトリクス値が改善
20Software Engineering Laboratory, Department of Computer Science, Graduate School of Information Science and Technology, Osaka University
実験:CK メトリクス値の変化 (2/3) S4 の CK メトリクス値の変化
S5 の CK メトリクス値の変化
S6 の CK メトリクス値の変化クラス名 WMC DIT NOC CBO RFC LCOM
NewClass 2 1 0 2 7 1
JavacOutputStream 4 1 0 2(+1) 10(-1) 0
TaskOutputStream 3 1 0 2(+1) 8(-1) 0
クラス名 WMC DIT NOC CBO RFC LCOM
Javac 23(-1) 3 1 11 93 128(-105)
MatchingTask 16(+1) 2 11 5(+1) 56(+4) 94(+79)
Rmic 17(-1) 3 0 8 66(-2) 98(-17)
クラス名 WMC DIT NOC CBO RFC LCOM
ProjectHelper 15(+2) 1 0 7(+1) 66(+7) 79(+27)
Expand 4 2 0 5 35(-3) 2
Untar 4 2 0 8 36(-3) 2
21Software Engineering Laboratory, Department of Computer Science, Graduate School of Information Science and Technology, Osaka University
実験:CK メトリクス値の変化 (3/3) コードクローンのリファクタリングは,必ずしも CK メトリク
ス値を改善するとは限らない 中には,クローンセット S0 や S1 のようにメトリクス値を悪化
させているだけのリファクタリングも存在した
CK メトリクスを測定するために ckjm を用いた このツールはメトリクス WMC として,単純にそのクラスで定
義されたメソッドの数を用いているWMC は Weigthed Method per Class の略本来は,各メソッドに対して重み付けを行った後,値を足し合わせ
る Extract Method のようにメソッド数が増えるリファクタリングの
場合は,必ず値が悪化してしまう サイクロマチック数などを用いて適切に重み付けをすれば,メ
ソッド数を増やすリファクタリングであっても WMC の改善があるかもしれない
22Software Engineering Laboratory, Department of Computer Science, Graduate School of Information Science and Technology, Osaka University
実験:総行数の変化 下図は各クローンセットのリファクタリング後の総行数の変
化を表す
5 つのリファクタリングで総行数が減っている 多くても 20 行程度しか減っておらず,サイズ面で効果がある
とはいい難い “Extract Class” パターンを適用したリファクタリングは,新し
いクラスを作成したために,リファクタリング前に比べて行数が増えてしまっている
リファクタリング
S0 後 S1 後 S3 後 S4 後 S5 後 S6 後
行数 19,982
(-4)
19,964
(-22)
19,981
(-5)
19981
(-5)
19,962
(-24)
19,990
(+4)
23Software Engineering Laboratory, Department of Computer Science, Graduate School of Information Science and Technology, Osaka University
実験:修正の流れ( 1/5 )(クローンセット S0 , S2 ) クローンセット S0
クローンセット S2
1.1 1.2 1.3 1.4 1.5 1.5.1 1.5.2 1.5.3 1.5.4 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 1.6.5
C0’ C0’’C0
C1 C1’’C1’
1.1 1.2 1.3 1.4 1.5 1.5.1 1.5.2 1.5.3 1.5.4 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 1.6.5
C0’C0’ C0’’C0’’C0C0
C1C1 C1’’C1’’C1’C1’
1.1 1.2 1.3 1.4 1.5 1.5.1 1.5.2 1.5.3 1.5.4 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 1.6.5
C0
C1
C0’
1.1 1.2 1.3 1.4 1.5 1.5.1 1.5.2 1.5.3 1.5.4 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 1.6.5
C0C0
C1C1
C0’C0’
コード片は Cn で表され,修正が加わるたびに Cn’, Cn’’ と変化していく
同一クローンセットに含まれるコード片は長方形で囲まれる
24Software Engineering Laboratory, Department of Computer Science, Graduate School of Information Science and Technology, Osaka University
実験:修正の流れ( 2/5 )(クローンセット S1 )1.1 1.2 1.3 1.4 1.5 1.5.1 1.5.2 1.5.3 1.5.4 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 1.6.5
C0
C1 C1’’’
C2
C3
C4
C5
C2’
C3’
C4’
C5’
C6
C7
C8
C0’
C1’
C2’’
C3’’
C4’’
C5’’
C9
C8’
C9’
C0’’
C1’’
C0’’’
C2’’’
C3’’’
C4’’’
C5’’’
C8’’
C9’’
C7’
1.1 1.2 1.3 1.4 1.5 1.5.1 1.5.2 1.5.3 1.5.4 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 1.6.5
C0C0
C1C1 C1’’’C1’’’
C2C2
C3C3
C4C4
C5C5
C2’C2’
C3’C3’
C4’C4’
C5’C5’
C6C6
C7C7
C8C8
C0’C0’
C1’C1’
C2’’C2’’
C3’’C3’’
C4’’C4’’
C5’’C5’’
C9C9
C8’C8’
C9’C9’
C0’’C0’’
C1’’C1’’
C0’’’C0’’’
C2’’’C2’’’
C3’’’C3’’’
C4’’’C4’’’
C5’’’C5’’’
C8’’C8’’
C9’’C9’’
C7’C7’
25Software Engineering Laboratory, Department of Computer Science, Graduate School of Information Science and Technology, Osaka University
実験:修正の流れ( 3/5 )(クローンセット S3 , S4 ) クローンセット S3
クローンセット S4
1.1 1.2 1.3 1.4 1.5 1.5.1 1.5.2 1.5.3 1.5.4 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 1.6.5
C0
C1
C0’
C1’
C0’’
C1’’ C1’’’
C0’’’ C0’’’’
C1’’’’
1.1 1.2 1.3 1.4 1.5 1.5.1 1.5.2 1.5.3 1.5.4 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 1.6.5
C0C0
C1C1
C0’C0’
C1’C1’
C0’’C0’’
C1’’C1’’ C1’’’C1’’’
C0’’’C0’’’ C0’’’’C0’’’’
C1’’’’C1’’’’
1.1 1.2 1.3 1.4 1.5 1.5.1 1.5.2 1.5.3 1.5.4 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 1.6.5
C0
C1
C0’ C0’’
1.1 1.2 1.3 1.4 1.5 1.5.1 1.5.2 1.5.3 1.5.4 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 1.6.5
C0C0
C1C1
C0’C0’ C0’’C0’’
26Software Engineering Laboratory, Department of Computer Science, Graduate School of Information Science and Technology, Osaka University
実験:修正の流れ( 4/5 )(クローンセット S5 , S6 ) クローンセット S5
クローンセット S6
1.1 1.2 1.3 1.4 1.5 1.5.1 1.5.2 1.5.3 1.5.4 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 1.6.5
C0
C1
C0’
1.1 1.2 1.3 1.4 1.5 1.5.1 1.5.2 1.5.3 1.5.4 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 1.6.5
C0C0
C1C1
C0’C0’
1.1 1.2 1.3 1.4 1.5 1.5.1 1.5.2 1.5.3 1.5.4 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 1.6.5
C0
C1
C0’
1.1 1.2 1.3 1.4 1.5 1.5.1 1.5.2 1.5.3 1.5.4 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 1.6.5
C0C0
C1C1
C0’C0’
27Software Engineering Laboratory, Department of Computer Science, Graduate School of Information Science and Technology, Osaka University
実験:修正の流れ( 5/5 ) リファクタリング箇所の後のバージョンでの修正回数はクロ
ーンセットによってさまざまであった
全てのクローンセットがバージョンをまたいで存在しているわけではなく,各コード片に対して異なる修正が加わった結果,コードクローンでなくなる場合もあった.本実験では7つクローンセットのうちの4つこれらのクローンセットには一度も共通の修正がなかった
一度でも共通の修正が加わった場合は,その後も修正される傾向がある実際に全てのコード片に同様の修正が加わった場合にリファクタ
リングを行うことで,その後の修正回数を減らすことができるのでは?
28Software Engineering Laboratory, Department of Computer Science, Graduate School of Information Science and Technology, Osaka University
考察 リファクタリングが有効であるかどうかは,その効果がコス
トを上回っているかどうかで決まる 例:クローンセット S0
コスト:ソースコード修正と回帰テストに7分を要した効果( CK メトリクス): WMC , RFC , LCOM が悪化効果(修正回数):バージョン 1.5 と 1.6.3 での修正箇所が 2
つから1つに減った 効果とコストの大小関係は一意に決めることができない
本実験で行ったリファクタリングは,基本的かつ汎用的であり,ソースコード修正を行う者のスキルや対象ソフトウェアのドメインを限定するものではない
リミテーション リファクタリングの規模が小さい メトリクス値で調査したのは複雑度の変化のみ
他の面からの評価も必要である
29Software Engineering Laboratory, Department of Computer Science, Graduate School of Information Science and Technology, Osaka University
まとめ コードクローンに対するリファクタリングのコストと効果を調
査した 実験対象は 15 バージョンのソースコードが公開されているオー
プンソースソフトウェア その最初のバージョンに対してリファクタリングを行った
コストの尺度 ソースコード修正と回帰テストに要した時間
効果の尺度 CK メトリクス値の変化 総行数の増減 集約箇所の後のバージョンでの修正回数
こらからの予定 コスト・効果項目を増やす企業ソフトウェアでも実験を行う( + 開発者へのインタビュー)
30Software Engineering Laboratory, Department of Computer Science, Graduate School of Information Science and Technology, Osaka University
31Software Engineering Laboratory, Department of Computer Science, Graduate School of Information Science and Technology, Osaka University
Source files
字句解析
変換処理
トークン列
検出処理
変換後トークン列
クローン情報
出力整形処理
クローンペア位置情報
コードクローン検出ツール : CCFinder検出プロセス
1. static void foo() throws RESyntaxException { 2. String a[] = new String [] { "123,400", "abc", "orange 100" }; 3. org.apache.regexp.RE pat = new org.apache.regexp.RE("[0-9,]+"); 4. int sum = 0; 5. for (int i = 0; i < a.length; ++i) 6. if (pat.match(a[i])) 7. sum += Sample.parseNumber(pat.getParen(0)); 8. System.out.println("sum = " + sum); 9. }10. static void goo(String [] a) throws RESyntaxException {11. RE exp = new RE("[0-9,]+");12. int sum = 0;13. for (int i = 0; i < a.length; ++i)14. if (exp.match(a[i]))15. sum += parseNumber(exp.getParen(0));16. System.out.println("sum = " + sum);17. }
static void foo ( ) { String a
[ ] = new String [ ] { "123,400" ,
"abc" , "orange 100" } ;
int sum = 0
; for ( int i = 0 ; i <
a . length ; ++ i )
sum
+= pat . getParen 0
; System . out . println ( "sum = "
+ sum ) ; }
throws RESyntaxException
Sample . parseNumber (
) )
if pat
. match a [ i ]( ) )
org . apache . regexp
. RE pat = new org . apache . regexp
. RE ( "[0-9,]+" ) ;
static void goo (
) {
String
a [ ]
int sum = 0
; for ( int i = 0 ; i <
a . length ; ++ i )
System . out . println ( "sum = " + sum
) ; }
throws RESyntaxException
if exp
. match a [ i ]( ) )
exp =
new RE ( "[0-9,]+" ) ;
(
RE
sum
+= exp . getParen 0
;
parseNumber ( ) )(
(
(
[ ] = new String [ ] {
} ;
int sum = 0
; for ( int i = 0 ; i <
a . length ; ++ i )
sum
+= pat . getParen 0
; System . out . println ( "sum = "
+ sum ) ; }
Sample . parseNumber (
) )
if pat
. match a [ i ]( ) )
pat = new
RE ( "[0-9,]+" ) ;
static void goo (
) {
String
a [ ]
int sum = 0
; for ( int i = 0 ; i <
a . length ; ++ i )
System . out . println ( "sum = " + sum
) ; }
throws RESyntaxException
if exp
. match a [ i ]( ) )
exp =
new RE ( "[0-9,]+" ) ;
(
RE
sum
+= exp . getParen 0
;
parseNumber ( (
(
(
static void foo ( ) { String athrows RESyntaxException
$
RE
$ . ) )
字句解析
変換処理
トークン列
検出処理
変換後トークン列
クローン情報
出力整形処理
[ ] = new String [ ] {
} ;
int sum = 0
; for ( int i = 0 ; i <
a . length ; ++ i )
sum
+= pat . getParen 0
; System . out . println ( "sum = "
+ sum ) ; }
Sample . parseNumber (
) )
if pat
. match a [ i ]( ) )
pat = new
RE ( "[0-9,]+" ) ;
static void goo (
) {
String
a [ ]
int sum = 0
; for ( int i = 0 ; i <
a . length ; ++ i )
System . out . println ( "sum = " + sum
) ; }
throws RESyntaxException
if exp
. match a [ i ]( ) )
exp =
new RE ( "[0-9,]+" ) ;
(
RE
sum
+= exp . getParen 0
;
parseNumber ( ) )(
(
(
static void foo ( ) { String athrows RESyntaxException
$
RE
$ .
[ ] = [ ] {
} ;
=
; for ( = ; <
. ; ++ )
+= .
; . . (
+ ) ; }
. (
) )
if
. [ ]( ) )
=
( ) ;
static (
) {[ ]
=
; ( = ; <
. ; ++ )
. . ( +
) ; }
throws
if
. [ ]( ) )
=
new ( ) ;
(
+= .
;
( ) )(
(
(
static $ ( ) {throws
$
$ .
$ $ $ $
$ $
$ $
$ $ $ $ $
$ $ $ $
$ $ $ $
$ $ $ $
$ $ $ $ $
$ $ $ $
$ $ $ $
$ $ $ $
$ $ $ $ $
$ $ $ $
$ $ $ $
$ $ $ $
$ $ $ $
$ $ $ $ $
new
forfor
new
[ ] = [ ] {
} ;
=
; for ( = ; <
. ; ++ )
+= .
; . . (
+ ) ; }
. (
) )
if
. [ ]( ) )
=
( ) ;
static (
) {[ ]
=
; ( = ; <
. ; ++ )
. . ( +
) ; }
throws
if
. [ ]( ) )
=
new ( ) ;
(
+= .
;
( ) )(
(
(
static $ ( ) {throws
$
$ .
$ $ $ $
$ $
$ $
$ $ $ $ $
$ $ $ $
$ $ $ $
$ $ $ $
$ $ $ $ $
$ $ $ $
$ $ $ $
$ $ $ $
$ $ $ $ $
$ $ $ $
$ $ $ $
$ $ $ $
$ $ $ $
$ $ $ $ $
字句解析
変換処理
トークン列
検出処理
変換後トークン列
クローン情報
出力整形処理
1. static void foo() throws RESyntaxException { 2. String a[] = new String [] { "123,400", "abc", "orange 100" }; 3. org.apache.regexp.RE pat = new org.apache.regexp.RE("[0-9,]+"); 4. int sum = 0; 5. for (int i = 0; i < a.length; ++i) 6. if (pat.match(a[i])) 7. sum += Sample.parseNumber(pat.getParen(0)); 8. System.out.println("sum = " + sum); 9. }10. static void goo(String [] a) throws RESyntaxException {11. RE exp = new RE("[0-9,]+");12. int sum = 0;13. for (int i = 0; i < a.length; ++i)14. if (exp.match(a[i]))15. sum += parseNumber(exp.getParen(0));16. System.out.println("sum = " + sum);17. }
字句解析
変換処理
トークン列
検出処理
変換後トークン列
クローン情報
出力整形処理
32Software Engineering Laboratory, Department of Computer Science, Graduate School of Information Science and Technology, Osaka University
リファクタリングできなかったクローンセット S2
コード片 C0
コード片 C1
protected void fireTargetStarted(Target target) { BuildEvent event = new BuildEvent(target); for (int i = 0; i < listeners.size(); i++) { BuildListener listener = (BuildListener) listeners.elementAt(i); listener.targetStarted(event); }}
protected void fireTaskStarted(Task task) { BuildEvent event = new BuildEvent(task); for (int i = 0; i < listeners.size(); i++) { BuildListener listener = (BuildListener) listeners.elementAt(i); listener.taskStarted(event); }}
33Software Engineering Laboratory, Department of Computer Science, Graduate School of Information Science and Technology, Osaka University