rails statsの出力項目が足りていない問題に取り組んだ話

はじめに

こんにちは、YOUTRUSTのしぶしゅん(YOUTRUST / X)です。

昨年Kaigi on Railsにブース出展し、「出張OPEN CODE」を行いました。 OPEN CODEはYOUTRUSTで定期的に開催しているYOUTRUSTで実際に利用しているソースコードを紹介するイベントです。 ブース出展の企画として出張開催しました。

Kaigi on Rails 2024 参加レポート!! - YOUTRUST Tech Blog

その際に、「rails statsの出力項目が足りていないのでは?」という質問をいただきました。 調査の結果、確かに出力項目が不足しており、正しい統計情報が得られていないことが判明しました。 今回はその調査内容と結果について紹介します。

rails statsとは

rails statsはRailsアプリケーションの統計情報を出力するコマンドです。 次のように実行することで出力できます。

$ bundle exec rails stats

このコマンドは、アプリケーションコードとテストコードをディレクトリ単位で統計情報として出力します。

修正前のrails statsです

YOUTRUSTのrails statsを出力した結果です。 Linesが行数、LOCがコメントなどを除いた行数を表します。 アプリケーションコードのCode LOCとテストコードのTest LOCの比率であるCode to Test Ratioはプログラムでどれだけテストが書かれているかの指標です。 Code to Test Ratio: 1:4.8となっており、アプリケーションコードに対してテストコードが5倍ほどあることになります。

問題点とYOUTRUSTのディレクトリについて

YOUTRUSTは2025年1月8日時点でRails7系を利用しています。 Rails7系のstatsは次のように実装されています。

rails/railties/lib/rails/tasks/statistics.rake at v7.0.8.7 · rails/rails · GitHub

STATS_DIRECTORIESで定義されたディレクトリのみを対象にしていました。

app配下のディレクトリです

YOUTRUSTのapp配下のディレクトリにはSTATS_DIRECTORIESで定義されたディレクトリに加え、use_casescommandsなどのディレクトリがあります。 定義されていないディレクトリが計測できていませんでした。

YOUTRUSTがCQSアーキテクチャを採用しているためこのようなディレクトリとなっています。 CQSアーキテクチャについては過去のテックブログで紹介しています。

カスタムコップでCQSの運用を改善した話 - YOUTRUST Tech Blog

またYOUTRUSTではテストにRSpecを利用しています。

rspec-rails/lib/rspec/rails/tasks/rspec.rake at v7.1.0 · rspec/rspec-rails · GitHub

STATS_DIRECTORIESで定義されたtest配下のディレクトリの代わりにspec配下のディレクトリをSTATS_DIRECTORIESに追加します。 またTest LOCとして計算されるようにTEST_TYPESにも追加します。

rails/railties/lib/rails/code_statistics.rb at v7.0.8.7 · rails/rails · GitHub

TEST_TYPESの定義箇所です。

問題点の修正と修正後のrails stats

app配下のディレクトリをすべてSTATS_DIRECTORIESに追加することでCode LOCを正しく数えるようにしました。 app以外のlibとspecは変更前と同じように追加しています。

namespace :custom_stats do
  desc 'Generate custom code statistics'
  task generate: :environment do
    require 'rails/code_statistics'

    def get_directory_pairs(*directories)
      pairs = directories.map do |directory|
        subdirs = Dir.entries(directory).select { |entry| File.directory?(File.join(directory, entry)) && !entry.start_with?('.') }
        # statsの出力と合わせるためにspecディレクトリの場合は複数形を単数形に変換してsuffixを調整する
        suffix = directory == 'spec' ? ' specs' : ''
        subdirs.map do |subdir|
          label = "#{directory == 'spec' ? subdir.singularize.capitalize : subdir.capitalize}#{suffix}"
          [label, File.join(directory, subdir)]
        end
      end.flatten(1)
      pairs
    end

    pairs = get_directory_pairs('app', 'spec')
    # statsの出力と合わせるためにlibディレクトリを追加
    pairs << ['Libraries', 'lib']

    # specのディレクトリ名をTEST_TYPESに追加してTest LOCとする
    pairs.select { |pair| pair[1].start_with?('spec') }.each do |pair|
      ::CodeStatistics::TEST_TYPES << pair[0] unless ::CodeStatistics::TEST_TYPES.include?(pair[0]) # rubocop:disable Style/RedundantConstantBase
    end

    stats = CodeStatistics.new(*pairs)
    puts stats
  end
end

実行すると次のように出力されます。

$ bundle exec rails custom_stats:generate

修正後のrails statsです

修正後のrails statsではuse_casescommandsなどのディレクトリが出力されています。 appディレクトリにあってCodeとして計測できなかったものを数えるようになり、Code to Test Ratio: 1:2.7となりました。 修正の結果4.8から2.7という結果になりましたが、他社と比較しても悪くない結果のようでした。

おわりに

YOUTRUSTのrails statsで正しい情報が得られるようになりました。 これからもアプリケーションコードだけでなくテストコードも充実させていきます。

次バージョンのRails8系ではregister_directoryを利用してより簡潔に実装できます。 バージョンアップ後にまた試してみます。

rails/railties/lib/rails/code_statistics.rb at v8.0.1 · rails/rails · GitHub

今回のrails stats出力項目修正のきっかけとなったOPEN CODEは次回開催に向けて準備中です。エンジニアの皆様と交流するのを楽しみにしております。

YOUTRUSTではエンジニアを募集しています。 興味のある方はぜひご応募ください。

youtrust.jp

career.youtrust.co.jp

参考文献

rails stats 2024 ~ Kaigi on Rails 2024 アフターイベント - connpass

rails statsで大解剖 🔍 “B/43流” のRailsの育て方を歴史とともに振り返ります - Speaker Deck

SmartHR の `rails stats`―― 良いところ・伸びしろ全部語り尽くしちゃいます - Speaker Deck

rails stats で紐解く ANDPAD のイマを支える技術たち - Speaker Deck

各社のrails stats実行結果を参考にさせて頂きました。

rails stats コマンドで app 以下のディレクリを全て計測できるようにする - Note

RSpecによる上書きについて参考にさせて頂きました。

ありがとうございます。