Page 1
ゆるふわCI入門
A casually guide for PHP Continuous Integration
2019-03-30 PHPerKaigi 2019 Day 1
Nerima Coconeri Hall #phperkaigi
公開日:
by USAMI Kenta@tadsan
に東京都の練馬区立区民・産業プラザ Coconeriホールで開催された『PHPerKaigi 2019』でレギュラートーク(30分)として発表しました。
A casually guide for PHP Continuous Integration
2019-03-30 PHPerKaigi 2019 Day 1
Nerima Coconeri Hall #phperkaigi
あんまり関連ないです
アジェンダ
CIとは何かCIで何ができるかCI実行環境の種類ゆるふわにCIを始める実際の事例について
CodeIgniter(Web Framework)の話はしません
CD (Continuous delivery/deployment)の話もしません
個別のCI製品の設定の話もしません
CIとは何かCIで何ができるかCI実行環境の種類ゆるふわにCIを始める実際の事例について
本題の前に
今回紹介するツールとGitLab CIの設定をまとめてセットアップできるプロジェクトを用意してます
https://gitlab.com/zonuexe/phperkaigi-ci
予め断っておきますがこの構成では規模の大きなプロジェクトではパフォーマンス目立ちます(断言)
実プロジェクトに導入する際は各自の責任で取捨選択してください
あとすみませんWindowsではたぶん動きません
CIとは何か
単にシーアイと呼びます
CIとはContinuous Integration(継続的インテグレーション)の略
もともとはXP(エクストリームプログラミング)コミュニティで明文化されたもの…らしい
有名な文章は2000年に書かれた
議論には登るが、実⾏に移されることの少ない「ベストプラクティス」がソフトウェア開発にはいっぱいある。その中でも、もっとも基本的かつ重要なもの⼀つが、「完全に⾃動化されたビルドとテストプロセス」だ。これは、プロジェクトチームが⾃分のソフトウェアのビルドやテストを⼀⽇に何度も⾏うことを可能にするものである。
–Martin Fowler, 継続的インテグレーション (オブラブ訳)
http://objectclub.jp/community/XP-jp/xp_relate/cont-j
全てのソースコードが格納され、誰でも最新の(そして過去の)ソースを取り出すことが可能な、ただ一つの出入口を設定すること
ビルドプロセスを自動化して、誰でも、コマンド一つでソースからシステムを作り出すことができること
テスト作業を自動化して、コマンド一つでいつでもテストスィートを実行できるようにすること
現行の実行可能モジュールで、もっとも適切であると自信を持てるようなものを、誰でも入手可能であるようにすること
–Martin Fowler, 継続的インテグレーション (オブラブ訳)
http://objectclub.jp/community/XP-jp/xp_relate/cont-j
Git/GitHub
Composer
全てのソースコードが格納され、誰でも最新の(そして過去の)ソースを取り出すことが可能な、ただ一つの出入口を設定すること
テスティングフレームワーク
ビルドプロセスを自動化して、誰でも、コマンド一つでソースからシステムを作り出すことができること
git tag / master
テスト作業を自動化して、コマンド一つでいつでもテストスィートを実行できるようにすること
現行の実行可能モジュールで、もっとも適切であると自信を持てるようなものを、誰でも入手可能であるようにすること
–Martin Fowler, 継続的インテグレーション (オブラブ訳)
http://objectclub.jp/community/XP-jp/xp_relate/cont-j
Git/GitHub
Composer
全てのソースコードが格納され、誰でも最新の(そして過去の)ソースを取り出すことが可能な、ただ一つの出入口を設定すること
テスティングフレームワーク
ビルドプロセスを自動化して、誰でも、コマンド一つでソースからシステムを作り出すことができること
git tag / master
テスト作業を自動化して、コマンド一つでいつでもテストスィートを実行できるようにすること
現行の実行可能モジュールで、もっとも適切であると自信を持てるようなものを、誰でも入手可能であるようにすること
–Martin Fowler, 継続的インテグレーション (オブラブ訳)
http://objectclub.jp/community/XP-jp/xp_relate/cont-j
銀の弾丸はない
コードの規模や構造によって導入できるツール・できないツールがある
大規模なコードになるほど実行時間が掛かるようになり工夫が必要になってくる
CIで何ができるか
継続的にされてると嬉しいこと
いろいろあるだろうが、基本的にはコードが正常に保たれてることは確認し続けたい(コード上の異常発生を迅速に知る)
そのほか属人化してる項目や忘れられがちなプロセスを盛り込めるとよい
コードの異常を検知するには
実行してチェックする
自動テスト(ユニットテスト, 受け入れテスト)
人間が動作確認
実行せずコードの品質を検査する
「QAツール」と総称される
自動テスト(ユニットテスト)
PHPUnit, phpspecなど
小さな単位でテストすることが理想だが、コードが古く結合度が高いプロジェクトではユニットテストに表現することが困難なこともある
自動テスト(受け入れテスト)
Codeception
実際にHTTPリクエストを行ってテストできるフレームワーク
古くテストが少ないプロジェクトではこちらの方が導入しやすいかもしれない
QAツール (Quality Assurance)
大まかに二種類に大別できる
字句解析ベースで主にスタイルを検査するもの
再帰的な型検査を行うもの
コーディングスタイルベース
コードを字句的に解釈する
PHPMD (PHP Mess Detector)
PHP_CodeSniffer & phpcbf
PHP Coding Standards Fixer
修正までやってくれるやつ
型検査を含む精密な型検査
字句的な静的解析ツールはオブジェクトの未定義メソッド検出などはできないのに対して、最近開発が活発なツールはコードパスを詳細に解析して、さまざまな情報を出してくれる
型検査を含む精密な型検査
それぞれ開発が活発なツール
PHPStan, Psalm, Phan
ぶっちゃけキャラが被ってるけど、それぞれ検出してくれるポイントが違ったりする
PHPStan vs Phan
Phanは純粋な静的解析
プロジェクト全体スキャン
PHPStanは実行時情報も利用し必要なファイルのみ解析
高速に結果を返したい場合はPHPStanの方が有利
PHPStanの制約
クラスや関数・定数の定義を予め(または遅延)読み込みできるようにする必要がある
PSR-1(定義だけのファイルと副作用の処理を分離すること)が重要
PHPStanの制約
ComposerとかPSR-1を考慮してない時代のPHPプロジェクトには厳しいが、ハードルを越えれば高速で頻繁なビルドが可能
PHPStanの効能
今回の本題とは少し離れるが、EmacsやVimでチェッカーのバックエンドとして適切に設定すると、PhpStormを凌ぐ情報量がリアルタイムで得られる
Vim+ALE
CIの実行環境
いろいろ
CIはいつ実行する
「たくさんやるほうが望ましい」
多くのCIサービスでGitHubと連携して、Pull Requestを作成したブランチにPushするたびに毎回ビルドを行うのが普通
結果はPRのページに表示される
汎用CIの実行環境
テストプログラムを「自動的」かつ「継続的」に実行する必要がある
汎用のCIと特定用途のCIがある
現実的には下記のどちらか
各種CI SaaSのどれかと契約
CI用のサーバを自前で用意
CI SaaS (hosted)
サーバ自前管理の必要がない
典型的にはGitHubなどと連携
CI側が用意したOS環境を利用するものと、Dockerイメージを利用するものがある
CI SaaSの制約
GitHub EnterpriseやオンプレのGitLabは連携できない
各種CIのオンプレ版(有償)を利用することで利用できるが、サーバの調達・管理は自前で行う必要がある
オンプレミスのCI
サーバを自前で調達・管理する必要がある
無料の製品ではJenkinsの牙城だった
自前でGitLab CEをCI機能を持ってるので連携することもできる
GitLabの場合
GitLabには複数ある
SaaS版のGitLab.com
オンプレ版のGitLab
それぞれの有料・無料版
どちらもCI機能が統合されてる
GitLab.com
無料でプライベートリポジトリ可
無料版でもCI機能が利用可能
グループあたり月2000分まで
設定ファイルに書くだけでDockerでビルドが実行される
特定用途のCI
PHP解析
SensioLabsInsight
Scrutinizer
コーディングスタイル
StyleCI
御託はわかった
で、結局いろいろ準備しなくちゃいけなくてめんどくさいんでしょ?
ゆるふわに始めるCI
もっと気軽に手を付けられるところからやっていきましょう
継続して動かせるサーバがないさてどうするか
全てのソースコードが格納され、誰でも最新の(そして過去の)ソースを取り出すことが可能な、ただ一つの出入口を設定すること
ビルドプロセスを自動化して、誰でも、コマンド一つでソースからシステムを作り出すことができること
テスト作業を自動化して、コマンド一つでいつでもテストスィートを実行できるようにすること
現行の実行可能モジュールで、もっとも適切であると自信を持てるようなものを、誰でも入手可能であるようにすること
–Martin Fowler, 継続的インテグレーション (オブラブ訳)
http://objectclub.jp/community/XP-jp/xp_relate/cont-j
複雑な反復作業があれば、一個のコマンド(スクリプト)でまとめてみることから始める
ところで
みなさんSyntaxErrorのPHPスクリプトを本番に反映して事故ったことはありますか?
私はたくさんあります
Syntax Errorになるファイルを確実に捕捉してみましょう
git ls-files '*\.php' |xargs -I{} php -l {}
Windowsにはxargsがない(たぶん)のでPHPでhttps://gist.github.com/zonuexe/a513afd1d6933b3cc5cca0eb866f2834
ファイルが数十個単位ならすぐに終るが、数千単位になると全数の検査はかなり時間が掛かるので注意
弊社での事例について
ファイル数 6264
行数 974419
毎回全ファイルをチェックするのはさすがにつらい
デプロイ時に常にgit tagをつけるデプロイスクリプトで、デプロイ成功したら日時と作業者名を含むタグを生成してoriginにpushする
最新のリリースタグとの差分をとるこれで最新デプロイと手元の差分があるファイル抽出できる
デプロイ時にphp -lを行う差分のあるファイル全部に対してチェックを実施し、一つでもエラーのファイルがあったらデプロイ処理を中断する中断されるとtagはつかないので、差分が隠れることはない
MergeRequestと二種類のビルド
PHPUnit
PHPStanおよび独自Linter
それぞれ実行時間は1分ちょっと
PHPStan
PHPStan本運用のためbootstrap処理の軽いリファクタリングをした
_autoloader_for_static_analysis.php
この作業によってPhpactorという別ツールも利用可能に
PHPUnit
直列実行で10分前後かかっていた
テストが依存するMySQLを複数起動し、PHPUnitのプロセスを並列実行することで1分程度で完了
masterブランチへのテスト
MRのテストを無視してmasterにマージされたときの防波堤
この段階で失敗したテストはSlackで報告される
時刻に依存したテストのランダムフェイルがたまに報告される
実行環境
GitLab CI + Jenkins
以前はPHPStanの警告はGitLabのMRへのコメントで報告
現在はCI実行はAWSまたはJenkinsで、それぞれの結果をGitLabのパイプラインに統合
まとめ
どのようなCIを導入するか
プロジェクトの現状・性質による
テストが書ける密結合度か
定義ファイルは分離されてるか
(同名の関数や定数が複数定義されてるとはまる)
発表時に書きそびれたこと
小姑CI
コーディングスタイルのような重箱の隅は人間がコードレビューで小うるさく責めるより、Botが鉄の心で指摘した方が角が立たない
PHP-CS-Fixerやphpcbfのようなコマンド一撃で修正されるようにすれば手間もかからない
どんな場合も静的解析を導入すべきか
普通の既存プロジェクトをPHPStanやPhanで解析すると異常な量の型の不整合の警告が出るのが普通
多すぎる警告を目のあたりにすると、人間は無力感に苛まれる(学習性無力感)
警告を深刻に受け止めない
そのプロダクトが実際は動いてるのであれば、現状をあまり深刻に感じる必要はない
警告は記述の不整合や曖昧な点を教えてくれてるだけなので、「警告を減らす」ことに価値がある
注目する警告を減らす
Phanであればmasterでのログ出力とブランチでの出力が減る(増えない)ことだけに注目する
PHPStanであれば、ブランチで変更したファイル(と、そのクラス/関数を使ったファイル)だけを対象にしてみる
解析に怯えすぎずご安全に
