こんにちは、Optimal Bizチームの片岡です。 今年度からQAチームに配属となり、Optimal Bizの品質向上のために何ができるかを日々考えています。
2021年度Q2から開発期間内に摘出されるバグの分析を始めており、今回はその取り組みの中で作ったバグチケットダッシュボードについて紹介します。
SQuBOK v3*1の3.9.3.2バグ分析
では、バグ分析には主に次の2種類の方法があると紹介されています。
(a) 摘出した個々のバグについて、その混入原因をなぜなぜ分析などの方法で研究し、根本的原因を追究、その根本的原因に対する対策を立てることにより同様のバグの混入を防止する方法。 (b) 摘出したバグをその属性から分類し、統計的に解析することにより、プロジェクト、プログラム、開発プロセス、開発組織、開発者などの解析対象の弱点をつかむ方法。分析結果を進行中のプロジェクトにフィードバックし、同一原因のバグがないかを見直すことにより、品質の早期向上を図る。また、開発プロセスにフィードバックすることにより同様のバグの混入を防止する。
上記の(b)に挑戦していきます。
- 進行中のプロジェクトにフィードバックを与えたい ∧ 品質ダッシュボード*2みたいなものを作ってみたい
という意欲のもと、バグチケットダッシュボード(という名のWikiページ)を作ってみました。
ダッシュボードを作ってみる
バグチケットダッシュボードに必要な要素
ダッシュボードに必要な要素を、以下のように定義しました。
- メンバーはWikiページにアクセスするだけで、バグチケット起票状況を知ることができる
- メンバーはWikiページにアクセスするだけで、バグチケット分析状況を知ることができる
- バグチケット起票状況/分析状況は定期的に更新され、最新の状態が保たれる
ざっくりとした処理の流れ
- 情報取得
- Windowsのタスクスケジューラでバッチファイルを実行
- バッチファイルの中でRedmine APIを叩くRuby製スクリプトを実行し、リリースバージョン毎のCSVを生成
- 情報集計
- バッチファイルの中でExcelのマクロを実行し、Excel内のデータを更新
- データの更新と連動して、Excel内で集計→グラフ化が行われる
- wiki更新
- iframeを用いて、Redmine WikiにExcelで作ったグラフを読み込む
では、作っていきます。
情報取得
リクエスト先のURIを用意する
Redmineは標準でREST API(以降 Redmine API
と表記)を持っており、これを利用してチケット情報の取得や作成などを行うことができます。*3
(以降、RedmineへのアクセスURL (例 : http://example.net/redmine) を <REDMINE URL>
、APIキーを <API KEY>
と表記)
Redmine APIの利用の仕方は、下記をご覧ください。
今回はバグチケットの情報を手に入れたいので、<REDMINE URL>./issues.csv
に対してリクエストを投げます。このとき、下記のようなクエリを作ります。
- tracker_idで"バグ"トラッカーのIDを指定(
<BUG ID>
と表記) - status_idで任意を指定
- fixed_version_idで取得したいリリースバージョンのIDを指定(
<VERSION ID>
と表記 )
この時点で、リクエスト先のURIは
<REDMINE URL>./issues.csv?tracker_id=<BUG ID>&status_id=*&fixed_version_id=<VERSION ID>&key=<API KEY>
のようになっているはずです。
更にこのクエリに、&c[]=status
という形式でCSVで取得したい情報を加えていきます。
チケットステータスを取得したい場合は &c[]=status
、チケットタイトルを取得したいときは &c[]=subject
、というように &c[]=<取得したい情報>
で取得する情報を増やしていくことができます。
Developer Guide内の Optional filters
で言及されているものならカスタムフィールド含め取得できます。
ここまでで、リクエスト先のURIは
<REDMINE URL>./issues.csv?tracker_id=<BUG ID>&status_id=*&fixed_version_id=<VERSION ID>&c[]=status&c[]=subject&key=<API KEY>
のようになっていると思います。
これで、リクエスト先のURIを用意できました。
GETリクエストを投げてレスポンスをCSVで保存するスクリプトを作成する
前述した通り、今回はRubyで作ってみます。Rubyのバージョンは2.7.2です。
スクリプト内の処理の流れは
- リクエスト先のURIを作成
- URIにリクエストを投げてレスポンスを得る
- 取得したレスポンスをCSVファイルに出力する
です。なので、今回は標準ライブラリの net/https
と csv
のみを使います。
まずURIの作成ですが、<REDMINE URL>
や<API KEY>
などは同じものを使いまわすので、定数として扱います。今回はリリースバージョンごとのバグチケット分析を行いたかったので、リリースバージョン以外は最初に定義しておきます。
def initialize @REDMINEURL = "<REDMINE URL>" @APIKEY = "<API KEY>" @target = "issues.csv" @query = "?tracker_id=<BUG ID>&status_id=*&fixed_version_id=" # selection : CSVで取得する情報を指定 @selection = [ "&c[]=status", #チケットの状態 "&c[]=subject" #チケットのタイトル ].join end # CSVレスポンスを取得するためのURIを生成する。 # version : 取得対象のリリースバージョン def createURI(version) return ($REDMINEURL + $target + $query + version.to_s + $selection + "&key=" + $APIKEY) end
次に、"URIにリクエストを投げてレスポンスを取得→ファイル書き込み" までを行うメソッドを作ります。ファイル名とリリースバージョンのIDを引数に取るようにしました。リリースバージョンのIDは、Redmineのロードマップ画面から調べることができます。*4
# Redmine APIを叩いてCSVを取得する。 # filename : 取得したCSVを保存するファイルの名前 # version : 取得対象のリリースバージョン def get_csv(filename, version) File.open(filename, "w") do |file| csv = Net::HTTP::get_response(URI.parse(create_uri(version))).body file.write csv end end
あとは必要に応じてget_csv()
メソッドを呼べばOKです。スクリプトの全容は下記の通りです。
require 'net/https' require 'csv' class BugticketsAnalysis def initialize @REDMINEURL = "<REDMINE URL>" @APIKEY = "<API KEY>" @target = "issues.csv" @query = "?tracker_id=<BUG ID>&status_id=*&fixed_version_id=" # selection : CSVで取得する情報を指定 @selection = [ "&c[]=status", #チケットの状態 "&c[]=subject" #チケットのタイトル ].join end # CSVレスポンスを取得するためのURIを生成する。 # version : 取得対象のリリースバージョン def create_uri(version) @REDMINEURL + @target + @query + version.to_s + @selection + "&key=" + @APIKEY end # Redmine APIを叩いてCSVを取得する。 # filename : 取得したCSVを保存するファイルの名前 # version : 取得対象のリリースバージョン def get_csv(filename, version) File.open(filename, "w") do |file| csv = Net::HTTP::get_response(URI.parse(create_uri(version))).body file.write csv end end end # このスクリプトで取得対象のリリースバージョンと対応するID release_target = { "任意のファイル名" => <VERSION ID>, "任意のファイル名" => <VERSION ID>, # 以下略。同時に取得したいリリースバージョンを書き連ねていく } # リリースバージョンごとにCSVを取得する release_target.each do |filename, version| BugticketsAnalysis.new.get_csv(filename, version) end
これで、任意のリリースバージョン毎のバグチケットの情報を含んだCSVを生成することができました。
情報集計
Excelでグラフを作成する
CSVデータを基に、グラフを作成していきます。
Excelを開き[データ] > [データの取得と変換] > [テキストまたはCSVから]を選択し、取得したCSVをインポートします。
テーブルとしてCSVがインポートされるので、[テーブル デザイン] > [ツール] > [ピボットテーブルで集計]を選択し、集計用のピボットテーブルを作成します。
あとは、目的に合わせてピボットテーブルのフィールドを選択してピボットグラフを作成すればOKです。
マクロ実行でデータ更新を行えるようにする
ActiveWorkbook.RefreshAll
*5 を実行するマクロを組めばOKです。
上記メソッドではCSVの再読み込みとピボットテーブルの更新を行えます。つまり、CSVを取得し直すタイミングで実行することで、CSVファイルの更新と合わせてグラフも更新できます。
Sub update() ' ' 更新 Macro ' ActiveWorkbook.RefreshAll End Sub
情報取得→集計までを自動化
Windowsのタスクスケジューラ機能でバッチファイルを実行し、上記までの情報取得→集計までを定期的に自動で行えるようにします。
今回はExcelで作成したグラフをそのままRedmine Wikiに読み込みたかったため、ExcelファイルやCSVファイルの置き場所をSharePoint上にする必要がありました。 SharePoint上のファイルをローカルから操作するために、SharePointの同期機能を用いて、エクスプローラーからファイルを触れるようにしました。
あとは、Ruby製スクリプトとExcelマクロを実行させるバッチファイルを書いてタスクスケジューラに登録すればOKです。
これで、任意のリリースバージョンのバグチケットの情報を自動で収集/更新して、グラフも更新できるようになりました。
wiki更新
最後に、Redmine WikiにExcelのグラフを読み込んでいきます。
Redmine Wiki Extensions plugin
*6を利用して、以下を参考にWikiページ上に埋め込んでいきます。記法としては、{{iframe(url, width, height)}}
を使います。
https://www.r-labs.org/projects/r-labs/wiki/Wiki_Extensions#任意のwebページをWikiページ内に表示する
wiki埋め込み用のURLを取得する
表示対象のURLは、Excel OnlineでExcelファイルを開いた後、[ファイル] > [共有] > [埋め込み]を選択します。
下記画像のような画面が出てきたら、[表示するデータ]から任意のグラフを選択します。
選択したグラフに対応するURLが[埋め込みコード]内のsrc=…
以下に記載されているので、それをコピーして使用します。
※[埋め込みコード]内のコードではRedmine Wiki Extensions plugin
が解釈してくれないので、URLだけコピーして使用してください。
これで、Excelで作成したグラフをWikiページに埋め込むことができます。
完成イメージ
グラフを埋め込んだバグチケットダッシュボードは、こういう感じになります。 画像ではなくグラフを直接埋め込んだため、Excelでグラフが更新されればWikiページにも反映されるようにできました。
リリースバージョンごとのバグチケット数も表示するようにし、直近のリリースバージョンのバグチケット分析状況とバージョンごとのバグチケット数の推移も一目で確認できるようにしました。
ちなみに、バグチケット数の表示はRedmine Wiki Lists plugin
*7を用いて簡単に行うことができます。
最後に
データを記録/集計してグラフに表せば、傾向が見えてきて仮説も立てやすくなり、類似バグの混入を防いだり開発プロセスを更にカイゼンしていくことも可能になっていきます。 その一手として、今回は、バグチケットの起票状況/分析状況をリアルタイムで確認できるバグチケットダッシュボードを作ってみました。
オプティムでは、プロダクトの品質向上のために一緒に働く仲間を募集しています!
参考
*1:https://www.ohmsha.co.jp/book/9784274226311/
*2:https://codezine.jp/article/detail/13527?p=3
*3:https://www.redmine.org/projects/redmine/wiki/Rest_Issues
*4:https://redmine.jp/glossary/v/version/
*5:https://docs.microsoft.com/ja-jp/office/vba/api/excel.workbook.refreshall
*6:https://www.r-labs.org/projects/r-labs/wiki/Wiki_Extensions
*7:https://www.r-labs.org/projects/wiki_lists/wiki/Wiki_Lists