社団法人 電子情報通信学会
THE INSTITUTE OF ELECTRONICS,
INFORMATION AND COMMUNICATION ENGINEERS

信学技報
TECHNICAL REPORT OF IEICE.

ソフトウェアメトリクスとメソッド内の構造を用いたリファクタリング
支援手法の提案
三宅 達也†

肥後 芳樹†

井上 克郎†† 大阪大学大学院情報科学研究科〒 560–8531 大阪府豊中市待兼山町 1–3
E-mail: †{t-miyake,higo,inoue}@ist.osaka-u.ac.jp
あらまし

リファクタリングはソフトウェアの外部的振る舞いを保ったまま，内部構造を変更することにより，ソフ

トウェアの設計品質を改善する．しかしながら，リファクタリングは複数の手順で行われる複雑な作業である．このため手動によるリファクタリングは誤りが発生しやすく，適切に行うには高い技術と多大な時間を必要とする．そこ
で本研究ではリファクタリング手順の一部を自動化する手法を提案する．具体的には，リファクタリング手順の重要な要素である「リファクタリングすべき箇所の識別」，「適用すべきリファクタリングパターンの決定」，「リファクタリ
ングの効果予測」を自動化する．
キーワード

リファクタリング, 自動化, ソフトウェアメトリクス

A Refactoring Approach Based on Software Metrics and Internal
Structure of Method
Tatsuya MIYAKE† , Yoshiki HIGO† , and Katsuro INOUE†† Graduate School of Information Science and Technology, Osaka University
1–3 Machikaneyama-cho, Toyonaka, Osaka, 560–8531 Japan
E-mail: †{t-miyake,higo,inoue}@ist.osaka-u.ac.jp
Abstract Refactoring is a set of operations to improve design quality of software without changing the external
behavior of it. However, refactoring is a complicated task. Manual refactoring is error-prone, and it requires certain
costs to be performed appropriately. This paper proposes an approach that automatizes a part of refactoring operations. The approach identiﬁes where should be refactored, and it suggests how they should be improved. Moreover,
the approach estimates the eﬀect of the refactorings.
Key words Refactoring, Automation, Software Metrics

1. は じ め に
ソフトウェアの設計品質はソフトウェアの開発や保守を効率ことは難しい．このような問題に対処するために，ソフトウェ
アの設計品質を向上させる技術の 1 つであるリファクタリングが注目されている．

的に行うための重要な因子である．近年，ソフトウェアは社会

リファクタリングとはソフトウェアの外部的振る舞いを保っのさまざまな分野で重要な役割を果たしており，より利便性やたまま，ソフトウェアの内部構造を改善することによりソフト

信頼性の高いソフトウェアが要求されている．しかし，ソフト

ウェアの設計品質を高める技術である [2]．しかしながら，手動ウェアの利便性を高めるため大規模化，複雑化したソフトウェによるリファクタリングは次の問題を抱えているため，実際にアの信頼性を高く保つには，開発や保守に大きなコストを必要

開発現場で用いられることは稀である．

とする．このため，ソフトウェアの設計品質の重要度はますま
す高まっている．
しかし，大規模ソフトウェアの開発プロジェクトでは複数のプログラマが，さまざまな要求を満たすようにソフトウェアを開発，修正していくため，ソフトウェアの設計品質を高く保つ•

大規模ソフトウェアから手動でリファクタリングすべき箇所を特定するのは非常に手間がかかる．

•

特定した箇所をどのようにリファクタリングすべきか決定するには高い技術力が必須である．

•

リファクタリングの効果を事前に予測することは難しい—1—

ため，必要としたコストに効果が見合わない可能性がある．

•

手動による変更は誤りが混入しやすく，開発者に多くのテストを強要する．

ができ，可読性が高まる．

•

オーバーライドが行いやすく，拡張性が高い．

また，Extract Method は他のさまざまなリファクタリング

これらの問題から開発者を解放するためには，リファクタリン

パターンの前準備として頻繁に利用される普遍的なリファクタ

グ作業を自動化する手法が必要である．

リングパターンの 1 つである．Extract Method は効果的で頻本研究では，リファクタリング作業の一部を自動化する手法

