Skip to content

PHPゆるふわCI入門

公開日:

東京都練馬区立区民・産業プラザ Coconeriホールで開催された『PHPerKaigi 2019』でレギュラートーク(30分)として発表しました。

Download PDF

スライドテキスト

Page 1

ゆるふわCI入門

A casually guide for PHP Continuous Integration

2019-03-30 PHPerKaigi 2019 Day 1

Nerima Coconeri Hall #phperkaigi

Page 2

お前誰よ

  • うさみけんた (@tadsan) / Zonu.EXE
  • GitHub/Packagistでは id: zonuexe
  • ピクシブ株式会社サービスプラットフォーム事業部
  • Emacs Lisper, PHPer
  • Emacs PHP Modeのメンテナ引き継ぎました
  • 好きなリスプはEmacs Lispです
  • Qiitaに記事を書いたり変なコメントしてるよ

Page 3

お前誰よ

  • 2013年頃から仕事でPHPを書いてます
  • その前はRubyをちょっとやってました
  • 普段はPHP勉強会@東京などでふざけた話をします
  • 今回は実用的な話をします
  • 去年は前夜祭トークでふざけた話をしました
  • 今回の発表の内容とは

あんまり関連ないです

  • 無関係ではないけど

Page 4

Page 5

Page 6

Page 7

アジェンダ

Page 8

CIとは何かCIで何ができるかCI実行環境の種類ゆるふわにCIを始める実際の事例について

Page 9

CodeIgniter(Web Framework)の話はしません

Page 10

CD (Continuous delivery/deployment)の話もしません

Page 11

個別のCI製品の設定の話もしません

Page 12

CIとは何かCIで何ができるかCI実行環境の種類ゆるふわにCIを始める実際の事例について

Page 13

本題の前に

Page 14

今回紹介するツールとGitLab CIの設定をまとめてセットアップできるプロジェクトを用意してます

https://gitlab.com/zonuexe/phperkaigi-ci

Page 15

予め断っておきますがこの構成では規模の大きなプロジェクトではパフォーマンス目立ちます(断言)

Page 16

実プロジェクトに導入する際は各自の責任で取捨選択してください

Page 17

あとすみませんWindowsではたぶん動きません

Page 18

CIとは何か

Page 19

単にシーアイと呼びます

CIとはContinuous Integration(継続的インテグレーション)の略

もともとはXP(エクストリームプログラミング)コミュニティで明文化されたもの…らしい

有名な文章は2000年に書かれた

Page 20

議論には登るが、実⾏に移されることの少ない「ベストプラクティス」がソフトウェア開発にはいっぱいある。その中でも、もっとも基本的かつ重要なもの⼀つが、「完全に⾃動化されたビルドとテストプロセス」だ。これは、プロジェクトチームが⾃分のソフトウェアのビルドやテストを⼀⽇に何度も⾏うことを可能にするものである。

–Martin Fowler, 継続的インテグレーション (オブラブ訳)

http://objectclub.jp/community/XP-jp/xp_relate/cont-j

Page 21

Page 22

テスト自動化に必要なこと (引用)

全てのソースコードが格納され、誰でも最新の(そして過去の)ソースを取り出すことが可能な、ただ一つの出入口を設定すること

ビルドプロセスを自動化して、誰でも、コマンド一つでソースからシステムを作り出すことができること

テスト作業を自動化して、コマンド一つでいつでもテストスィートを実行できるようにすること

現行の実行可能モジュールで、もっとも適切であると自信を持てるようなものを、誰でも入手可能であるようにすること

–Martin Fowler, 継続的インテグレーション (オブラブ訳)

http://objectclub.jp/community/XP-jp/xp_relate/cont-j

Page 23

テスト自動化に必要なこと (引用)

Git/GitHub

Composer

全てのソースコードが格納され、誰でも最新の(そして過去の)ソースを取り出すことが可能な、ただ一つの出入口を設定すること

テスティングフレームワーク

ビルドプロセスを自動化して、誰でも、コマンド一つでソースからシステムを作り出すことができること

git tag / master

テスト作業を自動化して、コマンド一つでいつでもテストスィートを実行できるようにすること

現行の実行可能モジュールで、もっとも適切であると自信を持てるようなものを、誰でも入手可能であるようにすること

–Martin Fowler, 継続的インテグレーション (オブラブ訳)

http://objectclub.jp/community/XP-jp/xp_relate/cont-j

Page 24

テスト自動化に必要なこと (引用)

Git/GitHub

CIの前提となる

Composer

全てのソースコードが格納され、誰でも最新の(そして過去の)ソースを取り出すことが可能な、ただ一つの出入口を設定すること

環境は揃ってるので

テスティングフレームワーク

ビルドプロセスを自動化して、誰でも、コマンド一つでソースからシステムを作り出すことができること

基本的に組み合せで

