読者です 読者をやめる 読者になる 読者になる

SideCI Blog

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



コーディング規約をチェックするRubocopとPHP_CodeSniffer

Ruby PHP Other

コーディング規約をチェックしてくれるツールをRuby、PHP用に1種ずつ紹介したいと思います。RubocopはRuby Style Guideにコードが準拠しているかをチェックしてくれるツールです。PHP_CodeSnifferはPHPの一般的なコーディング規約に準拠しているかをチェックしてくれるツールです。

コーディング規約

コーディング規約はコードの書き方に関して予め定めておく規約のことです。辞書サイトから引用すると下記のような意味やメリットが有ります。

『コーディングルール』
コードの書き方に関する決まりごと。プログラミング言語の文法とは異なり、様々な書き方が可能な場合にどういった書き方にするかを集団内の約束として決めたもの。変数や関数などの命名規則や、利用してはいけない機能などの禁止事項、インデントやスペース、括弧の書き方などで構成される。
企業の開発部門やオープンソースプロジェクトなど集団でプログラミングをする場合、各々ばらばらの流儀でコードを書くと他人の書いたコードを理解したり修正したりすることが難しくなる。コードの表記法をコーディングルールとして統一しておくと、可読性や保守性が高まり、開発効率を向上させることができる。
http://e-words.jp/w/E382B3E383BCE38387E382A3E383B3E382B0E383ABE383BCE383AB.html

SideCIの社内の開発では現状はテキストベースで規約を設けて、それを準拠するよう努力する程度にとどめ、コードレビューの際などに軽く触れ合う程度です。

しかし、開発人数が多くなってくると、コードの書き方の揺れもエンジニアにとっては気になってくることでしょう。みんなできればきれいな一貫性のあるコードを読み書きしたいものです。

今回紹介する2種はそれを支援してくれるOSSのツールです。いずれはSideCIサービス内でもワンクリックで有効化出来るようにする予定ですが、今しばらく時間がかかるため、ツールの紹介のみに留めさせて下さい。

チェックツール2種 Rubocop PHP_CodeSniffer

Rubocop

RubocopはRuby Style Guideにコードが準拠しているかをチェックしてくれるツールです。使い方は簡単です。

RubyGemsで管理されているのでワンコマンドでインストール出来ます。

$ gem install rubocop

実行もワンコマンドで可能です。

$ cd project_dir
$ rubocop

カレントディレクトリでRubocopにより解析が実行され、例えば下記のような結果が出力されます。

$ rubocop
Inspecting 35 files
CCWCCCCCC...CW.CCCC...CCCCCCCCCC..C

Offenses:

app/controllers/application_controller.rb:1:1: C: Missing top-level class documentation comment.
class ApplicationController < ActionController::Base
^^^^^
app/controllers/application_controller.rb:2:1: C: Trailing whitespace detected.
app/controllers/application_controller.rb:3:1: C: Trailing whitespace detected.
app/controllers/application_controller.rb:8:3: C: Use empty lines between defs.
  def index2
  ^^^
app/controllers/application_controller.rb:10:3: C: Use empty lines between defs.
  def index
  ^^^
app/controllers/application_controller.rb:12:1: C: Indent access modifiers like private.
private
^^^^^^^
app/controllers/application_controller.rb:12:1: C: Keep a blank line before and after private.
private
^^^^^^^
app/controllers/application_controller.rb:15:7: C: Prefer single-quoted strings when you don't need string interpolation or special symbols.
    p "test"
      ^^^^^^
app/controllers/application_controller.rb:16:5: C: Redundant return detected.
    return true
    ^^^^^^
(中略)
35 files inspected, 113 offenses detected

これらの元になるコーディング規約はカスタマイズが可能です。たとえば、日本語が入っていると標準では規約違反になりますが、文字列エンコードに関する規約チェックをオフにすれば、規約違反として検出はされなくなります。

また、「規約」チェックの特徴として、「規約」は非常に明確であることが多いです。そのため、Rubocopでは規約違反を自動修正することが出来ます。

$ rubocop -a
Inspecting 35 files
CCWCCCCCC...CW.CCCC...CCCCCCCCCC..C

Offenses:

app/controllers/application_controller.rb:1:1: C: Missing top-level class documentation comment.
class ApplicationController < ActionController::Base
^^^^^
app/controllers/application_controller.rb:2:1: C: [Corrected] Extra empty line detected at body beginning.
app/controllers/application_controller.rb:2:1: C: [Corrected] Trailing whitespace detected.
app/controllers/application_controller.rb:3:1: C: [Corrected] Extra blank line detected.
app/controllers/application_controller.rb:3:1: C: [Corrected] Trailing whitespace detected.
app/controllers/application_controller.rb:8:3: C: [Corrected] Use empty lines between defs.
  def index2

