【RuboCop】Rubyを用いたプロダクト開発で役立つ、RuboCop 運用改善方法【レベル別】

# はじめに

この記事は、Ruby を用いたプロダクト開発において、どのように RuboCop の運用のレベルを上げていくといいか、そのアイデアをレベル別に紹介する記事です。RuboCop を導入したけど莫大な `.rubocop_todo.yml` が減らずに困っている方や、これから RuboCop を導入しようと考えている方の役に立てば幸いです。

# RuboCopとは

![rubo-logo-horizontal-white.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/325392/06ff0014-23d3-6f23-3699-7db6662e5e20.png)

https://github.com/rubocop/rubocop

RuboCop とは、 Ruby のコードを解析して、よくない書き方をしている場合に警告してくれるツールです。

Ruby は自由度が高い言語なので、同じ内容のプログラム様々な書き方で記述可能です。ですが、チーム開発などで複数人で Ruby を使った開発をする場合は書き方を統一しておかないと新規で参入したメンバーの混乱につなったり、可読性の低下につながったりします。

そこで役に立つのが RuboCop です。次の節からレベル別で RuboCop の運用のアイデアを紹介していきます。

# レベル0: 導入する

当然ですが、RuboCop を運用していくためには RuboCop の導入が必要です。 この記事では導入方法の詳細は書きませんが、たいていの場合は Gemfile に `rubocop` gem を追加&インストールして、 `bundle exec rubocop --auto-gen-config` で  `.rubocop.yml` と `.rubocop_todo.yml` ファイルを生成すると思います。 

`.rubocop.yml` はRuboCopの設定ファイルで、`.rubocop_todo.yml` は、`.rubocop.yml`　を基準にルールを違反している数や違反しているファイル等を自動で生成して出力されたものです。

既存のリポジトリに RuboCop を導入する場合、最初は `.rubocop_todo.yml` に大量に違反しているルールが記載されることになります。ここから、 `.rubocop_todo.yml` が増えないように、そして減らしていくための旅が始まります。

# レベル1: CI に組み込む（初級）

RuboCop はインストールしただけでは何も変わりません。 RuboCop 自体はルールに違反しているコードを見つけてくれるだけ（一部、自動で修正する機能もありますが）なので、それを活用して、違反したコードが増えないようにする仕組みを作っていく必要があります。

CI は _Continuous Integration_ の略で日本語だと「継続的インテグレーション」とも言います。有名なものはCircleCI や Travis CI 、 GitHub Actions などがあります。

どれも、GitHub などに `git push` した際や Pull Request を作成した際などのタイミングで自動的にテスト等を実行してくれるようにするためのツールです。CI に RuboCop を導入することで、 Pull Request をマージする前に違反しているコードがないか自動でチェックされるようになります。

設定方法は `RuboCop GitHub Actions` 等で検索するとたくさんの記事がヒットすると思うので、そこから頑張って設定しましょう。

# レベル2: git に組み込む

CI で RuboCop によるチェックを導入したとしても、それを無視して merge してしまうと秩序は崩壊してしまいます。より確実にルールに違反しているコードを減らすためのアイデアとして、そもそも `git push` されないようにするという方法を紹介します。

(ここまで書いて気づいたのですが、さすがに皆さん git で管理していますよね？していない場合は RuboCop 導入の前に git を導入しましょう :sweat_smile:)

git には、「Git フック」という特定のアクションが発生したときにカスタムスクリプトを実行する機能を提供しています。

https://git-scm.com/book/ja/v2/Git-%E3%81%AE%E3%82%AB%E3%82%B9%E3%82%BF%E3%83%9E%E3%82%A4%E3%82%BA-Git-%E3%83%95%E3%83%83%E3%82%AF

Git フック の一つ `pre-commit` を設定することで、`git commit` コマンドでコミットされる前に RuboCop のコマンドを実行して、違反するコードが含まれる場合にコミットが失敗するようになります。

導入方法は様々ですが、 `pre-commit` gem や `husky + lint-staged` などいろいろ方法があり、導入方法が書かれた記事もあるので探してみてください。

https://github.com/jish/pre-commit

https://typicode.github.io/husky/#/

https://github.com/lint-staged/lint-staged


# レベル3: CI に組み込む（中級）

レベル2まで実施すれば、ある程度はルールに違反したコードが増えにくい状態になると思います。
しかし完璧ではありません。例として、以下の課題があります。

- `.rubocop_todo.yml` で無視しているルールがある場合、違反したコードが残り続ける
- `.rubocop_todo.yml` で無視しているファイルに、追加でルール違反が増えても気づかない

