Rubyコーディングスタイルの現状とStandard gemのご紹介


これはRuby Advent Calendar 2018の4日目の記事になります。昨日はpink_bangbiさんのあなたのしらない Refinements の世界でした。

一行まとめ

Rubyのコミュニティ共有コーディングスタイルを目論むStandard gemをJustin Searlsが作っているので、意見があれば議論に参加しましょう!

Rubyのコーディングスタイルについて

Rubyには公式のコーディングスタイルが決められていません。また公式のフォーマッターもありません。Ruby作者のまつもとさんは、コーディングスタイルについて、積極的には統一ルールを打ち出そうとはしていないようです。

まつもとさんの考えていることと、コーディング規約&オートフォーマッタの現状についてはSiderのインタビューに詳しいです。ちょっと長いですが引用します。

まつもと : コーディング規約を決めてくれないと仕事できないよ!っていうような人もいて、「君、本当に仕事してる?(笑)それは自分で考えようよ」と思っちゃう。ただ、インデントの幅とかスペースかタブかみたいな話は、修正するとdiffが大量に出てくるのでそれは事前に考えておいたほうがいいと思いますね。

角 : オートフォーマットで触ってないところもガーッと変わってしまったりしますよね。

まつもと : そうですね。それだけはよくないと思うんだけど、無駄なdiffが発生しないようにすればコーディング規約は特に必要ないんじゃないかなと思ってしまいます。例えば、変数名は必ず長い表現にしようとか。3回しか出てこない変数が長い名前だろうが、iだろうがどうでもよくない?と考えてしまうんです。

角 : 3回だったら全く関係ないですね。もしi がグローバルでどこでも使われていたらそれは問題ですけど、そんな馬鹿げたコードは書かないと思います。

まつもと : それは普通に考えたらわかることですよね。仮にそう書いちゃったとしても、コードレビューの時にダメだっていう理由があるわけだから、「これだけじゃわからん」みたいに指摘されちゃえばいいわけです。そう考えるとコーディング規約はそこまで重要じゃないんじゃないかなと思ってるんですよね。
Rubyコミュニティーの一部でもRuboCop万歳みたいな人たちが一定の割合でいて、でもRuboCopのデフォルトだと僕の好みとだいぶ違ったりして、どうして?となるようなルールも結構入ってる。もちろんRuboCopのような静的解析ツールの価値はわかるしRuboCopの人たちを尊敬してもいます。

角 : デフォルトのRuboCopは私も苦手ですね。SideCI社内のSlackでもこのプルリクエストがRuboCop本体にマージされちゃうのかぁ。という苦言のようなコメントが出ることはありますね。

まつもと : 基本的にプログラマは自主的な側面があると思うので、自分の事は自分で決めたらいいんじゃないかな。赤ん坊を扱うみたいに1から10までこれに従っとけばいいんだというのは、プログラマとしてまともに扱われてないんじゃないかと思います。私はそう扱われなくないし、だからこそ、他の人に対してもそういう扱いをしたくないと考えています。

角 : なるほど。
まつもと : ただ、ツールの支援で色々面倒くさいことが減るという明確な理由があれば、それでチェックすればいいしそれに従えばいいんです。

