A facade over a vendor client keeps the vendor out of your code

A payment provider’s SDK ends up referenced in a controller, in two models, in a console command and in nine tests. Changing provider then means changing all of them — and so does the SDK’s own 3.0 release, which is by some margin the more likely event.

interface PaymentGateway
{
    /**
     * @return string  the provider's reference for the charge
     * @throws PaymentDeclined
     */
    public function charge($amountInCents, $currency, CardToken $card);
}

// the only file in the application that names the SDK
class AcmeGateway implements PaymentGateway
{
    private $client;

    public function __construct(VendorSdkClient $client)
    {
        $this->client = $client;
    }

    public function charge($amountInCents, $currency, CardToken $card)
    {
        $response = $this->client->transactions()->create(array(
            'amount'   => $amountInCents,
            'currency' => strtolower($currency),
            'source'   => $card->token(),
        ));

        if (!$response->isApproved()) {
            throw new PaymentDeclined($response->declineCode());
        }

        return $response->id();
    }
}

The point is not portability — you will very likely never change provider. It is that the vendor’s vocabulary stops leaking. Their transaction object, their exception hierarchy and their opinion about what an amount is are confined to one class, and the rest of the application talks about charging money. The testing benefit follows for nothing: PaymentGateway takes four lines to fake, whereas faking their client means knowing which of its nine collaborators it constructs internally. What it costs is a translation layer that has to be kept honest. A facade that grows one method per SDK method has stopped being a facade and become an alias, and the first sign of that is a parameter named after something in their documentation.