continuous delivery-9

34
『継続的デリバリー』読書会 9非機能要件をテストする 大崎的デリバリー @LagerKorone

Upload: lagerkorone

Post on 17-Jan-2017

194 views

Category:

Documents


0 download

TRANSCRIPT

『継続的デリバリー』読書会 第9章

非機能要件をテストする

大崎的デリバリー

@LagerKorone

9.1 導入

• 本章は「非機能要件をテストするための方法」がテーマ

– 特に「キャパシティ」、「パフォーマンス」に重点を置く

• 他には「保守性」

1. 非機能要件の分析

2. キャパシティ要件を満たすためのアプリケーションの開発手法

3. キャパシティを計測する方法と計測用の環境の作り方

4. 自動化した受け入れテストスイートからキャパシティテストを作る戦略

5. 非機能要件のテストをデプロイメントパイプラインに組み込む方法

• 用語定義(マイケル・ナイガードと同じ用語を使う) – パフォーマンス

• 単一のトランザクションの処理に要する時間

• 単体で計測することもできれば負荷のかかった状態で計測することもできる。

– スループット

• 一定の期間内にシステムが処理できるトランザクション数

• 常に、システム内の何らかのボトルネックの制約を受ける。

– キャパシティ

• 一定の負荷がかかった状態で、個々のリクエストを許容範囲のレスポンスでさばききれる最大のスループット

9.1 導入 ~非機能要件の重要性~

• ソフトウェアプロジェクトのデリバリーに関する重大なリ

スクとなる

リスクの例

– 負荷に耐えられなくなる

– セキュリティを確保できなくなる

– 反応速度が遅すぎる

– コードの品質があまりにも低くて保守しきれなくなる(最もありが

ちな理由)

• 可用性やキャパシティ、セキュリティ、そして保守性と

いった「非機能要件」はどれも「機能要件」と同様に大切

– システムをきちんと動かすために不可欠なもの。

9.2 非機能要件を管理する

• 非機能要件についてはプロジェクトの序盤で検討することが重要

– システムのアーキテクチャは後から変更しにくい

• システムにとって最適なアーキテクチャを選択するために、事前に十分な分析

が必要になる

– 非機能要件は、その他の要件の領域まで範囲をまたがる傾向がある。

• 多くの分野にまたがるという性質のせいで、非機能要件の分析もその要件を満たすための

実装も非常に困難になる。

– 非機能要件の扱いは難しい

• ついついプロジェクトの計画から抜け落ちてしまいがち

• 分析の際にもきちんと検討できない

– 非機能要件の実装は複雑

• 非機能要件はシステム全体のアーキテクチャに大きな影響を及ぼすことが多い

– (例)高パフォーマンスを要求されるシステムでは、リクエストの処理を階層化するこ

となどない

9.2.1 非機能要件を分析する

• 非機能要件を扱う不適切な方法

– 非機能要件のことを機能的なストーリーの受け入れ要件と見なしてしまう。

– そして、特別な苦労をしなくても満たせるものであると考えてしまう。

• 適切な方法

– 非機能要件自体を扱うストーリーあるいはタスクをプロジェクトの開始時に別途作成する。

– 2つの手法を適宜取り混ぜて使う必要がある。(分野をまたがる問題に対処する手聞をできるだ

け軽減するのが狙い)

• 非機能要件を扱うことだけを考えるタスクを新たに作る

• 非機能要件を他のタスクの受け入れ要件ととらえる

• 例:可監査性を管理する

1. 「システム上の重要な操作はすべて、監査すること」などとして、関連するストーリーの受け

入れ基準に「やりとりを監査すること」を追加する。

2. 監査人側の視点での要件を考える。

• 監査人が見えるべきのもは何だろうか? 彼らが見たいと考えるレポートすべてに対して、

監査人側からの要件を提示できる。

– この方式にすれば、もはや機能をまたがる非機能要件ですらなくなる。

– その他の要件と同様に扱い、テストの対象にしたり他の要件と比べた優先順位をつけたりできるようになる。

9.2.1 非機能要件を分析する

• 大切なのは、非機能要件を分析するときにはある程度詳細なレベルまで踏み込むこと。

– レスポンスタイムに対する要件が「できるだけ速く」などでは不十分。

• どこまで速くすればいいのかがわからない

• どれだけの予算をつぎ込めばいいのかも判断できない

• すべての要件は、機能要件であるか非機能要件であるかにかかわらず、数値目標を設定

して見積もりや優先順位付けができるようにしておく必要がある。

– このようにしておけば、開発の際の最適な予算配分についても考えられるようになる。

• アプリケーションの受け入れ基準がきちんと把握できていない例

