Code Coverage
不要なコードを消すことの意義
不要なコード (以下 dead code) が存在するとプロダクトにも開発体験にも悪影響を及ぼします。 例として下のようなものがあります。
プロダクト
不要な処理によるバックエンドの速度劣化
不要な asset のダウンロードによるフロントエンドの体験劣化
開発体験
build 時間の増加
影響範囲推定の困難化
発見が簡単なものとそうでないものがありますが、ある dead code が他の dead code から参照されている場合、 前者の発見はより困難になります。 したがって dead code を減らしていくというアクションは継続的に行わないと簡単に対応が難しい状態になってしまいます。
dead code 検出方法
ここでは社内で作った本番環境から取得できるログをもとにした dead code 検出方法について解説します。 2023 年 6 月時点で一部の Rails のアプリケーションのみしか対応していないので主に Rails を前提にします。
simplecov viewer
下のフォーマットで社内のエンジニアに coverage を公開しています。
<app_name>
: repository 名 (例: wantedly/wantedly の場合はwantedly
)<env>
:production
,qa
,sandbox
,test
<date>
:YYYY-MM-DD
のフォーマット、もしくはlatest
Ruby における実装方法の背景上、ステートメントカバレッジのみ、つまりある行が実行されたかどうかしか記録していません。 このため、各行について少なくともその一部が実行されていることのみがわかります。
例
注意
この手法で検知できない dead code が存在し、また逆にここで hit していないと判定されても実際には dead code でない場合があります。 したがって実際に削除する場合には Pull Request に他の根拠を示してください。 理由としては下のようなものがあります。
「hit していない => 不要なコード」は成り立たない
定期実行 job なども測定対象だが、測定期間内に呼び出されなかっただけの可能性もある
Rails の場合 initializer など測定開始前に実行されるコードは検出できない
「検知されている => 消すことができない」は成り立たない
表示に影響のない HTML 要素や無駄な処理など仕様に影響のないコードもありえる
正確でない/勘違いしやすい場所がある
Rails の view は実装の制約上 render されたかどうか しか確認できない
ActiveRecord の scope などを 1 行で定義した場合
scope
が定義されたこととその中のproc
が実行されたことの区別はできない
実装
計測方法
Rails では oneshot coverage を利用しています。 view についてはこの手法では計測できないため、ActiveSupport::Notifications.subscribe
を用いて render されたかどうかのみを検知しています。 詳しい実装は wantedly/wantedly に存在する view_coverage.rb を確認してください。
ここで検出されたものを servicex の EventLogger
で BigQuery に保管しています。
集計方法
集計期間をできる限り長くするために次のような集計方法をとっています。
file ごとに期間を決めてその間に各行が hit したかどうかを集計する
期間
終了時点:
<date>
の日付開始時点: 終了時点と file の内容が変わっていない最も古い日付 (ただし最大 6 ヶ月前)
話を聞きに行きたい
Slack: #dx
もっと知りたい
最終更新