SideCI Blog

自動コードレビューサービスSideCIを提供している株式会社アクトキャットのコーポレートブログです。



Reek を使って嫌な感じのコードを取り除きましょう

コードを書いたり、読んでいて、何となく嫌な感じのするコードに出くわしたことはないでしょうか。そういったコードの存在はシステムの保守性や可読性を損なうものになります。Reek というツールではそれをコードスメル(悪臭のするコード)と呼んでいます。

Reek は多数のルールに基づいてRubyのコードを精査してくれます。そうして出力された結果を元に修正していくことで可読性の高いコードに直せるでしょう。今回はReekの利用法を紹介します。

Reek のインストール

インストールは Rubygems を使って行います。

$ gem install reek

Reek は 2.1〜2.4の MRI ruby に対応しています。JRubyやRubinius向けは公式ではサポートされていないものの動作するようです。

Reek の実行

実行は簡単で、ディレクトリを指定して reek コマンドを実行するだけです。

$ reek /path/to/project

ディレクトリまたは個別ファイルを指定できます。

そうすると問題のありそうな箇所をリストアップしてくれます。

$ reek . | more
lib/ncmb/acl.rb -- 16 warnings:
  [29]:BooleanParameter: NCMB::Acl#public has boolean parameter 'bol' [https://github.com/troessner/reek/blob/master/docs/Boolean-Parameter.md]
  [38]:BooleanParameter: NCMB::Acl#role has boolean parameter 'value' [https://github.com/troessner/reek/blob/master/docs/Boolean-Parameter.md]
  [33]:BooleanParameter: NCMB::Acl#user has boolean parameter 'value' [https://github.com/troessner/reek/blob/master/docs/Boolean-Parameter.md]
  [39, 40]:DuplicateMethodCall: NCMB::Acl#role calls '@fields[role.name.to_sym]' 2 times [https://github.com/troessner/reek/blob/master/docs/Duplicate-Method-Call.md]
  [39, 39, 40]:DuplicateMethodCall: NCMB::Acl#role calls 'role.name' 3 times [https://github.com/troessner/reek/blob/master/docs/Duplicate-Method-Call.md]
  [39, 39, 40]:DuplicateMethodCall: NCMB::Acl#role calls 'role.name.to_sym' 3 times [https://github.com/troessner/reek/blob/master/docs/Duplicate-Method-Call.md]

何の問題があるのかを提示したドキュメントのURLも出力されますので確認しやすくなっています。

-f [format] オプションを指定することで出力フォーマットが指定できます。例えばHTMLで出力する場合は次のようになります。

$ reek -f html . > result.html

f:id:a_nakatsugawa:20170619091636p:plain

フォーマットは text(デフォルト)/html/yaml/json/xml/code_climate が指定できます。

todo ファイルを作る

恐らく最初に Reek を実行すると多数の警告が出るはずです。それらをすべて、いきなり対応するのは困難でしょう。そこで一旦 todo ファイルを作成してみましょう。

$ reek -t .
'.todo.reek' generated! You can now use this as a starting point for your configuration.

こうすると .todo.reek というファイルが生成されます。これは警告内容をすべてオフにした Reek 用の設定ファイルです。内容は次のようになっています。

$ cat .todo.reek
---
BooleanParameter:
  exclude:
  - NCMB::Acl#public
  - NCMB::Acl#role
  - NCMB::Acl#user
DuplicateMethodCall:
  exclude:
  - NCMB::Acl#role

つまり、この設定ファイルを指定して実行すると警告が一切出ません。設定ファイルの指定は -c オプションになります。

$ reek -c .todo.reek 
Inspecting 32 file(s):
................................
 
0 total warnings

もちろんこのままでは意味がありませんので、徐々に設定を有効にしながら修正を進めていけば良いでしょう。

Reekはデフォルトで .reek という設定ファイルを読み込んで使います。ある程度の設定ができあがってきたら、 .reek にリネームすると良いでしょう。なお、SideCIでのオススメ設定はこちらの内容になります。

指摘される例とその回避策

例えば一つのクラスが多くのメソッドを持っていることを指摘します。デフォルトでは15以上のメソッドを持っていると TooManyMethods の警告が出ます。他にもイテレータがネストになっていると NestedIterators の警告が出ます(デフォルトは1つのネストで警告)。他にも複数回のメソッド呼び出しに対する警告もあります。

こうした警告の中には回避しようのない場合もあるはずです。設定ファイルを記述する方法もありますが、ソースコード中のコメントで回避することもできます。例えば複数回の呼び出しに対する警告を回避する場合は記述です。この時だけ設定を変更できます。

# :reek:DuplicateMethodCall { max_calls: 2 }
def user(user, read_or_write, value = true)
  @fields[user.objectId.to_sym] = {read: true, write: true} unless @fields[user.objectId.to_sym]
  @fields[user.objectId.to_sym][read_or_write.to_sym] = value
end

Reek の指摘はとても数多いので、コメントや設定ファイルを使って必要なものだけをピックアップして採用するのが良さそうです。SideCIのオススメ設定ファイルを利用するのもぜひ検討してください。


Reek は個人のローカルコンピュータ上で実行することもできますが、複数人での開発体制になったならばクラウドで全員分まとめてチェックできる仕組みが便利です。SideCIはReekにも対応しており、皆さんのRubyプロジェクトを保守性、可読性ともに高い状態に維持します。トライアルも提供していますのでぜひご利用ください