繁に適用されるリファクタリングであるため，自動化の効果はを提案する．提案手法はメソッド抽出リファクタリングとそこ

大きく，既存の研究においてもさまざまな自動化手法やツールから派生するリファクタリングを自動化する．具体的には，ソが提案されている [1], [5], [6]．

フトウェアメトリクスを用いてメソッドとして抽出すべきコー

2. 2. 2 Move Method

ド片の基点となる位置を特定した後，その周囲のブロック文構あるメソッドが不適切なクラスで宣言されている場合，Move

造や変数の使用状況に基づいて適切な抽出範囲と適用すべきリ

Method リファクタリングを用いて適切なクラスに移動するこ

ファクタリングパターンを決定する．さらに，リファクタリン

とにより，クラスが持つ責任を明確化する．このリファクタリ

グ前後におけるソフトウェアメトリクスの変化を予測すること

ングは単独でも行われるが，Extract Method から派生して行

により，リファクタリング適用前にその効果を予測する．

われることもある [2]．例えば，メソッドの一部分のみが不適切

以下，2 章ではリファクタリングの手順と本手法で自動化さなクラスに記述されている場合，該当部分を Extract Method

れるリファクタリングパターンについて述べる．3 章では提案手により新規メソッドとして抽出し，その後，Move Method を法に関して説明し，4 章でまとめと今後の課題について述べる．

用いて適切なクラスに移動する．

2. リファクタリング
リファクタリングとはソフトウェアの保守性や可読性，再利本手法でも，Extract Method により抽出されたメソッドを
適切なクラスに移動するためにこのリファクタリングパターンを利用する．

用性などを向上させるために，ソフトウェアの外部的振る舞い

2. 2. 3 Pull Up Methodを保ちつつ，内部的構造を変化させる一連の作業を意味する [2]．

同一の処理を行うメソッドが複数のサブクラスに存在する場

2. 1 リファクタリングプロセス

合，Pull Up Method を用いて重複したメソッドをスーパーク

リファクタリングは次の 5 つのプロセスに分けて行われる．

ラスに引き上げ 1 つのメソッドにまとめることにより，保守性

プロセス 1 ソフトウェアの品質が低くリファクタリングすべを向上させる．また，処理が重複していない場合も，対象となきである箇所 (以後，不吉な匂いと呼ぶ) を識別する．不吉な匂るメソッドがサブクラスの属性やメソッドを使用していなけれいの代表的な例として，長すぎるメソッドや複雑な制御構造，

ば，事前にスーパークラスに引き上げておくことにより，その重複コードなどが挙げられる [2]．

メソッドが再利用される可能性は向上する．

プロセス 2 識別した箇所をどのように修正すべきか検討する．

本手法では，Extract Method の対象となる範囲内でサブク

既存の研究において，不吉な匂いの種類に対応したさまざまなラスの属性やメソッドが利用されていない場合，このリファク

リファクタリングパターンが提案されている [2]．

タリングパターンを利用する．

プロセス 3 リファクタリングの効果とコストを予測する．これにより，コストに見合わないリファクタリングを回避することができる．

3. 提 案 手 法
本手法はメソッド抽出リファクタリングとそこから派生するプロセス 4 プロセス 2 で決定したリファクタリングパターン

リファクタリングを半自動化する．本手法は次のステップでリに基づいて内部構造を再構築する．

ファクタリングを半自動化する．

プロセス 5 再構築されたソフトウェアが外部的振る舞いを（ 1 ） メトリクスを用いて不吉な匂いを特定保っているか検証する．

（ 2 ） 新規メソッドとして抽出すべき範囲を識別

2. 2 リファクタリングパターン
本研究で半自動化されるリファクタリングパターンの概要を説明する．

（ 3 ） 新規メソッドの抽出先を決定（ 4 ） メトリクスの変化を計測し，リファクタリングの効果を予測

2. 2. 1 Extract Method

これにより，リファクタリングプロセス 1，2，3 が半自動化さ提案手法による半自動化の核となるリファクタリングパター