(中略)
35 files inspected, 136 offenses detected, 57 offenses corrected

自動修正後は35 files inspected, 61 offenses detectedまで規約違反数が減少しました。内容としてはインデントを合わせてくれたりホワイトスペースを削除してくれたりですね。 例:

-    def set_banana
-      @banana = Banana.find(params[:id])
-    end
+  def set_banana
+    @banana = Banana.find(params[:id])
+  end

PHP_CodeSniffer

PHP_CodeSnifferはPHPの一般的なコーディング規約に準拠しているかをチェックしてくれるツールです。RubocopのPHP版といったところです。PHP_CodeSnifferは2006-09-18に0.0.5がリリースされているので、0.0.0がMay 3, 2012にリリースされているRubocopより4年も歴史があるツールです。

おそらくJava言語用の類似ツールはより歴史あるツールが揃っていると思うのですが、ビルド型言語はIDEの時点でコーディング規約をチェックしていることが多く、今回は紹介するツールから外しています。

PHP_CodeSnifferの素晴らしいところの1つは、フレームワークごとの規約が用意されている点だと思います。たとえば、CakePHPにも対応しており、CakePHP用の規約はこちらで公開されています。
cakephp/cakephp-codesniffer

厳密には、PHP_CodeSnifferが用意しているのではなく、CakePHPがPHP_CodeSnifferに対応しているのですが。

PHP_CodeSnifferのインストールはpearかcomposerで行う事が出来ます。今回はPEARの方でしてみます。また、特に意味もなく、WordPressのconfigファイルをオプションなしで解析させてみました。

$ pear install PHP_CodeSniffer
$ cd project_dir
$ phpcs wp-config-sample.php 

実行結果は下記のようになります。

FILE: /Users/sumy/Downloads/wordpress/wp-config-sample.php
--------------------------------------------------------------------------------
FOUND 6 ERROR(S) AND 4 WARNING(S) AFFECTING 6 LINE(S)
--------------------------------------------------------------------------------
 15 | WARNING | PHP version not specified
 15 | ERROR   | Missing @category tag in file comment
 15 | ERROR   | Missing @author tag in file comment
 15 | ERROR   | Missing @license tag in file comment
 15 | ERROR   | Missing @link tag in file comment
 40 | WARNING | Line exceeds 85 characters; contains 123 characters
 41 | WARNING | Line exceeds 85 characters; contains 131 characters
 86 | WARNING | Inline control structures are discouraged
 87 | ERROR   | Spaces must be used to indent lines; tabs are not allowed
 90 | ERROR   | "require_once" is a statement not a function; no parentheses
    |         | are required
--------------------------------------------------------------------------------

1行が長すぎ!とか、署名書きなよ!とか、まぁ色々ですね。

次はCakePHP用の規約を使って、CakePHPのMITなサンプルプロジェクトを適当にダウンロードしてきたものを解析してみました。

$ pear channel-discover pear.cakephp.org
$ pear install cakephp/CakePHP_CodeSniffer
$ cd project_dir
$ phpcs --standard=CakePHP .
FILE: .../Sample Project on CakePHP 2.2.4 Framework/Controller/AppController.php
--------------------------------------------------------------------------------
FOUND 1 ERROR(S) AFFECTING 1 LINE(S)
--------------------------------------------------------------------------------
 1 | ERROR | End of line character is invalid; expected "\n" but found "\r\n"
--------------------------------------------------------------------------------

standardオプションでコーディング規約を指定しています。ちなみに、指定可能な規約は下記のコマンドで確認可能です。

$ phpcs -i
The installed coding standards are CakePHP, MySource, PEAR, PHPCS, PSR1, PSR2, Squiz and Zend

--standard=CakePHPオプションなしで実行すると下記のような結果になります。Framework指定はほぼ必須ですね。

