プレイブック

SDK (ソフトウェア開発キット) を漏らさないプロバイダーの抽象化: ゲートウェイの限界 (Sdk)

プロバイダー ゲートウェイは PSP SDK をどのように所有しているのですか。なぜチェックアウト オーケストレーターはセマンティック インターフェイスのみを参照する必要があるのでしょうか?カードとウォレットの流れは異なります...

分散型決済エンジン

一部 9 の 22

取得と完了の間のギャップを埋める一連の分散型支払いアーキテクチャ。

Distributed payment engine architecture diagram

前のセクションでは、支払い証拠と支払い状態の違いについて説明しました。PSP からの証拠は、システム自身の決定とは異なるものです。このセクションの質問は、より基本的な制限に関するものです。つまり、チェックアウト オーケストレーターは PSP の SDK を参照する必要がありますか?

簡単に言うと「ノー」です。オーケストレーターが知っているのは、支払いが要求され、結果が返されたことだけです。どの PSP がどの SDK バージョンとどの HTTP クライアントでこの結果を生成したか。これはオーケストレーターの仕事ではなく、プロバイダー ゲートウェイの責任です。```text Checkout Orchestrator │ ChargeRequest (semantik) ▼ Provider Gateway │ PSP SDK / HTTP client ▼ PSP A veya PSP B


## 最初に説明した概念```text
📦 Provider Gateway
PSP SDK'sını, kimlik doğrulamasını ve provider'a özgü akışları sahiplenen tek servis.

📦 Semantik Arayüz
Orchestrator'ın gördüğü, hiçbir provider tipine referans vermeyen sözleşme.

📦 Anti-Corruption Layer
Dış sistemin veri modelinin, kendi domain dilinizi kirletmesini engelleyen çeviri katmanı.

📦 Adapter
Provider'a özgü isteği semantik isteğe, provider'a özgü yanıtı semantik sonuca çeviren kod.
```「SDK リーク」は、ここでは専門的な話ではありません。PSP の `ChargeObject` 型がオーケストレーター コードに出現した瞬間、その PSP を変更することは、単一のファイルを変更することを意味するのではなく、オーケストレーターの奥深くに影響を与えることを意味します。

## SDK リークが卑劣な借金である理由

プロバイダー ゲートウェイを設定する場合、最も簡単な方法は、PSP の SDK オブジェクトをそのままオーケストレーターに移動することです。`ChargeResponse` タイプをインポートして直接使用し、フィールドを読み取り、ステータスを確認します。最初の一週間は早いですね。ただし、このタイプがオーケストレーターの署名に入力されるとすぐに、2 つのサービス間に隠されたバージョンの結合が作成されます。つまり、SDK が更新され、ドメイン名が変更され、オーケストレーターでコンパイル エラー、またはさらに悪いことにサイレント ロジック エラーが発生します。```text
❌ Orchestrator kodu
if (pspResponse.charges.data[0].outcome.network_status === 'approved') { ... }

✓ Orchestrator kodu
if (chargeResult.status === ChargeStatus.Captured) { ... }
```2 行目にはプロバイダー名が含まれていません。プロバイダー ゲートウェイは、どの PSP のどの領域を調べるべきかを知っています。オーケストレーターはセマンティックな結果のみを知っています。

## カードとウォレットのフローが同じインターフェイスを共有しているのに、同じフローではない理由

カード支払いはほとんど同期的に行われます。リクエストが送信され、承認/拒否の結果が数百ミリ秒以内に返されます。ウォレットまたは銀行主導の支払い (ユーザーが PSP ページにリダイレクトされるフロー) は非同期です。最初のリクエストは「保留中」ステータスとリダイレクト URL のみを返します。実際の結果は数分後に Webhook 経由で届きます。```text
Kart akışı
  ChargeRequest → [senkron çağrı] → ChargeResult (Captured/Declined)

Wallet akışı
  ChargeRequest → ChargeResult (Pending + redirectUrl)
         ...
  Webhook → ChargeResult (Captured/Failed) [asenkron, sonradan]
```セマンティック インターフェイスは、両方を同じ形状 `ChargeResult` で表します。違いを伝えるフィールドは `status` です (`Pending` は 3 番目のケースとして存在します)。 Orchestrator は、「この PSP はリダイレクトを使用しますか?」という質問にはまったく関心がありません。それは、「結果は最終的なものですか、それとも保留中ですか?」という質問に答えるだけです。

## インターフェイスを設計するときにどのフィールドを越えてはいけないのか

プロバイダー固有のエラー コード、プロバイダー固有のオブジェクト ID (PSP の内部課金 ID 形式など)、プロバイダー固有のメタデータ構造がセマンティック インターフェイスから漏洩してはなりません。代わりに、ゲートウェイはこの情報を独自のログの独自の診断領域に保持します。オーケストレーターは、相関 ID に一致する結果のみを返します。```text
Gateway içinde tutulan (dışarı sızmaz)
  provider_raw_code, provider_object_id, provider_response_headers