れる．また，本手法が提供するリファクタリングは単純なメンである．このリファクタリングは長すぎるメソッドからそのソッド抽出であるが，それゆえに変更後のコードは制御フロー

一部を新しいメソッドとして抽出することにより，短いメソッやデータフローを変更前のまま維持しており，ホワイトボック

ドに分割する．短いメソッドは次の利点をもつ [2]．

ステストの新しいテストケースを必要としない (プロセス 5 の•他のメソッドから利用できる可能性が高い (再利用性が高い) ため，重複コードの生成防止につながる．

•

コストが軽減される)．さらに，本手法を Eclipse [1] などの既存のツールと併用することにより，プロセス 4 も自動化するこ

適切な命名を行うことで内部の処理の理解が容易になる．

とができ，すべてのプロセスを半自動化することが可能である．

また，呼び出しもとのメソッドをコメント列のように読むこと

本章では，まず本研究で提案する概念である「ローカル変数—2—

のカプセル化」について述べ，次に本手法の詳細を各ステップごとに述べる．

3. 1 ローカル変数のカプセル化
オブジェクト指向プログラミングにおいて，クラスの属性は外部からの干渉を避けるために隠蔽 (属性のカプセル化) され

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;
メソッドdrawText内で可視な変数の数: 10

る．ローカル変数のカプセル化とはあるコード片において利用可能であるが利用する必要のないローカル変数をそのコード片
から不可視にすることである．クラスの属性を隠蔽する場合，
その属性の宣言にアクセス制約を記述することによりアクセスを制限し，必要に応じてアクセサメソッドを用意する．一方，
ローカル変数を隠蔽する場合は，そのローカル変数を不可視にしたいコード片を新規メソッドとして抽出する．そして，抽出されたコード片の外側で宣言されているが可視のままにしておきたい変数のみ引数や返り値を用いてアクセスする．これにより抽出されたコード片内の変更による影響を，抽出もとのメ
ソッドで考慮する必要がなくなる．また，抽出もとのメソッド
内の変更を抽出されたコード片側で考慮する必要がなくなる．
これは属性のカプセル化と同様の効果であり，ソフトウェアの
保守性や再利用性を向上させると考えられる．

(a) メソッド抽出前

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);

ローカル変数のカプセル化の例を図 1 に示す．図 1(a) のソー
スコードにおいて，枠線で囲まれた if-else 文内で可視変数の数}

return tokens;

可視変数数：3, 使用変数数：3(可視であった変数の7/10が不可視)

は，パラメータ変数とローカル変数を合わせると 10 である．しかし，実際に使用されている変数は変数 buf f er，lang ，tokensの 3 つのみであり，残りの 7 つの変数は使用されていない．こ(b) 枠線部のメソッド抽出後

図 1 ローカル変数のカプセル化のような場合，枠線で囲まれた if-else 文を含むコード片を新規メソッドとして抽出し，図 1(b) のソースコードのように変更

よって提案された複雑度メトリクスである [4]．プログラムのすることにより，枠線で囲まれた if-else 文内で可視である変数

制御フローを有向グラフで表現したとき，開始ノードから終了

は使用されている変数のみとなり，使用する必要がない 7 つのノードまでの経路の数で表される．この値は直観的にはソース変数に対する処理を考慮する必要がなくなる．このとき，枠線

コード上の分岐の数に 1 を加えた数を表す．サイクロマチックで囲まれた if-else 文内のみで使用されている変数 lang は，変数が大きいほど制御フローは複雑になり，保守性や可読性が低

数宣言自体を新規メソッドとして抽出する範囲に含むことによいことを意味する．サイクロマチック数の高いコード片は，メり，抽出もとのメソッド drawT ext から不可視になる．これにソッドとして抽出することにより条件記述を分解できるため，

よりメソッド drawT ext 側で変数 lang に対する処理を考慮す

Extract Method の対象に含まれる [2]．

る必要がなくなる．抽出もとのメソッドで宣言された変数を参一般にサイクロマチック数はメソッドの複雑度を表す尺度と照したい場合は，変数 buf f er のようにパラメータ変数を用いして用いられるが，本手法ではブロック文単位で計測する．ブて参照することができる．抽出もとのメソッドで宣言された変ロック文 B に含まれる条件文の数を n とすると， サイクロマ数に代入したい場合は，変数 tokens のように新規メソッドのチック数 CC(B) は次の式で表される．

