Download presentation
Presentation is loading. Please wait.
1
ソースコード差分検出を用いた 探索的手法による impure リファクタリングの検出
○堤祥吾1 吉田則裕2 崔恩瀞3 井上克郎1 1大阪大学 2名古屋大学 3奈良先端科学技術大学院大学
2
リファクタリング ソフトウェアの外部的振る舞いを保ったまま内部の構造を改善していく作業[1] コードの保守性や読みやすさを高める目的
[1] M. Fowler,“Refactoring:Improving the Design of Existing Code.” Addison Wesley,1999.
3
メソッド引き上げリファクタリングにより,
リファクタリング例 abstract class Customer{ … } class RegularCustomer extends Customer{ int calcTax(int amount){ … } } class PremiumCustomer abstract class Customer{ int calcTax(int amount){ … } } class RegularCustomer extends Customer{ … } class PremiumCustomer メソッド引き上げリファクタリングにより, コードがまとまり保守性・可読性が高まる
4
Impureリファクタリング バージョン間,コミット間の変更の際 複数のリファクタリングが同時適用されている
リファクタリング,非リファクタリング変更が混在して適用されている
5
Impureリファクタリング例 メソッド引き上げ(青枠)に加え, 非リファクタリング変更(赤)が行われた
abstract class Customer{ … } class RegularCustomer extends Customer{ int calcTax(int amount){ … } } class PremiumCustomer abstract class Customer{ double calcTax(int amount){ … } } class RegularCustomer extends Customer{ … } class PremiumCustomer メソッド引き上げ(青枠)に加え, 非リファクタリング変更(赤)が行われた
6
リファクタリング検出必要性 リファクタリングがソースコードの品質に与える影響に関心が持たれている
リファクタリングに関する調査を行うために,ソースコードから自動的にリファクタリングを検出するためのツールが必要となる … void func(){ a = calc(); } int calc(){ … void func(){ a = 3 + 5; } メソッド抽出 フィールド引き上げ …
7
研究背景 複数のリファクタリングや非リファクタリングが同時に適用されている場合,現状では検出が難しい
探索的手法を用いることで,複数のリファクタリングが適用されていても検出する研究がされている[2] [2] Hayashi, et al,“Search-Based Refactoring Detection from Source Code Revisions”, IEICE Transactions on Information and Systems, 2010.
8
先行研究の手法 コミットAからコミットBの間に行われたリファクタリングを検出したい
メソッド抽出 リネーム 定数置き換え コミットB リネーム その他 リファクタリング フィールド 引き上げ …
9
先行研究[2]の課題 先行研究では,複数のリファクタリング操作列を探索によって検出する
非リファクタリングの変更が混在する場合にはうまく検出されない(impureリファクタリング) ソースコード差分検出を用いることにより,impureリファクタリングも検出できるようにする [2] Hayashi, et al, “Search-Based Refactoring Detection from Source Code Revisions”, IEICE Transactions on Information and Systems, 2010.
10
本手法の特徴 探索的リファクタリングを用いることにより,複数のリファクタリングが重ねて適用されていても検出が可能
非リファクタリング変更が行われていても検出が可能であり,リファクタリングと区別して検出することができる
11
提案手法の手順 テストによる 探索的 動作確認 リファクタリング検出 コミット 取り出し 非リファクタリング差分の検出 旧 実行結果の
3 2 コミット 取り出し 旧 1 実行結果の 一致を確認 旧 非リファクタリング差分の検出 4 新 新 … a = 3 – a a = b + 5 * a 最終状態 新版コード 出力
12
Step 2(1/3):探索の手順 初期状態 𝑠 0 (旧版コード)を,新版コード 𝑠 𝑛 との差分(評価値)とともにキューに入れる
キューから評価値最良の状態を取り出す( 𝑠 𝑖 とする) 𝑠 𝑖 と 𝑠 𝑛 とを比較し,適用された可能性のあるリファクタリングを列挙 列挙されたリファクタリングを 𝑠 𝑖 に適用し,評価値を計算し,それぞれキューに入れる 終了条件を満たせば評価値最良の状態 𝑠 𝑡 を探索結果とし,そうでなければ2へ 0.85 メソッド抽出 フィールド引上 … 0.90 0.65 0.60
13
評価関数𝐹( 𝑠 𝑖 ) := 𝑗=1 𝑛 𝑑 𝑗 𝑗=1 𝑛 max( 𝑡 𝐴𝑗 , 𝑡 𝐵𝑗 )
Step 2(2/3):探索順を定める 評価関数 𝑠 𝑖 と 𝑠 𝑛 との編集距離を𝑑 比較はメソッドごとに行い,比較するメソッドのそれぞれのトークン数を 𝑡 𝐴 , 𝑡 𝐵 とする 各ファイルについて求めるので,それぞれ( 𝑑 1 , 𝑑 2 ,…, 𝑑 𝑛 ), ( 𝑡 𝐴1 , 𝑡 𝐵1 , …,[ 𝑡 𝐴𝑛 , 𝑡 𝐵𝑛 ])とする 評価関数𝐹( 𝑠 𝑖 ) := 𝑗=1 𝑛 𝑑 𝑗 𝑗=1 𝑛 max( 𝑡 𝐴𝑗 , 𝑡 𝐵𝑗 ) 𝑡 𝐴 𝑗 + 𝑡 𝐵 𝑗 論文ではmaxとなっているが誤りで, 正しくは和を用いている
14
Step 2(3/3):評価関数の例 𝐹( 𝑠 𝑖 ) := 0+7 8+8+18+13 ≒ 0.27 A B メソッド名 𝒕 𝑨 𝒕 𝑩
abstract class Customer{ abstract int calc(int value); int calcTax(int amount){ return (int)(amount * 1.08); } abstract class Customer{ abstract int calc(int value); int double calcTax(int amount){ return (int)(amount * 1.08); } メソッド名 𝒕 𝑨 𝒕 𝑩 編集距離d calc 8 calcTax 18 13 7 𝐹( 𝑠 𝑖 ) := ≒ 0.27
15
Step 3:テストによる動作確認 ツールがリファクタリングを正しく適用した場合は動作を変更しない
しかし,適切なコード変換が行われなかった場合はその限りではない 探索段階で正しくリファクタリングを適用できたかを確認する必要がある 𝑠 0 と 𝑠 𝑡 のテスト結果を比較する
16
Step 4(1/2):非リファクタリング差分検出
探索ではリファクタリング操作の適用しか行わない 非リファクタリング変更が存在する場合,探索後のコード 𝑠 𝑡 と新版コード 𝑠 𝑛 に必ず差分が生じる 非リファクタリング差分 メソッドの引き上げ メソッド抽出 旧版コード 新版コード 状態1 状態3
17
Step 4(2/2):差分の求め方 𝑠 𝑡 と 𝑠 𝑛 との差分を求め,それを非リファクタリング差分とする
トークン列同士の編集距離を求める abstract class Customer{ abstract int calc(int value); int calcTax(int amount){ return (int)(amount * 1.08); } abstract class Customer{ abstract int calc(int value); int double calcTax(int amount){ return (int)(amount * 1.08); } doubleの挿入 int, カッコの削除 により,編集距離は7
18
適用例 公開リファクタリングデータベース[3]から,impureリファクタリングが含まれるコミットを目視で選択
Apache Xerces を除き,それぞれ別のコミットとなる リファクタリングが含まれるファイルに対し,本手法を適用した [3] G. Bavota et al. “An Experimental investigation on the Innate Relationship between Quality and Refactoring.” Journal of Systems and Software, 2015.
19
各適用対象の情報 プロジェクト クラス 旧クラス トークン数 追加 削除 Apache Xerces DocumentImpl 3391 9
83 CoreDocumentImpl 3464 631 1 Apache Ant Launcher 1170 253 108 ComponentHelper 3790 432 343 AntTypeDefinition 1165 268 113 Main 2607 453 368 Project 5155 222 34 TarEntry 1691 229 192
20
探索例(DocumentImpl) 色 対象メンバ リファクタリングの 種類 黄色 userData フィールド引き上げ 緑色
旧版コード 1 3 色 対象メンバ リファクタリングの 種類 黄色 userData フィールド引き上げ 緑色 setUserData メソッド 引き上げ 青色 getUserData 2 13 8 12 4 9 5 11 7 6 10
21
差分検出段階 探索段階にてリファクタリング検出後,差分検出を行った 探索直後cloneNode 差分適用後cloneNode
public Node cloneNode(boolean deep) { DocumentImpl newdoc = new DocumentImpl(); cloneNode(newdoc, deep); // experimental newdoc.mutationEvents = mutationEvents; return newdoc; } // cloneNode(boolean):Node public Node cloneNode(boolean deep) { CoreDocumentImpl newdoc = new CoreDocumentImpl(); callUserDataHandlers(this, newdoc, UserDataHandler.NODE_CLONED); cloneNode(newdoc, deep); newdoc.mutationEvents = mutationEvents; return newdoc; } // cloneNode(boolean):Node
22
検出されたリファクタリング リファクタリング検出段階において検出された数を表に示す All – 実際に含まれる数 Find – 検出された数
クラス All Find DocumentImpl (CoreDocumentImpl) 3 Launcher 4 ComponentHelper AntTypeDefinition 2 Main 1 Project TarEntry リファクタリング検出段階において検出された数を表に示す All – 実際に含まれる数 Find – 検出された数 リファクタリングの誤検出はなかった 検出されなかったリファクタリングはいくつか見られた
23
検出できなかった例 抽出する内容が例外処理を必要とするものであったが,編集距離だけでは追加できず
private Object createAndSet(...) { try { java.lang.reflect.Constructor ctor = null; boolean noArg = false; try {...} catch (...) { ... } return o; } catch (...) { private Object createAndSet(...) { try { Object o = innerCreateAndSet(c, project); return o; } catch (...) { ... } public Object innerCreateAndSet(...) throws ...Exception, { Constructor ctor = null; boolean noArg = false; try {...} catch (...) { 旧AntTypeDefinition.java 抽出する内容が例外処理を必要とするものであったが,編集距離だけでは追加できず 新AntTypeDefinition.java 例外処理を検知し追加する処理が必要
24
検出できた例 いくつかの非リファクタリング変更が加わりつつも, 子クラスから親クラスへのメソッド引き上げを検出した
public Node cloneNode(boolean deep) { DocumentImpl newdoc = new DocumentImpl(); cloneNode(newdoc, deep); // experimental newdoc.mutationEvents = mutationEvents; return newdoc; } // cloneNode(boolean):Node public Node cloneNode(boolean deep) { CoreDocumentImpl newdoc = new CoreDocumentImpl(); callUserDataHandlers(this, newdoc, UserDataHandler.NODE_CLONED); cloneNode(newdoc, deep); return newdoc; } // cloneNode(boolean):Node 新CoreDocumentImpl.java 旧DocumentImpl.java いくつかの非リファクタリング変更が加わりつつも, 子クラスから親クラスへのメソッド引き上げを検出した
25
考察 すべて正しくリファクタリングされたのは8つのファイルのうち4つであった
そうでないファイルについては,いくつか正しく検出できないリファクタリングが存在した 検出できない場合 例外処理を含む場合 ブロック・行をまたぐ機能抽出があった場合
26
まとめ 探索的手法と,ソースコード差分検出を組み合わせた手法を提案した 既存手法では難しかったimpureリファクタリング検出を可能とした
今後の課題 検出精度の向上 検出可能なリファクタリングの種類を増やす 探索範囲となるファイルやクラスを増やす
Similar presentations
© 2024 slidesplayer.net Inc.
All rights reserved.