RuboCopカスタムルールの導入効果

こんにちは。メディアサービス開発部 Webアプリケーション開発課のシゲタです。

以前このブログでRuboCopのカスタムルールを作成する方法についての記事を書きました。 https://developers.bookwalker.jp/entry/2023/03/31/174906

カスタムルールとは個別のプロジェクトやチームのコーディングスタイルに合わせたRuboCopの拡張ルールのことです。 この記事を書いてから約一年程が経ち、私が参画しているプロジェクトでも実際にカスタムルールを運用し始めました。

今回は実際にカスタムルールを導入して得られた効果について紹介したいと思います。

カスタムルールの導入効果

実際に導入して得られた効果は下記のとおりです。

  1. コーディング規約をコード化できる
  2. コードレビューの一部をRuboCopに移譲できる
  3. 規約に反するコードを手動で直す手間が省ける

それぞれの効果について具体的なメリットを記載していきます。

コーディング規約をコード化できる

チーム開発をする中で、チーム独自のコーディング規約ができました。しかしその多くは口頭ベースでやり取りされていたので文書化にまで至らなかった、あるいはPullリクエストのコメントに書いたけど古すぎて埋もれてしまった、といったものでした。そういった経緯もあり、コーディング規約を決めても「これどうすんだっけ?」となったり、レビューで同じような指摘が繰り返されることが何度か起きていました。

こうした口頭ベースで生まれるコーディング規約をカスタムルールとしてコード化することで、RuboCopが規約に違反しているかどうかをチェックしてくれるようになり、Pullリクエストを出す前に規約違反に気づけるようになりました。

コードレビューの一部をRuboCopに移譲できる

コードレビューもRuboCopが行ってくれるため、カスタムルールとしてコード化できている規約については、レビューから漏れたコードがmainブランチにマージされてしまうこともなくなりました。 コードレビューの一部をRuboCopに移譲することで、レビューコストも削減されるというのもカスタムルール作成のメリットです。

規約に反するコードを手動で直す手間が省ける

規約に違反するコードをちまちま手動で直していくこともできますが、修正量がそれなりに多いと腰が重くて作業も億劫になります。

「ハッシュの要素はキーのABC順に並べることにしよう」という話をチームでした際も、ABC順に並んでいないハッシュが100ファイル以上に及んで存在していたので、まず手動修正は諦めました。 そこで、ハッシュの要素を並び替えてくれるルールを実装して指摘箇所を修正することにしました。

対応としては、要素の並び替えによって処理の挙動が変わりテストが落ちるケースがあったので、指摘箇所にrubocop:todoコメントを追加し、範囲を絞って自動修正することにしました。すべてのハッシュを手動で直していくより遥かに作業負担を軽減させることができたと思います。

違反を指摘するルールは手間要らず

導入効果というより感想ですが、違反を指摘するだけのルールに関しては(あくまで私が観測できた範囲では)手間をかけずに実装できるものが多いと感じました。たとえば、デフォルト引数にTime.zone.nowを使えないようにするルールは以下のようになります。

module RuboCop
  module CustomCop
    class DetectTimeInDefaultArgs < RuboCop::Cop::Base
      MSG = '`Time.zone.now` is detected in a default argument.'

      def on_optarg(node)
        check_for_time_zone_now(node)
      end

      def on_kwoptarg(node)
        check_for_time_zone_now(node)
      end

      private

      def check_for_time_zone_now(node)
        return if node.default_value.source != 'Time.zone.now'

        add_offense(node.default_value)
      end
    end
  end
end

on_optargon_kwoptargがそれぞれ、デフォルト引数とキーワード引数に対して呼ばれるフックです。 それぞれの中で、デフォルト引数であるnode.default_value.sourceTime.zone.nowだったら指摘するシンプルな実装です。

これが自動修正に対応したルールだと勝手が変わるのですが、特定のケースにおいてメソッドや定数の使用を指摘するルールであれば手間をかけずに作成できていることも規約のコード化を行う上で大変助かっています。

おまけ

カスタムルールを導入する際に活用したtipsです。本筋と離れますが個人的に有益だったので共有します。

rubocop:todoコメントを活用する

RuboCopによる指摘箇所をすぐに修正できない場合はrubocop {-a|-A} --disable-uncorrectableコマンドを活用しました。 --disable-uncorrectableオプションは-a-Aと一緒に使うことで、RuboCopの指摘箇所すべてにrubocop:todoをコメントしてくれるものです。 rubocop:todoをコメントすることでRuboCopのルールに違反する指摘を無視させることができます。

https://docs.rubocop.org/rubocop/usage/auto_correct.html#generating-comments

注意点として--disable-uncorrectableオプションは、自動修正に対応していないルールにのみ有効ということです。 なので、自動修正に対応したカスタムルールの指摘箇所にrubocop:todoをコメントしたい場合は、ルールから自動修正に該当する処理を削除した状態でコマンドを実行する必要があります。

InternalAffairsを有効化する

InternalAffairsはカスタムルール開発のためのルール群です。カスタムルール実装時のショートハンドなどを提案してくれるので有効化しました。

RuboCop本体より提供されているので、以下のように.rubocop.ymlにてrubocop/cop/internal_affairsをrequireするとルールを有効化できます。

require:
  - rubocop/cop/internal_affairs

終わりに

本記事ではRuboCopカスタムルールを導入して得られた効果について紹介しました。 これからカスタムルールを作成してみようか検討されている方の参考になれば幸いです。

最後に、ブックウォーカーではエンジニアを募集しています。興味がありましたらぜひ、ブックウォーカーの採用情報ページからご応募ください