任意粒度機能モデルコードクローン検出手法のリファクタリング理解への適用の試み...

27
任意粒度機能モデルコードクローン検出手法の リファクタリング理解への適用の試み 神谷 年洋 はこだて未来大学 [email protected] 電子情報通信学会技術研究報告, Vol.115, No.248, pp.41-46 (2015-10-14).

Upload: kamiya-toshihiro

Post on 16-Apr-2017

354 views

Category:

Science


1 download

TRANSCRIPT

Page 1: 任意粒度機能モデルコードクローン検出手法のリファクタリング理解への適用の試み

任意粒度機能モデルコードクローン検出手法の リファクタリング理解への適用の試み

神谷 年洋

はこだて未来大学[email protected]

電子情報通信学会技術研究報告, Vol.115, No.248, pp.41-46 (2015-10-14).

Page 2: 任意粒度機能モデルコードクローン検出手法のリファクタリング理解への適用の試み

任意粒度機能モデルコードクローン検出手法の リファクタリング理解への適用の試み

神谷 年洋

はこだて未来大学[email protected]

島根大学大学院総合理工学研究科

[email protected]

Page 3: 任意粒度機能モデルコードクローン検出手法のリファクタリング理解への適用の試み

(注)今回の検出手法は(2013年5月, 同7月のSIGSSで発表)とはアルゴリズム/データ構造が異なる。2015年1月発表のコード検索手法に近い。

あらすじ

● 目的: リファクタリングの分析

● 背景: AGMクローン– 動的解析により、実行トレースが類似するコード断片を検出– 検出した類似コード断片を手続きの呼び出し関係のグラフとして

視覚化

● アプローチ: リファクタリング検出に向けた拡張– 複数のリビジョンの間での類似を検出– リビジョン間の類似と差異を視覚化

● 実験– オープンソースプロダクトのstackitを対象とした予備的な実験

Page 4: 任意粒度機能モデルコードクローン検出手法のリファクタリング理解への適用の試み

ソフトウェアの変更を理解する

● ソフトウェアはさまざまな目的で変更される– 機能拡張– 不具合の修正– リファクタリング(後述)

● ソフトウェアの変更の履歴を知る → 保守上の問題を理解する

● 変更履歴を分析/利用する研究が行われている– リスク、コスト、品質– テスト– 変更の粒度(バージョン管理システムによって記録された「変更」

⇔ 人間がひとつの「変更」だと思うもの)

Page 5: 任意粒度機能モデルコードクローン検出手法のリファクタリング理解への適用の試み

リファクタリングとは?

● Eclipseのリファクタリングメニュー?– メソッドの名前を変更 → そのメソッドを呼び出している箇所も名

前が変わったメソッドを呼び出すように修正される– メソッドの一部を取り出した新しいメソッドを定義(プルアップ)→

元のコードは新しく作られたメソッドの呼び出しに修正される

● 一般にはソフトウェアの外部の振る舞いを保ったまま内部の構造を改善する修正のことを指す

● コードを「健康」に保つ– 修正しやすく、理解しやすく、バグが見つかりやすく

Page 6: 任意粒度機能モデルコードクローン検出手法のリファクタリング理解への適用の試み

リファクタリングの特定、理解

● リファクタリングをその他の種類の変更と区別したい– その他の種類の変更と同時にされることも– 開発者の記述(コミットログ)はときに曖昧

● 「Refactoring + PEP8 compliance」「Add entry points and deletes shell」「Adding API key, fixing stderr redirect」「 Removing embarrassing past script」

● リファクタリングを区別することで– テスト: リグレッションの判断基準(修正前後で同じテストが通る

べき?)– ソフトウェアの理解: アーキテクチャや構造の問題の切り分け

Page 7: 任意粒度機能モデルコードクローン検出手法のリファクタリング理解への適用の試み

コードクローンとは?

● 「コードクローン」「重複コード」「コピペ」– 「重複したロジックは修正が難しい」

● 定義: 互いに類似したコード断片の集合

● 手法: コードクローン検出手法、分析手法、管理手法– 「保守上の問題になるコードクローンはどんなもの?」