git tag / master

テスト作業を自動化して、コマンド一つでいつでもテストスィートを実行できるようにすること

かなりいける

現行の実行可能モジュールで、もっとも適切であると自信を持てるようなものを、誰でも入手可能であるようにすること

–Martin Fowler, 継続的インテグレーション (オブラブ訳)

http://objectclub.jp/community/XP-jp/xp_relate/cont-j

Page 25

銀の弾丸はない

コードの規模や構造によって導入できるツール・できないツールがある

大規模なコードになるほど実行時間が掛かるようになり工夫が必要になってくる

Page 26

CIで何ができるか

Page 27

継続的にされてると嬉しいこと

いろいろあるだろうが、基本的にはコードが正常に保たれてることは確認し続けたい(コード上の異常発生を迅速に知る)

そのほか属人化してる項目や忘れられがちなプロセスを盛り込めるとよい

Page 28

コードの異常を検知するには

実行してチェックする

自動テスト(ユニットテスト, 受け入れテスト)

人間が動作確認

実行せずコードの品質を検査する

「QAツール」と総称される

Page 29

自動テスト(ユニットテスト)

PHPUnit, phpspecなど

小さな単位でテストすることが理想だが、コードが古く結合度が高いプロジェクトではユニットテストに表現することが困難なこともある

Page 30

自動テスト(受け入れテスト)

Codeception

実際にHTTPリクエストを行ってテストできるフレームワーク

古くテストが少ないプロジェクトではこちらの方が導入しやすいかもしれない

Page 31

QAツール (Quality Assurance)

大まかに二種類に大別できる

字句解析ベースで主にスタイルを検査するもの

再帰的な型検査を行うもの

Page 32

コーディングスタイルベース

コードを字句的に解釈する

PHPMD (PHP Mess Detector)

PHP_CodeSniffer & phpcbf

PHP Coding Standards Fixer

修正までやってくれるやつ

Page 33

型検査を含む精密な型検査

字句的な静的解析ツールはオブジェクトの未定義メソッド検出などはできないのに対して、最近開発が活発なツールはコードパスを詳細に解析して、さまざまな情報を出してくれる

Page 34

型検査を含む精密な型検査

それぞれ開発が活発なツール

PHPStan, Psalm, Phan

ぶっちゃけキャラが被ってるけど、それぞれ検出してくれるポイントが違ったりする

Page 35

Page 36

PHPStan vs Phan

Phanは純粋な静的解析

プロジェクト全体スキャン

PHPStanは実行時情報も利用し必要なファイルのみ解析

高速に結果を返したい場合はPHPStanの方が有利

Page 37

PHPStanの制約

クラスや関数・定数の定義を予め(または遅延)読み込みできるようにする必要がある

PSR-1(定義だけのファイルと副作用の処理を分離すること)が重要

Page 38

PHPStanの制約

ComposerとかPSR-1を考慮してない時代のPHPプロジェクトには厳しいが、ハードルを越えれば高速で頻繁なビルドが可能

Page 39

PHPStanの効能

今回の本題とは少し離れるが、EmacsやVimでチェッカーのバックエンドとして適切に設定すると、PhpStormを凌ぐ情報量がリアルタイムで得られる

Page 40

Page 41

Vim+ALE

Page 42

CIの実行環境

いろいろ

Page 43

CIはいつ実行する

「たくさんやるほうが望ましい」

多くのCIサービスでGitHubと連携して、Pull Requestを作成したブランチにPushするたびに毎回ビルドを行うのが普通

結果はPRのページに表示される

Page 44

汎用CIの実行環境

テストプログラムを「自動的」かつ「継続的」に実行する必要がある

汎用のCIと特定用途のCIがある

現実的には下記のどちらか

各種CI SaaSのどれかと契約

CI用のサーバを自前で用意

Page 45

CI SaaS (hosted)

サーバ自前管理の必要がない

典型的にはGitHubなどと連携

CI側が用意したOS環境を利用するものと、Dockerイメージを利用するものがある

Page 46

Page 47

CI SaaSの制約

GitHub EnterpriseやオンプレのGitLabは連携できない

各種CIのオンプレ版(有償)を利用することで利用できるが、サーバの調達・管理は自前で行う必要がある

Page 48

オンプレミスのCI

サーバを自前で調達・管理する必要がある

無料の製品ではJenkinsの牙城だった

自前でGitLab CEをCI機能を持ってるので連携することもできる

Page 49

GitLabの場合

GitLabには複数ある

SaaS版のGitLab.com

オンプレ版のGitLab

それぞれの有料・無料版

どちらもCI機能が統合されてる

Page 50

GitLab.com

無料でプライベートリポジトリ可

無料版でもCI機能が利用可能

グループあたり月2000分まで

設定ファイルに書くだけでDockerでビルドが実行される

Page 51

特定用途のCI

