BuildBot

Patterns That Matter

Adapter & facade

Lesson 3 of 5

What you'll learn

  • Use the Adapter pattern to normalize differently-shaped external responses.
  • Use a facade to present a small, clean surface over a complex subsystem.
  • See why an MCP tool surface is a facade in disguise.

Adapter: tame the shape at the boundary

An adapter sits at the edge of your system and translates an external shape into your internal shape. The win is that the mess stops at the boundary — your domain code never sees the third party's quirks.

type User = { id: string; name: string; email: string };

// Two providers, two shapes. Adapters converge them.
const fromGithub = (r: { login: string; node_id: string }): User => ({
  id: r.node_id,
  name: r.login,
  email: `${r.login}@users.noreply.github.com`,
});

const fromGoogle = (r: { sub: string; name: string; email: string }): User => ({
  id: r.sub,
  name: r.name,
  email: r.email,
});

Keep adapters as pure functions. They are trivially testable, and you can swap or add a provider without touching anything downstream. This is the single highest-leverage place to apply a pattern in integration-heavy code.

Facade: one clean door into a subsystem

A facade hides a complicated subsystem behind a small interface. You are not reshaping one response — you are collapsing many moving parts into a few named operations.

// A facade over auth, billing, and email subsystems.
function createAccountService(deps: {
  auth: { register: (e: string) => Promise<string> };
  billing: { createCustomer: (id: string) => Promise<void> };
  email: { welcome: (e: string) => Promise<void> };
}) {
  return {
    async signUp(email: string) {
      const id = await deps.auth.register(email);
      await deps.billing.createCustomer(id);
      await deps.email.welcome(email);
      return id;
    },
  };
}

An MCP tool surface is exactly this: a curated set of named tools that hide sprawling internal APIs behind a stable, simplified contract the model can call.

A facade is not a dumping ground

When a facade grows dozens of unrelated methods, it has become a god object. Split it by capability. The point is a small surface, not a single class that does everything.

Normalize two API shapes

Run the adapters. Two providers return user data in different shapes; each adapter maps it to one canonical User shape so downstream code stays uniform.

Loading editor…
Knowledge check

What is the main job of an adapter in modern integration code?

Saved on this device. Sign in to sync your progress everywhere.