An automatically created novel bug dataset and its validation in bug prediction
アブストラクト¶
- ソフトウェア開発においては、頻繁なコード変更や厳しい納期などにより、バグの発生は避けられない
- そのため、このミスを見つけるためのツールが不可欠
- バグを特定する1つの方法としては、過去のバグのあるソースコード要素の特性を分析し、同じ特性に基づいて現在のバグを予測することがある
- BugHunterデータセットを紹介
- ファイル、クラス、メソッドからなるコード要素、幅広いコードメトリクス、バグ情報を含む自動で構築されたバグデータセット
- 既存のバグデータセットでは、事前に選ばれたリリースバージョンにおけるすべてのソースコード要素の特性が収集されていた
- BugHunterデータセットは、バグの存在を特定できる最も狭い期間において、同じソースコード要素のバグあり状態と修正済み状態を捉える
- 新しいデータセットは、バグ予測モデルにおいてF1スコア0.74を達成
はじめに¶
- バグのあるソースコード要素の特性評価は近年注目されている研究分野である
- 未知の欠陥のあるコード要素を識別するには既知の欠陥のあるコード要素の特性評価が必要
- ソフトウェア開発においてプログラマーはバグ追跡、タスク管理、バージョン管理システムなどの様々なツールを使用
- これらのツールのほとんどにバグ追跡機能が含まれているため、この情報を使用してバグのあるソースコードの特徴付けを行える
- 実際に特徴付けを行うには、ソースコードのホスティングプロバイダーが管理しているバグレポートを適切なソースコードに関連付ける必要がある
- コミットメッセージに含まれるバグレポートのリンクを使用することで、問題のあるソースコードが追加されたバージョンを特定できる
- バグのあるコードの特性に関する有用な情報を含むデータセットを構築するために、GitHubを選択した
- GitHubには、定期的にメンテナンスされている複数のプロジェクトがホストされており、自動データ取得ツールを実装するためのAPIも備わっているため
- 対象システムとして15のJavaプロジェクトを選択した
- これらのプロジェクトは、規模、ドメイン、報告されたバグの数などの様々な点で互いに異なる
- これまでに公開されたデータセットはには、分析対象システムの1つ以上のバージョンからのすべてのコード要素(バグのあるものとないものの両方)が含まれる
- 本研究では、バグの影響を受けたコード要素とその特性の修正前と修正後のスナップショットを収集し、バグの影響を受けなかったコード要素は考慮しないという新しいアプローチを作成した
- このデータセットは、バグ修正時のコードメトリクスの変化を捉えるのに役立つ
- 新しいデータセットはBugHunter Datasetと呼ばれ、無料で入手できる
- この新しいデータセットがバグ予測に適しているかどうかを確認するための実験も行った
関連研究¶
バグの特定とソースコード管理¶
- バグの特性評価と位置特定については、多くのアプローチが発表されている
- BugLocator: バグレポートとソースコードの間のテキストの類似性を使用して問題が発生しやすいファイルをランク付け
- ReLink: バージョン管理システムでコミットされたコード変更と修正されたバグとの間の関連性を探索
- これらのツールは、SZZアルゴリズムを使用して要る
- SZZアルゴリズムはファイルレベルのテキストの特徴を使用してバグとソースコードの間の追加情報を抽出
- バグ追跡システムによって管理されるバグレポートを使用して、ソフトウェアシステム内のバグのあるファイルを迅速に見つける方法が紹介された
公開データセット¶
- PROMISE: オープンソースやクローズドソースの産業用ソフトウェアシステムから収集されたバグが含まれている
- Bug prediction dataset: クラスとバグを関連付けている
- iBUGS: 自動的にソフトウェアの欠陥位置を特定する方法をテストするための環境を提供
- Bugcatchers: 対象システムで検出されたバグとコードの臭いを含んでいる
- ELFF: メソッドレベルのデータセット
- Had-oops!: 連続する8つのHadoopのバージョンを分析し、時系列が欠陥予測のパフォーマンスに与える影響を調査
データソース¶
GitHub¶
- 最も人気のあるソースコードホスティングサービスの1つ
- バグ追跡システム、イシュー追跡システムなどの共同作業支援サービスも提供
- レポートにバグラベルを追加するとバグレポートとして分類でき、コミットメッセージからバグレポートのIDを参照することでバグとイシューを関連付けられる
- GitHubには、他のシステムのリポジトリを管理したり、それらに関する情報を調べたりするために使用できるAPIがある
選ばれたプロジェクト¶
- Javaで書かれている
- 規模が大きい
- バグとしてラベル付けされたイシューの数が十分である
- コミットメッセージから特定のバグ混入コミットを参照している
- 現在も積極的にメンテナンスされている
- スターとウォッチの数の合計を人気度と定義し、人気度を参考にした
- 選択されたプロジェクト
- Android Universal Image Loader
- ANTLR v4
- Elasticsearch
- MapDB
- mcMMO
- Mission Control Technologies
- Neo4j
- Netty
- OrientDB
- Oryx 2
- Titan
- Eclipse plugin for Ceylon
- Hazelcast
- Broadleaf Commerce
メトリクス¶
- ソフトウェアメトリクスは、ソフトウェアプロジェクトの特性を定量化した指標
- この研究では静的コードメトリクス(ソフトウェア製品メトリクス)を使用
- OpenStaticAnalyzerを使用して、選択されたシステムの様々なソフトウェア製品メトリクスを取得
データセットの作成¶
データの収集¶
- GitHub APIを介して、選択したプロジェクトに関するデータを保存
- 保存するデータには、リポジトリに割り当てられたユーザー(コントリビューター)のリスト、未解決および解決済みのバグレポート(イシュー)、全てのコミットが含まれる
- 未解決のイシューについては、作成日のみを保存
- 解決済みのイシューについては、作成日、解決日、修正コミットのハッシュとそのコミット日を保存
- どのコミットからも参照されていない解決済みのバグは保存しなかった
- GitHubのイシューに関連付けられるラベルに基づいて、これらのフィルタリングを行った
- 保存したコミットに関するデータには、コントリビューターのID、親コミット、影響を受けるファイルとそれに対応する変更が含まれる
- これらの生の情報は、次の処理の入力として使用するために全てXML形式で保存された
生データの処理¶
- GitHubから保存されたデータには全てのコミットが含まれているが、この研究ではバグレポートに関連するコミットだけが必要
- データセットを構築するには、バグ修正コミットを適用する直前のコミットIDとバグを修正するコミットIDが必要
- コミットメッセージだけでなく、バグレポートからも、バグ修正コミットを適用する直前のコミットIDとバグを修正するコミットIDを取得
ソースコード解析¶
- それぞれのコミットIDに対応するコミットのソースコードを収集し、OpenStaticAnalyzerでコードメトリクス(特徴量)を抽出
バグの数の抽出¶
- コード分析の結果とGitHubから収集したデータの2つのデータセットを関連付け、バグの特徴を抽出
- 影響を受けるソースコードを特定するために、SZZアルゴリズムに似たアプローチが用いられた
- GitHubデータから保存したdiffファイルを使用し、変更された全てのファイルのソースコードを調べ、どのコード要素が変更によって影響を受けるかを特定
- OpenStaticAnalyzerのソース行マッピングという機能を使用
- 「生データの処理」ステップで選択されたコミットを取得し、これらのコミット内のバグの影響を受けたコード領域をマークするために、その要素の完全修飾名を収集
- 特定のバージョンのソースコード要素に複数の問題がマークされている場合、そのバージョンには複数のバグが含まれている
CSVファイルの結合¶
- OpenStaticAnalyzerのCSV出力とそれ以外のCSV出力を結合
フィルタリング¶
- データセットには、さらなる調査を複雑にする様々なエントリーが含まれている可能性がある
- データセットには、同じメトリック値を持ちながら、異なる数のバグが割り当てられているエントリーが存在する可能性がある
- 異なるバグを持つ異なるメソッド\(M_{f_1}\)と\(M_{f_2}\)、バグが修正された異なるメソッドド\(M_{g_1}\)と\(M_{g_2}\)を考えたときに、メトリック値において\(M_{f_1} = M_{f_2}\)あるいは\(M_{g_1} = M_{g_2}\)であった場合、バグ予測のための機会学習の精度に悪い影響を与える冗長性が生まれる
- この問題を解決するために、生のデータセットをフィルタリングして冗長なエントリーを排除するための、異なるアプローチを使用
- Removal: より大きなエントリー数を持つクラスにあるエントリーを保持
- Subtract: より大きなエントリー数を持つクラスのエントリーを、より小さなエントリー数を持つクラスのエントリー数と同じ数だけ削除
- Single: より小さなエントリー数を持つクラスのエントリーを削除し、より大きなエントリー数を持つクラスは1つのエントリーのみを保持
- GCF: 両方のクラスのエントリー数をそれらの最大公約数または最大公約除数で割り、その結果として得られる数のエントリーのみをそれぞれのクラスが保持
- フィルタリング手法ごとの評価では、Removal法のF1スコアが最も高かった
分類と再サンプリング¶
- バグの存在を示すフラグを予測することに研究を限定した
- 分類アルゴリズムを適用
- 2値分類を行うために、バグが0のインスタンスを「バグなし」クラスに、バグが1つ以上あるインスタンスを「バグあり」に分類
- 不均衡データによる予測精度の低下を防ぐためにRandom Under Samplingを使用し、それぞれのカテゴリーから同数のデータを取得
BugHunterデータセット¶
- 主な貢献として、ファイル、クラス、メソッドの各レベルでソースコード要素の修正前後の状態を含む新しい種類のバグデータセットを構築した
検証¶
- JUnitプロジェクトのデータセットを検証
- このプロジェクトには、クローズされたバグレポートが84件あり、データセットにはそのうちの37件が含まれている
- これは、多くの修正コミットがソースコードやJavaコードに関連していないため
- JUnitプロジェクトのエントリーのおよそ1%が不適切であった
ファイルとクラスの関係¶
- Javaの場合は、通常、.javaファイルごとに1つのクラスが存在
- 実際に対象プロジェクからランダムに100個のコミットを選択し、分析対象ファイルに含まれるクラス数を数えたところ、ほとんどのファイルは1つのクラスのみを含んでいるが、複数のクラスを含むファイルもある程度存在した
- この結果から、1つのファイルを1つのクラスに関連付けることはできないことが分かった
データセット拡張の計算コスト¶
- データセットの拡張には計算コストがかかる
- データセットに新しいプロジェクトを追加するには、そのプロジェクトがバグレポートとバグ修正コミットを持っている必要がある
- このようなプロジェクトを見つける作業は手動で行うため、時間がかかる
- 最も重要なステップは、適切なバグを収集すること
- GitHubには1時間あたりのAPIリクエスト数に制限があったため、バグ収集に時間がかかった
- 最も時間とリソースを消費する作業は、ソースコード分析
- OpenStaticAnalyzerは深い静的分析を実行するため、単純なパーサーツールよりも多くのリソースが必要
評価¶
- 新しいバグデータセットの有用性を評価するために、機械学習アルゴリズムを用いてバグ予測モデルを作成
- 訓練中に10分割交差検証を用いてモデルの精度を測定
- モデルの比較には適合率、再現率、F1スコアを使用
- 以下のアルゴリズムを使用してデータセットでのパフォーマンスを確認
- ナイーブベイズ
- 多項ナイーブベイズ
- ロジスティック回帰
- 単純ロジスティック回帰
- SGD(Stochastic Gradient Descent, 確率的勾配降下法)
- 投票パーセプトロン
- ディシジョンテーブル
- OneR
- C4.5
- ランダムフォレスト
- ランダムツリー
- ソースコードには3つのレベル(ファイル、クラス、メソッド)があり、選択されたプロジェクトは15個あり、機械学習アルゴリズムは11個ある
RQ1: 構築されたデータセットはバグ予測のために使用できるか?¶
メソッドレベル¶
- F1スコアが最も高かったのはランダムフォレスト
- 平均F1スコアはおよそ0.63
クラスレベル¶
- F1スコアが最も高かったのは単純ロジスティック回帰
- 平均F1スコアはおよそ0.57
ファイルレベル¶
- F1スコアが最も高かったのはランダムツリー
- 平均F1スコアは0.55
RQ2: クラスレベルに投影されたメソッドレベすの指標は、クラスレベルの指標よりも優れた予測因子であるか?¶
- メソッドレベル学習の結果をクラスレベルに投影する実験を行った
- メソッドレベル学習の交差検証では、メソッドを含むクラスを用いて、バグありとバグなしに分類されたクラスの数から混同行列を計算した
- バグのあるメソッドを少なくとも1つ含むクラスは、バグありとみなした
- この方法はクラスレベルのメトリクスによる予測よりも高いF1スコアを達成
- F1スコアは最も高かったのはランダムフォレスト
- 平均F1スコアはおよそ0.74
RQ3: BugHunterは、伝統的なアプローチで構築されたGitHub Bugデータセットよりも強力で表現力豊かであるか?¶
- GitHub Bugデータセットはリリースバージョンごとに静的解析を行い、バグの数を数える
- BugHunterはバグ混入コミットとバグ修正コミットに対して静的解析を行う
- この関係から、GitHub Bugデータセットは、BugHunterよりも静的解析によって得られたコードメトリクスの変化が大きいことが分かる
- それが原因で、GitHub Bugデータセットの方がBugHunterよりも、データセット自体に含まれるノイズが少なくなり、GitHub Bugデータセットの方がF1スコアが高くなったと考えられる
- しかし、BugHunterはより長い期間にわたってデータを収集しており、バグの混入による影響をより細かく捉えているため、実際のバグ予測では、BugHunterの方がバイアスが少なく、より汎用性の高いモデルであると考えられる
妥当性への脅威¶
構成概念妥当性¶
- データセットを自動で構築する際に使用されるマッチングアルゴリズムを、JUnitで検証した
内的妥当性¶
- ソースコード要素の特性を単一のツールで測定した
外的妥当性¶
- 構築されたデータセットは15個のプロジェクトで構成されている
結論¶
- データセットの一般化可能性を高めるために、GitHub以外のデータソース(SourceForge, Bitbucket)からもデータを収集する予定
引用情報¶
- 著者: Rudolf Ferenc, Péter Gyimesi, Gábor Gyimesi, Zoltán Tóth, Tibor Gyimóthy
- タイトル: An automatically created novel bug dataset and its validation in bug prediction
- 雑誌 / 会議名: Journal of Systems and Software
- 巻号: vol. 169
- ページ: p. 110691
- 出版日: November 2020
- DOI: https://doi.org/10.1016/j.jss.2020.110691