FILE: .../Sample Project on CakePHP 2.2.4 Framework/Controller/AppController.php
--------------------------------------------------------------------------------
FOUND 20 ERROR(S) AND 2 WARNING(S) AFFECTING 12 LINE(S)
--------------------------------------------------------------------------------
  1 | ERROR   | End of line character is invalid; expected "\n" but found
    |         | "\r\n"
 16 | WARNING | Line exceeds 85 characters; contains 97 characters
 16 | ERROR   | The @copyright tag is in the wrong order; the tag follows
    |         | @author
 16 | ERROR   | @copyright tag comment indented incorrectly; expected 1 spaces
    |         | but found 5
 17 | ERROR   | The @link tag is in the wrong order; the tag follows @version
 17 | ERROR   | @link tag comment indented incorrectly; expected 6 spaces but
    |         | found 10
 18 | ERROR   | Package name "app.Controller" is not valid; consider
    |         | "AppController" instead
 18 | ERROR   | @package tag comment indented incorrectly; expected 3 spaces
    |         | but found 7
 19 | ERROR   | The @since tag is in the wrong order; the tag follows @see (if
    |         | used) or @link
 19 | ERROR   | @since tag comment indented incorrectly; expected 5 spaces but
    |         | found 9
 20 | ERROR   | @license tag comment indented incorrectly; expected 3 spaces
    |         | but found 7
 21 | WARNING | PHP version not specified
 21 | ERROR   | Missing @category tag in file comment
 21 | ERROR   | Missing @author tag in file comment
 23 | ERROR   | @copyright tag must contain a year and the name of the
    |         | copyright holder
 32 | ERROR   | Package name "app.Controller" is not valid; consider
    |         | "AppController" instead
 32 | ERROR   | @package tag comment indented incorrectly; expected 1 spaces
    |         | but found 7
 33 | ERROR   | @link tag comment indented incorrectly; expected 4 spaces but
    |         | found 1
 34 | ERROR   | Missing @category tag in class comment
 34 | ERROR   | Missing @author tag in class comment
 34 | ERROR   | Missing @license tag in class comment
 36 | ERROR   | Opening brace of a class must be on the line after the
    |         | definition
--------------------------------------------------------------------------------

参考リンク:
Manual :: Standard usage information
cakephp/cakephp-codesniffer PHP Code Snifferを使ってCakePHPのコーディング規約をチェックする - Composerで簡単インストール

現在時点(2014/05/07)の安定版では自動修正機能はありませんが、アルファ版として公開されている2.0系では自動修正機能が追加されています。
http://www.squizlabs.com/php-codesniffer/2.0.0a2-released

RubocopやPHP_CodeSnifferをどうやって使うか?

RubocopやPHP_CodeSnifferは先述したようにコマンド実行で結果を得ることが出来ますが、わざわざ規約をチェックするためにコマンドを実行するのは面倒かとは思います。。。

今のところ、下記の3つの方法を使っている方が多いかと思います。

  • エディタ連携
  • CIツール連携
  • 外部サービス

エディタ連携では、Guardなどのファイルの保存などのタイミングを検知するプラグインツールを組み合わせたりして、Sublime textやVimなどのプラグインとあわせて、規約違反をリアルタイムに検出することが出来ます。コードの綺麗さが気になる方にはこの方法が一番オススメだとおもいます。
デメリットとしては、せっかくのスクリプト言語なのに、コードを少しでも書く度に、解析が走るので、マシンが重くなってしまうことでしょうか。

CIツール連携では、Jenkinsなどで定期的にコマンド実行、もしくはライブラリでの該当コマンドの実行を行うことで、毎日のコード規約違反数の増加・減少などをトラッキングしたりすることが出来るかと思います。マシンに負荷もかからず、CIサーバにのみ導入すれば良いのでチームへの導入もし易いです。
デメリットとしては、解析結果は分かるけれども、それが修正に活きやすいか?という疑問点が残るところです。ビルドが失敗するというわけではないので、あまり結果は見ないような状況が推測出来そうです。

外部サービスは、PullReviewなどが挙げられますね(Ruby用)。静的コードレビューに特化したサービスです。導入がGitHubユーザであればワンクリックであることや、結果が非常に見やすくなっていることなどがメリットとして挙げられます。
デメリットとしては、やはり「結果を見るか?活きるか?」というところや、サービスの利用料がかかってしまうところでしょうか。

今この記事を書いている時点での私のおすすめはローカルですね。指定ファイルの変更時のみなど解析タイミング、解析ファイルを限定することで、マシンリソースをなるべく利用しないようにすることが出来ますので。人数が多い、もしくはある程度プロジェクト開始から年数が経過しているプロジェクトなどはCIツールでの導入・運用がおすすめな気がします。お試ししてみたいなら外部サービス系はトライアル期間がある場合が多いので、とりあえずお試ししてみると良いと思います。

SideCIでのRubyやPHPのコーディング規約チェック

このブログの運営者である私たちが提供しているSideCIβではまだRubocopなどが提供するほどの「コーディング規約」のチェックは提供しておらず、PHPにも対応しておりません。

現状ではRailsのセキュリティホールチェックやRailsの良いコードの書き方(BestPractices)チェック、ライブラリのバージョン検知などを提供しています。マイルストーンとして、2014年5月末頃を目処にCIツールとしての箱(コンテナ)機能を提供開始予定です。

このコンテナ機能ではRubocopやPHP_CodeSnifferを実行することが可能になる予定です。また、実行結果を見やすくサービス上で整形して表示したり、GitHub上やチャットツール上に通知するなどの機能を提供し、CIツールでの自動コードレビューでの問題点だった「解析結果が活きるのか?」を解決していく予定です。

Railsプロジェクトを取り扱っている方などはSideCIをお試し頂ければ幸いです。 https://www.sideci.com/

f:id:sideci:20140507155007p:plain