– 「すべてのユーザーインターフェイスは2秒未満で応答を返すこと」

– 「システムが一時間に80,000トランザクションを処理できること」

一見きちんと定義できているように見えるが不十分

– どんな状況でもそうでなければならないということだろうか?

• どこかのデータセンターがダウンしてしまったとして、それでも2秒未満という要件を満たす必要がある?

• めったに使わないような操作と頻繁に使う操作をどちらも同じ基準で扱うのだろうか?

– 「2秒」というけれど、

• その2秒は処理が成功して完了するまでの時間なのだろうか?

• それとも2秒未満でとりあえず何らかの反応を返せればいいだけなのだろうか?

• 何か問題が起こってエラーメッセージを返すときも2秒未満にしなければならないのだろうか?

• それとも、処 システムに負荷がかかっているときや処理のピーク時にも2秒という条件を満たさねばならないのだろうか?

• それとも、平均の応答時間が2秒未満ならいいのだろうか?

• 理が正しく行われたときだけのルールなのだろうか?

9.3 キャパシティを確保するためのプログラミング

• 非機能要件についての分析が不十分の場合

– 考えすぎた設計や不適切な最適化をしてしまいがち

– 「高パフォーマンスな」コードを書くために無駄に時間を費やしてしまうこともよくある。

• プログラマは一般的に、アプリケーションのパフォーマンス上のボトルネックがどこにあ

るのかを予測するのが下手である。

• コードを不必要に複雑にしてしまい保守しづらくなったけれども、結局パフォーマンスが

どれだけ向上したのかは疑わしいということになりがち。

• 解決策を見つける前に、まずは問題の原因を特定しなければならない。

• さらにその前に、問題があるということに気づかねばならない。

• キャパシティテストステージの狙いは、問題があるかどうかを知ること。

– 問題を発見できれば、修正に向けて考えを進められるようになる。

– 推測するな、計測せよ。

9.3 キャパシティを確保するためのプログラミング ~キャパシティの問題に対応するときの手順~

• バランスが大切

– 「キャパシティの問題はすべて後で何とかなる」と楽観すること、逆に「あとでキャパシティの

問題が発生するだろうから」と対策しすぎてコードを複雑にしてしまうこと。

• キャパシティ問題に対応するときの手順

1. アプリケーションのアーキテクチャを決める。

– プロセスやネットワークの境界、そして入出力などには細心の注意を払う。

2. システムの安定性やキャパシティに影響するパターンを身につけ、アンチパターンを回避する。

– マイケル・ナイガードのすばらしい著書「Release It!本番用ソフトウェア製品の設計とデプロ

イのために」に、詳細な説明がある。

3. チームの作業は、選択したアーキテクチャによって定められる境界内に留める。

– このときに、適切な場面でパターンを適用するのはよいが、キャパシティのためと称してそれ以

外の最適化を始めてしまわないようにする。

– 秘伝の技を使うのではなく、コードをできるだけ明確かつシンプルに保つよう心がける。

– テストをして利益が得られるとはっきりわかったものでないかぎり、キャパシティのために可読

性を犠牲にしてはいけない。

4. データ構造やアルゴリズムの選択に気をつけ、そのアプリケーションに適したものを選ぶようにする。

– たとえば、O (1)のパフォーマンスを要する場面でO(n)のアルゴリズムを使ってはいけない。

9.3 キャパシティを確保するためのプログラミング ~キャパシティの問題に対応するときの手順~

5. スレッドには細心の注意を払う。

– 著者が現在かかわっているプロジェクトでは、最大級のパフォーマンスを要するシステム(為替取引のシステム

で、秒間数万トランザクションを処理できるもの)を構築している。ハイパフォーマンスを達成するためのポイ

ントとなる方法のひとつは、アプリケーションのコアをシングルスレッドに保つことだった。

– ナイガードも言うように、「ブロックされたスレッド」アンチパターンは多くの障害の主因であり、「連鎖反

応」および「カスケード障害」につながりやすい。

6. 自動テストの仕組みを用意し、必要なレベルのキャパシティが確保できているかどうかを確かめる。

– テストが失敗したら、そのテストを指針として問題を修正する。

7. プロファイリングツールは、あくまでもテストで見つけた問題を修正するための手段として使う

– 決して「とりあえず、できるだけ高速化する」ために使うものではない。

8. できる限り、実際に要求されるキャパシティ指標を使う。

– 実際の本番環境のシステムこそが、唯一の真の指標となる。

– 本番環境のシステムの訴えに耳を傾けよう。特に注意すべきなのは、システムの利用者数やその操作パターン、

そして本番データの大きさである。

9.4 キャパシティを計測する ~計測方法~

