Skip to content
Search lessons, topics, tests…
Esc

    ↑ ↓ moveEnter openEsc close
    Cheat sheets: all cheat sheets

    Adapter vs Facade for Checkout Integrations: Pick the Right Boundary

    Learn how to choose between Adapter and Facade when integrating a payment provider into a checkout flow, including intent, dependency direction, migration trade-offs, and common interview pitfalls.

    Learning outcome

    By the end of this lesson, you should be able to explain the difference between Adapter and Facade, spot which one fits a checkout integration, and justify the boundary in a design interview. The core idea is simple: Adapter changes one interface into another, while Facade simplifies access to a subsystem. In payment-provider work, that difference affects dependency direction, how much the checkout orchestration knows about the provider, and how easy future migrations will be.

    Intuition

    Imagine a checkout service that needs to charge a card, reserve inventory, and create an order. A payment provider might expose a callback-heavy, provider-specific API with concepts like intent IDs, capture windows, and error codes. A Facade can sit inside your application and present a clean checkout-oriented flow such as “authorize payment,” “capture payment,” and “void payment.” A consumer-facing team uses the Facade to avoid juggling provider details.

    An Adapter is different. It is useful when your code already expects a specific interface, but a payment provider ships a different one. The Adapter translates between the two so existing code can keep using its preferred shape. In other words, the Adapter is about compatibility; the Facade is about simplification.

    Deep dive

    The easiest interview test is to ask: “What is the source of friction?” If the friction is a mismatch between two interfaces, think Adapter. If the friction is that a subsystem is too complicated to use directly, think Facade.

    Dependency direction matters:

    • With an Adapter, your application code often depends on an abstraction it already understands, and the Adapter depends on the provider API.
    • With a Facade, your application code depends on a simpler entry point, which delegates to the subsystem. The number of calls behind it does not determine the pattern.

    In a checkout orchestration example, a Facade can coordinate the whole checkout boundary: payment authorization, inventory reservation, fraud checks, and order creation. It protects the rest of the app from “who do I call first?” complexity. That is especially useful when the orchestration is business logic owned by your system.

    By contrast, an Adapter is a good fit when your checkout service has an internal payment port, but the provider speaks a different dialect. You may already have a PaymentGateway abstraction, and a provider-specific implementation translates provider request/response models into your domain types. In this design, the Adapter owns provider-protocol translation, not the checkout business workflow. It may need several provider calls to implement one payment operation, as the CreateIntent/ConfirmIntent example below shows.

    Ask what contract the class serves. ProviderPaymentAdapter exists to satisfy the payment port using one provider. CheckoutFacade offers callers a simpler checkout capability. Surviving provider replacement does not by itself answer that contract question. For example, an unchanged CheckoutWorkflow can keep enforcing the same inventory rule while its payment Adapter is replaced.

    When neither pattern is needed

    Sometimes the best boundary is no extra pattern at all.

    • If the provider API is already simple and your app only makes one or two direct calls, adding a Facade can be needless indirection.
    • If your own interface already matches the provider exactly, an Adapter adds ceremony without value.
    • If the checkout flow is tiny and stable, the extra layer may slow understanding more than it helps.

    Use patterns to reduce complexity, not to decorate architecture.

    Failure modes

    Common interview mistakes include:

    • Calling everything a Facade just because it sits in front of something external.
    • Saying an Adapter “hides complexity” without noting that its main job is interface conversion.
    • Mixing orchestration with translation in one class and then being unable to explain why it exists.
    • Forgetting that a Facade can depend on multiple subsystems, while an Adapter usually bridges one target interface to one adaptee.
    • Treating migration from one payment provider to another as automatically requiring a Facade; sometimes an Adapter around a stable port is enough.

    Migration trade-offs are important. A Facade can make it easier to swap internal steps because callers only know the simplified boundary. But if your application leaks provider-specific concepts through the Facade, migration becomes harder. An Adapter can support provider replacement behind a stable interface, but only if the interface itself is domain-oriented and not overly coupled to the provider’s vocabulary.

    Worked boundary trace

    Use this fictional provider contract; it is not a recipe for a particular payment SDK. The application requests authorization of 2,500 minor units in currency USD for checkout C-42. The provider requires CreateIntent, followed by ConfirmIntent, and can return Authorized, Declined, or Pending. Assume it also supports looking up status by the same logical operation identity.

    1. CheckoutFacade accepts the checkout request. The application workflow chooses when inventory and payment steps run.
    2. ProviderPaymentAdapter maps the amount, currency, and logical operation identity, performs the provider protocol, and returns the payment-port result. Pending stays pending; it must not be converted into success.
    3. The workflow creates a confirmed order only after its stated prerequisites hold. If inventory was reserved and payment is declined, this exercise's policy releases that reservation and returns a failed checkout.
    4. If the provider confirmed authorization but the reply was lost, the application has an unknown result, not a proven decline. Before allowing another authorization, use the assumed status lookup with the same operation identity. If that lookup is unavailable or still pending, retain an unresolved checkout for later recovery. A wrapper class alone cannot supply a missing recovery contract.

    Check your answer: Which class changes if the replacement provider calls its operation ReserveFunds? The provider Adapter. Which changes if the business now requires inventory reservation before authorization? The application workflow. A caller-facing Facade may remain unchanged in both cases.

    Tests to name: Assert exact amount/currency mapping; preserve all three outcomes; verify a known decline releases the reservation under this exercise's policy; simulate a lost authorization reply and verify that no confirmed order is reported while the result remains unknown.

    Interview drill

    Use these four scenario questions to sharpen your answer.

    1. Scenario: The checkout service already exposes AuthorizePayment, but a new provider uses CreateIntent and ConfirmIntent. Which pattern fits?

    Answer: Adapter. The problem is a mismatch between your expected interface and the provider’s API.

    1. Scenario: The checkout flow must call fraud screening, payment, inventory, and receipts, and the rest of the app should not know the sequence.

    Answer: Use a checkout Facade as the simple entry point. In this example, assign the sequence and failure policy to CheckoutWorkflow. If payment succeeds but inventory fails, the workflow must still return and recover from that partial result; naming the entry point does not undo the payment.

    1. Scenario: The provider API is simple, and the checkout code only needs one direct charge call.

    Answer: Neither pattern may be necessary. Direct integration may be clearer.

    1. Scenario: Your team wants to replace the payment provider next quarter without changing the checkout orchestration code.

    Answer: Prefer a domain-oriented port plus an Adapter per provider. If the orchestrator is also simplifying multiple internal steps, you may additionally use a Facade at the checkout boundary.

    Decision checklist

    Ask these questions in order:

    • Am I translating one interface into another, or simplifying access to a subsystem?
    • Does the class mainly map request/response shapes, or does it coordinate business steps?
    • Should callers depend on provider details, or on a stable domain boundary?
    • Will this layer help future provider migration, or just add indirection?
    • Can I explain who owns translation and who owns checkout policy, even when an Adapter sits behind a Facade?

    Revision checklist

    Remember these compact distinctions:

    • Adapter = compatibility layer.
    • Facade = simplified entry point.
    • Adapter changes form; Facade changes experience.
    • Adapter usually bridges one interface to one implementation.
    • Facade can coordinate multiple services or provider calls.
    • Neither pattern is required when the direct integration is already clear and stable.

    In interviews, lead with intent, then dependency direction, then trade-offs. That sequence shows you understand not just the labels, but the reason the boundary exists.

    TechInterviewNotes Editorial Team · Updated 7 Oct 2026 ·