返り値を用いて代入することができる．

CC(B)(CyclomaticComplexity) = n + 1

3. 2 (1) 不吉な匂いの特定
ソフトウェアメトリクスを計測して，その値をもとに抽出すべきブロック文を特定する．
計測されるメトリクスは次の 3 つである．
サイクロマチック数

サイクロマチック数とは，McCabe に抽出対象のコード片に含まれるブロック文のサイクロマチック
数が高いほど，抽出もとのメソッドのサイクロマチック数の減
少値が大きい (メソッド抽出の効果が大きい)．
メソッドのサイクロマチック数 CC(M ) と CC(B) の比率—3—

RCC(B) を計算する．
RCC(B)(Ratioof CyclomaticComplexity) =CC(B)CC(M )RCC(B) が高すぎるとき，ブロック文 B を抽出しても条件記
述は新しいメソッドに移動するだけで，分解されることはない．
以上のことをふまえ，次の条件を満たすブロック文 B を含む
コード片をメソッド抽出の対象とする．

(CC(B) >= Tcc ) ∧ (RCC(B) <= Trcc )(Tm : メトリクス m の閾値)
LOC(Lines Of Code) LOC はソースコードの行数を表す．
一般に LOC が高いメソッドは可読性が低く，保守が行いにくい．このため，LOC が高いメソッドは Extract Method の対象となる不吉な匂いの代表として知られている [2]．

void METHOD() {VAR v1, v2, v3, v4, v5;……………………………
F ( B1) = { v1, v 2 , v 3 , v 4 , v 5 , v 6 , v 7 , v 8 , v 9}
BLOCK1 {F ( B1 _ after ) = { v1, v 2 , v 3 , v 4 , v 5 , v 6 , v 7 , v 9}
VAR v6, v7;……………………………
F ( B 2 + B 3 ) = {v1, v 2 , v 3 , v 4 , v 6 , v 7 , v 8 , v 9}
BLOCK2 {VAR v8 = v1 + v2; F ( B 2 ) = {v1, v 2 , v 3, v 4 , v 6 , v 7 , v 8}
v6 = v3 + v8;
VC ( B1, B 2 + B3)
HC ( B 2, B3)
v7 = v4 + v8;| {v1, v 2, v3, v 4, v6, v7, v9} || {v1, v 2, v6} |}==Min(| F ( B1 − ( B 2 + B3)) |, | F ( B 2 + B3) |)Min(| F ( B 2) |, | F ( B3) |)……………………………
= 0.875
VAR v9 = 0;
= 0.75BLOCK3 {v9 = v1 + v2 + v6; F ( B 3 ) = {v1, v 2 , v 6 , v 9}}
v5 = v7 + v9}……………………………
VAR v10;……………………………
F ( B 4 ) = {v 5, v10 , v11, v12 , v13 , v14}
BLOCK4 {F ( B 4 _ after ) = {v 5 , v10 , v11}
HC ( B1, B 4)
VAR v11;……………………………
| {v5} |=| {v10} |BLOCK5 {Min(| F ( B1) |, | F ( B 4) |)VC ( B 4, B5) =VAR v12, v13, v14;
Min(| F ( B 4 − B5) |, | F (5) |)= 0.17……………………………
= 0.33v10 = v12 + v13 + v14;}
F ( B 5 ) = {v10 , v12 , v13 , v14 }v5 = v10 + v11;}}

本手法ではブロック文単位の LOC と，そのブロック文のメ
ソッド内における占有率を計測する．メソッド M の LOC を： ブロック文間の結合度が閾値(0.6)より高く，互いに結合している： ブロック文間の結合度が閾値(0.6)より低く，互いに結合していない

LOC(M )，メソッド M に含まれるブロック文 B の LOC を
LOC(B)，とするとブロック文 B の占有率 RLOC(B) は次の

図2

ブロック文間の結合度を用いた機能分割式で表される．