• キャパシティを計測するには、アプリケーションの特性に関する幅広い調査が必要となる。計測の方

法には、このようなものがある。

– スケーラビリティテスト

• 個々のリクエストに対する応答時間や利用可能な同時ユーザー数が、サーバーやサービス

あるいはスレッドの設定を変えたときにどのように変化するか?

– 長期稼働テスト。

• システムを長時間動かし続け、処理をずっと続けた場合にパフォーマンスが変化するかを

調べる。

• この種のテストでは、メモリリークや安定性の問題を検出できる。

– スループットテスト

• システムが一秒間に処理できるトランザクション数やメッセージ数、あるいはページ数は

どの程度か?

– 負荷テスト。

• アプリケーションへの負荷が本番と同等あるいはそれ以上になったときに、キャパシティ

はどのように変化するか?

• これはおそらく、キャパシティテストで最も一般的なものである。

9.4 キャパシティを計測する ~キャパシティテストのポイント~

• キャパシティテストの重要なポイント

– そのアプリケーションの実際の利用シナリオをシミュレートできるということ。

• ビジネス寄りに焦点を合わせたなどのほうが現実的。

– 通常の利用パターンで、秒間に何件の売り上げを処理できるか

– 想定ユーザー層は、負荷が最も高くなる時期にもシステムを普通に使えるだろうか?

• これ以外のとらえ方:システム上のある技術的な操作をベンチマークするというアプローチ

プロジェクトを進める過程ではこの手のベンチマークが役立つ場面もあるだろうが、あまり現実的

ではない。

– 技術的な操作のベンチーマーク

• 「データベースに秒間何トランザクションを保存できるか?」

• メッセージキューが秒間何メッセージを処理できるか?」

ベンチマーク形式のキャパシティテストが非常に有用なケース

• コードを特定の問題から守ったり特定の範囲のコードを最適化したりする場合

• そのテストから得られる情報が、使う技術を選択するときの参考になることもある。しか

しそれは、全体像のごく一部に過ぎない

9.4 キャパシティを計測する ~キャパシティテストの要件~

• シナリオベースのテストが、他の操作に関する別のキャパシティテストと同時に実行できなければな

らない。

• 最も効率を上げるには、複数のキャパシティテストをひとつのテストスイートにまとめて並列実行で

きるようにしておく必要がある。

– モダンなシステムのほとんど(少なくとも我々が通常目にする範囲において)は、一度にひとつのことだけをするわけ

ではない。

• POSシステムは、売り上げを処理する際に同時に在庫情報も更新するし、各種サービス用の発注を扱った

りタイムシートを記録したり、店内で使う監査証跡を残したりといったことも行っている。

• どんな負荷をどの程度かけるかを考え、さらに観点の異なるシナリオ(まったく無関係なインデッ

• クスサービスがシステムの邪魔をするなど)まで考慮することには、ナイガードも言うとおり「熟練

• と科学が求められる。本番環境における本物のトラフイックを真似るのは不可能なので、トラフイツ

• ク解析と経験と直感を活用し、できる限り現実に近いシミュレーションを行う」のだ*30

9.4.1 キャパシティテストの成功・失敗の判断基準は?

• 成功したか失敗したかの判断は、収集した結果に基づく人間の判断に委ねられる。

– (我々がこれまでに見てきた)キャパシティテストの多くは、実際のところテストというよりはむ

しろ計測といったほうがよいもの

– キャパシティをテストするのではなく計測してしまうことの弱点は、結果の分析に時間がかかる

ことである。

• しかし、キャパシティテストシステムがこういった計測結果を生成してくれることは非常に有用。

– それを見れば何が起こったのかを吟味できるので、単に成功したか失敗したかだけのレポートよ

りはずっと役立つ。

– キャパシティテストにおいては、ひとつのグラフの有用性は千の言葉に匹敵する。

– 判断を下す際には、全体的な傾向のほうが実際の値よりも重要となる。そのため、我々は常に

キャパシティテストでグラフを生成している。

– そしてそのグラフには、デプロイメントパイプラインのダッシュボードから容易にアクセスでき

るようにしている。

9.4.1 キャパシティテストの成功・失敗の判断基準は?

• キャパシティテストが通るための一定のレベルを設定することは容易ではない。

• 不適切な設定をしていると、問題となる可能性のある現象に気づくのがかなり遅れてしまう。

– 気づいたころにはその原因となった変更の詳細を忘れてしまっているということになる。

– あまりにも高いレベルを追求しすぎ、万事順調に動いたときしか通らないようにすると、不意にテストに失敗す

るという現象が頻発してしまう。

• たまたま他のタスクがネットワークを使っていたとか、キャパシティテスト環境で他のタスクが同時に動