PHP解析

SensioLabsInsight

Scrutinizer

コーディングスタイル

StyleCI

Page 52

御託はわかった

Page 53

で、結局いろいろ準備しなくちゃいけなくてめんどくさいんでしょ?

Page 54

ゆるふわに始めるCI

Page 55

もっと気軽に手を付けられるところからやっていきましょう

Page 56

継続して動かせるサーバがないさてどうするか

Page 57

テスト自動化に必要なこと (引用)

全てのソースコードが格納され、誰でも最新の(そして過去の)ソースを取り出すことが可能な、ただ一つの出入口を設定すること

ビルドプロセスを自動化して、誰でも、コマンド一つでソースからシステムを作り出すことができること

テスト作業を自動化して、コマンド一つでいつでもテストスィートを実行できるようにすること

現行の実行可能モジュールで、もっとも適切であると自信を持てるようなものを、誰でも入手可能であるようにすること

–Martin Fowler, 継続的インテグレーション (オブラブ訳)

http://objectclub.jp/community/XP-jp/xp_relate/cont-j

Page 58

複雑な反復作業があれば、一個のコマンド(スクリプト)でまとめてみることから始める

Page 59

ところで

Page 60

みなさんSyntaxErrorのPHPスクリプトを本番に反映して事故ったことはありますか?

Page 61

私はたくさんあります

Page 62

Syntax Errorになるファイルを確実に捕捉してみましょう

Page 63

git ls-files '*\.php' |xargs -I{} php -l {}

Page 64

Windowsにはxargsがない(たぶん)のでPHPでhttps://gist.github.com/zonuexe/a513afd1d6933b3cc5cca0eb866f2834

Page 65

ファイルが数十個単位ならすぐに終るが、数千単位になると全数の検査はかなり時間が掛かるので注意

Page 66

弊社での事例について

Page 67

Page 68

ファイル数 6264

行数 974419

Page 69

毎回全ファイルをチェックするのはさすがにつらい

Page 70

デプロイ時に常にgit tagをつけるデプロイスクリプトで、デプロイ成功したら日時と作業者名を含むタグを生成してoriginにpushする

Page 71

最新のリリースタグとの差分をとるこれで最新デプロイと手元の差分があるファイル抽出できる

Page 72

デプロイ時にphp -lを行う差分のあるファイル全部に対してチェックを実施し、一つでもエラーのファイルがあったらデプロイ処理を中断する中断されるとtagはつかないので、差分が隠れることはない

Page 73

MergeRequestと二種類のビルド

PHPUnit

PHPStanおよび独自Linter

それぞれ実行時間は1分ちょっと

Page 74

PHPStan

PHPStan本運用のためbootstrap処理の軽いリファクタリングをした

_autoloader_for_static_analysis.php

この作業によってPhpactorという別ツールも利用可能に

Page 75

PHPUnit

直列実行で10分前後かかっていた

テストが依存するMySQLを複数起動し、PHPUnitのプロセスを並列実行することで1分程度で完了

Page 76

masterブランチへのテスト

MRのテストを無視してmasterにマージされたときの防波堤

この段階で失敗したテストはSlackで報告される

時刻に依存したテストのランダムフェイルがたまに報告される

Page 77

実行環境

GitLab CI + Jenkins

以前はPHPStanの警告はGitLabのMRへのコメントで報告

現在はCI実行はAWSまたはJenkinsで、それぞれの結果をGitLabのパイプラインに統合

Page 78

まとめ

Page 79

どのようなCIを導入するか

プロジェクトの現状・性質による

テストが書ける密結合度か

定義ファイルは分離されてるか

(同名の関数や定数が複数定義されてるとはまる)

Page 80

発表時に書きそびれたこと

Page 81

小姑CI

コーディングスタイルのような重箱の隅は人間がコードレビューで小うるさく責めるより、Botが鉄の心で指摘した方が角が立たない

PHP-CS-Fixerやphpcbfのようなコマンド一撃で修正されるようにすれば手間もかからない

Page 82

どんな場合も静的解析を導入すべきか

普通の既存プロジェクトをPHPStanやPhanで解析すると異常な量の型の不整合の警告が出るのが普通

多すぎる警告を目のあたりにすると、人間は無力感に苛まれる(学習性無力感)

Page 83

警告を深刻に受け止めない

そのプロダクトが実際は動いてるのであれば、現状をあまり深刻に感じる必要はない

警告は記述の不整合や曖昧な点を教えてくれてるだけなので、「警告を減らす」ことに価値がある

Page 84

注目する警告を減らす

Phanであればmasterでのログ出力とブランチでの出力が減る(増えない)ことだけに注目する

PHPStanであれば、ブランチで変更したファイル(と、そのクラス/関数を使ったファイル)だけを対象にしてみる

Page 85

解析に怯えすぎずご安全に