【論文纏め】LLMによる自動リファクタリングの可能性
Title: An Empirical Study on the Potential of LLMs in Automated Software Refactoring
Link: https://arxiv.org/abs/2411.04444
Intro / Conclusion
- ソフトウェアのリファクタリングは特に可読性/保守性/再利用性を向上させるために行われる。
- 自動リファクタリングのためにIntelliJ IDEAやJDeodorantなどのツールが用いられるが、このツールを適用する前に開発者は"リファクタリングするべき箇所"、"リファクタリングの種類"、"リファクタリングの詳細なパラメータ"を指定する必要があり、時間がかかる。
- GPT-4やGeminiのようなLLMは以上の問題を解決する自動ソフトウェアリファクタリングができる可能性が高い。しかし、LLMによるリファクタリングが効果的か否かは未知のままであるため、本研究では以下の問いに答える。
- RQ1-1: リファクタリングの種類を指定しない場合、LLMはどれだけうまくリファクタリング機会を見つけられるか?
- RQ1-2: リファクタリングの種類を明示した場合、LLMはどれだけうまくその機会を見つけられるか?
- RQ1-3: リファクタリング対象のコードが長くなると、LLMの性能はどう変わるか?
- RQ1-4: LLMが得意なケース・苦手なケースはどんなときか? もっとリファクタリングを見つけやすくするプロンプトの工夫はあるか?
- RQ2-1: LLMが提案したリファクタリング案は、人間の専門家が行ったリファクタリングと比べてどうか?
- RQ2-2: LLMが提案したリファクタリングは安全か? もし安全でないなら、どのくらいの頻度でそうなる? 具体的に何が問題か?
- 20のプロジェクトから180のリファクタリング事例を集めてリファクタリング用データセットを構築する。その後、発見されたリファクタリング必要箇所をリファクタリングするようにLLMに依頼する。そして、以下のように評価。
- リファクタリング箇所の特定能力を定量評価
- リファクタリング案に対して3人の専門家にレビューしてもらう (定性評価)
- その結果、リファクタリングの種類によっては性能に差があることが分かった。(簡単な名前変更には強いが構造的変更には弱いなど)。そのためリファクタリングの分類ごとに性能を整理。
- 本論文の貢献を纏めると以下である。
- ソフトウェアリファクタリングにおけるLLMの強みと弱みを整理。
- ソフトウェアリファクタリングのリスクを軽減するための検出と再適用戦略の提案。
- 複数のツールおよびリファクタリングの専門家によって検証された高品質のリファクタリングデータセット。
Study Design
Dataset
- LLMの能力を検証するために、信頼できるリファクタリング事例を含むデータセットを以下方法で作成。
- ReExractorとRefactoringMinerで検出したリファクタリングを専門家3人で個別に確認。
- 意見が一致すれば「正しいリファクタリング」として採用。
- 研究では以下1ファイル内で簡潔するリファクタリングに限定している。この評価項目でリファクタリングの精度を評価。
高レベル / 低レベル | リファクタリングの種類 |
---|---|
高レベル | rename method(メソッド名の変更) rename attribute(属性名の変更) rename parameter(パラメータ名の変更) rename variable(変数名の変更) |
低レベル | extract method(メソッドの抽出) extract variable(変数の抽出) inline method(メソッドのインライン化) inline variable(変数のインライン化) |
- データセットには以下のような問題が含まれているため、逆リファクタリングしたデータをLLMに入力して元の良いコードを生成してもらう。
問題 | 解決策 |
---|---|
実際のコミットにはリファクタリング以外の変更も含まれていて、LLMが正確に再現できない | 逆リファクタリングで、純粋にリファクタリングだけを含む形に変える |
リファクタリングは機能変更などの動機に依存していて、単独では意味がない場合がある | 機能変更の影響を除くことで、本当に必要なリファクタリングだけをLLMに学習・実行させる |
Prompt Template
- 本論文ではベストプラクティスに従い、異なる質問に応じた以下異なるテンプレートを調整。このそれぞれの調整済テンプレートによってLLMの効果を測定。
Metrics
- 各リファクタリングタイプ(単一のコードエンティティに適用されるリファクタリングと複数のコードエンティティを含むリファクタリング)に対して特定とヒューリスティックを定義する。
用語 | 意味 |
---|---|
#commons (共通ステートメント数) |
LLMが抽出したコードの中で、人間が正しいと判断した抽出(オラクル)と一致していたものの数 |
#extracted |
LLMが実際に抽出したコードの数 |
#oracle |
「正解」として与えられた人間のリファクタリング例で抽出されたコードの数 |
- 具体例:
- 正解(オラクル)が 4行のコードを抽出していた
- LLMは 5行のコードを抽出した
- そのうち、3行が正解と一致していた
このとき:
$$
\text{tolerance} = \frac{2 \times 3}{4 + 5} = \frac{6}{9} ≒ 0.67
$$
→ 0.5以上なので、LLMは「正しくリファクタリングの機会を見つけた」とみなされます。
Answer Question
RQ1-1: リファクタリングの種類を指定しない場合、LLMはどれだけうまくリファクタリング機会を見つけられるか?
- プロンプトテンプレートP1によってリファクタリング箇所の特定精度を評価した結果は以下。
- Answer: 一般的なプロンプトによるリファクタリング箇所の特定タスクは、全体的に成功率が低い。一方、GPTの関数抽出のリファクタリングを特定する能力は著しく高い。
RQ1-2: リファクタリングの種類を明示した場合、LLMはどれだけうまくその機会を見つけられるか?
- プロンプトテンプレートP2によってリファクタリングタイプを命じ的に指定した場合、リファクタリング箇所の特定精度を評価した結果は以下。
- リファクタリング提案は偽陽性を報告し、それが精度に悪影響を及ぼしている。
- Answer: リファクタリングタイプを示すことで、LLMの精度は飛躍的に向上。しかし、インラインリファクタリング含むいくつかのリファクタリングタイプでは成功率が低い。
RQ1-3: リファクタリング対象のコードが長くなると、LLMの性能はどう変わるか?
- リファクタリング対象のソースコードサイズとリファクタリング箇所の特定の際のLLMの成功率相関を調査した。その結果が以下。
-Answer: ソースコードサイズとリファクタリング箇所の特定成功率には負の相関がある。ソースコードが長ければ長いほど成功率も低くなる。
RQ1-4: LLMが得意なケース・苦手なケースはどんなときか? もっとリファクタリングを見つけやすくするプロンプトの工夫はあるか?
- LLMのリファクタリング箇所解く知恵能力の強味と弱みをより深く理解するためにリファクタリングの理由を手動で分析し、23のリファクタリングサブカテゴリに分類した。その結果が以下。
※右上の数値はサブカテゴリに手動で割り当てられたインスタンスの数
※青いバーはテンプレートP2の元でリファクタリング箇所を特定する際の成功率を表している。
※空のバーはそのカテゴリで常に失敗したことを示している。
-
結果を見ると以下が分かる。
- GPTはインラインリファクタリングが苦手。参照だけを目的とした変数(use as reference)やプロキシメソッドはGPTは発見出来なかった。
- 関数/クラス抽出(extract method/extract class)に関しては比較的安定して得意。コード重複(duplicate code)を見つけて抽出する能力は高い。
- 名前変更(rename)系のリファクタリングは最も得意。
-
異なるサブカテゴリにおけるリファクタリング箇所の特定性能を調査するために各サブカテゴリに対して新しいプロンプトテンプレートを設計。本テンプレートはin-context learning (文脈内で求められる入力と出力の例をいくつか提供する) を使用。
-
このテンプレートによるGPTの成功率は図5の緑のバーで示されている。サブカテゴリを明示的に指定した場合は成功散るが有意に改善する。
-
コードサイズが成功率と逆相関であるため、各リファクタリングサブカテゴリーに対して検索空間を狭めた。具体的には検索空間を全体のドキュメントから単一のメソッドに限定した。
-
Answer: LLMはコードの重複解消や名前変更に関するリファクタリングには強い一方で、クラスの分解 (Extract Class) には弱い。また、リファクタリングのサブカテゴリを指定し、且つコードサイズを絞ることでそのパフォーマンスが大幅に向上する。
RQ2-1: LLMが提案したリファクタリング案は、人間の専門家が行ったリファクタリングと比べてどうか?
-
LLMが提案したリファクタリング案を専門家が評価した結果は以下である。
-
GPTは176件中、112件(63.6%) が「人間のリファクタリング案と同等、またはそれ以上の品質」。さらに、GPTの48件、Geminiの25件の提案が、実際の開発者が行ったリファクタリングと完全一致。
-
GPTは51件(29%) の提案が「人間の案より質が劣る」と評価。
-
GPTは180件中 4件 において、リファクタリング案を出せなかった。
-
GPTの提案の中で 13件(7.4%) が「バグあり」。LLMのア提案でロジック敵に変わってしまったものが18件、構文エラーでそもそも動かないものが4件。
-
リファクタリングの種類ごとに成績に大きな差がある。例えばインライン系(inline method, inline variable)や抽出系(extract method, extract class, extract variable)のリファクタリングには強いが、名前変更系 (rename method, rename variable) のリファクタリングは弱い。
-
ほぼすべてのリファクタリングの種類でバグのある提案が出た。
-
Answer: LLMは高品質のリファクタリングソリューションを提案することができる可能性がある。具体的には、60%以上のソリューションがしばしば人間の専門家が考案したものと同等かそれ以上であることが多い。
RQ2-2: LLMが提案したリファクタリングは安全か? もし安全でないなら、どのくらいの頻度でそうなる? 具体的に何が問題か?
- Answer: LLMによって提案されたリファクタリング案は安全ではない可能性が高い。つまり、意図された機能を変更するバグや構文エラーを引き起こす可能性がある。
Proposed Method
- 前セクションで示した通り、LLMベースのリファクタリング手法は有望な結果を残しているが、安全性の観点で問題がある。そのため、本問題を解決するためにdetect-and-reapply tactic (RefactoringMirrorと呼ぶ) を提案する。
- RefactoringMirrorはLLMが提案したリファクタリングの良いぶぶんだけを取り込み、不要な変更を排除することを目的とした手法。
- RefactoringMirrorのフローは以下。
- リファクタリングの検出: ReExtractorによって、元のコードとLLMがリファクタリングしたコードを比較してどのようなリファクタリングタイプが適用されたか&リファクタリング箇所を検出する。
- リファクタリングの詳細解析: 得られたリファクタリング内容をさらに解析し、リファクタリングの種類毎に手動でどの部分を解析/抽出してどのようにリファクタリングするかをパラメータ化しておく (IntelliJ IDEAなどのリファクタリングツールに入力できるような形式にする)。
- 抽出したパラメータを入力してIntelliJ APIを使用してリファクタリングする。
補足: 論文中で紹介されたプログラム
- RefactoringMirrorと論文中のプロンプトテンプレート: https://github.com/bitselab/LLM4Refactoring/tree/master
- ReExtractor: https://github.com/lyoubo/ReExtractor
Discussion