いていたとか、そんな理由でもテストは失敗してしまうだろう。

– 逆に、低すぎるレベルだと、問題を検出できない。

• テストで調べているのはアプリケーションが秒間100トランザクションを処理できるかどうかだけれども、

そのアプリケーションが実は秒間200トランザクションをさばける能力があった。スループットを半減さ

せるような変更をしてしまっても、気づけない。

• 取り得る戦略

1. 安定した再現性のある結果を目指すという戦略

• 現実的に可能な範囲で、キャパシティテスト環境をできるだけ他の影響から隔離し、キャパシティの計測

専用に使わせる。

– そうすれば、テストに関係ない他のタスクの影響を減らせ、結果がより一貫したものとなる。

2. テストが通るための閥値を微調整する戦略

• テストが通るたびに、受け入れレベルを少しずつ厳しくしていく。

– こうすれば、本来通るべきテストが失敗してしまうことを防げる。

– あるコミットの後でテストが失敗するようになったとしよう。その時点でもし要件を上回る閲値を

設定しているのなら、必要に応じて(そのコミットによってある程度キャパシティが落ちるのが納得

済みで受け入れられる場合は) 閥値を下げればよい。

9.4.1 キャパシティテストの成功・失敗の判断基準は?

• 覚えておくべき重要なこと

– 多くのシステムは負荷の変動が激しく、状況によって負荷は大きく変わる

– このようなテストをするときは、推定される最高の負荷がかかった状態を元にして条件を算出し

なければならない。

• 自分たちのテストを、単なるパフォーマンス測定ではない真のテストにするために

– 各テストが固有のシナリオを具現化したものでなければならない。

– その閥値は、テストが通ることを要求される値を上回らなければならない。

9.5 キャパシティテスト環境 ~システムのキャパシティを確実に計測する(理想)~

• 最終的にシステムが稼働する本番環境を可能な限り再現したテスト環境を用意しなければならない。

• キャパシティやパフォーマンスが重要になるアプリケーションなら、システムのコア部分については

ある程度の投資をして本番環境の複製を用意するべきだ。

– 設定の異なる環境であっても有用な情報を得ることは可能だろう。しかし、計測に基づいたもの

でない限り、テスト環境のキャパシティから本番環境のキャパシティを推測しようとしても、か

なり不確かなものとなってしまう。

– ハイパフォーマンスなコンピュータシステムのふるまいは、専門的で複雑な領域である。

– 設定の変更がキャパシティに与える影響は、非線形的になる傾向がある。

– アプリケーションサーバーの接続やデータベースの接続に対して許可するUIセッションの割合

を変更するといったシンプルな変更が、システム全体のスループットを桁違いに向上させること

もあり得る。

– 同じハードウェアやソフトウェアを用意し、本書の内容に従って構成を管理して、各環境の構成

を(ネットワークやミドルウェア、osの設定も含めて) 確実にそろえておく。

9.5 キャパシティテスト環境 ~システムのキャパシティを確実に計測する(現実)~

• キャパシティテストを行うときには、カナリアリリース戦略(詳細は321ページの「カナリアリリー

ス」を参照) の一環として実行する。

• 新たな変更によってアプリケーションのキャパシティが悪化するというリスクを軽減するには、より

頻繁にリリースすればよい。

• しかし、ほとんどのプロジェクトはこんな極端な状況にはない。

• そういったプロジェクトでは、キャパシティテスト環境をできる限り本番環境に近づけるべきだ。

• たとえプロジェクトの規模が小さすぎて本番環境を複製するための費用を捻出するのが難しい場合で

も、これだけは覚えておく。

– 低スペックのハードウェアでキャパシティテストをしていると、重大なキャパシティの問題は目

立つが、アプリケーションが実際のところそのキャパシティ要件を満たしているかどうかは示せ

ない。これは、プロジェクトのリスクとして評価しなければならない。

– 計算すればなんとかなるというのは甘い考え。

• 複雑なシステムでは、パフォーマンスが直線的に変化することはまずあり得ない。

– もしどうしようもない場合は、テスト環境と本番環境の違いを変化させたときのベンチマークを

可能な限り多く実行するようにしよう。

9.5 キャパシティテスト環境 ~テスト環境のコストを抑えつつある程度正確なパフォーマンス計測を行える

ようにする方法~

• 本番環境が図9-1のようなサーバファームになっている場合。

– テスト環境は、サーバ群の一部を切り取って図9-2のようにすればよく、全体を複製する必用は

ない。

– 最小限セットで動かしたときのパフォーマンスをかなり正確に測定出来る。

– 複数のサーバが別の層のリソースを巡って競合したときに発生する問題も見つけられる。