( https://blog-ja.sideci.com/entry/2018/03/02/120636 より)

やっぱりそうですよねー、というまつもとさんらしいご意見です。

とはいえ、最近は最後にあるような、「ツールの支援で色々面倒くさいことが減るという明確な理由があれば、それでチェックすればいいしそれに従えばいい」というところが強く受け入れられているのか、積極的に規約を作ったり、オートフォーマッターを導入していたりしている傾向があります。

例えばPythonは、PEP 8で言語のPythonのスタンダードライブラリにおける標準的なスタイルを定義しています。

Goは標準のフォーマッターgofmtを提供しています。

またJavaScriptではJavaScript Standard Styleが作られたり、またprettierが良く使われているように見受けられます。

Rubyにもこういうのがあると良いよね、ていうかなんでないの? という意見が出てきても不思議ではありません。

Rubyで広く導入されているツールと言えば、上記インタビューでも触れられている通り、RuboCopである、という見解は大方の賛同を得られるのではないでしょうか。一方で、RuboCopの特徴として挙げられるのはそのカスタマイズ性であり、多くの場合はそれなりのカスタマイズを施した上で使われているように思います。それはそれで重宝する反面、もうちょっと手頃で、そのまま使えるフォーマッタがあると良いのでは…? という気持ちもあります。

そんなあなたにご紹介したいのが、このStandard gemです。

Standard gemとは

StandardはRubyConf 2018のLightening Talksで紹介されていたものです(私のはこの発表で初めて知りました)。

LTの動画は公式リポジトリからもリンクされているので拝見できます。


Standard Ruby Style Guide - RubyConf 2018 (https://www.youtube.com/watch?v=uLyV5hOqGQ8)

作者はJustin Sealsです。Justinはオハイオ洲在住の関西人(以前滋賀に住んでいたことがあったと聞いています)の方で、RubyKaigi 2016のキーノートスピーカーだったので覚えている方もいるかと思います。誰も知らない謎の人が提案したわけではありません。

コードを見ても、試しに実行してみても分かる通り、実装としてはRuboCopを使ったものです。standard --helpを実行すると「Usage: rubocop [options] [file1, file2, ...]」と出てくるくらいにrubocopです(と思ったら最新版では出なくなってました)。rubocopとは違うStandardの特徴は、READMEによれば以下の3点です。

  • No configuration. 設定なしでそのまま使う前提です(実際には対象外のディレクトリ指定等はできます)。
  • Automatically format code. standardrb --fixで自動的に修正されます。
  • Catch style issues & programmer errors early. 貴重なコードレビューのコストを減らして、レビュアーとコントリビューターとのやりとりを減らすためのものです。

……いやまあそうは言っても元はRuboCopなんだし、と思わないでもないですが、結局大きく違うのはデフォルトのcopの設定ということになります。

Standardで採用しているスタイルは以下になります。

  • インデントは2 spaces
  • 文字列リテラルは原則"
  • Hashは1.9以降の書き方{hash: syntax}
  • ブロックは、戻り値を使う関数的ブロックは{…}、 副作用のある手続き的ブロックはdo…end
  • 複数行のメソッドチェーンは行末に.を使う

そんなに意外性はないですが、納得しない人は納得しなさそうというか、いかにもバイク小屋なところではあります。個人的にはブロックのスタイルはちょっと引っかかります(1行は{...}で複数行はdo..end派)が、絶対に許せないというほどではありません。

使い方

gem install standardでインストールした後は、好きなレポジトリのrootディレクトリで、

standardrb --fix

と実行するだけです。もちろん、Gemfileにgem "standard"をつけて、bundle exec standardrb --fixでもOKです。--fixをつけなければ、警告のみが出力されます。

ちなみに現状では、警告の出力の最後に、

Notice: Disagree with these rules? While StandardRB is pre-1.0.0, feel free to submit suggestions to:
  https://github.com/testdouble/standard/issues/new

と表示されます。そういうことです。

で、どのくらいの警告が出るかですが、試しにsinatraで実行してみると以下のようになりました。

$ standardrb | wc
    8355  117083 1220614
$ standardrb --fix >/dev/null
$ git diff | wc
   25082   98534  821837

ざっとdiffを見たところ、'"の修正が一番多く、次に多いのがHashキーの記法(hash rocket)の変更でした。

終わりに

以上、Standard gemについて紹介してきましたが、この記事は現時点ではStandardの積極導入を求めるものではありません。

最初に引用したように、まつもとさんがコーディングスタイル標準を決めようとしていない以上、Rubyの公式スタイルが用意されることはしばらくはないでしょう。なので、コミュニティによる(強制力のない)デファクトスタンダードができるかどうか、できたとしてどういうものになるか、どの程度(あなたにとって)うれしいものになるか、という程度の話です。自分の管理するリポジトリのスタイルについてはこれからも自分の好きな通りに設定できるでしょう。なので、Rubyのスタイル一般について興味ないのであれば、ここで話は終わります。

ですが、もし興味があるとか、変なのに決まるとうれしくないとか、むしろ積極的に提案したいことがあるという場合は、お早めに https://github.com/testdouble/standard/issues にissueを立てるなりpull requestを送るなりしてみると良いのではないか、というのがこの場を借りてお伝えしたかったことです。

一度決まってしまった後だとなかなか意見が通らない可能性もあるわけで(そうじゃないと決めた意味がない)、今が良い機会かと思います。ご健闘をお祈りします。

追記

この記事を書くためにqiitaのコーディング規約タグを見ていたら、ちょうど昨日公開された記事がJavaScript Standard Styleの話でした。これについては若干ネガティブな反応も強いようですね。まあJSでセミコロン禁止はバイク小屋議論が捗りそう……と思わないでもありません。

明日はshugoさんになります。