● 応用: リファクタリング、コードの剽窃の検知(著作権管理)

コピペ

バグ発見,修正

修正したはずのバグが再現

Page 8: 任意粒度機能モデルコードクローン検出手法のリファクタリング理解への適用の試み

AGMクローン検出

● 動的解析を用いたコードクローン検出手法

● 概略– 対象となるプログラムを実行して実行トレースを取得し、– 実行トレース内の類似した部分列を特定し、

● 実行トレースを手続き呼び出しの列とみなす● 呼び出している手続きの集合の類似性

– 特定した部分列に対応するソースコード内のコード断片を求めて、コードクローンとして出力する

● 特徴: 検出されるコードクローンはソースファイル中で必ずしも連続していない– (複数の手続きにまたがっていることがある)

任意粒度機能モデル 動機「ソースコードが多少書き換えられてもコードクローンを検出したい」

Page 9: 任意粒度機能モデルコードクローン検出手法のリファクタリング理解への適用の試み

AGMクローン検出処理のステップ

(1)紐付き風船(SB)の生成– 紐付き風船とは、実行トレースの部分列とそのソースコード内で

の位置を表現するためのデータ構造– 詳細は後述

(2)類似SB集合の特定

(3)冗長なSBの除去

Page 10: 任意粒度機能モデルコードクローン検出手法のリファクタリング理解への適用の試み

(1)SBの生成

※ 説明の都合上、コールツリーを使っているかのように話しますが、実装ではコールツリーではなく実行トレースを利用します

main()

os.listdir()print_extensions_w_for_stmt()

print_extensions_w_map_func()

os.path.splitext() print str.join()get_extensions() print

map()

lambda() at line 8

os.path.splitext()

Page 11: 任意粒度機能モデルコードクローン検出手法のリファクタリング理解への適用の試み

(1)SBの生成 (つづき)

main()

os.listdir()print_extensions_w_for_stmt()

print_extensions_w_map_func()

os.path.splitext() print str.join()get_extensions() print

map()

lambda() at line 8

os.path.splitext()

print_extensions_w_map_func()

main()

get_extensions(),map(),lambda() at line 8,os.path.splitext(),print,str.join()

それぞれの節点について その節点からコールツリーの

根に向かうパスを「紐」とし、

その節点から(直接あるいは間接的に)呼び出される節点のラベルの集合を「風船」とする

Page 12: 任意粒度機能モデルコードクローン検出手法のリファクタリング理解への適用の試み

(2)類似SB集合の特定

● 類似した風船部分を特定(頻出アイテム集合を求めるアルゴリズムにより)

print_extensions_w_map_func()

main()

get_extensions(),map(),lambda() at line 8,os.path.splitext(),print,str.join()

print_extensions_w_for_stmt()

main()

os.path.splitext(),print

main()

get_extensions(),map(),lambda() at line 8,os.listdir(),os.path.splitext(),print,print_extensions_w_for_stmt(),print_extensions_w_map_func(),str.join()

{ os.path.split(), print }

{ get_extensions(), map(), lambda() at line 8, os.path.split(), print, str.join() }

Page 13: 任意粒度機能モデルコードクローン検出手法のリファクタリング理解への適用の試み

(3)冗長なSB集合の除去

● ソースコード中の同じ場所から(ループの繰り返しのたびに)生成されるSB– → 紐が同じ

● 呼びだされている手続き(callee)のSBと呼び出している手続き(caller)のSB– → calleeの紐 ⊃ callerの紐

print_extensions_w_map_func()

main()

get_extensions(),map(),lambda() at line 8,os.path.splitext(),print,str.join()

print_extensions_w_for_stmt()

main()

os.path.splitext(),print

main()

get_extensions(),map(),lambda() at line 8,os.listdir(),os.path.splitext(),print,print_extensions_w_for_stmt(),print_extensions_w_map_func(),str.join()

{ os.path.split(), print }

Page 14: 任意粒度機能モデルコードクローン検出手法のリファクタリング理解への適用の試み

AGMクローンの視覚化

● 検出された類似SBの集合のそれぞれについて– 基準節点を根とするコールツリー

