代表的な面接トピック

バックエンド面接:コンシューマ駆動契約テストを用いてマイクロサービスAPIを安全にリリースするにはどうすればよいか?

バックエンド難しい
Offer.cc 編集チーム公開日 更新日

質問

APIプロバイダがWeb、モバイル、および非同期コンシューマにサービスを提供しています。契約のスコープ、状態の分離、バージョン選択、CIゲート、およびロールバックを含む、コンシューマ駆動契約テスト(consumer-driven contract testing)を設計してください。

課題とスコープ

注文プロバイダがWeb、モバイル、および非同期コンシューマにサービスを提供しています。チームは、コミットごとにすべての本番同様サービスを起動することなく、プロバイダのリリース前に破壊的変更を検知したいと考えています。コンシューマが何を記述し、プロバイダがどのように検証し、ブローカーがどのようにバージョンを選択し、プロバイダ状態がどのように機能し、いつデプロイが許可されるかという、コンシューマ駆動契約ワークフローを設計してください。

これは、APIの境界、テストの階層化、バージョンの互換性、および継続的デリバリーを評価するものです。Pactは、コンシューマが必要とするリクエストと最小限のレスポンスとして契約をモデル化し、それをプロバイダに対して再生します。これは単体テスト、統合テスト、またはエンドツーエンド(E2E)テストを置き換えるものではありません。

面接官が見ているポイント

  • コンシューマの振る舞いが、プロバイダ実装のコピーではなく、最小限のインタラクション契約になっているか。
  • コンシューマのモックテスト、プロバイダの検証、ブローカー、およびデプロイマトリクスを連携できるか。
  • プロバイダ状態が、共有データベースの順序依存や本番クレデンシャルを使用せずに前提条件を分離できているか。
  • 複数のコンシューマバージョン、未検証の契約、メッセージ契約、およびロールバックを適切に処理できるか。

最初に明確にすべき質問

  1. インターフェースはHTTP、非同期メッセージング、またはその両方ですか? 契約の伝達手段が異なります。
  2. コンシューマは実際にどのフィールドを使用していますか? 契約には必要なリクエストと最小限のレスポンスを表現する必要があります。
  3. プロバイダ状態はテストデータの作成、クリーンアップ、パラメータ化が可能ですか? どの依存関係をスタブ化する必要がありますか?
  4. バージョンはどのように識別され、本番環境への移行前にどのコンシューマとプロバイダの組み合わせをパスさせる必要がありますか?
  5. ブローカー、ブランチのタギング、保留中の契約(pending pacts)ポリシー、およびロールバック戦略は存在しますか?

30秒で答えるフレームワーク

コンシューマはPactモックに対してインタラクションテストを記述し、必要なリクエストとレスポンスのアサーションのみを含む契約を生成してブローカーに発行します。プロバイダの検証ツールは対象のコンシューマバージョンを選択し、プロバイダ状態をセットアップして隔離された環境でリクエストを再生し、結果を発行します。CIのデプロイゲートは実際のバージョンマトリクスをチェックします。未検証の新しい契約は保留状態(pending)にするか、リリースをブロックすることができます。契約はメッセージの形式とインタラクションを証明するものであり、ビジネスロジックの完全な正当性を証明するものではありません。失敗した場合は、デプロイを停止し、プロバイダを修正するか、マトリクスをパスしたバージョンにロールバックします。

ステップ・バイ・ステップの回答

1. コンシューマの振る舞いからインタラクションを定義する

各インタラクションには、メソッド、パス、必須ヘッダー、重要なリクエストフィールド、および最小限のレスポンスアサーションを記述します。コンシューマテストは実際のプロバイダではなくPactモックを呼び出すため、実際のコンシューマの利用状況に直結した、高速で共有可能な契約が生成されます。

text
consumer test -> pact file -> broker
provider verifier + provider state -> replay -> verification result
deployment gate -> compatible version matrix -> deploy or block

2. 契約を最小限かつ安定した状態に保つ

使用していないレスポンスフィールド、ランダムなID、またはデータベース全体の完全なスナップショットに対してアサーションを行わないでください。型、フォーマット、必須構造にはマッチャー(matchers)を使用し、動的なタイムスタンプやUUIDはその形状(形式)のみを検証します。契約テストは一般的なプロバイダ機能ではなく、通信メッセージに焦点を当てます。

3. プロバイダ状態(provider states)の設計

プロバイダ状態とは、「注文が支払い済みである」といったインタラクションの前提条件です。状態ハンドラは、検証前にデータを作成またはスタブ化し、事後にクリーンアップします。パラメータは本番環境のクレデンシャルなしで追跡可能かつ冪等である必要があり、インタラクションが制御されていない順序に依存してはなりません。

4. ブローカーでバージョンと検証を管理する

コンシューマは、ブランチ、バージョン、または環境ラベルを付けて契約を発行します。プロバイダは選択されたコンシューマバージョンを検証し、結果を発行します。デプロイゲートは、単に「latest」が成功しているかだけでなく、実際に稼働するコンシューマに対して候補となるプロバイダをチェックします。保留(pending)機能を使用すると、新しい契約をブロックするかどうかを決定する前に、検証して記録することができます。