LOC(B)RLOC(B)(Ratioof LinesOf Code) =LOC(M )

ソッドとして抽出すべき範囲とする．これにより，効果的 (メトリクスが改善) かつ適切 (機能に基づいた分割) なメソッド抽
出リファクタリングを行える．

RLOC(B) が高すぎるとき，新しいメソッドが抽出もとのメ
ソッドの問題 (LOC が高い) を継承してしまうため，リファク
タリングの効果は低い．
これらのことをふまえ，次の条件を満たすブロック文 B を含
むコード片をメソッド抽出の対象とする．

LOC(B) >= Tloc ∧ RLOC(B) <= Trloc(Tm : メトリクス m の閾値)
LVA(Local Variables Availability) このメトリクスは本

ここで，メソッドの機能はそのコード内に現れる変数の値を決定する計算であると捉えることができる．つまり，コード内の特定の機能を指定するには，その機能に対応した変数を指定すればよい [6]．ただし，メソッド内の処理は複数の変数を用いた計算により成立する．これらのことを考慮すると n 個のローカル変数が内部で使用されているメソッド M の機能 F (M ) は
次のように変数の集合で表すことができる．

F (M ) = {v1 , v2 , · · · vn }(vi : M 内で使用されている変数)

論文で提案する新しいメトリクスである．LVA はあるブロック

同様に考えると，メソッド M 内のブロック文 B の機能 F (B) は文内で利用可能なローカル変数の数と実際に利用されている変ブロック文 B 内で使用されている変数の集合で表すことができ数の数の比率を表す．ブロック文 B 内で使用可能な変数の集合

る．このとき，2 つの集合 F (M )，F (B) 間には F (B) ⊂ F (M )を AV (B)，実際にブロック文 B 内で使用されている変数の集が成り立ち，機能 F (B) は機能 F (M ) の一部であると判断でき

合を U V (B) とすると，LVA(B) は次の式で表される．

る．ブロック文 B はメソッド M の内部のコードであるため，|U V (B)|
LVA(B) =|AV (B)|
ローカル変数のカプセル化が行われていないメソッドは，そのこの判断の妥当性は高い．
このことを踏まえ，メトリクスに基づいて特定されたブロック文と同一の機能に属するブロック文および単文 (宣言文や代入文など) を識別する．

内部のあるブロック文において利用可能であるが利用されてい3. 3. 1 ブロック文間の結合ない変数が多くなる．すなわち LVA の値が小さくなる．この次の 2 つの結合度を用いて 2 つのブロック文が同一の機能にため，LVA の値が閾値よりも小さいブロック文を含むコード片属するか否か識別する．結合度が大きいほど 2 つのブロック文を，メソッド抽出の対象とする．

が同一の機能に属する可能性が高いと判断する．

3. 3 (2) 抽出べき範囲を識別

水平結合度

抽出箇所の特定により，メソッドとして抽出することでメト

ここで水平の関係とは，同一のブロック文の直下にある 2 つリクスの値が改善するブロック文が特定される．しかし，本来，ブロック文間の関係を意味する．例えば，図 2 の BLOCK1 とメソッドの抽出はメトリクスの値を改善させるためではなく，BLOCK4，BLOCK2 と BLOCK3 は互いに水平の関係を持つ．

機能ごとに分割することを目的に行われる．そこで本手法であるブロック文 B1 の機能を F (B1 )，もう一方のブロック文は特定されたブロック文を含む機能的範囲を識別し，それをメB2 の機能を F (B2 ) とすると，2 つのブロック文の水平結合度

水平の関係を持つブロック文間の結合度を表す．

—4—

HC(B1 , B2 ) は次の式で表される．|F (B)| は機能 F (B) を構成

理由で，内側のブロック文の機能は外側のブロック文の機能のする変数の数を表す．

一部，もしくは，類似した機能であると判断できる．このため，|F (B1 ) ∩ F (B2 )|HC(B1 , B2 ) =M in(|F (B1 )|, |F (B2 )|)(M in(A, B) : A と B のうち小さい方の値を示す)

3. 2 節で特定されたブロック文と外側のブロック文の垂直結合度が閾値より大きい場合，外側のブロック文もメソッド抽出の範囲に含まれる．