レベル3 ではこれまで気づかなかった「`.rubocop_todo.yml` で無視しているファイルに、追加でルール違反が増えた場合」 に **気付く** ことができるようになるためのアイデアを紹介します。

`.rubocop_todo.yml` には、 無視しているルールと、**そのルールに違反している数** が記載されます。また、`rubocop --auto-gen-config` コマンドで `.rubocop_todo.yml` を再生成すると、**違反している数** も更新されます。この機能を活用します。

具体的には、CI にて `rubocop --auto-gen-config` コマンドで `.rubocop_todo.yml` を再生成して、`.rubocop_todo.yml` ファイルに差分が発生するかを確認します。差分が発生したさいに、以下のように出力して CI が失敗したことを伝えると、これまでは気づけなかったルールの違反にも気づけます。

```diff: CIの出力の例
$ diff 
(省略)
- Offence count: 34
+ Offence count: 38
Metrics/BlockLength
```

上記の例では 「`Metrics/BlockLength` というルールが、これまでは 34 件違反していたが、あなたの追加した PR では 38件に増えたよ」 ということがわかります。

# レベル4: メンバーの意識を統一する

レベル3ですべてのルールの違反にも気づけるようになりました。ですが、ルールに違反した場合も `.rubocop_todo.yml` ファイルを再生成してコミットしてしまうと、CIは通ってしまいます。

ここからは、「みんなで `.rubocop_todo.yml` を減らしていくぞ！」という意識を持ち、社内のエンジニア全体にその意識を浸透させていく必要があります。まずは、レベル3で追加した、 `.rubocop_todo.yml` の差分チェックに対して、違反数が増えないようにしていくとよいと思います。

RuboCop のドキュメントを用意して、「この場合はこうする」といったように、どう対応すればいいかわかりやすくすることも有効だと思います。

また、RuboCop には様々なルールがありますが、中にはデフォルトの設定では基準が厳しすぎるものもあります。そのようなルールは適宜変更していくべきです。必要に応じて、「このルールは本当に必要なのか？」など、議論を行い、自分たちにとって適切な設定を `.rubocop.yml` に構築していく必要があります。

# レベル5: `.rubocop_todo.yml` を空に近づける

ルールに違反したコードが増えないようになったら、あとは `.rubocop_todo.yml` を減らしていくだけです。 RuboCop のルールの中には 自動で修正ができるものもあるので、そういったものから、少しずつ地道に減らしていくだけです。ですが、それだけではなかなか大変だと思います。

僕はまだ使ったことがありませんが、以下の `rubocop_challenger` というツールを発見したので紹介しておきます。

https://github.com/ryz310/rubocop_challenger

Rubocop Challenger は RuboCop の自動修正機能をもとに自動で修正の PR を作ってくれるツールのようです。

Rubocop Challengerでも修正できないものもあると思うので、やはり地道に少しずつ無視しているルールを適用していく必要もありそうです。1人ではかなり時間がかかってしまうと思うので、チームメンバーや、開発にかかわるすべてのエンジニアが日々少しずつ消化していくとよいと思います。

# レベル MAX

`.rubocop.yml` に最適な設定を行い、 `.rubocop_todo.yml` が空になり、違反したコードがこれ以上増えないような体制が完成したら、さらにその先へ進みましょう。

RuboCop は、`rubocop` gem に含まれているルールだけでなく、後からルールを追加することが可能です。`Rails` に関するルール `rubocop-rails` や `RSpec` のルール `rubocop-rspec` 、 graphql-ruby を使っている場合には `rubocop-graphql` など、様々な追加のルールが存在します。

https://github.com/rubocop/rubocop-rails

https://github.com/rubocop/rubocop-rspec

https://github.com/DmitryTsepelev/rubocop-graphql

自分たちのリポジトリで使っている技術に対応した RuboCop のルールを導入することで、コードの品質を高めることができるかもしれないです。満足するルールが見つからない場合は、自分で新たな RuboCop のルールを作成して、OSSとして公開してみましょう！

# さいごに

ここまでで紹介してきた内容をまとめると、RuboCop は導入するだけでなく、運用方法が重要です。特に「RuboCop を活用して、ルールに違反したコードが増えないような仕組み作り」と「エンジニア全員でRuboCop のルールに違反したコードを減らしていく、という共通認識作り」が大事です。

どちらも簡単ではないですが、これらを達成することでコードの品質向上につながり、新規参入メンバーの即戦力化がはやくなったり、開発速度の向上につながる可能性があるので、やってみる価値はあると思います。

RuboCop を活用して、快適な Ruby 生活を実現しましょう！