『継続的デリバリー』 第8章 学習メモ
自動受入テストの概観
1.はじめに
継続的デリバリーにおける、自動受入テストについての調査記録です。
継続的デリバリーの中での、自動受入テストについての概観を記載します。
『継続的デリバリー 信頼できるソフトウェアリリースのためのビルド・テスト・デプロイメントの自動化』の第8章に対応します。
2.概要・目的
自動受入テストは、ドメインの観点でシステムをテスト・表現する。
ドメインの要求に対してサービスを検証し、またリグレッションから保護する。
3.対応概要
自動受入テストの観点は以下の通り。
保守しやすい受入テストスイートのために、受入テストをレイヤ化する。
実装レイヤでは、ドメインの言語を使用し、アプリケーションとのやりとりの詳細を含まず、APIやUIを参照しない。
また、GUIに対するテストの回避のために、APIをテストハーネスから呼び出す。
4.対応詳細
(1)受入テストの作成
受入テストの作成の観点は以下の通り。
- アナリスト・テスターの役割
- イテレーティブな分析プロセスにおけるメンバの役割
- 受け入れ基準の表現
- DSLの役割・ふるまい
(2)アプリケーションドライバレイヤの実装
アプリケーションドライバレイヤの実装の観点は以下の通り。
(3)受入テストの実装
受入テストの実装の観点は以下の通り。
- 状態を扱う
- 最小限のデータ
- 可能ならアトミック
- アカウントなどでスコープを分離
- 状態へのガードと状態の相対的表現
- テスト用のバックドア(特権アクセス)を作らない
- 非同期処理を同期的に検証
- 外部システムへのテストダブルの使用とあわせて、外部システムとのインターフェースを表すインタラクションテストを実施
- 統合ポイントへの小粒のテストスイートを作成。完全でなくてよく、実行タイミングを分ける。
(4)受入テストステージ
受入テストステージの観点は以下の通り。
- 受入テストの記録
- ステージに失敗したときはデプロイ不可
- 受入テストをグリーンに保つ
- 受入テスト前にデプロイメントテスト・スモークテストを実施し、受入テストの前提を検証する。このテストが失敗したとき、ステージをすぐに失敗させる。
(5)受入テストのパフォーマンス
受入テストテストのパフォーマンス改善のための観点は以下の通り。
- テストヘルパークラスを分離
- 高価なリソースを共有
- 並列テスト・コンピュートグリッドを使用
- 受入テストのためのクラウドコンピューティング
5.影響・作用
受入テストによって、デリバリーチームはユーザがシステムに求めるふるまいに集中できる。
自動受入テストをユーザの視点から見たシステムのふるまいを保証するテストとして用いることで、リグレッションによる問題への重大な防御策となる。
受け入れ基準が駆動するテストを採用することで、以下を達成できる。
- ソフトウェアが目的にかなうことを保証
- リグレッションへの防御
- 自動リグレッションテストを包括的に実施し、品質を大幅に改善
- 欠陥を素早く検出・修正
- テスターの労力を仕様の開発・探索的テストやユーザテストの実行に移せる
- サイクルタイムを減少させ、継続的な開発を可能にする
6.おわりに
以上が、継続的デリバリーの中での、自動受入テストについての概観です。
7.参考文献
『継続的デリバリー 信頼できるソフトウェアリリースのためのビルド・テスト・デプロイメントの自動化』 第8章 自動受け入れテスト
『継続的デリバリー』 第7章 学習メモ
コミットステージの概観
1.はじめに
継続的デリバリーにおける、コミットステージについての調査記録です。
継続的デリバリーの中での、コミットステージについての概観を記載します。
『継続的デリバリー 信頼できるソフトウェアリリースのためのビルド・テスト・デプロイメントの自動化』の第7章に対応します。
2.概要・目的
コミットステージの責務は、リリース候補の生成である。
コミットステージは、デプロイメントパイプラインの実装の開始地点である。
3.対応概要
コミットステージの原則とプラクティスは以下の通り。
- コミットステージでは、早期のフィードバックが重要であり、CIサーバはプレテストコミット(プレフライトビルド)を提供する。
- コミットステージが失敗したときは、チーム全体で対応する。
- 疎結合なスクリプトが重要である。
- 開発者がコミットステージを制御する。
- ビルドマスターが必要となるパターンがある。
コミットステージの出力についての観点は以下の通り。
- 成果物リポジトリの媒介的責務。
バージョン管理のリビジョンと紐づける。
コミットテストスイートにおけるユニットテストの観点は以下の通り。
- 高速かつ広範囲。
- 検証対象の単一化。
4.対応詳細
コミットテストスイートの原則とプラクティスは以下の通り。
- UIはテストしない。
- DIで他のオブジェクトから分離する。他のオブジェクトとの結合を弱める。
- DBに依存しない。ステートレスなコミットテスト。
入力と出力の組み合わせを期待結果と比較するという、テストの基本構造で表現できる疎結合なテスト設計とする。 - 非同期処理を回避する。
- テストダブルで対象でないオブジェクトをスコープから除外する。
モックで対象オブジェクトとのやり取りを検証する。スタブは呼ばれ方を表現できない。 - 時間を抽象化する。
遅延・待ちの原因となるふるまいをすべてスタブ・モック化する。 - コミットテストスイートを高速にするための解決策は以下の通り。
- テストスイートを分割し、並列実行する。
- CIサーバのビルドグリッド機能を使用する。
- 失敗しづらく時間がかかるテストを受入後のステージに移す。
5.影響・作用
コミットステージにより、変更によって入り込む欠陥をできるだけ早く検出し、開発者に通知し、問題を素早く修正できるようにすることができる。
CIに含まれるその他のプラクティスと組み合わせることで、デリバリープロセスの品質と信頼性が大幅に向上する。
6.おわりに
以上が、継続的デリバリーの中での、コミットステージについての概観です。
7.参考文献
『継続的デリバリー 信頼できるソフトウェアリリースのためのビルド・テスト・デプロイメントの自動化』 第7章 コミットステージ
『継続的デリバリー』 第6章 学習メモ
ビルド・デプロイメントスクリプトの概観
1.はじめに
継続的デリバリーにおける、ビルド・デプロイメントスクリプトについての調査記録です。
継続的デリバリーの中での、ビルド・デプロイメントスクリプトについての概観を記載します。
『継続的デリバリー 信頼できるソフトウェアリリースのためのビルド・テスト・デプロイメントの自動化』の第6章に対応します。
2.概要・目的
アプリケーションのビルド・テスト・パッケージングのスクリプト化のための最初のステップが、コマンドラインからのビルドの実行である。テストも、有名なフレームワークを使えば比較的簡単に実行できる。これらにより、CIを開始できる。
コンポーネントの増加や、通常と異なるパッケージングの必要から、複雑なビルドスクリプトを作る必要が生じる。さらに、デプロイメントの自動化のためには、より一層複雑になる。
本稿では、これらの複雑なスクリプトを扱うために、ビルド・デプロイメントツールに共通した原則の概要や、必要な情報、テクニック、さらなる参照などを記載する。
3.対応概要
本節では、ビルドスクリプトとデプロイメントスクリプトに関する一般的な原則とプラクティスを紹介する。
(1)ビルドスクリプトの設計
ビルドスクリプトが実装しているプロセスを明確に表現したものであることが理想。
スクリプトを適切な構造にし、きれいに保ち、コンポーネント間の依存関係を最小化する。
プロジェクト開始時点は、デプロイメントパイプラインを実行するためのあらゆる処理をひとつのスクリプトにまとめておく。自動化されていないステップにはダミーのターゲットを入れておく。
スクリプトが十分に長くなったとき、パイプラインのステージごとに別々のスクリプトに分ける。
これにより、コミットスクリプトができる。このスクリプトは、アプリケーションをコンパイルし、パッケージングし、コミットテストスイートを実行し、コードの静的解析を行うために必要なターゲットをすべて含む。
次に必要となるものが機能の受入テストスクリプトとなる。デプロイメントツールを呼び出してアプリケーションを適切な環境にデプロイし、必要なデータをすべて準備し、最後に受入テストを実行する。また、ストレステストやセキュリティテストといった非機能のテストを実行するスクリプトもある。
スクリプトはすべて、ソースコードと同じバージョン管理リポジトリに格納する。
(2)デプロイメントツールの使用
デプロイメントを自動化する際には、汎用スクリプティング言語ではなく適切なツールを使用する。
デプロイスクリプトは、アプリケーションをスクラッチからインストールするときと同様に、アップグレードも実施する必要がある。そのため、デプロイする前に実行中のアプリケーションをシャットダウンする必要がある。また、既存のDBを更新することもゼロから作成することもできる必要がある
(3)すべての環境へのデプロイに同じスクリプトを使う
デプロイメントスクリプトから区別した設定情報を、スクリプトから検索できる仕組みを提供する。
(4)OSのパッケージングツールを使用する
ファイルシステムをまたがって分散するファイル一式のデプロイのためOSのパッケージングツールを使用する。
また、バイナリのパッケージングは自動化する。
(5)デプロイメントプロセスの冪等化
デプロイするたびに、すべてスクラッチからデプロイする必要がある。 環境設定を宣言的に指定するツールを使用する。
(6)デプロイメントシステムをインクリメンタルに開発する
デプロイメントシステムはインクリメンタルに開発する。
4.対応詳細
(1)ビルドツールの責務
ビルドツールは、依存関係のネットワークをモデル化するという共通のコアを持つ。
タスク指向のビルドツールは、コンパイラがインクリメンタルビルドのためのロジックを持つC#などの言語のコンパイルに向いている。
プロダクト指向のビルドツールは、インクリメンタルビルド機能を持ち、CやC++のコンパイルに向いている。
(2)ビルドツールの歴史
ビルドツールの歴史を紐解いた結果として、著者の執筆時点では、以下が洗練されたツールとされている。
- Buildr
- Gradle
Psake
(3)プロジェクト構造
観点は以下の通り。
レイアウト
- ソースコード管理
- テスト管理
ビルドスクリプトで別々に実行 - ビルドの成果物の管理
ターゲットディレクトリからはバージョン管理にコミットしない。
ビルドプロセスで、アプリケーション内のコンポーネントの構成を決める。 ライブラリの管理
(4)デプロイメントスクリプトの実装
リモートマシンへのデプロイ
デプロイメントツールや基盤管理ツールの使用か、またはエージェントモデルのCIサーバにより、ローカルスクリプトをリモート環境で実行する。あるいは、自前のスクリプトでも可能。デリバリーの核:「各プロセスは前のプロセスの検証を土台とする」
- デプロイメント前の低次レイヤの検証
(5)ビルド・デプロイメントの振る舞い
観点は以下の通り。
- デプロイメント前の低次レイヤの検証
- 成果物はチェックインせず、メタデータでリビジョンと紐づける
- バイナリからバージョン管理へのトレーサビリティ
- 1ビルドに対して1コミットテストスイートを完遂
- 統合スモークテストでアプリケーションを制限
5.影響・作用
以下の観点でスクリプトの開発を実施することで、ソフトウェアのビルド・テスト・デプロイ・リリースの自動化のための仕組みを構築できる。
- デプロイメントパイプラインはイテレーティブかつインクリメンタルに開発する。
- スクリプトをバージョン管理し、デプロイメントの唯一の手段とする。
6.おわりに
以上が、継続的デリバリーの中での、ビルド・デプロイメントスクリプトについての概観です。
7.参考文献
『継続的デリバリー 信頼できるソフトウェアリリースのためのビルド・テスト・デプロイメントの自動化』 第6章 ビルド・デプロイメントスクリプト
『継続的デリバリー』 第5章 学習メモ
デプロイメントパイプラインを解剖する
1.はじめに
継続的デリバリーにおける、デプロイメントパイプラインについての調査記録です。
継続的デリバリーの中での、デプロイメントパイプラインの責務や構成について記載します。
『継続的デリバリー 信頼できるソフトウェアリリースのためのビルド・テスト・デプロイメントの自動化』の第5章に対応します。
2.概要・目的
デプロイメントパイプラインでは、まず、CIでシステムをコントロールする。
また、デプロイメントプロセスを自動化することで、アクセスの容易さとフィードバックの高速化を実現し、速さと安全さを提供する。
ビルド・デプロイ・テスト・リリースプロセスを自動化することで、最終的にプルシステムが構築でき、デプロイメントパイプラインは自由と柔軟性をもたらす。
3.対応概要
(1)デプロイメントパイプラインによるプロセスのモデル化
デプロイメントパイプラインとは、ソフトウェアをバージョン管理から取り出してユーザに手渡すまでのプロセスを自動化して表現したものである。
コンセプトから対価の獲得までのプロセス全体は、バリューストリームマップとしてモデル化できる。
継続的デリバリーでは、バリューストリームのうちの、開発からリリースまでの間を扱う。
バージョン管理における特定のリビジョンが、パイプラインに対するインプットとなる。
デプロイメントパイプラインのパターンを適用することで、以下の恩恵を得られる。
- ビルドを徹底的にテストすることで、不適切なビルドを本番にリリースしてしまうことを効率的に避けられる。また、リグレッションバグを避けられる。
- デプロイメントと本番リリースの自動化により、素早く、反復可能で信頼できるプロセスとなる。
以前のバージョンに戻すことも容易になり、リリースのリスクがなくなる。
デプロイメントパイプラインを実現するための、あらゆるプロジェクトに共通したサブセットは以下の通りとなる。
- コミットステージ
- 技術レベルの検証。
- 自動受入テストステージ
- 機能および非機能レベルの検証。
- 手動テストステージ
- ユーザ視点の価値の検証。
- リリースステージ
- システムをユーザにデリバリーする。
これらのステージと、その他のソフトウェアデリバリープロセスをモデル化するために必要なステージを合わせて、デプロイメントパイプラインと呼ぶ。
(2)基本的なデプロイメントパイプライン
参考文献の図5-4に基本的なデプロイメントパイプラインの構成図が載っている。
構成のポイントは以下の通り。
- バージョンコントロールと成果物リポジトリは、パイプラインのすべてのステージと関係する。
受入ステージ以降に対しては、バージョンコントロールは環境とアプリの設定を提供する。 - コミットステージと受入ステージの完了後は、UAT・キャパシティ・本番の各ステージに枝分かれする。
また、受入ステージの完了後は、デプロイメントのための自動スクリプトを使用し、手作業でデプロイする。
さらに、特定のチェックインとビルドを、パイプライン上で通過したステージに関連付けて可視化することも重要である。
4.対応詳細
(1)デプロイメントパイプラインのプラクティス
デプロイメントパイプラインのプラクティスとして、以下が挙げられる。
- バイナリのビルドは1回限りとし、ファイルシステムやCIサーバで管理する。
- バイナリを環境に対して疎結合にする。もろくコストの高いプロセスにしないため。
- あらゆる環境に対して同じやり方でデプロイする。
デプロイメントスクリプトは各環境で同じものを使い、各環境ごとに一意の設定は別々のプロパティファイルとし、バージョン管理に格納する。 - 環境に依存しないプロセスとすることで、デプロイの失敗の原因を限定できる。
- デプロイメントのスモークテストは、最優先のユニットテストスイートの次に優先するテストとする。
アプリケーションが依存するすべてのサービスに煙を流す。 - 本番のコピーにデプロイする。
環境が同一であることを示すために、以下を確認する必要がある。 - 各変更が直ちにパイプライン全体を通り抜けるよう、スケジューリングを行う。
受入テストが完了して初めて、CIは新しい変更を取得できる。
(2)コミットステージ
「ユニットテスト + コミットテスト用選抜テスト = コミットテストスイート」となる。
実行可能なコードの生成自体を成功基準として扱うことで、CIによりビルドプロセス自体を評価できる。
コミットステージが問題の大半を検出し、きわめて素早く実行できる必要がある。
これにより、後に続くテストステージが通ることを推測し、デプロイメントパイプラインの実行と並行して、新しいフィーチャの開発ができる。
(3)自動受入テスト
「機能の受入 + リグレッション = 受入テスト」となる。
受入テストのプラクティスとして、以下が挙げられる。
(4)後に続くステージ
デプロイメントパイプラインにより、テスターがあらゆるビルドをテスト環境に好きなようにデプロイできる。
手動テストでは、自動テストでうまくできないテストに集中する。
非機能のテストの結果に対する評価は人間が判断してもよい。
(5)リリースに備える
デプロイメントパイプラインが以下を達成することで、リリースの問題を緩和する。
- デリバリーにかかわるすべての人がリリース計画を作成し、保守する。
- 最もエラーの起こりやすいステージからプロセスを自動化し、ヒューマンエラーの影響を最小化。
- 疑似本番環境で行われるプロセスを繰り返すことで、プロセスやそのための技術をデバッグできる。
- 計画通りいかなかったときにバックアウトを可能にする。
- 設定と本番データを移行する戦略を、アップグレードとロールバックプロセスの一部とする。
リリースプロセスの完全な自動化が目標となる。
a.デプロイメントとリリースの自動化
本番環境の変更は、自動化されたプロセスを通じてのみ行われるべき。
これにより、信頼できる監査、問題の診断、修正にかかる時間の予期が可能となる。
また、本番環境を管理するプロセスは、ステージング環境やインテグレーションテスト環境といったその他の環境でも使う。
キャパシティテストのフィードバックにより、設定の変更を評価する。
環境のプロビジョニングと保守を自動化するコストは、自動プロビジョニングや環境の管理、適切な構成管理プラクティス、仮想化により大幅に低減できる。
リリースプロセスは、継続的に評価され、改善される必要がある。
b.変更のバックアウト
最善のバックアウト戦略は、アプリケーションの1つ前のバージョンをリリースの間も使えるようにしておくこと。
次善の戦略は、以前の適切なバージョンを1から再デプロイすること。
(6)デプロイメントパイプラインの実装
デプロイメントパイプラインを実装するためのステップは以下の通り。
ビルドとデプロイメントの自動化の要点は以下の通り。
- バイナリが開発ツールに依存しない
- CIサーバの設定
- デプロイメント先環境の用意
- 自動デプロイメントのテスト
- バイナリと設定の分離
コミットステージが5分を超えたら、いくつかのスイートに分割する。
パイプラインは以下のために拡張されうる。
- バリューストリームの進化
- コンポーネント
- ブランチ
パイプラインの実装のために、以下の3つのプラクティスがある。
- バイプラインはインクリメンタルに実装する。
- パイプラインの実装では、プロセスの開始時刻と終了時刻、またどの変更がプロセスの各ステージを通過したかを記録する。これにより、プロセスのボトルネックを特定できる。
- パイプラインのリファクタリングを実施する。
(7)メトリクス
ソフトウェアデリバリープロセスにとっての最も重要なメトリクスは、サイクルタイム。
サイクルタイムの短縮のために、以下のプロセスに従うことで、制約理論を適用できる。
- システムにとっての制約条件を特定。制約条件とはボトルネックのこと。
- ボトルネックの箇所のスループットを最大化。
- 他のプロセスをすべて制約に従属させる。
- 制約の限界を上げる。リソースを増やす。
- 繰り返す。
その他のメトリクスは以下の通り。
- 自動テストのカバレッジ
- コードベースの特徴
- 欠陥の数
- 速度
- 1日当たりのバージョン管理システムへのコミット数
- 1日当たりのビルド回数
- 1日当たりのビルド失敗回数
- 自動テストを含むビルドにかかる時間
5.影響・作用
デプロイメントパイプラインの目的は、デリバリーにかかわるすべての人にとって、チェックインからリリースまでのビルドの進展の可視化にある。
また、ボタン1つで手動テスト環境にデプロイでき、環境にどのリリース候補があるのかわかるようになる。
デプロイメントパイプラインを実装することで、リリースプロセスの非効率な部分を特定できる。
さらに、プロセスを分析するための情報を得られる。
6.おわりに
以上が、継続的デリバリーの中での、デプロイメントパイプラインの責務や構成です。
7.参考文献
『継続的デリバリー 信頼できるソフトウェアリリースのためのビルド・テスト・デプロイメントの自動化』 第5章 デプロイメントパイプラインの解剖学
『継続的デリバリー』 第4章 学習メモ
テスト戦略
1.はじめに
継続的デリバリーにおける、テスト戦略についての調査記録です。
継続的デリバリーの中での、テスト戦略の実装方法について記載します。
『継続的デリバリー 信頼できるソフトウェアリリースのためのビルド・テスト・デプロイメントの自動化』の第4章に対応します。
メモ:以下、文中はである調になります。
2.概要・目的
(1)概要
W・エドワード・デミングが挙げた14のポイントのうちの一つに、「高品質を実現するために、大人数での調査に頼るのをやめよ。まずはプロセスを改善し、本番の品質を作りこめ」とある。
テストは職務横断的な活動であり、チーム全体を巻き込む。
品質を作りこむために、自動テストを様々な抽象度(ユニットテスト・コンポーネントテスト・受入テスト)で書く必要がある。
デプロイメントパイプラインの一部としてこれらのテストを実行し、さらに、あらゆる変更に対してデプロイメントパイプラインをトリガーする。
この自動テストに加えて、品質を作りこむために、手動テストも実施する。
ショーケース・ユーザビリティテスト・探索的テストを、プロジェクトを通じて継続的に実施する。
(2)目的
テスト戦略の設計は、第一に、プロジェクトのリスクを識別して優先順位をつけ、そのリスクを緩和するためのアクションを決定するプロセスである。
さらに、優れたテスト戦略によって、以下のような作用が生じる。
- テストによって、ソフトウェアが期待通りに動いていることを保証できる。バグ・サポートのコストを減らし、製品に対するユーザの評価を高められる。
- テストをすることで開発プロセスに制約を課し、優れた開発プラクティスを促進する。
- 包括的な自動テストスイートが、アプリケーションに関する最も完全で最新化された形式のドキュメントとなる。実行可能な仕様のかたちを取り、システムがどう動くべきか、実際にどう動くかを表す。
3.対応概要
(1)テストの種類
テストは上記の画像のように分類できる。
y軸は価値を表し、x軸はフィードバック先を表す。
(2)第2象限のテスト
この区画には機能の受入テストがある。
受入テストは、ストーリーに対する受け入れ基準が満たされていることを保証するテスト。
受入テストによって、開発者の完了条件と、ユーザの要件を表現する。
(3)受入テストの自動化
受入テストの自動化の作用は、以下の通り。
- フィードバックループの加速
- テスターが、探索的テストやもっと価値の高い活動に集中できるようになる
- 受入テストが強力なリグレッションテストスイートとなる
- テストから要件ドキュメントを自動生成でき、要件ドキュメントが陳腐化しない
自動受入テストは、通常、正常パス的なふるまいを完全に網羅するのみとする。
このとき、ほかの種類の自動リグレッションテストは包括的なものが一式揃っている必要がある。
優先して自動化すべきテストが、主要な正常パスに対するテストである。
代替正常パスと異常パスの優先度は、アプリケーションの安定性に依存する。
(4)第3象限のテスト
第3象限のテストは、ユニットテスト、コンポーネントテスト、デプロイメントテストである。
ユニットテストは、システムのコンポーネント間でやりとりしないテスト。
この制約により、ユニットテストは非常に高速に実行でき、素早いフィードバックを実現する。
コンポーネントテストでは、アプリケーションの様々な構成要素間のやりとりで発生する問題を検出する。
デプロイメントテストは、アプリケーションをデプロイする際に必ず実施する。
アプリケーションが正しくインストールされ、正しく設定され、必要なサービスと接続できて、レスポンスが戻ってくることを確認する。
(5)第1象限のテスト
第1象限のテストでは、期待されている価値をアプリケーションがユーザに対してデリバリーしていることを検証する。
カナリアリリースなどの発展的なアプローチによって、効果の高い機能を採用することができる。
(6)第4象限のテスト
非機能テストでは、機能以外のシステムの品質をすべてテストする。
システム全体にフィードバックするテストであり、機能要件と同じ検証方法を用いる。
非機能のテストのためのツールを使用することで、非機能の問題を早期検出できるプロセスを構築する。
(7)テストダブル
テストダブルとは、テスト対象の検証のためのシミュレーション用部品である。 例として、モックやダミーがある。 モックはコラボレーターとのやり取りをアサートし、コードの動作に関する詳細はアサートしない。
4.対応詳細
(1)起こりうる状況と戦略
a.新規プロジェクト
新規プロジェクトにおいては、受け入れ基準をドメインの観点で表現することが重要である。
これにより、保守性の高いテストスイートを作成できる。
b.プロジェクトの途中
プロジェクトの途中においては、ドメインの核となるユースケースをリグレッションから守る、正常パステストを優先して自動化する必要がある。
さらに、変更のないテストについても、自動化を進める。
シンプルなスクリプトと多様なデータによって、アプリケーションの状態を多く表現する。
c.レガシーシステム
レガシーシステムでは、まず自動ビルドを構築する。
次に、リグレッションテストスイートを作成する。
その後、自動テストをレイヤ化するアプローチを取る。
自動テストは、リグレッションから守るという目的に対して、価値がある。
あるいは、数多くの別々の環境でソフトウェアを実行する必要がある場合も、価値が生まれる。
d.インテグレーションテスト
インテグレーションテストでは、アプリケーションの各部分が、依存サービスと連携できることを保証する。
テストダブルの構築では、正常系と異常系をそれぞれシミュレートする必要がある。
外部サービスとの統合の問題として、以下が挙げられる。
- 使えるテストサービスがあるか。性能は十分か。
- サービスプロバイダは、質問に答えたりバグフィックスをしたりカスタマイズ機能を追加したりしてくれるか。
- システムの本番バージョンにアクセスして、キャパシティや可用性の問題を診断するためにテストすることができるか。
- サービスAPIはアプリケーション開発に使っている技術を用いて簡単にアクセスできるか。あるいはチーム内に専門スキルを持つ人が必要か。
- 自分たちで使うテストサービスを書いたり保守したりする必要があるか。
- 外部サービスが期待通りふるまってくれなかった場合に、自分たちのアプリケーションはどう動くべきか。
(2)受入テストの作成プロセスの最適化
受入テストや受入テストの目的を簡潔に書くことで、開発者はストーリーの概要を適切にとらえ、最も重要なシナリオを理解できる。
テスターと開発者が早いうちから協力関係を築くことで、開発者とテスター間のフィードバックサイクルの量を減らすことができ、機能の漏れやバグの数も削減できる。
(3)欠陥バックログの管理
バグのバックログがあるとき、問題が誰にでもはっきりとわかるようになっていること、また、開発チームのメンバが責任をもってバックログを減らすためのプロセスを推進することが重要である。
あるいは、欠陥をフィーチャと同様に扱うというアプローチを取る。
5.影響、作用
テストによるフィードバックループを構築することで、各プロセスの「完了」を表現できる。
これにより、プロジェクトの前進性を保証することができる。
6.おわりに
以上が、継続的デリバリーの中での、テスト戦略の実装方法です。
7.参考文献
『継続的デリバリー 信頼できるソフトウェアリリースのためのビルド・テスト・デプロイメントの自動化』 第4章 テスト戦略を実装する
『継続的デリバリー』 第3章 学習メモ
継続的インテグレーション(CI)
1.はじめに
継続的デリバリーにおける、継続的インテグレーションについての調査記録です。
継続的デリバリーにおいて、継続的インテグレーションをどのように実現するか記載します。
『継続的デリバリー 信頼できるソフトウェアリリースのためのビルド・テスト・デプロイメントの自動化』の第3章に対応します。
2.概要・目的
CIの目標は、ソフトウェアを常に動く状態とすることである。
CIを実現することで、素早くデリバリーができ、バグの量を削減できる。
また、バグを早期検出することで、修正コストを節約できる。
本稿では、CIを実現する上での準備と、CIにおけるプラクティスを記載する。
3.対応概要
(1)CIを始める前に必要なもの
CIを始めるために、以下の3つが必要となる。
- バージョン管理
- 自動ビルド
- チームの合意
(2)CIシステムの構築
CIシステムは、以下の手順で構築する。
- CIツールのインストール
- 設定
以下の項目を指定する。 - CIツールでビルドを実行+手順の記録、保存
CIツールでビルドを実行するために、以下の2つが必要となる。
- システムが依存しているソフトウェアや設定をバージョン管理にチェックイン
- 新しいボックスのプロビジョニングを行うプロセスの自動化
(3)チェックイン
変更のチェックインの手順は、以下の通りとなる。
- ビルドが実行中でないことを確認(実行中なら待つ)。
- 開発環境のコードをバージョン管理の最新バージョンで更新。
- ビルドスクリプトとテストを開発環境上で実行。または、CIツールの個人ビルド機能を実行。
- バージョン管理にコードをチェックイン。
- CIツールのビルドの結果を確認。
- ビルド失敗→即座に修正→ステップ3に戻る。
- ビルド成功→修了(次タスクへ)。
4.対応詳細
(1)CIの前提となるプラクティス
CIの前提として、以下の3つのプラクティスがある。
- 定期的なメインラインへのチェックイン。
- 包括的自動テストスイートの作成。
ビルドプロセスとテストプロセスを短く保つ。
(2)プロセスの短縮
a.テストプロセスの分割
プロセスの短縮のために、テストプロセスをコミットステージと受入テストステージに分割し、複数タスクを並列実行する。
コミットステージでは、ソフトウェアのコンパイルと、ユニットテストスイートを実行し、デプロイ可能なバイナリを生成する。
受入テストステージでは、コミットステージからバイナリを取得し、受入テスト(+あれば統合テスト、性能テスト)を実行する。b.その他
プロセスの短縮のために、テストプロセスの分割の他に以下の2つの方法がある。
テストスイートの並列実行。
ビルドグリッド。
(3)開発ワークスペースの管理
開発者が高い生産性で健全に作業するために、開発環境は以下の条件を満たす必要がある。
CIの自動テストに通った、最新のリビジョンでコーディングを始められること。
このために、ソース・テストデータ・DBスクリプト・ビルド_デプロイスクリプトを、すべてバージョン管理に格納する必要がある。- 依存しているサードパーティライブラリを、MavenやIvyのようなツールで管理していること。
- スモークテストを含む自動テストを、開発環境で実行できること。
実際に、大きな労力なくアプリケーションを開発環境で実行できることは、優れたアプリケーションアーキテクチャの指標となっている。
(4)CIサーバソフトウェア
CIサーバソフトウェアの核心には、以下の2つのコンポーネントがある。
- 定期的に、シンプルなワークフローを実行する。
- ビルドやテストの結果を通知し、テストレポートやインストーラへのアクセスを提供する。
また、CIサーバのオプション機能を使うことで、ビルドの状態を可視化できる。
(5)CIを機能させるための必須プラクティス
ソフトウェアが常に動くことを確認するための必須のプラクティスは以下の通り。
- ビルドが壊れているときはチェックインしてはいけない。
常にグリーンなビルドにする。 - ローカルでのコミットテストを実行する。
テストの失敗とコミットの失敗を分離する。 - 問題が起きても対処できる時間にチェックインする。
- 常に以前のリビジョンに戻す準備をする。
- リバート前の修正可能時間を設定する。
- 失敗したテストをコメントアウトしない。失敗したテストは適切に修正する。
- 変更者がビルドの成功に対して責任を持つ。また、そのためにコードへのアクセス権を付与する。
- テスト駆動開発。
UTのカバレッジを高め、CIの核である高速フィードバックを実現するため。
(6)必須ではないがやったほうがよいプラクティス
CIのために、必須ではないがやったほうがよいプラクティスは以下の通り。
- XPの開発プラクティス。
- アーキテクチャ上の違反に対して、ビルドを失敗させる。
- テストが遅い場合に、ビルドを失敗させる。
警告やコードスタイルの違反があったときに、ビルドを失敗させる。
ラチェット方式で実施する。(7)分散したチーム
CIを分散したチームでやるときは、バージョン管理システムとCIシステム、さらにデプロイメントパイプラインを共有することが最も効果的である。
その他のアプローチについては、以下の通り。コミュニケーションプロセスの改善などで、チーム間の信頼関係を構築する。
- 中央集権的CIにより、品質を標準化する。仮想化も、中央集権CIサーバとうまく組み合わせられる。
- 分散バージョン管理システムを使用することで、回線やネットワークの問題を解消する。
- 基盤へのアクセスと、基盤についての問題の対応方法を共有する。
(非推奨)回線の問題を解消できないときは、CIシステム・テストシステム・バージョン管理システムをローカルに立てる。
(8)分散バージョン管理システム(DVCS)
a.メインラインモデル
バージョン管理のメインラインモデルやCIを実行するために、DVCSでは、一つのリポジトリをマスターと定める。
このリポジトリに変更があったときに、CIサーバが動くよう設定する。b.GitHubモデルなどその他のモデル
GitHubモデルで疑似CIを実行するためには、各リポジトリに対してCIビルドを構築する。
これにより、フォークやメインリポジトリの保守担当者に、フォークがメインリポジトリに統合可能か通知できる。
DVCSを使うモデルがCIを代替するためには、以下の条件を満たす必要がある。少人数で洗練されたコミッターのチームが、パッチのプルを管理し、自動テストの面倒を見ることで、ソフトウェア品質を保証すること。
- フォークから定期的にプルを行い、マージの問題を小さくすること。
- 少人数の中心的開発者が、比較的ゆっくり作業をする大きなコミュニティに支えられていること。
5.影響・作用
CIを実現することで、アプリケーションは基本的に動く状態となる。
ただし、保証するレベルは、自動テストのカバレッジに依存する。
CIを実現するにあたって、以下の2つが必須となる。
- 適切な構成管理
- 自動ビルド・テストプロセスの構築と保守
この2つは、インクリメンタルに実現が可能である。
6.おわりに
以上が、継続的デリバリーにおける継続的インテグレーションの実現のための、準備とプラクティスです。
7.参考文献
『継続的デリバリー 信頼できるソフトウェアリリースのためのビルド・テスト・デプロイメントの自動化』 第3章 継続的インテグレーション
『継続的デリバリー』 第2章 学習メモ
構成管理
1.はじめに
継続的デリバリーにおける、構成管理についての調査記録です。
継続的デリバリーの中での、構成管理が持つ責務について記載します。
『継続的デリバリー 信頼できるソフトウェアリリースのためのビルド・テスト・デプロイメントの自動化』の第2章に対応します。
2.概要・目的
構成管理とは、あらゆる成果物とその関係を保存、検索、識別、修正するプロセスである。
構成管理では、以下の5項目について、ベースラインを格納し、変更をコントロールするための戦略を準備する必要がある。
- アプリケーションのソースコードやビルドスクリプト、テストドキュメント、要件、データベーススクリプト、ライブラリ、設定ファイル。
- デプロイメントやテスト、運用に使うツールチェーン。
- 開発環境、テスト環境、本番環境。
- アプリケーションに関連するすべてのアプリケーションスタック。バイナリと設定両方。
- あらゆる環境で実行されるあらゆるアプリケーションに関連する設定。
この設定は、アプリケーションのライフサイクル全体(ビルド、デプロイメント、テスト、運用)をまたがるもの。
構成管理戦略を適切に策定することで、以下を達成できる。
- あらゆる環境を正確に再現。
再現すべきものは以下の項目。- OSのバージョン
- パッチレベル
- ネットワーク構成
- ソフトウェアスタック
- デプロイされるアプリケーションとその設定
- 再現すべき項目それぞれに対して、個別にインクリメンタルな変更を行い、それを自分の環境のどれかや、すべてに対して簡単にデプロイできる。
- 特定の環境で発生した変更を、簡単に見分けられる。
また、変更の内容(What,Who,When,Why)を追跡して正確に突き止められる。 - 従うべきコンプライアンスの規約をすべて満たすことができる。
- チームのメンバ全員が必要な情報を取得し、必要な変更を行うことが容易となる。
- 効率的なデリバリーを妨げず、サイクルタイムを短く保ち、十分なフィードバックを得られる。
3.問題
構成管理における問題として、以下の3点がある。
- アプリケーションのビルド・デプロイ・テスト・リリースプロセスを管理するために必要な前提条件として、以下の2つを問題とする。
- バージョン管理。
- 依存関係の管理。
- アプリケーションの設定の管理。
- 環境全体に対する構成管理。
ソフトウェア、ハードウェア、アプリケーションが依存する基盤を含む。
4.対応概要
(1)バージョン管理
- 問題:ソフトウェアの特定のバージョンの構成要素の識別。ソフトウェアのバイナリと設定の特定の状態を再現すること。
対応:一度格納されたあらゆるファイルに対して、すべてのバージョンを保持し、アクセスできるようにする。 - 問題:変更の内容(What,Who,When,Why)を追跡して、正確に突き止められるようにする。アプリケーションの経緯を分かるようにする。
対応:バージョン管理システムにより、分散したチームでも協力を可能にする。
(2)アプリケーションの構成管理
アプリケーションの構成管理の原則として、以下が挙げられる。
- アプリケーションのライフサイクルの中で、設定を注入する意味のある時点を特定する。
- アプリケーションで使うことのできる設定オプションを、ソースコードと同じリポジトリ内に保持する。
ただし、設定とコードのライフサイクルの違いや、セキュリティの問題から、値は別の場所に保持する。 - 常に、自動化されたプロセスで、設定リポジトリから取得した値で設定する。
- アプリケーション・バージョン・デプロイされる環境に応じて、アプリケーションに個別の値を提供する。
- 設定オプションには、明確な命名規約を使用する。
- 設定情報をモジュール化し、カプセル化する。
- Don't Repeat Yourself.
- 要件や意味があるときのみ、設定情報を使用する。
- できるだけ、設定はシンプルにする。
- デプロイメント時やインストール時に、確実にテストを実施する。
(3)環境の管理
環境構築を完全に自動化されたプロセスで行い、環境を再現できるようにすることで、以下を満たすことができる。
- 基盤や設定が、特定の人に依存するリスクの回避。
- 正しく動くとわかっている状態に、既知の時間で戻すことができる。
- テスト環境を本番環境の正確なレプリカとすることで、設定の問題を早期発見できる。
5.対応詳細
(1)バージョン管理
a.バージョン管理に入れるべきもの
ソースコードと設定情報の他に、アプリケーションサーバ・コンパイラ・仮想マシン・ツールチェーンの一部について、バイナリイメージをバージョン管理する。
これらをバージョン管理することで、開発・テスト・本番環境のための、安定したプラットフォームを作ることができる。
b.バージョン管理に入れるべきでないもの
アプリケーションをコンパイルした結果のバイナリはバージョン管理に格納しない。
これは、リポジトリ内の1バージョンを特定できるという理念が崩れてしまうため。
この理念は、デプロイメントパイプラインを作るうえで重要となる。
c.フィーチャブランチの問題点
フィーチャブランチには、統合・マージ。リファクタリングが困難になるという問題がある。
この問題は、以下の条件を満たすことで回避できる。
- オープンソースソフトウェアで、十分な制約があるとき。
- 定期的にメインラインに統合されるとき。
d.ソフトウェアを常に動く状態に保つ
新しい機能をインクリメンタルに開発し、バージョン管理のメインラインに定期的にコミットする必要がある。
これにより、CIサーバが自動テストをメインラインに対して実行することで、ソフトウェアが常にテストされた状態になる。
統合にかかわる問題が即座に、容易に修正できるうちに検出できる。
e.チェックインでアプリケーションを壊さない
チェックインの際にアプリケーションを壊さないことを保証するため、以下のプラクティスを実践する。
- チェックイン前のコミットテスト、プレコミットテストを実施する。
- 変更をインクリメンタルに行う。
f.コミットメッセージ
コミットメッセージは、以下の理由で必要となる。
- ビルドが壊れた時に、誰がどんな理由で壊したかわかる。
- 複雑な問題のデバッグのコストが下がる。
適切なコミットメッセージの書き方として、以下の2点がある。
- 1行目に要約を書き、2行目以降に詳細な説明を記載する。
- 取り組んでいるフィーチャやバグを、プロジェクト管理ツールに紐づける。
(2)依存関係の管理
a.外部ライブラリの保持
外部ライブラリは、以下のいずれかの方法で保持する。
- ローカルでコピーを保持する。
- 組織用のリポジトリで、利用するライブラリの適切なバージョンを保持する。
b.ビルドシステム
ビルドシステムでは、利用している外部ライブラリの正確なバージョンを指定する必要がある。
c.コンポーネントの分割
コンポーネントを複数のパイプラインに分割するときは、ソースではなく、バイナリに依存関係を持たせる。
理由は、依存関係のリコンパイルが非効率的なうえに、テストしたものとは潜在的に異なる成果物となるためである。
(3)設定の管理
アプリケーションを構成する主な3つの要素は、設定・バイナリ・データである。
a.設定の問題
設定の問題として、検証レベルが低いことがある。
この問題は、開発スモークテストを実施することで和らげられる。
b.設定の注入
設定は以下の4つのタイミングで注入できる。
- ビルド。
- パッケージング。
- デプロイメント。
- 起動時や実行時。
アプリケーションと組織内にあるすべての環境のための設定情報は、同じ仕組みを使って提供する必要がある。
同じ仕組みで提供することで、設定の変更や管理・バージョン管理・(必要な時は)上書きを行うときの、起点を統一できる。
c.バージョン管理から分離
設定情報のうち、パスワードやデジタル認証などのセキュリティに関連する設定要素は、バージョン管理から分離しなければならない。
d.設定情報の格納場所
設定情報の格納場所の候補は以下の3つである。
- データベース。
- バージョン管理システム。
- ディレクトリやレジストリ。
e.設定情報の取得
あらゆるアプリケーションが必要な設定を取得できるように設定を管理する上で、最も効果的な方法は、中央集権的なサービスを置くことである。
設定情報へのアクセスのための技術的詳細からアプリケーションを隔離するために、シンプルなファサードクラスを作成する。
f.設定の構成
アプリケーションの設定は、タプルの集合で構成される。
設定は以下の3つに依存する。
- アプリケーション。
- アプリケーションのバージョン。
- アプリケーションの実行環境(開発環境、UAT環境、性能環境など)。
g.設定のモデリング
設定をモデリングするときに考えるべきユースケースは以下の5つである。
- 新しい環境を追加するとき、新しい環境にデプロイされるアプリケーション用に、新しい値の集合を定義する。
- アプリケーションの新しいバージョンを生成するとき、新しい設定を導入し、古い設定を削除する。
- アプリケーションの新しいバージョンをある環境から別の環境に移しかえるとき、新しい環境から新しい設定にアクセスする。
- データベースサーバをリファクタリングするとき、単純なやり方で、データベースを参照している設定を更新して、新しいデータベースに向ける。
- 仮想化によって環境を管理するとき、仮想化管理ツールを使って、特定の環境の新しいインスタンスを作る。
h.環境をまたがった設定管理
環境をまたがった設定管理のためには、本番の設定として期待されるものをデフォルトとし、それ以外の環境では、適切に上書きする。
このアプローチにより、環境に特化した調整が、どれも設定プロパティだけにまとめられる。設定を変更することで、ソフトウェアがその特定の環境で動くことを保証する。
i.設定のテスト
設定のテストのためには2つのステージがある。
最初のステージでは、設定にある外部サービスへの参照が、適切であることを保証する。
デプロイメントスクリプトやインストールスクリプト内で、(少なくともpingを打つなど)スモークテストの実施することで、設定を検証する。
第2のステージでは、アプリケーションがインストールされた後で、期待どおりに作動することを確認する。
設定が正しいかどうかに依存する機能を動作させるテストを含めた、スモークテストを実施することで検証する。
テストに失敗したときは、アプリケーションを止めて、インストールやデプロイメントプロセスを失敗させる。
j.アプリケーションをまたがった設定管理
環境の設定を確定するために、アプリケーションをまたいで設定を管理するときは、各アプリケーションにある設定オプションをすべて一覧化しておく。
このために、設定管理の方法は統一する必要がある。
(4)環境の管理
a.環境設定の対象
環境設定の対象として、以下の5つが挙げられる。
- 環境にある様々なOS。バージョン・パッチレベル・設定を含む。
- 各環境で、追加でインストールする必要のあるソフトウェアパッケージ。パッケージのバージョンや設定を含む。
- ネットワークトポロジー。
- アプリケーションが依存する外部サービス。サービスのバージョンや設定を含む。
- アプリケーション内の、あらゆるデータや状態。
b.効果的な構成管理のための原則の適用
効果的な構成管理のための原則として、以下の2つがある。
- バイナリファイルを構成情報から独立させること。
- 設定を1か所にまとめておくこと。
この原則により、新しい環境の構築やシステムの一部のアップグレード、システムを止めずに新しい設定をロールアウトさせるといったプロセスを自動化されたシンプルなものにできる。
この原則が適用できるソフトウェアの条件として、以下の2つがある。
c.ソフトウェアを評価するための構成管理上の観点
ソフトウェアを評価するための構成管理上の観点として、以下の3つがある。
- デプロイ可能か。
- 設定のバージョンを効率的に変えられるか。
- 自動デプロイメント戦略と整合するか。
d.自動化された環境プロビジョニングシステム
自動化された環境プロビジョニングシステムによって、あらゆるベースラインの構築、再構築が可能となる。
e.OS管理
OS管理を自動化するツールとして、Puppet・CfEngineがある。
これらのツールにより、筐体へのアクセス権をどのユーザに付与するかについてや、どのソフトウェアをインストールするかについて、宣言的に定義できる。
さらに、この定義は、バージョン管理できる。
f.環境に対する変更プロセスの検証
環境に対して変更を行うプロセスをテストするため、テスト環境へのデプロイメントプロセスを、本番へのデプロイメントプロセスと揃える。
6.影響・作用
構成管理によって、以下の3点が可能となる。(同時に、以下の3点が構成管理の検証観点となる。)
- バージョン管理された資産により、本番システムを、スクラッチから完全に再構築できる。ただし本番データは除く。
- 正しく動くとわかっている以前の状態に、アプリケーションを戻すことができる。
- 本番・ステージング・テストといったデプロイ対象の環境が、正確に同じやり方でセットアップされていると保証できる。
7.おわりに
以上が、継続的デリバリーの中での、構成管理が持つ責務です。
8.参考文献
『継続的デリバリー 信頼できるソフトウェアリリースのためのビルド・テスト・デプロイメントの自動化』 第2章 ソフトウェアデリバリーの問題