の部分木を求める– ラベルが同じ節点をまとめる– 基準節点▶ 単一の矩形で囲う

→ コードクローンに相当するコード断片を含む手続き

– 風船に相当する節点▶ 灰色で表示

→ それらコード断片の共通点(共通して呼び出す手続き)

– 上記以外の節点▶

→ それらコード断片の間の差異

print_extensions_w_for_stmt()

print_extensions_w_map_func()

print

str.join()get_extensions()

map()

lambda() at line 8

os.path.splitext()

共通点と差異の分析のための

Page 15: 任意粒度機能モデルコードクローン検出手法のリファクタリング理解への適用の試み

リファクタリング分析

● 本研究で検出できる(したい)リファクタリング

– コード断片がある手続きpから別の手続きqに移動。p内の、そのコード断片があった部分はqの呼び出しが書かれる

– プログラムを実行すると、元のプログラムとだいたい同じタイミングでそのコード断片が実行される

● リファクタリングカタログでは– {Extract,Inline,Move,Pull up} Method, Rename Methodなど

def p():

p()

旧 新

Page 16: 任意粒度機能モデルコードクローン検出手法のリファクタリング理解への適用の試み

手法の拡張

検出手法

● 新旧のソースコードの間のコードクローンを検出する– SBの紐や風船のラベルには新旧を表すマークを付加する

● クローンを検出した後に「(4) リファクタリングの特定」を行う– コードクローンに含まれる新旧SBを比較したとき➢ 紐が同じ新SBと旧SBのペアがある → 移動していないコード断

片(Cunr)と判断

● 紐が同じ ⇔ エントリポイントから全く同じ呼び出し階層でそのコード断片に到達する

➢ そのようなペアがない → 移動したコード断片(Crfd)と判断

Page 17: 任意粒度機能モデルコードクローン検出手法のリファクタリング理解への適用の試み

予備的な実験: セットアップ

● 実装: Pythonで記述(実行トレース取得ツール 487行 + AGMクローン検出および視覚化ツール 2894行)

● 検出パラーメータ– 基準節点から手続き呼び出しの深さが 4 以内– 共有する手続きが5個以上のコードクローン

