はじめまして。配配メール開発課所属Jazumaです。 本稿では昨年2022年に当社プロダクト配配メールにおいてCI/CDパイプラインを整備した過程やその結果についてご紹介します。 CIツールの使い方やCI/CDとは何かといった内容は取り扱いません。あらかじめご了承ください。
プロダクトについて
弊社プロダクト配配メールは2007年サービス開始の長寿サービスです。
長らくお客様にご愛顧いただいていましたが、CI環境が未整備・ユニットテストが少ない・静的解析がなく目視でコードレビューする等開発環境・体制に課題がありました。
そこで、開発体制を改善すべく2022年度にCI環境を拡充しました。
2022年開始時点の状況
- ユニットテストはちょっとある
- E2Eテストは整備されている
- 静的解析は存在しない
- Jenkinsでpushの度にテストを実行しているが、あまり運用されていない
施策1: 運用ルールの整備とCIツールの移行
まずは4つ目の問題を解消するためにCIの運用ルールを整備しました。
ルールと言っても複雑なものではなく、「テストが失敗したらメンバーのメールアドレスに通知が飛ぶ。通知を受けたら原因を調査する」というシンプルなものでした。 とはいえルールが整備されたことでテストが失敗した時の対応漏れが減りました。
また、合わせてCIツールをJenkinsからGitLabCI/CDに移行しました。
理由は以下の通りです。
- Jenkinsfileよりもgitlab-ci.ymlの方が読み書きしやすいという意見があり、それに対する反論が特になかった
- JenkinsとGitLabを連携する手間が減る
- GitLabCI/CDの方がUIが洗練されており使いやすい
施策1の結果
テストが拡充したわけではないため、劇的な効果はありませんでした。 とはいえこの施策によってチームのCI基盤が整ったため、後の改善の土台となる重要な改善だったと言えます。
施策2: サブシステム構築に伴うユニットテスト・静的解析の整備
2022年8月に「業種業態・配信目的別スコアの確認」という機能をリリースすることになりました。この機能では【全サーバ全アカウントのスコア(メールの開封率や挿入されたURLのクリック率)を集計する】という要件が求められました。
この要件を満たすために、データ集計用の新規サブシステムを構築することになりました。 新規サブシステムは既存システムのコードやアーキテクチャの影響を受けないということで、「静的解析とユニットテストをしっかりと作り込もう」という方針で開発を進めました。
新規サブシステムはメインシステムと同様にPHPで開発するためユニットテストにはPHPUnit・静的解析にはPHPStanを採用しました。 この辺りは極めてオーソドックスな技術選定だったのではないかと思います。
CIの実行ルールも特に変わったところはなく、pushやマージの度にパイプラインを実行するというものです。
施策2の結果
この施策は結果としては成功だったと言えます。具体的には2つの成果につながりました。
1つは「業種業態・配信目的別スコアの確認」機能を計画通りリリースできた上、この機能に関して2023年6月現在不具合が発生していないことです。 この機能は難易度が高く計画の遅れなどが懸念されていましたが、上記の通り大きな問題なくリリースすることができました。その要因の一つとして静的解析とユニットテストでソースコードの品質を作り込むことができたこともあったのではないかと思います。
もう1つは「ユニットテストを書く」という文化がチーム内に広がったことです。「業種業態・配信目的別スコアの確認」機能の次のバージョンにて「フォローメール」という大規模な新機能がリリースされました。この機能の開発時にも可能な限りユニットテストが作成されました。
施策3: サブシステムの検証環境への自動デプロイ
パイプラインにサブシステムを検証環境に自動でデプロイする処理を追加しました。 この施策には明確な目的があったわけではなく「せっかくの機会だし自動化できる所はしておこう」くらいの意識で進みました。
仕組みとしてはごくシンプルでタグを作成する ⇒ アプリケーションに必要なファイル一式を含んだtar.gzファイルを作成 ⇒ 検証環境にデプロイする というものでした。
施策3の結果
この施策はあまり効果がありませんでした。サブシステム自体の変更頻度が低くデプロイが実行される機会がほとんどなかったことに加え、仕組みが完成した時期が遅く、活用できる場面が無かったことが原因です。 しかし、今までCI/CDパイプラインの実装経験が無かったメンバーが担当したことでチーム内に知見が広まった他、逆説的に以下のような教訓が得られました。
- 自動デプロイは変更頻度が高いシステムから優先的に実装すべきである
- 機能が完成してから自動デプロイの実装に着手しても遅い。機能開発と並行して進める必要がある
施策4: メインシステムの検証環境への自動デプロイ
2022年の秋にシステムテストを改善する取り組みを行いました。 ここでは「テストの品質を上げる( = バグを検知できるようにする)」「テストを効率化する( = 工数を削減する)」という2つの目的の元改善作業を行いました。
自動デプロイは2つ目の目的を達成するために実施しました。 試算ではシステムテスト中のデプロイおよびデプロイ作業漏れに起因する手戻りが年間10時間程度かかっていたため、自動化の効果が大きいと判断されました。
今回は施策3の教訓を踏まえて「変更頻度の大きいシステムを対象にする」「システムテストまでに完了させる」という方針で進めました。 具体的には対象をメインシステムに絞り、デプロイ処理を追加しました。
今回は全自動化したいということで、タグの作成ではなく「リリース用のブランチへのマージ」をトリガーとしてデプロイスクリプトを起動する実装としました。
施策4の結果
この施策は成功しました。 「定期的にリリースブランチへのマージを確認して検証環境へのデプロイを実行する」という雑務が無くなったことで稼働に空きができた他、割り込み作業がなくなりました。 また、検証環境が常に最新の状態に保たれていることが担保されるようになったため 不具合が見つかった場合の原因調査がスムーズになりました。
施策5: アーキテクチャテストの導入・静的解析の拡充
2023年5月に添付ファイルを直接メールに添付せずに送信する機能をリリースしました。
この機能においてもサブシステムを新しく構築しました。 今回は施策2のようなユニットテスト・静的解析に加えて新しく2つのことを試みました。
1つはアーキテクチャテストです。deptracというツールを用いてクラス間の依存関係を検査するようにしました。 これにより、関数やクラス単位の品質だけではなく「クラス同士の依存関係が適切に設定されているか」という点まで担保できるようになりました。
もう1つは静的解析の拡充です。施策2で導入したphpStanでは主に型定義や未定義変数の検出等、一般的な観点を検査しました。 今回はコード規約違反の検出など、よりチームの実情に即した観点を検査することになりました。
静的解析ツールとしてはPHP_CodeSnifferを採用しました。 (静的解析はこまめに実行できる方が手戻りのコストが小さく済むので、PHP_CodeSnifferはCIに加えてIDE上でも実行できるようにしました。本稿の趣旨からは逸れますので詳しくは取り上げません。)
施策5の結果
この施策も施策2と同様に成功しました。特にPHP_Codesniffer導入の恩恵が大きかったです。 今までは目視で確認していた項目を機械的に検出できるようになったため、コードレビューの負担が大きく減りました。 PHP_Codesniffer導入についてはこちらの記事でも触れていますのでぜひご一読ください。
現時点の課題
2022年には配配メール開発チームにおいてCI/CDパイプラインが大きく拡充されました。 しかし、課題も多く残っています。
1. 昔からあるコードにはテストを追加できていない
テストコードは主として新規に追加されるコードを対象に実装されました。
しかし、配配メールのコア機能を支え続けている古いコードにはほとんどテストコードを追加することができていません。 昔からあるコードは複雑度が高かったり密結合だったりしており、テストコードを書くことができない状態です。
テストを書くためにリファクタリングしようとしても影響範囲が大きくなかなか手が出せないという(よくある) ジレンマに直面し続けています。
2. 自動デプロイのスコープがアプリケーションのみに留まっている
現状では自動デプロイの対象はアプリケーションコードのみです。環境設定やデータベース・ミドルウェアの変更は手動で行う必要があります。
本来であれば環境・データベース・ミドルウェア含めて常に正しい状態を再現できるようになっているべきですが、稼働に余裕がない・ノウハウが足りないため手が回っていません。
最後に
ここまでお読みいただきありがとうございました。 今後も配配メール開発チームではCI/CDパイプラインを活用して より高品質なプロダクトを開発できるように努めていきます。