こんにちは。
久々の更新です。
最近Schemaというフレームワークを作っており、
PHPでの開発について色々と新たな知識を得る機会がたくさんあります。
そこでまずは開発環境の構築編として、最低限のお作法を担保する Gitのhook を作成してみました。
それくらいきちんとやれよ という話に尽きるのですが、
自動で確認してくれるに越したことはありません。
プログラマは得てして機械的な確認が苦手な生き物です。楽することに全力であるべきです。
(マジレスをすると、人的要素を排除することで、うっかりや人為的なミスが無くなるので、より確実にコードの品質を担保できます。
ただし、このチェックが通れば完璧というわけではないので、加えて動作確認やコードレビュー等の人的チェックも必要かと思います)。
と能書きはこのくらいにしておいて、具体的にやりたいことは以下の通りです。
上記5点の確認をコミットする前に行い、どれか1つでもコケた場合は コミットできない という縛りを加えようと思います。
さすがに業務や複数人でやるプロジェクトでこれは相当キツイので、
いくらか縛りを外せば、ちょうどいい感じの制約になると思います。
それぞれの項目について説明していきます。
これは5番目のテストとかぶるのですが、
たまに 自分が書いたコードを一度も実行・確認せずにコミットしやがる輩 が居て、pullした途端に動かなくなるということがあります。
そんなゴミクズ野郎にならないように、最低限構文エラー起こしてるコードはコミットしないためにチェックします。
PHPのコーディング標準として、PSRというものが挙げられています。
コミットの制約に加えるか否かはさておき、読んでおいて損はない規約だと思います。
あと3と4もあるのですが、とりあえずこれだけ知っておけば問題ないので割愛します。 これら一般的なコーディング規則に則ったコードになっているかをチェックしていきます。
書いてる途中で気付けよ というお話ではありますが、
もしこのようなコードをうっかり書いてしまい、それに気づかずコミットしてしまわないようにコードの品質チェックを行います。
PHPにはcomposerという依存関係の解決ツールがあります。
RubyでいうとこのBundler
みたいなものです。
ナウいPHP開発をしているならcomposer
の存在はほぼマストになっていると思います。
昨今では、だいたいのライブラリがcomposer経由でインストールできるようになっています。
私がよくやらかすケツカンマ問題
とシングルクオートつけちゃう問題
のチェックをしてもらいたいがためのチェックです。
「ケツカンマ」とは、配列の末尾要素のあとにカンマをつけたりオブジェクトの末尾にカンマをつけてしまうアレです。
jsではIE9以降ならケツカンマがきちんとパースされてしまうので、つい忘れがちですがJSONの書式としては不正です。
シングルクオートは言わずもがな、JSONでは不正な形式です。
「ケツカンマ問題」
— Sotaro KARASAWA© (@sotarok)
2012, 5月 2
「テストを書かずに実装だけドバドバ貯めていって、あとからテストを埋めてく」のはいささか危険です。
私の経験談では、趣味でのコーディングではほぼ確実に途中で心が折れます。
最近上司の教えで、コードとテストコードを併せてレビューして頂いているのですが、
実装と実装した分テストを書くのであれば、記述量がそこまで多くないのと、実装した直後なので割と仕様や考慮漏れに気づくことが出来ます。
これは良い習慣だ と思ったので強制的に癖をつけようということで制約に追加しました。
あとはREADMEの日本語チェックとかも入れたかったのですが、
色々やりすぎるとコミットできなくなって飽きる
と思ったので制約はこれくらいにしておきます。
上記の制約なら、普通にコード書いていれば問題ないはずの制約です。
自分自身の「当たり前」のクオリティを上げるために矯正ギプスをはめます。
Gitプロジェクトであれば、./.git/hooks
の中に色々とファイルが入っています。
bareリポジトリでGit pushされたら云々する、とかにも使うやつです。
今回はコミット前にチェックをしたいので、pre-commit
を使用します。
hooksディレクトリの中にpre-commit.sample
というファイルがあるので、.sample
を除去したファイルを複製します。
ls .git/hooks
cp .git/hooks/pre-commit.sample .git/hooks/pre-commit
エディタはなんでもいいので、複製したpre-commit
を開いて下さい。
#!/bin/sh
#
# An example hook script to verify what is about to be committed.
# Called by "git commit" with no arguments. The hook should
# exit with non-zero status after issuing an appropriate message if
# it wants to stop the commit.
#
# To enable this hook, rename this file to "pre-commit".
if git rev-parse --verify HEAD >/dev/null 2>&1
then
against=HEAD
else
# Initial commit: diff against an empty tree object
against=4b825dc642cb6eb9a060e54bf8d69288fbee4904
fi
# If you want to allow non-ASCII filenames set this variable to true.
allownonascii=$(git config --bool hooks.allownonascii)
# Redirect output to stderr.
exec 1>&2
# --- 長いので割愛 ---
という感じのファイルになっていると思います。
このファイルを実行した時の終了コードが1
なら、コミットが失敗するようにできています。
すでに先駆者の方がいらっしゃったので、そちらをパクりつつ、拡張とカスタマイズを加えます。
gitのpre-commit hookを使って、綺麗なPHPファイルしかコミットできないようにする
— http://blog.manaten.net/entry/645
先ほどの長いので割愛以下に、このコードを貼り付けて下さい。
IS_ERROR=0
# コミットされるファイルのうち、.phpで終わるもの
for FILE in `git status -uno --short | grep -E '^[AUM].*.php$'| cut -c3-`; do
# シンタックスのチェック
if php -l $FILE; then
# PHPMDで未使用変数などのチェック
if ! ./vendor/bin/phpmd $FILE text unusedcode,codesize,naming; then
IS_ERROR=1
fi
# PSR準拠なコードかチェック
if ! ./vendor/bin/php-cs-fixer fix $FILE --dry-run -v --diff; then
IS_ERROR=1
fi
else
IS_ERROR=1
fi
done
# composer.jsonのバリデーション
if ! ./composer.phar validate; then
IS_ERROR=1
fi
# テストを実行
if ! ./vendor/bin/phpunit -c tests/phpunit.xml; then
echo " ,、,,,、,,, "
echo " _,,;' '\" '' ;;,, "
echo " (rヽ,;''\"\"''゛゛;,ノr) "
echo " ,; i ___ 、___iヽ゛;, テスト書いてないとかお前それ@t_wadaの前でも同じ事言えんの?"
echo " ,;'''|ヽ・〉〈・ノ |゙ ';, "
echo " ,;''\"| ▼ |゙゛';, "
echo " ,;'' ヽ _人_ / ,;'_ "
echo " /シ、 ヽ ⌒⌒ / リ \ "
echo "| \"r,,`\"'''゙´ ,,ミ| "
echo "| リ、 ,リ | "
echo "| i ゛r、ノ,,r\" i _ | "
echo "| `ー――-----------┴ ⌒´ ) "
echo "(ヽ _____________ ,, _´) "
echo " (_⌒_______________ ,, ィ "
echo " T |"
echo " | |"
IS_ERROR=1
fi
exit $IS_ERROR
</code>
テストを書かない人にはサバンナからお導きがあるようなので、そちらを使わせていただきました。
カバレッジの話になると閾値の調整が難しいのでカバレッジは見てません。判断基準は、テストに通るか否かです。テストがない場合も通ってしまいますが、そこは人力チェックで問題ない範囲でしょう。
参考元の記事ではphp-cs-fixer
は勝手に修正を加えるようになっていたのですが、
勝手に直されるのは性分じゃないので、自動的な修正はせず怒ってもらって、自分で修正するようにします。
このpre-commitの実行にはいくつかコマンドが必要なので、
composer.json
にこれらを追加しておいて下さい。
"require-dev": {
"phpmd/phpmd": "@stable",
"fabpot/php-cs-fixer": "@stable",
"phpunit/phpunit": "4.*"
}
これらを考慮し、新規プロジェクトを作成するときの最低限のコマンドをまとめます。
mkdir SOME_PROJECT
cd SOME_PROJECT
git init
# --- composer
curl -sS https://getcomposer.org/installer | php
./composer.phar init # 必要事項を入力
vim composer.json # phpmd,php-cs-fixer,phpunitの指定を追加
./composer.phar install
echo vendor >> .gitignore
# --- PHPUnit
git clone tests
rm -rf tests/.git
# --- git hook
cp .git/hooks/pre-commit.sample .git/hooks/pre-commit
vim .git/hooks/pre-commit # 先ほどのhookを貼り付け
# --- initial commit
touch README.md
git add .
git commit -m "initial commit"
PHPUnitの設定は結構面倒なので、gistにスケルトンを作っておき、それをtests
というディレクトリ名でcloneしてます。
ほかは特に変わったところはないと思います。
いかがでしたでしょうか。
PHPのプロジェクト作成と一口にとっても、色々と改良の余地がありそうです。 こんな感じで、少しでもウンコード発生率を下げましょう! ! !
冒頭に紹介したschemaはまだこの記事を書く前に作成されたプロジェクトなので、PSR0準拠できていません。
ぼちぼちと修正中です。
PHPMD – PHP Mess Detector
— http://phpmd.org/
The PHP Coding Standards Fixer for PSR-1 and PSR-2
— http://cs.sensiolabs.org/