図9-1 本番サーバファームの例 図9-2 キャパシティテスト環境の例

9.6 キャパシティテストを自動化する

• デプロイメントパイプラインの一つのステージとして組み込む

• キャパシティテストをパイプラインに組み込むには、まず自動化したキャパシティテストスイートを

用意しなければならない。

• コミットステージや(もしあれば)受け入れテストステージを通過したすべての変更に対して、そのテ

ストスイートを実行する必要がある。

– これはそんなに簡単ではない。

• その他の受け入れテストにくらべてキャパシティテストは壊れやすく複雑になりがちで、

ソフトウェアにほんの少し変更が加わるだけで簡単に動かなくなってしまうからだ。

9.6 キャパシティテストを自動化する ~キャパシティテストの条件~

• キャパシティテストは、このような条件を満たさねばならない。

1. 実際にあり得るシナリオをテストすること。

• テストをあまりにも抽象化しすぎてしまうと、実際の利用中に起こる重大なバグを見落と

してしまう。

2. どこまでいけば成功と見なすのか、闘値を事前に決めておくこと。

• そうしないと、そのテストが成功したのか失敗したのかの判断ができない。

• 実行時間は短くし、キャパシティテストが妥当な時間内に完了するようにしておくこと。

3. 変更に対して堅牢にしておくこと。

• アプリケーションに変更があるたびにテストをそれに追従させる作業が発生するようでは

いけない。

4. 複数を組み合わせてより大規模で複雑なシナリオをテストできるようにしておくこと。

• そうすれば、現実的な使用例をシミュレートできる。

5. 繰り返し実行できるようにしておくこと。また、複数のテストを順に実行することも同時に実

行することもできるようにしておくこと。

• そうすれば、そのテストスイートを負荷テストや長期稼働テストにも流用できる。

9.6 キャパシティテストを自動化する ~方法~

1. 既存の受け入れテストからいくつかピックアップしてそれをキャパシティテスト用に書き換える

– 受け入れテストがうまくできていれば、それはきっと実際のシステム上であり得る現実的なシナリオを反映して

いることだろう。

• そしてきっと、アプリケーションに変更があってもあまり変更せずにすむはずである

– 受け入れテストに欠けているのは、規模を拡大する(アプリケーションに対して厳しめの負荷をかける)ことと、

成功したかどうかを判断することである。

– それ以外の観点については、これまで、の章における助言に従って受け入れテストの作成や管理を行っていれば、

先ほどまとめた「よいキャパシティテストの条件」のほとんどはすでに満たせていることだろう。

2. 本番環境に近い現実的な負荷をかけること。

3. 負荷のかかる現実的な状況(ただし、異常な状態)を再現することである。

– 受け入れテストでは、万事順調な正常系だけをテストするわけではない。キャパシティテストでもそれは同様で

ある。

– たとえば、システムの規模が拡大しでもきちんと動作するかどうかを判断するうまいテクニックとして、ナイ

ガードは次のような提案をしている。

• 「コストが最も高いトランザクションを何でもいいから特定し、そうしたトランザクションの割合を2-3

倍しよう。」

– もしこれらのテストがシステムとやりとりする内容を記録し、それを何度も複製した上で再び実行できるのなら、

さまざまな種類の負荷をテスト対象システムにかけられるようになり、したがって、さまざまなシナリオをテス

トできるようになる。

9.6 キャパシティテストを自動化する ~基本的な考え方~

実際に使っている技術はそれぞれ異なっていたし、キャパシティテストの要件もそれぞれ異なっていた。

一貫していたのは基本的な考え方だけである。

1. 機能的な受け入れテストの出力を記録してから後でその規模を拡大し、個々のテストが成功した

と見なせる条件を定義してから、システムに大量の負荷をかけた状態でテストを再度実行すると

いう流れ。

2. まず最初に決めなければならないのは、アプリケーションの操作の記録と再生をどこで行うかと

いうことである。

3. 目標は、システムを実際に使うときの流れにできるだけ近づけるということである。

• UI経由の操作でシステムに負荷をかけようとしてはいけない。

• システムのふるまいやベースとなるアーキテクチャなどのさまざまな要素によって、記録

と再生を行う場所は次のいずれかに落とし込める(図9-3)

1. ユーザーインターフェイスを使う。

2. サービスあるいは公開APIを使う。(たとえば、HTTPリクエストを直接Webサー

バーに送る)

3. 低レベルAPIを使う。(たとえば、サービス層やデータベースを直接呼び出す)

9.6.1 ユーザーインターフェイス経由のキャパシティテスト ~~

• 操作の記録や再生を行う場所として最も明白なところは、ユーザーインターフェイスである。

