この文書は
- Railsアプリの循環的複雑度を測定した際の個人メモ+スニペットです
問題と対処
- metric_fuのsaikuroで複雑度を測定しました
- するとhtmlのレポートが作成されます
- しかし複雑度順にずらーっとメソッド・クラスが並ぶのみで集計値がありません
- metric_fuの出力はhtmlだけでなくyamlもあったので、読み込んでグレード別に集計するスニペットを書きました
グレードの定義
- 複雑度のグレードは若干の揺れがありつつおおむね下記のような基準が多く用いられているみたいなので、今回はこれで行きます。
グレード | 循環的複雑度 | 複雑さの状態 |
---|---|---|
A | 10以下 | 非常に良い構造 |
B | 11以上 | 普通 |
C | 30以上 | 構造的なリスクあり |
D | 50以上 | テスト不可能 |
E | 75以上 | いかなる変更も誤修正を生む |
メトリクスの出力
- metric_fuをGemfileに追記します。
gem 'metric_fu'
- インストール、実行します。
bundle install
bundle exec rake metrics:saikuro
-
Rails.root/tmp/metric_fu/report.yml
yamlファイルにメトリクス情報が出力されます
メトリクスの集計
集計の実施
- 下記のスニペットをrails runner経由などで実行します
- *.rbファイルの全メソッドを複雑度のグレード別に分類しています
snippet.rb
d = YAML.load_file('tmp/metric_fu/report.yml')
all_complexity = []
d[:saikuro][:files].each do |file|
file[:classes].each do |klass|
# ここでは.rbファイルだけとする
if file[:filename] =~ /\.rb$/
klass[:methods].each do |m|
all_complexity << m[:complexity]
end
end
end
end
grade_a = 0
grade_b = 0
grade_c = 0
grade_d = 0
grade_e = 0
all_complexity.each do |c|
if c <= 10
grade_a += 1
elsif c <= 29
grade_b += 1
elsif c <= 49
grade_c += 1
elsif c <= 74
grade_d += 1
else
grade_e += 1
end
end
total = all_complexity.length
puts "total :#{total}"
puts "total : %5d %6.2f%" % [total, 100]
puts "A(-10) : %5d %6.2f%" % [grade_a, grade_a.fdiv(total) * 100]
puts "B(11-29): %5d %6.2f%" % [grade_b, grade_b.fdiv(total) * 100]
puts "C(30-49): %5d %6.2f%" % [grade_c, grade_c.fdiv(total) * 100]
puts "D(50-74): %5d %6.2f%" % [grade_d, grade_d.fdiv(total) * 100]
puts "E(75-) : %5d %6.2f%" % [grade_e, grade_e.fdiv(total) * 100]
集計結果
- 下記のように出力されます。
total : 1300 100.00%
A(-10) : 1250 96.15%
B(11-29): 47 3.62%
C(30-49): 3 0.23%
D(50-74): 0 0.00%
E(75-) : 0 0.00%
- 今回の分析対象は複雑度にはあまり問題はなさそうです
終わりに
- その適当スニペットの複雑度をどうにかしろよという突っ込みはなしでお願いします