Orchestrator'a geçen (semantik)
  ChargeResult { status, amount, currency, providerRef }
````providerRef` が唯一の例外です。これは不透明な参照文字列であり、サポートと診断のために保存されますが、分岐されることはありません。

## 混同されやすい区別```text
❌ SDK'yı bir sınıfa sarmak (wrap) yeterlidir
✓ Sarmalama tip sızıntısını çözmez; davranış hâlâ provider'a özgü kalabilir

❌ Abstraction = interface tanımlamak
✓ Abstraction = orchestrator'ın hiçbir zaman bilmemesi gereken şeyi seçmek

❌ Tek PSP varsa abstraction gereksizdir
✓ Tek PSP'de bile abstraction, test edilebilirlik ve mock'lanabilirlik sağlar
```## ラッパーと実際の抽象化の違い

|基準 |薄いラッパー |意味論的な抽象化 |
| --- | --- | --- |
|チップリーク |通常は | を持ちます。なし |
| PSPを変更するとオーケストレーターに影響が出ますか? |はい |いいえ |
|カードとウォレットの差額は誰が管理するのか |オーケストレーター |ゲートウェイ |
|テスト容易性 | PSP モックは必須です |擬似意味論的な結果で十分です。

## インターフェース設計時のチェックリスト

1. PSP の名前、ドメイン、またはエラー コードが `ChargeResult` に直接記載されていますか?
2. オーケストレーターは、ストリームがリダイレクトを使用しているかどうかを知らなくても、`Pending` のケースを正しく処理できますか?
3. 新しい PSP を追加するときに、オーケストレーター コード内の 1 行を変更する必要がありますか?必要に応じて抽象化リークが行われます。
4. ゲートウェイのテストは、実際の PSP に接続せずにすべてのセマンティック状態を二重生成できますか?
5. `providerRef` 以外の不透明なフィールドがオーケストレーターの決定ロジックに入力されますか?

これらの質問に対する「はい」または「いいえ」の答えは、アーキテクチャの議論を「クリーンなコード」という抽象的な問題から、測定可能な境界テストに還元します。

## この記事で覚えておくべきこと

1. プロバイダー ゲートウェイは、SDK およびすべてのプロバイダー固有の詳細の唯一の所有者です。
2. Orchestrator は意図 (ChargeRequest) とセマンティック結果 (ChargeResult) のみを認識します。
3. カードとウォレットのフローは同じインターフェースを共有します。違いは、`status` フィールドの `Pending` ステータスです。
4. `providerRef` 以外の不透明なフィールドまたはプロバイダー固有のフィールドは境界を越えてはなりません。

> 抽象化の実際のテストは、新しいプロバイダーを追加したときにオーケストレーターのコードがまったく変更されないことです。

次のセクションでは、この制限をイベント側に移動します。ゲートウェイによって生成された Webhook は、生のプロバイダー ペイロードとしてオーケストレーターに到達する必要があるのか​​、それともセマンティック イベントとして到達する必要があるのか​​?

FAQ

よくある質問

プロバイダーゲートウェイとは何ですか?

PSP SDK、認証、およびプロバイダー固有のフローを採​​用する唯一のサービス。

セマンティックインターフェイスとは何ですか?

オーケストレーターが認識する、プロバイダーの種類を参照しないコントラクト。

「SDKをクラスにラップすれば十分」というのは本当でしょうか?

ラッピングしてもチップの漏れは解決しません。動作は依然としてプロバイダー固有のままである可​​能性があります

このセクションでは何を修正しますか?

この区別は簡単そうに見えますが、3 年後にどの PSP を交換できるかはこの決定によって決まります。プロバイダー ゲートウェイは、SDK およびプロバイダー固有の詳細の唯一の所有者です。前のセクションでは、支払い証拠と支払い状態の違いについて説明しました。PSP からの証拠は、システム自身の決定とは異なるものです。このセクションの質問は、より基本的な制限に関するものです。つまり、チェックアウト オーケストレーターは PSP の SDK を参照する必要がありますか?

学んだエンジニアリング原則

  • SDK タイプがオーケストレーターに漏洩すると、PSP の交換はシステム全体に影響を及ぼします。
  • セマンティック インターフェイスは、プロバイダーではなく、意図と結果を定義します。
  • カードとウォレットは同じ契約を共有しますが、同じタイミングではありません。

続きを読む

続きを読む

シリーズの次のシリーズ

シリーズの次のシリーズ

同じシリーズ

エッセイ

支払いエラーの分類法

タイムアウト、429、5xx、ビジネスの低下とインフラストラクチャのエラーは同じものではありません。カテゴリごとに異なる再試行ポリシーが必要です。

Paylaş