– 大半の商用負荷テスト製品は、ユーザーインターフェイス経由での操作を行っている。

– この手のツールは、スクリプトを書いてやりとりを記録したり、あるいはユーザーインターフェ

イス経由で直接やりとりを記録したりする。

– そして、記録した内容を複製して大規模なテスト操作を準備する。

– これを使えば、ひとつのテストに対して何百あるいは何千ものやりとりをシミュレートできる。

• 大規模なシステムでは必ずしもこの手法が現実的であるとは限らない。

• システム全体を通してテストを実行することには多大な利点があるのだが、大規模なシステムの中に

はそうもいかない。

– 大きな弱点:分散型アーキテクチャで、複数のサーバー重要なビジネスロジックを分担して受け

持っている(このような場合はキャパシティの問題がより重要になる) 場合は、システムに適切

な負荷をかけて十分にテストすることが不可能になる可能性がある。

• キャパシティテストにおける最も一般的なアプローチ「UI経由でのキャパシティテストを避ける」

– 例外があるとすれば、UI 自体を精査することが重要な場合や、クライアント・サーバー間のや

りとりがボトルネックになっていない場合くらいである。

9.6.2 サービスや公開APIに対するインタラクションを記録する

• この戦略が使えるのは、グラフイカルなユーザーインターフェイスではなくAPIを公開しているよう

なアプリケーション

– Webサービス

– メッセージキュー

– その他のイベント駆動な通信

• サービスや公開APIは、やりとりを記録する場所として理想的なポイントになり得る。サービス指向

アーキテクチャのシステムには、この方式が最適。

– クライアント数の増加に関する問題も回避できる

– 何百あるいは何千ものクライアントプロセスを管理せずに済む

– ユーザーインターフェイス経由でシステムとやりとりするほどにはもろくない。

• 図9-4にキャパシティテストの記録用コンポーネントを示す。

• これは、両者の間でインタラクションが発生した際にそれを記録するためのコンポーネントである。

受け入れテストホスト サーバー/公開API

図9-4 公開APIに対するインタラクションを記録する

記録された テンプレート

キャパシティテスト基盤

9.6.3 記録したインタラクションテンプレートを使う ~受け入れテストの出力からインタラクションテンプレートを作成~

• 後で置換するためのタグをつけている値もあればそのまま残しているところもある。

– そのまま残しているのは、その値があってもテストを行う意味に影響を与えないからである。

– 必要に応じてメッセージ内のタグ付けを多くすることも少なくすることもできる。

• 全体としては、置換項目はできるだけ少なく抑えるように心がけている。

– テストでうまく使えるための必要最小限の置換だけにしておくべき。

– テストとテストデータ間が過度に結合してしまわないようにでき、テストをより柔軟かつ壊れに

くくできる。

<Order number=‘x567342'> <Customer id='7736443 ' /> <OrderItems> <Orderltem productCode=MF77823 '>

<Quantity>4</Quantity> <Color>Dark Blue</Color> <Pricc>23.5</Pricc>

</Orderltem> <Orderltem productCode=MF77824 '>

<Quantity>4</Quantity> <Price>5.34</Price> </Orderltem>

</OrderItems> </Order>

<Order number=‘{{!ORDER_NUMBER}}'> <Customer id='{{!CUSTOMER_ID}}' /> <OrderItems> <Orderltem productCode=MF77823 '>

<Quantity>4</Quantity> <Color>Dark Blue</Color> <Pricc>23.5</Pricc>

</Orderltem> <Orderltem productCode=MF77824 '>

<Quantity>4</Quantity> <Price>5.34</Price> </Orderltem>

</OrderItems> </Order>

記録 タグ

受け入れテストの出力 インタラクションテンプレート

9.6.3 記録したインタラクションテンプレートを使う ~テンプレートとともに使うテストデータを作成~

• このデータはインタラクションテンプレートと組み合わせて使うためのもので、テストデータのコレ

クションを適切なテンプレートと組み合わせると、テスト対象のシステムに対する有効なインタラク

ションとなる。

• テンプレートに記録した内容に加えて、そのテンプレートが表すテストが成功するための条件も追加

することになる。(どのように?)

<Order number=‘{{!ORDER_NUMBER}}'> <Customer id='{{!CUSTOMER_ID}}' /> ・・・

</Order>

タグ

インタラクションテンプレート

<case> <ORDER_NUMBER>x567342</ORDER_NUMBER> <CUSTOMER_ID>7736443</CUSTOMER_ID>

</case> <case>

<ORDER_NUMBER>x778654</ORDER_NUMBER> <CUSTOMER_ID>0909785</CUSTOMER_ID>

</case>

テストデータ

<Order number=‘x567342'> <Customer id=‘7736443' /> ・・・