HC(B1 , B2 ) が大きいとき，F (B1 ) と F (B2 ) のうち一方もし

垂直結合度は水平の関係を持つ複数のブロック文群とそれらくは両方の要素の大部分がもう一方の集合に含まれる．特の外側のブロック文に対しても計測することができる．この場に HC(B1 , B2 ) の値が 1(最大値) のとき，F (B1 ) ⊂ (もしく合，内側のブロック文群の機能は各ブロック文の機能を表す集は ⊃)F (B2 ) が成り立つ．つまり，HC(B1 , B2 ) の値が閾値よ合の和集合で表される．

り大きければ，一方のブロック文の機能はもう一方のブロック

垂直結合度の閾値を 0.6 としたときの例を図 2 に示す．ブロッ

文の機能の一部，もしくは，類似した機能であると判断できる．

ク文 BLOCK5 内では 4 つの変数が使用されており，機能 F (B5 )このため，3. 2 節で特定されたブロック文との水平結合度が大は v10, v12, v13, v14 で表される．BLOCK5 を新規メソッドときいブロック文が存在する場合，そのブロック文もメソッド抽して抽出する場合，BLOCK5 で使用されている変数のうち，出の範囲に含まれる．

BLOCK5 内で宣言されている変数 v12，v13，14 は BLOCK4

水平結合度の閾値を 0.6 としたときの例を図 2 に示す．ブから不可視になる．変数 v10 のみが，新規メソッドの引数とロック文 BLOCK2 内では 7 つの変数が使用されており，機能して BLOCK4 内で使用され続ける．このため，BLOCK5 をF (B2 ) は v1, v2, v3, v4, v6, v7, v8 で表される．同様にブロック文

メソッドとして抽出した後の BLOCK4 の機能 F (B4 af ter ) は

BLOCK3 の機能 F (B3 ) は v1, v2, v6, v9 で表される．このとき，v5, v10, v11 で表される．このとき，F (B4 af ter ) ∩ F (B5 ) はF (B2 )∩F (B3 ) は v1, v2, v6(要素数 3)，M in(|F (B2 )|, |F (B3 )|)v10(要素数 1)，M in(|F (B4 af ter )|, |F (B5 )|) は 3 となる．ゆえは 4 となる．ゆえに，水平結合度 HC(B2 , B3) は 0.75 となりに，垂直結合度 HC(B4 , B5) は 0.33 となり閾値より低いため，

閾値より高いため，BLOCK2 と BLOCK3 は同一の機能に属BLOCK4 と BLOCK5 は異なる機能に属すると判断する．また，すると判断する．また，BLOCK1 と BLOCK4 の水平結合度

BLOCK2 と BLOCK3 を含むコード片の機能 F (B2 + B3 ) はは 0.17 であり，閾値より低いため 2 つのブロック文は異なる

F (B2 ) ∪ F (B3 ) で表される．このため，BLOCK2 と BLOCK3

機能に属すると判断する．

を含むコード片と BLOCK1 の垂直結合度は 0.875 となり閾

垂直結合度値より高いため，BLOCK2 と BLOCK3 を含むコード片と垂直の関係を持つブロック文間の結合度を示す．

ここで垂直の関係とは，あるブロック文 Bin とその外側のブ

BLOCK1 は同一の機能に属すると判断する．

ロック文 Bout 間の関係を意味する．例えば，図 2 の BLOCK1

3. 3. 2 同一機能に属するブロック文群の識別と BLOCK2，BLOCK1 と BLOCK3，BLOCK4 と BLOCK5

3. 2 節で特定されたブロック文と同一の機能に属すると考えは互いに垂直の関係にある．ここで，Bin の機能を F (Bin )，られるブロック文群をブロック文間の結合を用いて，次のアルBout の機能を F (Bout ) とする．また，ブロック文 Bin 内で宣ゴリズムで識別する．

言している変数群を DV (Bin ) とする．このとき，ブロック文

Bin がメソッドとして抽出されると仮定すると，抽出後の外側のブロック文 Bout af ter にとって，内側のブロック文 Bin 内で

