機能的関心事を抽出するためのプログラムスライシン

ソフトウェアメトリクスと
メソッド内の構造を用いた
リファクタリング支援手法の提案
大阪大学
M2 三宅達也
Department of Computer Science,
Graduate School of Information Science & Technology,
Osaka University
研究概要

リファクタリングプロセスの一部を自動化する手
法の提案
 ソフトウェアメトリクス
 メソッド内の構造
 変数の宣言、参照位置
⇒ 効率的かつ適切なリファクタリングを支援
SIGSS
Department of Computer Science, Graduate School of Information Science & Technology, Osaka University
2
発表の流れ
背景
 提案手法
 評価実験
 関連研究
 まとめと今後の課題

SIGSS
Department of Computer Science, Graduate School of Information Science & Technology, Osaka University
3
リファクタリング

リファクタリングとは?
 ソフトウェアの外部的振る舞いを保ったまま,内部
の構造を改善する技術

リファクタリングの効果は?
 ソフトウェアの保守性が増し,後の保守作業効率が
向上する
SIGSS
Department of Computer Science, Graduate School of Information Science & Technology, Osaka University
4
リファクタリングプロセス

Step 1: リファクタリングを適用すべきコード(Bad
Smell)を特定
 長すぎるメソッド
 複雑な制御構造

Step 2: どのようなリファクタリングを適用すべきかを
決定
 既存の研究で様々なリファクタリングパターンが提案
Step 3: 適用するリファクタリングの効果を予測
 Step 4: プログラムの修正
 Step 5: 修正されたプログラムが正しく動作するかテス
ト

SIGSS
Department of Computer Science, Graduate School of Information Science & Technology, Osaka University
5
リファクタリングの問題点と本研究の目的

手動リファクタリングの問題点
 Bad
Smellの特定や適用すべきリファクタリングパ
ターンの決定には豊富な知識と経験が必要
 時間と手間が大きい
 誤りが混入しやすい

研究目的
 リファクタリングプロセスの一部を自動化し、リファク
タリングのコストを削減するための手法を提案
SIGSS
Department of Computer Science, Graduate School of Information Science & Technology, Osaka University
6
提案手法の概要

リファクタリングすべきコードを検出
 検出対象
: メソッド内のコードの一部
 複雑度メトリクスの高い部分
 同一の機能に関連する範囲を識別

適用すべきリファクタリングパターンを特定
 変数やメソッドの利用状況から特定
 Extract Method
 Move Method
 Pull

Up Method
リファクタリングの効果を測定
 複雑度メトリクスの変化で評価
SIGSS
Department of Computer Science, Graduate School of Information Science & Technology, Osaka University
7
メソッド抽出リファクタリング

メソッドの一部を新しいメソッドとして抽出
 対象


長すぎるメソッド
複雑な制御構造をもつメソッド
 効果




再利用性の向上
適切な命名を行うことで内部の処理の可読性が向上
拡張性の向上
普遍的で頻繁に行われるリファクタリングパターン
⇒自動化の効果が大きい
SIGSS
Department of Computer Science, Graduate School of Information Science & Technology, Osaka University
8
提案手法の概要

リファクタリングすべきコードを検出
 検出対象
: メソッド内のコードの一部
 複雑度メトリクスの高い部分
 同一の機能に関連する範囲を識別

適用すべきリファクタリングパターンを特定
 変数やメソッドの利用状況から特定
 Extract Method
 Move Method
 Pull

Up Method
リファクタリングの効果を測定
 複雑度メトリクスの変化で評価
SIGSS
Department of Computer Science, Graduate School of Information Science & Technology, Osaka University
9
複雑度メトリクスを用いたBad Smellの検出

メソッド単位だけでなく,ブロック分単位で計測
 メトリクス値の悪いブロック分を検出

複雑度を測る際に利用するメトリクス
 サイクロマチック数


