形骸化しないコーディング規約のために


# はじめに

コーディング規約を守り続ける、簡単そうでとても難しいことです。
数多の宗教論争の末に打ち立てられたコーディング規約が次第に形骸化していくのはとても悲しいことです。

なぜコーディング規約を守るのは難しいのか、形骸化させないためにはどうしたら良いか考えようと思います。

# なぜコーディング規約を守れないのか

前述の通り、コーディング規約を守り続けるのはとても困難です。
明文化されていたとしても困難ですので、ましてや暗黙の了解のようになってしまっていたらもはや守るのは不可能でしょう。(暗黙的になっている時点で規約としては破綻していると思いますが)

「おい、コーディング規約守れよ(半ギレ」みたいなことを言ってしまう前に、まずはなぜ規約を守り続けることが難しいかを考えてみましょう。

## 皆、違う道を歩んできたのだ...

プログラミングの学習過程は当然ながら一人一人大きく異なっていますし、「俺は初めてJavaScriptに触れた時からみっちり[Airbnb JavaScript Style Guide](https://github.com/airbnb/javascript)を体に叩き込んでるぜ!」とか「PHPはHello Worldする時からPSR-4を意識していました。今では自然とPSR-4で書いてます。」なんていうエリートは極々少数でしょう。
つまり、程度の差はあれど全てのプログラマは何らかのクセを抱えています。
そして、企業やプロジェクトで定められた規約がクセと完全に合致していることはまず有り得ません。
(リードプログラマが強権を発揮してオレオレ規約を定めた場合は別ですが...)
よって、どんなに美しく見える規約でも各人には大なり小なり不自然な行為を強いていることになります。

このことを前提に考えることは重要かと思います。

## 人間の能力の限界

例え違和感を覚えるコーディングスタイルだったとしても、規約と定められれば各人はそれに従おうと努力してくれるでしょう。
(悪意をもって反逆する人もいるかもしれませんが、それは別次元の問題なのでここでは扱いません)

しかし、元々からして不自然な行為なので、本人に悪意がなくてもつい忘れてしまうことはおおいに有り得ます。病院で処方された薬を飲み忘れるという経験は誰にでもあるかと思います。

そして、コードをレビューする側としても規約に準じているかをチェックすることには限界があります。すると少しずつ規約から外れたコードが混ざっていくようになります。それを見つけた人が「ここ規約から外れてるやん、直したろ!」となるようなモラルの高いチームなら問題ないかもしれませんが、そんなチームを作り上げて維持し続けるのは、それはそれで非常に難しいでしょう。


# コーディング規約を守り続けるために

ここまでの考察をまとめると、
コーディング規約を守り続けるのが難しい理由は

1. コーディング規約は大なり小なり各人の感覚と合わない部分があるから
2. ゆえに、気をつけてても抜けることがあるし、それを全て拾い上げるのも人力では難しい

の2点になるでしょう。

つまり **規約の遵守を個人の努力に委ね、それを人がチェックするのがダメ** ということになります。
そうなると解決策としては

1. 意識しなくても自動的に規約に沿ったコーディングをできる仕組みを作る
2. チェックは人間がするのでなく、機械に任せる
3. 規約を守らざるを得ないようなフローにする


というディストピア的方法をとることになります。
ここから先は実際に私が導入しているツールを紹介する形で進めたいと思います。

## 規約遵守の自動化

[editorconfig](http://editorconfig.org)の導入が有効です。

文字コード、改行コード、インデントといった項目を.editorconfigファイルに書き、あとはメンバーにeditorconfig対応のIDEなりエディタなりを使うようにしてもらえば、ソフトタブとハードタブが入り乱れたり、シェルスクリプトにCRLFが混ざり込んだせいでLinuxで動かすと死ぬといった現象から解放されます。

.editorconfigファイルはこんな感じ

```.editorconfig
# EditorConfig is awesome: http://EditorConfig.org

# top-most EditorConfig file
root = true

# Unix-style newlines with a newline ending every file
[*]
end_of_line = lf
insert_final_newline = true

# Matches multiple files with brace expansion notation
# Set default charset
[*.{js,py}]
charset = utf-8

# 4 space indentation
[*.py]
indent_style = space
indent_size = 4

# Tab indentation (no size specified)
[Makefile]
indent_style = tab

```

これ自体はただのテキストファイルなので、バージョン管理できるし、簡単に使いまわせるし、それでいてプロジェクトごとに変えたりもできるしで非常に取り回しが良いです。

ただし、editorconfigで対応できるのは本当に全般的な部分ですので、ソースの中身に踏み込んだチェックはできないということは注意しましょう。

## チェックの自動化

私は主にJavaScriptを扱ってるので、[ESLint](http://eslint.org)を導入しています。
JavaScriptのLintツールは他にも[JSLint](http://www.jslint.com)とか[JSHint](http://jshint.com)とかありますが「[時代はESLint。JSLintでもJSHintでもなくESLint。](http://qiita.com/inuscript/items/dcf48f56d8f484c0a1a8)」とのことなので。

個人的に感じたESLintの素敵なところは

* ルールが豊富な上に個別にon/offを設定できる
* 設定ファイルをJSON形式で保存できる
* プリセットのルールで結構対応できる
* **簡単に直せるやつ(セミコロン必ずつけろ、とか)は自動的に直してくれる**

といったところです。
使えるルールは本当に多いので、導入前に必ず公式ドキュメントに目を通しておきましょう。

## 規約を守らざるを得ないフロー

editorconfigは自動的に適用されていくので良いのですが、ESLintに関しては結局各人が適宜cliを叩くなどして実行する必要があります。
まあ、コードレビューの段階で最初にレビュアーがESLintを走らせて、引っかかったら実装担当者に突き返すようにするだけでも効果的とは思いますが、 **レビュアーもLintし忘れるという事態も十分あり得ます**。

そこで活躍するのがJenkinsのようなCIツールですね。

私の開発環境ではAWS使いまくりで

1. CodeCommitの特定のブランチへのpushを検知
2. CodeBuildでビルド・テストを実行
3. ElasticBeanstalk(ステージング環境)にデプロイ
4. Dockerイメージを作成してECSにpush
5. ステージング環境で確認して問題なければ最新のDockerイメージを本番サーバにデプロイ

という流れにして、1~4をCodePipelineで自動化してるのですが、2にESLintでのチェックを盛り込み、規約違反を検知したらその時点で止めるようにしています。
これによって規約を守らざるを得なくなりますし、3以降に進んだソースは少なくとも規約が守られていることが保証されて安心ですね。

# まとめ

というわけで、途中からはただの紹介になってしまいましたがまとめますと、

* 人間がコーディング規約を守り続けるのは難しい
* なので、以下のような施作が必要
	1. 自動的に規約に沿うような仕組みづくり(editorconfig)
	2. 静的にソースを解析するツールの導入(ESLint)
	3. ワークフローにLintチェックを盛り込む(CIツール、CodeBuild)

といったことがコーディング規約を守り続けるために必要かと思います。

ソースを綺麗に保って、快適なコーディングライフを送りましょう!

# 参考

## 公式

* [Airbnb JavaScript Style Guide](https://github.com/airbnb/javascript)
* [editorconfig](http://editorconfig.org)
* [ESLint](http://eslint.org)
* [JSLint](http://www.jslint.com)
* [JSHint](http://jshint.com)


## Qiita記事

* [JavaScriptのスタイルガイドまとめ(おすすめ4選)](http://qiita.com/takeharu/items/dee0972e5f39bfd4d7c8)
* [どんなエディタでもEditorConfigを使ってコードの統一性を高める](http://qiita.com/naru0504/items/82f09881abaf3f4dc171)
* [時代はESLint。JSLintでもJSHintでもなくESLint。](http://qiita.com/inuscript/items/dcf48f56d8f484c0a1a8)