1. RESULT = NULL
2. B = 3.2 節で特定されたブロック文

宣言していた変数群 DV (Bin ) は不可視になる． このため，機3. HCB = B と水平結合しているブロック文群 (B を含む)

能 F (Bout af ter ) は次の式で表される．

5. OB = B の外側のブロック

F (Bout af ter ) = F (Bout ) − DV (Bin )4. NHCB = B と水平結合していないブロック文群
6. if (NHCB が空でない)
7.
8.

抽出もとのメソッドに残るブロック文の機能 F (Bout af ter ) と新規メソッドとして抽出されたブロック文の機能 F (Bin ) が類似している場合，同一の機能が複数のメソッドにまたがって実装されることになる．このため，機能に基づいた分割を実現す
るには，内側のブロック文 Bin のみでなく，外側のブロック文

Bout ごと抽出する必要がある．以上のことを考慮し，2 つのブロック文 Bin ，Bout の垂直結合度 V C(Bin , Bout ) は抽出も

アルゴリズム9.

if (VC(OB,HCB) > VC(OB,NHCB))NHCB を新規メソッドとして抽出
else

10.

HCB を新規メソッドとして抽出

11.

EXIT

12.

end if

13. end if
14. if(OB と HCB が垂直結合している)
15.
16.
17.
18.

if(OB がメソッド全体でない)
B = OB
GOTO 行 3
end if

19. elseとのメソッドに残るブロック文の機能 F (Bout af ter ) と新規メソッドとして抽出されたブロック文の機能 F (Bin ) の類似度で表す．具体的には次の式で表される．

|F (Bout af ter ) ∩ F (Bin )|V C(Bin , Bout ) =M in(|F (Bout af ter )|, |F (Bin )|)V C(Bin , Bout ) が大きいとき，水平結合が大きいときと同様の

20.

HCB を新規メソッドとして抽出

21. end if

このアルゴリズムを図 2 のコードに適用した場合の例を示す．水平結合と垂直結合の閾値はどちらも 0.6 とする．3. 2—5—

節でメトリクスを用いてメソッドとして抽出すべき箇所と3. 5 (4) ファクタリングの効果を予測して BLOCK2 が特定される (行 2) と仮定する．このときリファクタリングの効果を示す尺度としてメトリクスの変化

BLOCK2 は BLOCK3 と水平結合しており (行 3)，BLOCK1を利用することができる [3]．本手法では 3. 2 節で記述したメト内に BLOCK2 と水平結合していないブロック文は存在しない

リクスの変化量をリファクタリングの効果とする．3. 2 節で記(行 4,5,6)．BLOCK2 と BLOCK3 を含むコード片は BLOCK1

述したメトリクスの変化は，基本的には抽出対象となる部分のと垂直結合している (行 14)．BLOCK1 はメソッド全体ではな

メトリクスに等しい．

くメソッド内のブロックの 1 つであるため，他のブロックとのまた，抽出されたメソッドを他のクラスに移動した場合，ク結合を調べる (行 16,17)．BLOCK1 は BLOCK4 と水平結合

ラス間の結合度が変化する可能性がある．このため，Move

しておらず (行 4,6)，外側のブロックであるメソッド本体とはMethod を利用する場合は，リファクタリング前後のクラス間

BLOCK1 の方が強く垂直結合している (行 7) ため，BLOCK4の結合度の変化も測定する．

を新規メソッドとして抽出する (行 8)．残った BLOCK1 は外側

これらのメトリクスの変化をもとにリファクタリングの効果のブロックであるメソッド本体と垂直結合している (行 14,15)と副作用を予測し，リファクタリングを行うか否か決定する．

ため，もとのメソッド METHOD 内に残る (行 18,21)．以上の処理によりメソッド METHOD は BLOCK1 を含むコード片とBLOCK4 を含むコード片に分割される．

4. まとめと今後の課題
本論文ではリファクタリング作業の一部を自動化する手法を

3. 3. 3 同一の機能に属する周囲のコードの識別提案した．本手法は既存のオブジェクト指向プログラムから新3. 3. 2 節のアルゴリズムでメソッドとして抽出すべきブロッ

