Playbook
Provider-Abstraktion ohne SDK (Software Development Kit)-Leckage (Provider Abstraktion Ohne Sdk Leckage)
Wie das Provider-Gateway das PSP-SDK besitzt, während der Checkout-Orchestrator nur eine semantische Schnittstelle sieht — und warum Karten- und Wallet-Flows…
Verteilte Payment Engine (Distributed Payment Engine)
Teil 9 von 22
Serie zur verteilten Payment-Architektur — die Lücke zwischen Capture und Complete.
Im vorherigen Teil haben wir die Grenze zwischen Payment Evidence und Payment State gezogen. Dieser Teil zieht eine noch grundlegendere Grenze: Sollte der Checkout-Orchestrator jemals das SDK eines PSP zu Gesicht bekommen?
Die kurze Antwort: nein. Der Orchestrator sollte genau zwei Dinge wissen: Eine Zahlung wurde angefordert, und ein Ergebnis ist zurückgekommen. Welcher PSP dieses Ergebnis mit welcher SDK-Version erzeugt hat, ist Aufgabe des Provider-Gateways, nicht des Orchestrators.
Checkout Orchestrator
│ ChargeRequest (semantisch)
▼
Provider Gateway
│ PSP SDK / HTTP Client
▼
PSP A oder PSP B
Diese Grenze wirkt trivial — bis man drei Jahre später einen Provider austauschen muss. Dann entscheidet genau diese Grenze, ob der Wechsel einen Tag oder ein Quartal dauert.
Wo die Begriffe zuerst auftauchen
📦 Provider Gateway
Der einzige Dienst, der das PSP-SDK, die Authentifizierung und providerspezifische Abläufe besitzt.
📦 Semantische Schnittstelle
Der Vertrag, den der Orchestrator tatsächlich sieht — er verweist auf keinen Provider-Typ.
📦 Anti-Corruption Layer
Eine Übersetzungsschicht, die verhindert, dass das Modell eines externen Systems die eigene Domänensprache verschmutzt.
📦 Adapter
Code, der eine providerspezifische Anfrage in eine semantische umwandelt und umgekehrt.
'SDK-Leckage' ist kein Stilproblem: Sobald der ChargeObject-Typ eines PSP im Orchestrator-Code auftaucht, wird ein Providerwechsel nicht mehr zu einer Dateiänderung, sondern zu einem Eingriff in den Kern des Orchestrators.
Warum SDK-Leckage eine stille Schuld ist
Der schnellste Weg, ein Provider-Gateway zu bauen, ist es, die SDK-Objekte des PSP direkt an den Orchestrator weiterzugeben: ChargeResponse importieren, ein Feld lesen, auf einen Status verzweigen. In der ersten Woche ist das schnell. Aber sobald dieser Typ in der Signatur des Orchestrators landet, entsteht eine stille Versionskopplung: Das SDK wird aktualisiert, ein Feld wird umbenannt, und der Orchestrator kompiliert nicht mehr — oder schlimmer, verhält sich stillschweigend falsch.
❌ Orchestrator-Code
if (pspResponse.charges.data[0].outcome.network_status === 'approved') { ... }
✓ Orchestrator-Code
if (chargeResult.status === ChargeStatus.Captured) { ... }
Die zweite Zeile trägt keinen Providernamen. Das Gateway weiß, welches PSP-Feld zu prüfen ist; der Orchestrator kennt nur das semantische Ergebnis.
Warum Karten- und Wallet-Flows eine Schnittstelle, aber keinen Ablauf teilen
Kartenzahlungen sind meist synchron: Eine Anfrage geht raus, und innerhalb weniger hundert Millisekunden kommt ein Autorisierungs- oder Ablehnungsergebnis zurück. Wallet- oder Redirect-Flows (bei denen der Kunde auf die Seite des PSP geleitet wird) sind asynchron: Der erste Aufruf liefert nur einen Pending-Status und eine Redirect-URL; das eigentliche Ergebnis kommt Minuten später per Webhook.
Karten-Flow
ChargeRequest → [synchroner Aufruf] → ChargeResult (Captured/Declined)
Wallet-Flow
ChargeRequest → ChargeResult (Pending + redirectUrl)
...
Webhook → ChargeResult (Captured/Failed) [asynchron, später]
Die semantische Schnittstelle bildet beide mit derselben ChargeResult-Form ab; der Unterschied steckt im status-Feld, in dem Pending als legitimer dritter Zustand existiert. Der Orchestrator fragt nie, ob ein PSP einen Redirect nutzt — er fragt nur, ob das Ergebnis schon final oder noch offen ist.
Was die Grenze niemals überschreiten darf
Providerspezifische Fehlercodes, providerspezifische Objekt-IDs (das interne Charge-ID-Format des PSP) und providerspezifische Metadatenstrukturen dürfen die semantische Schnittstelle niemals verlassen. Das Gateway behält diese Information in eigenen Logs und Diagnosedaten; der Orchestrator erhält nur ein Ergebnis, das über seine eigene Correlation-ID verknüpft ist.
Bleibt im Gateway (leckt nie)
provider_raw_code, provider_object_id, provider_response_headers
Geht an den Orchestrator (semantisch)
ChargeResult { status, amount, currency, providerRef }
providerRef ist die einzige Ausnahme: eine opake Referenz für Support und Diagnose, auf der niemals verzweigt wird.
Häufig verwechselte Unterschiede
❌ Das SDK in eine Klasse zu verpacken reicht aus
✓ Verpacken löst die Typ-Leckage nicht; das Verhalten bleibt providerspezifisch
❌ Abstraktion bedeutet, ein Interface zu definieren
✓ Abstraktion bedeutet zu entscheiden, was der Orchestrator niemals wissen darf
❌ Mit nur einem PSP ist Abstraktion unnötig
✓ Auch mit einem PSP bringt Abstraktion Testbarkeit und Mockbarkeit
Dünner Wrapper vs. echte Abstraktion
| Kriterium | Dünner Wrapper | Semantische Abstraktion |
|---|---|---|
| Typ-Leckage | meist vorhanden | keine |
| Orchestrator betroffen bei PSP-Wechsel | ja | nein |
| Wer verwaltet Karten-/Wallet-Unterschiede | Orchestrator | Gateway |
| Testbarkeit | benötigt PSP-Mocks | ein gefälschtes semantisches Ergebnis reicht |
Checkliste beim Entwurf der Schnittstelle
- Taucht in
ChargeResultirgendein Providername, Feldname oder Fehlercode direkt auf? - Kann der Orchestrator ein
Pending-Ergebnis korrekt verarbeiten, ohne zu wissen, ob ein Redirect verwendet wurde? - Erfordert ein neuer PSP auch nur eine Zeile Änderung im Orchestrator-Code? Wenn ja, leckt die Abstraktion.
- Kann das Test-Double des Gateways alle semantischen Zustände erzeugen, ohne den echten PSP anzusprechen?
- Erreicht irgendein opakes Feld außer
providerRefdie Entscheidungslogik des Orchestrators?
Diese Ja-Nein-Fragen machen aus 'saubere Architektur' einen messbaren Grenztest statt einer abstrakten Debatte.
Was bleiben soll
- Das Provider-Gateway ist der alleinige Besitzer des SDK und jedes providerspezifischen Details.
- Der Orchestrator kennt nur Absicht (
ChargeRequest) und semantisches Ergebnis (ChargeResult). - Karten- und Wallet-Flows teilen dieselbe Schnittstelle; der Unterschied steckt im
Pending-Status. - Außer
providerRefdarf nichts Opakes oder Providerspezifisches die Grenze überschreiten.
Der eigentliche Test einer Abstraktion ist, dass ein neuer Provider niemals den Code des Orchestrators berührt.
Der nächste Teil verschiebt diese Grenze zu Events: Sollten die Webhooks des Gateways den Orchestrator als rohe Provider-Payloads erreichen — oder als semantische Events?
FAQ
Häufige Fragen
Was ist Provider Gateway?
Der einzige Dienst, der das PSP-SDK, die Authentifizierung und providerspezifische Abläufe besitzt.
Was ist Semantische Schnittstelle?
Der Vertrag, den der Orchestrator tatsächlich sieht — er verweist auf keinen Provider-Typ.
Stimmt es, dass „Das SDK in eine Klasse zu verpacken reicht aus“?
Verpacken löst die Typ-Leckage nicht; das Verhalten bleibt providerspezifisch
Was legt dieser Teil fest?
Diese Grenze wirkt trivial — bis man drei Jahre später einen Provider austauschen muss. Dann entscheidet genau diese Grenze, ob der Wechsel einen Tag oder ein Quartal dauert. Das Provider-Gateway ist der alleinige Besitzer des SDK und jedes providerspezifischen Details. Im vorherigen Teil haben wir die Grenze zwischen Payment Evidence und Payment State gezogen. Dieser Teil zieht eine noch grundlegendere Grenze: Sollte der Checkout-Orchestrator jemals das SDK eines PSP zu Gesicht bekommen?
Gelernte Engineering-Prinzipien
- Wenn ein SDK-Typ in den Orchestrator leckt, trifft ein PSP-Wechsel das ganze System.
- Eine semantische Schnittstelle beschreibt Absicht und Ergebnis, niemals den Provider.
- Karte und Wallet teilen einen Vertrag, kein Timing.
Weiterlesen
Weiterlesen
Nachster Teil der Serie
Semantische Events statt roher Provider-Payloads
Sollte der Webhook, den das Provider-Gateway empfängt, mit dem eigenen Event-Namen des PSP weitergegeben werden — oder als semantisches Event wie…
Nachster Teil der Serie
Zahlungsbeleg vs. Zahlungsstatus
Beleg (Evidence) ist, was der PSP sagte. Status (State) ist, was Sie entschieden haben. Vermischen Sie beide, weiß die Wiederherstellung nicht, wem sie…
Aus derselben Serie
Taxonomie der Zahlungsfehler
Ein Timeout, ein 429, ein 5xx, eine Business-Ablehnung und ein Infrastrukturfehler sind nicht dasselbe. Jede Kategorie braucht ihre eigene Retry-Strategie.