値が大きいほど制御構造が複雑
制御文の条件式の数 + 1
 LOC(Lines

Of Code)
メソッド内の占有率
 LVA(Local
Variable Availability)
使用されている変数の 数
LVA 
使用可能な変数の数
SIGSS
Department of Computer Science, Graduate School of Information Science & Technology, Osaka University
10
ローカル変数のカプセル化


他クラスで使用しない属
性を隠蔽することによって
保守性を向上

メソッドの場合も、使用しな
いローカル変数を隠蔽すれ
ば保守性の向上が見込める

フィールドをprivate宣言


必要なフィールドに対しての
みアクセサメソッドを作成

フィールドのカプセル化

メソッドの一部を新規メソッドと
して抽出
必要なローカル変数のみ引数
や返り値を利用してアクセス
ローカル変数のカプセル化
⇒ 使用しない変数へのアクセスを制限
SIGSS
Department of Computer Science, Graduate School of Information Science & Technology, Osaka University
11
ローカル変数のカプセル化の例
int drawText(Graphics g, int x, int y, int p0, int p1) {
int returnVal = super.drawText(g, x, y, p0, p1);
String token = null;
int toknePos = p0;
String buffer = getDocument.getText(p0, p1);
LangHighlight lang = getLangHighlight();
StringTokenizer tokens = null;
if(lang== LangHighlight.JAVA)
toknes = new StringTokenizer(buffer, “…”, true);
else if(lang == LangHighlight.COBOL)
tokens = new StringTokenizer(buffer, “…”, true);
else
tokens = new StringTokenizer(buffer, “…”, true);
可視変数数:10,
使用変数数:3
・
(省略)
・
return returnVal;
}
int drawText(Graphics g, int x, int y, int p0, int p1) {
int returnVal = super.drawText(g, x, y, p0, p1);
String token = null;
int toknePos = p0;
String buffer = getDocument.getText(p0, p1);
StringTokenizer tokens = getTokens(buffer);
・
(省略)
drawText内の変数に
drawText内の変数は
返り値を利用して代入
引数として参照
・
return returnVal;
}
メソッドdrawText内で可視な変数の数: 9
StringTokenizer getTokens(String buffer) {
LangHighlight lang = getLangHighlight();
StringTokenizer tokens;
if(lang== LangHighlight.JAVA)
toknes = new StringTokenizer(buffer, “…”, true);
else if(lang == LangHighlight.COBOL)
tokens = new StringTokenizer(buffer, “…”, true);
else
tokens = new StringTokenizer(buffer, “…”, true);
メソッドdrawText内で可視な変数の数: 10
return tokens;
可視変数数:3, 使用変数数:3
(可視であった変数の7/10が不可視)
}
SIGSS
Department of Computer Science, Graduate School of Information Science & Technology, Osaka University
12
提案手法の概要

リファクタリングすべきコードを検出
 検出対象
: メソッド内のコードの一部
 複雑度メトリクスの高い部分
 同一の機能に関連する範囲を識別

適用すべきリファクタリングパターンを特定
 変数やメソッドの利用状況から特定
 Extract Method
 Move Method
 Pull

Up Method
リファクタリングの効果を測定
 複雑度メトリクスの変化で評価
SIGSS
Department of Computer Science, Graduate School of Information Science & Technology, Osaka University
13
変数を用いた機能の抽象化

メソッドの機能:コード内に現れる変数の値を決
定する計算
 コード内の特定の機能はその機能に対応する変数