規メソッドとして抽出すべきコード片を特定し，さらに，そのク文群が識別される．しかし，より精度の高い機能分割を実現

コード片の適切な抽出先を決定する．さらに，リファクタリン

するためには，それぞれのブロック文の前後の文も，ブロックグの効果をコード変更前に予測するため，ユーザは効果的なリ文と同一の機能に属するようであれば，メソッド抽出範囲としファクタリングのみを選択することができる．

て識別する必要がある．本手法では，簡単なプログラムスライ

今後の課題としては次の内容があげられる．

シングを用いて識別する．スライシングの基点にはブロック文•

本研究ではメソッドの機能を変数の集合で表現している．

の外側で宣言さている変数 (以降，外部変数と呼ぶ) のうち，ブ

しかし，メソッドの機能を実装するうえで，各変数の重要度はロック文と関連が強い変数を指定する．ブロック文と外部変数異なる．例えば，使用頻度の高い変数や返り値となる変数は，の関連の強さは，その外部変数がブロック文の内外のどちらで他の変数と比べて重要度が高いと考えられる．このことを考慮

頻繁に使用されているかで決定される．ブロック文の内部で頻し，各変数に応じた重みを負荷したうえで，LVA やブロック文

繁に使用されている外部変数ほど，そのブロック文と関連が強間の結合度を計測することにより，自動化されたリファクタリ

いと判断する．ただし，メソッドの機能はそのコード内に現れングがより妥当になると考えられる．

る変数の値を決定する計算であると捉えることができるため，•

本研究では新しいメトリクスである LVA を提案してい変数がブロック文の内部のみで代入されている場合は，外部でる．本論文ではオブジェクト指向プログラミングのカプセル化

頻繁に参照されていても内部で代入を行っているブロック文との概念をもとに，定性的な観点から LVA の有用性を評価して関連が強いと判断する．この際，変数の初期化に関しては，代いるが，定性的な評価のみでは必ずしも有用であるとは言え入であるとは見なさない．これらのことを考慮すると，図 2 のない．そこで，LVA とバグの相関などを調査することにより，

変数 v9 は BLOCK3 の外側で宣言，初期化されているが，ブ

LVA がソフトウェアの品質に与える影響を定量的に調査する必ロック文の内部で値が決定されているため，BLOCK3 と関連要がある．

の強い外部変数であると判断され，スライスの基点とする．

3. 4 (3) 新規メソッドの抽出先を決定
抽出対象のコード片内で使用されている属性や呼び出されているメソッドをもとに，抽出対象のコード片をどのクラスのメソッドとして抽出すべきか決定する．

•

抽出対象のコード片内で自クラスの属性やメソッドが主に使用されている場合，自クラスのメソッドとして抽出する．

•

自クラスと継承関係がないクラスの属性やメソッドを主に使用している場合，Move Method を使用し，属性やメソッド
が最も多く使用されているクラスのメソッドとして抽出する．

•

抽出対象のコード片内でスーパークラスの属性やメソッドが主に使用されており，かつ，自クラスの属性やメソッド

文

献[1] Eclipse. http://www.eclipse.org.
[2] M. Fowlor. Refactoring: improving the design of existingcode. Addison Wesley, 1999.
[3] Y. Higo, Y. Matsumoto, S. Kusumoto, and K. Inoue. Refactoring Eﬀect Estimation based on Complexity Metrics. In
Proc. of the 19th Australian Software Engineering Conference, pp. 219–228, March 2008.
[4] T. McCabe. A Complexity Measure. IEEE Transactions
on Software Engineering, 2(4):308–320, Dec 1976.
[5] E. Murphy-Hill and A. P. Black. Breaking the Barriers to
Successful Refactoring: Observations and Tools for Extract
Method. In Proc. of the 30th Intenational Conference on
Software Engineering, pp. 421–430, May 2008.
[6] 丸山. 基本ブロックスライシングを用いたメソッド抽出リファク
タリング. 情報処理学会論文誌, 43(6):1625–1637, Jun 2002.

がまったく使用されていない場合，Pull Up Method を使用しスーパークラスのメソッドとして抽出する．

—6—