</Order> <Order number=‘x778654'>

<Customer id=‘0909785' /> ・・・

</Order>

テストインスタンス

9.6.3 記録したインタラクションテンプレートを使う ~キャパシティテストを実行するときに、これらの個別のテストインスタンス

をシステムに対して同時に実行~

• 方法は2つ

– Apache JMeterやMarathonあるいはBench といったオープンソースのパフォーマンステスト

ツールへの入力として使う。

– シンプルなテストハーネスを書いて、この方式でテストを管理したり実行したりすることもでき

る。

9.6.4 キャパシティテスト用スタブを使ったテスト作り ~~

• テスト対象のアプリケーション(あるいはインターフェイス、テクノロジー)の何もしないシンプルな

スタブの作成から始める

– これから書くテストが十分高速に動くことを確認できるし、相手側が何もしないときに正しくテ

ストが通ることも確認できる。

– 非常に高いパフォーマンスを要求されるシステムのキャパシティテストでは、キャパシティテス

トを書くほうがそのテストを通るくらいに十分高速なコードを書くよりも困難であることが多い。

– そのため、作ったテストが本当に必要な要件を検証できるのかを確かめることが重要となる。

• まずはじめにテストスタブ相手に各テストを実行してテスト自体が正しく機能することを確かめる。

– これによって、その後の結果の信頼性を保証している。

– ベンチマーク実行の結果は他のキャパシティテストの結果とは別に報告されるので、何か問題が

あればすぐに気づける。

9.7 キャパシティテストをデプロイメントパイプラインに追加する ~キャパシティテストをデプロイメントパイプラインの受け入れテストステージに含め

ることを勧めない理由~

1. 真に効果的なテストをするなら、キャパシティテストはそれ専用の環境で実行する必要がある。

1. あるリリース候補がキャパシティ要件を大幅に悪化させたとしよう。

2. もしその真の原因が「同じ環境で他の自動テストが同時に動いていたから」だとしたら、それを見つけるのは至難の業だ。

2. CIシステムには、テスト用のターゲット環境を指定できるものもある。この機能を使えば、キャパシ

ティテストを個別に分けて、受け入れテストと並列に実行できるようになる。

3. キャパシティテストの中には、非常に実行時聞がかかるものがある。その結果、受け入れテストの結

果を得るまでに耐えがたい遅延が発生してしまう。

4. 受け入れテスト以降の多くの段階で、最新版の動作するソフトウェアのデモや手動テスト、インテグ

レーションテストなどとキャパシティテストを並列実行できる。これらの作業のためにキャパシティ

テストの通過が必須だというわけではなく、多くのプロジェクトにとってこれは非効率的である。

5. プロジェクトによっては、キャパシティテストを受け入れテストと同じ頻度で実行するのはあまり意

味がないことがある。

9.7 キャパシティテストをデプロイメントパイプラインに追加する ~自動キャパシティテストをそれ単体のステージとしてデプロイメントパイプラインに

組み込む~

• パイプライン内でキャパシティテストステージをどのように扱うかは、プロジェクトによって異なる。

• プロジェクトによっては、受け入れテストステージと同様の扱いにするのもよいだろう。

– 完全に自動化されたデプロイメントを行うためのひとつの関門にするということだ。

– キャパシティテストステージでのテストがすべて通らなければ、手動で手を加えない限りデプロ

イできないということ。

• ハイパフォーマンスを要求されるシステムや大規模なシステムには、この方針が最も適している。

– 熟考の上で設定されたキャパシティの闘値を満たせなければ、それだけでアプリケーションとし

ては役立たずになるからである。

– これは最も厳格な形式のキャパシティテストであり、一見するとほとんどのプロジェクトに適し

ているように感じる。しかし、常にそうだとは限らない。

9.7 キャパシティテストをデプロイメントパイプラインに追加する ~自動キャパシティテストをそれ単体のステージとしてデプロイメントパイプラインに

組み込む~

• 広い目で見ると、デプロイメントパイプラインにおける受け入れテストステージは、キャパシティテ

ストも含めたそれ以降のすべてのテストステージのテンプレートとなる。

– その様子を図9-7に示す。キャパシティテスト(そしてその他の受け入れテスト以降のテスト)ス

テージは、まずデプロイの準備から始まる。

– その後デプロイし、環境やアプリケーションが正しく設定されてデプロイできているかどうかを

確認する。キャパシティテストを実行するのはそれからとなる。

UAT 環境設定

バイナリデプロイ スモークテスト

キャパシティステージ 環境設定

バイナリデプロイ スモークテスト

本番 環境設定

バイナリデプロイ スモークテスト

受け入れステージ 環境設定