で表すことができる[1]
⇒メソッドMの機能をF(M)とすると
F ( M )  {v1, v 2, v3 vn  1, vn}
(vi : M内で使用されている変 数)
[1]丸山.基本ブロックスライシングを用いたメソッド抽出リファクタリング.
SIGSS
情報処理学会論文誌43(6):1625-1637,
Jun 2002.
Department of Computer Science, Graduate School of Information Science & Technology, Osaka University
14
変数を用いた機能の抽象化例
void METHOD() { F ( M )  {v1, v2, v3, v4, v5}
VAR v1, v2, v3;
F ( B1)  F ( M )
……………………………
BLOCK1 {
F ( B1)  {v1, v2, v4, v5}
VAR v4,v5;
……………………………
F ( B2)  F ( B1)
BLOCK2 {
v4 = v1 + v2;
F ( B2)  {v1, v2, v4}
}
……………………………
BLOCK3 {
v5 = v1 + 4;
F ( B3)  {v1, v4, v5}
}
v5 = v1 + v2
F ( B3)  F ( B1)
}
……………………………
}
SIGSS
Department of Computer Science, Graduate School of Information Science & Technology, Osaka University
15
抽象化された2つの機能の類似度

共通要素が小さいほうの機能を
占める割合
共通要素の数
| F1  F 2 |
Sim ilarity( F 1, F 2) 
Min(| F 1 |, | F 2 |)
小さいほうの機能の要素数

類似度が高いとき2つの機能は
同一の機能である可能性が高い
 1つのメソッドにまとめるべき
F
FF111
{
{{vvv11,,1,vvv222,,,vvv33,,3,vvv444,,,vvv55}
}5}
2  {v 3, v 4, v 5}
FFF22
{{vv3,5,vv46,,vv5,7,vv6}8}
F
2  {v 3, v 4, v 5}
F 11 

FF
F
1
2 
F{2 v3,{vv45,}v5}
Similarity
( 1F,1,F
1, F 2 )  1
Similarity
Similarity
((FF
F22))00..75
25
SIGSS
Department of Computer Science, Graduate School of Information Science & Technology, Osaka University
16
垂直の関係と水平の関係とは
public void sample ( ) {
int i = 0;
String str;
while( hoge() ) {
str = “string”;
if( jar( I ) ) {
make(str);
}
foo(i);
for( int j = 0; j < I ; j++) {
sam( i );
if( log ) {
System.out.println(i);
}
}
}
・
while( ) {
bar(i);
make(str);
}
}
sample ( )
while
if
while
for
垂直の関係
水平の関係
if
SIGSS
Department of Computer Science, Graduate School of Information Science & Technology, Osaka University
17
ブロック文の水平結合

水平の関係にあるブロック文間の結合度
 水平の関係にあるブロック文の機能の類似度
 B1とB2が水平の関係にある時
HC( B1, B 2)  Sim ilarity( F ( B1), F ( B 2))
| F ( B1)  F ( B 2) |

Min(| F ( B1) |, | F ( B 2) |)

水平結合度が閾値以上
 2つのブロック文は1つのメソッドとして抽出すべき
SIGSS
Department of Computer Science, Graduate School of Information Science & Technology, Osaka University
18
ブロック文の垂直結合

垂直の関係にあるブロック文間の結合度
 内側のブロック文 Bin の機能と Bin をメソッド抽出した
後に残る外側のブロック文 Bout _ after の機能の類似度
VC ( Bin , Bout )  Sim ilarity( F ( Bin ), F ( Bout _ after ))
| F ( Bin )  F ( Bout _ after ) |

Min(| F ( Bin ) |, | F ( Bout _ after ) |)

垂直結合度が閾値以上
 内側のブロック文だけでなく外側のブロック文ごとメ
