はじめに
この記事は、Ruby を用いたプロダクト開発において、どのように RuboCop の運用のレベルを上げていくといいか、そのアイデアをレベル別に紹介する記事です。RuboCop を導入したけど莫大な .rubocop_todo.yml
が減らずに困っている方や、これから 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 を導入しましょう )
git には、「Git フック」という特定のアクションが発生したときにカスタムスクリプトを実行する機能を提供しています。
Git フック の一つ pre-commit
を設定することで、git commit
コマンドでコミットされる前に RuboCop のコマンドを実行して、違反するコードが含まれる場合にコミットが失敗するようになります。
導入方法は様々ですが、 pre-commit
gem や husky + 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
(省略)
- 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
というツールを発見したので紹介しておきます。
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
など、様々な追加のルールが存在します。
自分たちのリポジトリで使っている技術に対応した RuboCop のルールを導入することで、コードの品質を高めることができるかもしれないです。満足するルールが見つからない場合は、自分で新たな RuboCop のルールを作成して、OSSとして公開してみましょう!
さいごに
ここまでで紹介してきた内容をまとめると、RuboCop は導入するだけでなく、運用方法が重要です。特に「RuboCop を活用して、ルールに違反したコードが増えないような仕組み作り」と「エンジニア全員でRuboCop のルールに違反したコードを減らしていく、という共通認識作り」が大事です。
どちらも簡単ではないですが、これらを達成することでコードの品質向上につながり、新規参入メンバーの即戦力化がはやくなったり、開発速度の向上につながる可能性があるので、やってみる価値はあると思います。
RuboCop を活用して、快適な Ruby 生活を実現しましょう!