バイナリデプロイ スモークテスト 受け入れテスト

コミットステージ コンパイル

コミットテスト アセンブル コード分析

環境&アプリ 設定

ソースコード 環境&アプリ

設定

成果物リポジトリ

図5-4 基本的なデプロイメントパイプライン

レポート メタデータ

バイナリ バイナリ

レポート メタデータ

レポート バイナリ メタデータ

バージョン コントロール

開発者 コードメトリクスと

テストの失敗を確認する テスター

自分でデプロイ

運用 ボタン1つで リリース

図9-7 デプロイメントパイプラインにおける キャパシティテストステージ

環境と アプリの 設定

キャパシティテスト ステージ

環境設定

バイナリのデプロイ スモークテスト

キャパシティテスト

成果物 リポジトリ

バイナリ レポート メタデータ

9.8 キャパシティテストシステムのもうひとつの利点

• キャパシティテストシステムは、想定している本番システムに最も近い構成になることが多い。

– それ自体、非常に価値のあるリソースである。

– さらに、我々の助言に従ってキャパシティテストを設計し、組み合わせ可能なシナリオベースの

テストを作ったのなら、それは本番システムを非常にうまくシミュレートしたものとなる。

– シナリオベースのテストはシステムとの実際のやりとりのシミュレーションである。これらのシ

ナリオを複雑に組み合わせれば、さまざまな検証や調査を疑似本番システム上で効率的に行える。

• 基本的にキャパシティテストシステムは実験用のリソースであり、必要に応じて効率的に活用できる。

• このシステムを使ってあらゆる実験を行えば、発生した問題の調査や将来起こるであろう問題の予知、

そしてその回避策を検証する助けとなるだろう。

9.8 キャパシティテストシステムのもうひとつの利点 ~この仕組みを利用して出来る作業(著者らが行っているもの)~

1. 本番環境での複雑な不具合の再現

2. メモリリークの検出とデバッグ

3. 長期稼働テスト

4. ガベージコレクションの影響の検証

5. ガベージコレクションのチューニング

6. アプリケーションの設定パラメタのチューニング

7. サードパーティーのアプリケーション(OSやアプリケーションサーバー、データベースなど)の設定のチューニング

8. 最悪の状態である異常系のシミュレート

9. 複雑な問題に関するさまざまな解決策の検証

10. インテグレーションの失敗のシミュレート

11. さまざまなハードウェア構成で実行を繰り返すことによる、アプリケーションのスケーラビリティの計測

12. 外部システムとの通信の負荷テスト

– ただし、我々の行うキャパシティテストは、本来、インターフェイスのスタブを相手に実行するすることを意図

していた

13. 複雑なデプロイメントのロールパック作業のリハーサル

14. いくつか抜粋したパーツやアプリケーションを失敗させることによる、サービスの劣化に関する評価

15. 現実世界でのキャパシティのベンチマークを、差し当たり手に入る本番用ハードウェアで実行する。それにより、そ

れ以降長期にわたって使うことになる低スペックなキャパシティテスト環境上でのテスト結果をより正確に評価でき

るようにする。

9.9 まとめ

1. 非機能要件を満たすようにシステムを設計するのは、複雑な作業。

– 非機能要件の多くは機能をまたがるもの→それがプロジェクトにもたらすリスクを管理することは難しい。

– 次のふたつのふるまいにつながりがちとなる。

1. プロジェクトの開始時期から非機能要件に注意を払わなくなること。

2. 過剰に反応しすぎてアーキテクチャを作り込みすぎること。

※技術者としては技術的なソリューションを第一に考えてしまいがちだが、そうならないように注意が必要

2. 顧客やユーザーときちんと向き合い、そのアプリケーションにとって何が大切なのかを確かめ、詳細

な非機能要件を定義するときには実際のビジネス上の価値に基づいて考えなければならない。

1. デリバリーチームはそのアプリケーション用に適切なアーキテクチャを決められるようになる。

2. 非機能要件に関する受け入れ基準も、機能要件を考えるときと同様に設定できる。

3. そうすれば、非機能要件を満たすために必要な作業の見積もりや優先順位付けも、機能要件の場合とまったく同

様にできるだろう。

3. そこまで終えたら、デリバリーチームは自動テストを作成して、これらの要件を満たすことを確かめ

られるようにしなければならない。

1. テストはデプロイメントパイプラインの一環として動かし、アプリケーションや基盤そして設定に関する変更が

コミットステージと受け入れテストステージを通過するたびに実行することになる。

2. 受け入れテストを元にした、より広範囲なシナリオベースのテストで非機能要件を検証する。

4. これが、システムの特性を包括的で保守可能な形式で、保つための最善策である。