ソッド抽出すべき
SIGSS
Department of Computer Science, Graduate School of Information Science & Technology, Osaka University
19
ブロック文の垂直結合例
void
F
( BMETHOD()
1 _ after){  {v1, v2, v3, v4}
……………………………
BLOCK1 {
VAR v1,v2,v3,v4;
……………………………
newMETHOD(v1,v2);
……………………………
}
……………………………
void METHOD() {
F ( B1)  {v1, v2, v3, v4, v5, v6}
……………………………
BLOCK1 {
VAR v1,v2,v3,v4;
……………………………
F ( B2)  F ( B1)
BLOCK2 {
VAR v5,v6
}
v5 = v1 + v2;
v6 = v1 + v5;
void newMethod(VAR v1, VAR v2) {
}
BLOCK2 {
……………………………
F
(
B
2
)

{
v
1
,
v
2
,
v
5
,
v
6
}
VAR v5,v6
}
v5 = v1 + v2;
……………………………
v6 = v1 + v5;
}
}
}
SIGSS
Department of Computer Science, Graduate School of Information Science & Technology, Osaka University
20
同一機能に属するブロック文群識別アルゴリズム
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
RESULT = NULL
B = 特定されたブロック文
HCB = B と結合しているブロック文群(Bを含む)
NHCB = B と水平結合していないブロック文群
OB = Bの外側のブロック文
if ( NHCB が空でない)
if ( VC( OB, HCB ) > VC( OB, NHCB ) )
NHCBを新規メソッドとして抽出
else
HCBを新規メソッドとして抽出
EXIT
end if
end if
if ( OBとHCBが垂直結合している )
if ( OBがメソッド全体でない )
B = OB
GOTO 行3
end if
else
HCBを新規メソッドとして抽出
end if
SIGSS
Department of Computer Science, Graduate School of Information Science & Technology, Osaka University
21
同一機能に属するブロック文群識別の例
void METHOD() {
VAR v1, v2, v3, v4, v5;
……………………………
BLOCK1 {
……………………………
BLOCK2 {
VAR v8 = v1 + v2;
v6 = v3 + v8;
v7 = v4 + v8;
}
……………………………
VAR v9 = 0;
BLOCK3 {
v9 = v1 + v2 + v6;
}
v5 = v7 + v9
}
……………………………
BLOCK4 {
……………………………
BLOCK5 {
VAR v12, v13, v14;
……………………………
v10 = v12 + v13 + v14;
}
}
}
SIGSS
Department of Computer Science, Graduate School of Information Science & Technology, Osaka University
22
評価実験
対象言語: Java
 対象ソフトウェア

 高品質なソフトウェア
 JHotDraw
 低品質なソフトウェア
 学生の書いたプログラムなど
 バージョンの異なるソフトウェア

評価基準
 Bad
smellの自動特定の妥当性
 同一の機能に含まれる範囲識別の妥当性
 適用すべきリファクタリングパターンの自動決定の妥当性
SIGSS
Department of Computer Science, Graduate School of Information Science & Technology, Osaka University
23
適用例
for1
for2

抽出元メソッド



不吉な匂い(if1)


サイクロマチック数 12
行数
LVA 0.233
for3
If1,for3,for4が同一の機
能



主観的判断
コードコメント
再利用可能な機能的単
位
for4
if1
SIGSS
Department of Computer Science, Graduate School of Information Science & Technology, Osaka University
24
関連研究

Eclipseのリファクタリング機能



コード修正(リファクタリングプロセス4)の自動化
本手法と組み合わせることが可能
基本ブロックスライシングによるメソッド抽出

変数を1つ指定し,影響範囲をメソッドとして抽出



メソッドの機能は複数の変数を用いた計算により成立
絡み合ったコードを分割することができる
Murphy-Hillらの研究

リファクタリングツール作成のガイドライン
軽快なツール
 例外的なフォーマットへの対応
 特定のタスクに特化した機能

SIGSS
Department of Computer Science, Graduate School of Information Science & Technology, Osaka University
25
まとめと今後の課題

まとめ
 リファクタリングプロセスの一部を自動化するリファクタリン
グ支援手法を提案した

ソフトウェアメトリクス
ローカル変数のカプセル化
 LVA



機能の抽象化
今後の課題
 適用実験による定量的な評価
 LVAとバグの相関調査
SIGSS
Department of Computer Science, Graduate School of Information Science & Technology, Osaka University
26
Department of Computer Science, Graduate School of Information Science & Technology, Osaka University