5. ロールアウト順序と互換性ウィンドウを選択する

下位互換性のある変更の場合は、古いリクエストを理解し、古いコンシューマが読み取れるレスポンスを返すプロバイダを先にデプロイし、その後にコンシューマをアップグレードします。破壊的変更の場合は、デュアルリード/ライト、バージョニングされたパス、または移行期間が必要です。メッセージ契約(Message pacts)はメッセージポートを検証しますが、実際のブローカーの配信、リトライ、順序制御には別途テストが必要です。

6. 障害への対処と本番環境のオブザーバビリティ

失敗したインタラクション、プロバイダ状態、バージョン、コミットSHA、および環境を記録します。デプロイをブロックし、マトリクスを通過した最後のバージョンにロールバックします。リリース後は、4xx/5xxエラー、デシリアライズエラー、デッドレター、およびビジネスメトリクスを監視します。契約テストの成功は本番環境での正当性を完全に保証するものではないため、ランタイム保護を維持してください。

高品質な模範回答

各コンシューマはPactモックに対して実際のインタラクションを記述し、必要なリクエストと最小限のレスポンスのみを含む契約を生成してブローカーに発行します。プロバイダ検証ツールはコンシューマのバージョンを選択し、再現可能なプロバイダ状態を隔離環境で実行してリクエストを再生し、プロバイダのバージョンとコミットSHAとともに結果を発行します。CIゲートは、一緒に稼働するコンシューマとプロバイダのバージョンに検証実績があるかどうかをチェックします。保留中の契約(pending pacts)により、古いプロバイダを即座に壊すことなく新しい契約を検証できます。

契約がカバーするのは通信の形式と使用されているフィールドであり、単体、統合、E2E、またはビジネスロジックのテストすべてを網羅するものではありません。破壊的な書き込みを行う前に読み取り側を順次展開します。つまり、プロバイダが古いリクエストとレスポンスとの互換性を維持したままコンシューマを移行し、破壊的変更にはバージョニングされたパスまたはデュアルライト期間を使用します。失敗時にはリリースをブロックして最後に成功したマトリクスに戻しつつ、ランタイムエラー、デッドレター、およびビジネスメトリクスを監視し続けます。メッセージ契約はメッセージの内容をカバーしますが、メッセージブローカー自体のセマンティクスには別途テストが必要です。

よくあるアンチパターン・失敗例

  • 契約をプロバイダレスポンスの完全なスナップショットにしてしまい、無関係なフィールドの変更でリリースがブロックされる。
  • コンシューマのモックのみを実行し、プロバイダに対して契約を一度も再生しない。
  • プロバイダ状態を共有データベースの順序、ランダムデータ、または本番クレデンシャルに依存させる。
  • 最新(latest)バージョンのみをチェックし、実際のデプロイマトリクスやロングテールなクライアントを見落とす。
  • PactをE2Eテストとして扱い、実際のメッセージブローカー、認証、パフォーマンス、ビジネスルールを無視する。
  • 検証失敗後にデプロイしてしまう、または検証済みのロールバック先バージョンが存在しない。

追加の質問と回答例

なぜレスポンスへの期待値を最小限に保つ必要があるのですか?

コンシューマは自身が使用するフィールドのみを固定(アサーション)すべきだからです。期待値を最小限に抑えることで偶発的な密結合を防ぎ、プロバイダが無関係なフィールドを安全に追加できるようになります。

プロバイダ状態とテストフィクスチャの違いは何ですか?

プロバイダ状態は、検証ツールがプロバイダ環境でセットアップおよびクリーンアップできる実行可能な前提条件インターフェースです。フィクスチャは単なるデータ成果物にすぎず、サービス間の状態を正しく確立できない場合があります。

保留中の契約(pending pact)はどのような問題を解決しますか?

新しい契約がブローカーに登録された際、その未検証の契約によって古いプロバイダのビルドが即座に失敗するのを防ぎつつ、検証を実行できるようにします。これを有効にするかどうかは組織のリリース方針によります。

契約の肥大化(スプロール化)をどのように防ぎますか?

実際のコンシューマのインタラクションの重複を排除し、古いバージョンを廃止し、ランダムなフィールドや完全なスナップショットを制限し、ブローカーに所有者、バージョン、最終検証日時を記録します。

なぜコンシューマのバージョン選択が重要なのですか?

ゲートは、本番環境で同時に稼働するバージョンを検証する必要があるためです。mainやlatestのみをチェックしていると、本番環境にまだ残っている古いモバイルアプリや別ブランチのバージョンを見落とす可能性があります。

Pactはプロバイダのビジネスロジックの正当性を証明できますか?

いいえ。インタラクションがコンシューマの契約を満たしていることを証明するだけです。ビジネスの不変条件、パフォーマンス、認可、障害復旧、および実際のインフラストラクチャには、依然として他のテストや本番環境での監視が必要です。

公開情報ソース

関連する質問