● 対象プログラム: stackit (https://github.com/lukasschwab/stackit)– CLI。質問をタイプすると開発者向け QA サイトである

stackoverflowで検索を行い,検索結果のテキストを表示する● 外部の振る舞いの等価性の判定: 同じ質問を入力したときの検索結果のテキストが同じか

– ソースコードの総行数は最新版で 245 行

Page 18: 任意粒度機能モデルコードクローン検出手法のリファクタリング理解への適用の試み

実験に利用したPCとパフォーマンス

● 実験用PC – CPU Intel Core i3-4010U 1.70GHz, RAM 16GiB, SSD

● 検出ツールの実行

– 実行トレースを入力とし Cunr と Crfd を得る

– 経過時間は 86 秒から 136 秒– ピークメモリ(peak resident memory)利用量は 187MiBから 239MiB

Page 19: 任意粒度機能モデルコードクローン検出手法のリファクタリング理解への適用の試み

RQ

● リファクタリング前後のプログラムに AGM クローン検出・視覚化を適用することで

● (RQ1) リファクタリングの特定が可能か– あるバージョン(リビジョン)の修正にリファクタリングが含まれて

いるかを数値(Crfd, Cunr)で判断できるか

● (RQ2) リファクタリングによる構造変化の分析が可能か– リファクタリングの内容を視覚化結果から読み取れるか

Page 20: 任意粒度機能モデルコードクローン検出手法のリファクタリング理解への適用の試み

実験の手順

● リファクタリングに相当するリビジョンを特定する– ソースコードが変更されていてプログラムの出力が変化していな

いリビジョンを特定

● 特定した各リビジョンに手法を適用– 視覚化したものから変更内容を読み取る– 手作業でソースコードを調べた結果と突き合わせる

Page 21: 任意粒度機能モデルコードクローン検出手法のリファクタリング理解への適用の試み

リファクタリング相当のリビジョンを特定

● 対象プロダクト(stackit)の全リビジョン(176個)– → (A) masterブランチのリビジョンのみ(104個)– → (B)ソースファイル(*.py)を修正しているもの(50個)– → 削除された行数が多いもの上位10個

● → そのリビジョンと(B)の系列で直前のリビジョンを実行して出力が変化しなかったもの(6個)を適用対象とする– @~8, @~15, @~34, @~66, @~74, @~78

Page 22: 任意粒度機能モデルコードクローン検出手法のリファクタリング理解への適用の試み
Page 23: 任意粒度機能モデルコードクローン検出手法のリファクタリング理解への適用の試み

特定したリビジョンに手法を適用

● CunrとCrefを求め、Crefが空ではないならリファクタリングと判定– 5/6は正しく判断– @~34はデットコードの削除

● 実行されないのでトレースに含まれない

Page 24: 任意粒度機能モデルコードクローン検出手法のリファクタリング理解への適用の試み

視覚化(@~15)

● @~15(と@~16)に適用– @~15の接点 「1.*」– @~16の接点 「2.*」

1.click.types//convert_type1.click.termui//_build_prompt

1.stackexchange.core/StackExchangeResultset/__iter__1.stackexchange.core/StackExchangeResultset/next 1.click.termui//prompt

1.click.termui//prompt_func

1.click.utils//echo

agm.trace.hook/In/readline

agm.trace.hook/Out/write

1.click.termui//style

2.σ//focusQuestion 2.σ//promptUser

1.σ//focus_question

2.σ//printQuestion

bs4.element/Tag/prettifyhtml2text/HTML2Text/handlebs4.element/BeautifulSoup/find

requests.api//getbs4.element/Tag/__getattr__requests.models/Response/text

bs4/BeautifulSoup/__init__

1.σ//print_question

1.σ//_search

requests.packages.urllib3.response/HTTPResponse/closedstackexchange/Site/search_advanced

2.σ//searchTerm

warnings//_show_warning(a)

(b)

(c) (d)

(A)

(B)

(D)

(E)

略記: σ → stackit.stackit_core

printQuestion → print_question … (b)focusQuestion →focus_question … (c)promptUser → click.termui.prompt … (d)

Page 25: 任意粒度機能モデルコードクローン検出手法のリファクタリング理解への適用の試み

まとめ

● 実行トレースからAGMクローンを検出する手法– 紐付き風船データ構造– 頻出アイテム集合

● AGMクローンの視覚化手法– 同一部分と異なる点を視覚化

● リファクタリング分析への応用– 異なったリビジョンの間でAGMクローンを検出

● 予備的な実験

Page 26: 任意粒度機能モデルコードクローン検出手法のリファクタリング理解への適用の試み

▶(飽和)頻出アイテム集合とは?

● 頻出アイテム集合(Frequent Item Set)– 例: 「スーパーの客のレシートのデータから、同時に購入される商

品の組を見つけたい」– 多くの集合(トランザクションと呼ぶ。例では「レシート」)に共通し

て含まれる要素(アイテムと呼ぶ。例では「商品」)

Apple

Cupcake

Donut

Cupcake

Donut

Eclair

Apple

Banana

Cupcake

Donut

Apple

Banana

Donut

A

CD

CD

E

ABCD

AB

D

A

CD

CD

E

ABCD

AB

D

{ Apple, Donut }

{ Cupcake, Donut }

Page 27: 任意粒度機能モデルコードクローン検出手法のリファクタリング理解への適用の試み

▶(飽和)頻出アイテム集合とは? (つづき)

● 飽和頻出アイテム集合(Closed Frequent Item Set)– サポート: そのアイテム集合を含むトランザクションの数– 飽和: そのアイテム集合にアイテムを足したものは、そのアイテム

集合よりもサポートが小さい

● 本研究では– あるコード断片から(直接的、間接的に)呼び出される手続きをアイテム

– 呼び出す手続きが共通しているコード断片を求めるのに利用

A

CD

CD

E

ABCD

AB

D

{ Apple, Banana }は飽和頻出アイテム集合ではない←Donutを足してもサポートが減らない