skip to content

questions

6

What problem does the Facade design pattern solve, and what does a facade actually add to a system?

level: juniorimportance: must knowfreq 72%

answer

  1. Unified higher-level interface over a subsystem
  2. Adds convenience, not capability
  3. Clients depend on one type, not ten
  4. Subsystem stays reachable — not a security wall
  5. One-way: client → facade → subsystem

basics

~20 s

Facade puts one simple, higher-level object in front of a complicated group of classes. Clients call the facade instead of wiring the parts together themselves, so calling code is shorter and depends on fewer internal types.

solid answer

~50 s

Facade is a structural pattern whose intent is to provide a unified, higher-level interface to a set of interfaces in a subsystem, making the subsystem easier to use. The subsystem stays exactly as it is — the facade adds no new capability. What it adds is a single, task-oriented entry point that encapsulates the ordering, wiring and glue a correct call sequence requires (create X, configure Y, call Z in this order, handle cleanup). The payoff is coupling: clients depend on one type instead of a dozen, so internal refactors of the subsystem stop rippling into callers, and the number of ways to use it wrongly drops. The facade is not a wall — the subsystem classes usually stay reachable for advanced callers who need the extra control. A facade is a convenience layer, not an access-control or security layer.

code

typescript · 22 lines
typescript
// Subsystem (still public, still usable directly)
class Reader { open(p: string) {/*...*/} }
class Codec { pick(fmt: string) {/*...*/} }
class Muxer { write(/*...*/) {/*...*/} }

// Facade: one task-shaped method, encodes the correct order + defaults
class VideoConverter {
  constructor(
    private reader = new Reader(),
    private codec = new Codec(),
    private muxer = new Muxer(),
  ) {}

  convert(path: string, format: string): Blob {
    this.reader.open(path);
    this.codec.pick(format);
    return this.muxer.write(/* ... */) as unknown as Blob;
  }
}

// Client: names ONE type instead of three
new VideoConverter().convert("clip.avi", "mp4");

go deeper

for a junior

State the intent in one sentence (one simple entry point over many classes) and give a concrete example such as a converter or a logging factory.

for a middle

Add the coupling argument and the one-way dependency rule, and separate Facade from Adapter and Mediator explicitly.

for a senior

Lead with the trade-off: simplicity for the common case vs. preserved access for advanced cases, and discuss transparent vs. opaque facades and escape hatches.

for a principal

Frame it as a module/architecture boundary: single public API per module, enforcement via visibility and architecture tests, contract/versioning implications, and the risk of the facade becoming an org-wide bottleneck.

### The situation Facade addresses A **subsystem** is a group of collaborating classes/modules that together do one job — for example a video-conversion library made of `FileReader`, `CodecFactory`, `BitrateResolver`, `AudioMixer`, `MuxWriter`. Each part has a legitimate, fine-grained API. But a client that only wants "turn this file into an MP4" must know: - which objects to create, - in what order to call them, - which defaults are sane, - how to clean up if step 3 fails. That knowledge leaks into every caller. Two costs follow. First, **duplication of glue**: ten callers write the same ten-line dance, each slightly differently, each with its own bugs. Second, **coupling**: every caller now names ten subsystem types, so renaming or replacing any of them breaks ten call sites (and any test that stubs them). ### The pattern Facade introduces one object — the *facade* — that exposes a small set of **task-shaped** methods (`convert(file, "mp4")`) and internally performs the dance against the subsystem. The formal intent, from the Gang of Four catalogue, is: *provide a unified interface to a set of interfaces in a subsystem; Facade defines a higher-level interface that makes the subsystem easier to use.* Key properties: - **Additive, not restrictive.** The facade does not remove the subsystem's own API. GoF explicitly notes that clients needing more control can still talk to subsystem classes directly. Facade optimises the common case without amputating the uncommon one. - **No new behaviour.** A facade orchestrates existing capability. If it invents domain rules, computes results, or holds business state, it has drifted into being a service/application layer — which may be fine, but it is no longer *just* a facade. - **Direction of dependency.** Clients → facade → subsystem. The subsystem knows nothing about the facade; it must never call back into it. That one-way rule is what keeps the subsystem independently reusable and testable. ### What it buys you 1. **Reduced coupling / smaller surface.** Callers import one type. This is the reason Facade is the standard shape for a *module's public API*: expose one `OrdersApi`, keep repositories, mappers and entities package-private. 2. **Fewer misuse paths.** Ordering and lifecycle rules are encoded once, in the facade, instead of being folklore in a wiki. 3. **A refactoring seam.** Because callers only see the facade, the subsystem behind it can be split, merged, or swapped (say, replaced by a remote service) without touching callers — as long as the facade's contract holds. 4. **A layering enforcement point.** Facades are how layered architectures keep upper layers from reaching into lower-layer internals. ### What it does not buy you - **Not security.** If subsystem classes are reachable, a caller can bypass the facade. Enforcement needs visibility modifiers, module systems, or architecture tests (ArchUnit, Spring Modulith, `internal`/package-private, JPMS, ESLint import rules) — the facade only makes the good path the easy path. - **Not decoupling from *behaviour*.** Callers still depend on what the subsystem does semantically; only the type-level dependency shrinks. - **Not automatic simplicity.** A facade with 60 methods that mirror the subsystem 1:1 gives you a second surface to maintain and zero simplification. ### The core trade-off Every facade trades **expressive power for ease of use**. Its methods encode opinionated defaults; anything outside those defaults is unreachable through it. There are three responses, and choosing consciously between them is the senior-level skill: - **Transparent facade** — subsystem stays public; advanced callers drop down to it. Maximum flexibility, weakest boundary. - **Opaque facade** — subsystem hidden; every need must be met by the facade. Strongest boundary, but the facade becomes a bottleneck and tends to grow parameters and overloads over time. - **Escape hatch** — mostly opaque, but the facade exposes a deliberate lower-level accessor (e.g. `underlyingClient()`), or a configuration/options object. Pragmatic, and honest about the fact that the abstraction is incomplete. ### Recognising it in the wild - `jQuery('#x').fadeOut()` over raw DOM + timers. - Spring's `JdbcTemplate` over `DriverManager`/`Connection`/`Statement`/`ResultSet` lifecycle. - SLF4J's `LoggerFactory` over concrete logging backends (facade + a bit of adapter). - A backend-for-frontend endpoint that fans out to five microservices so a mobile client makes one call. - A module's single public `*Api` type in a modular monolith. ### How to know you need one Count the types a typical caller must name to accomplish one intent, and count how many callers repeat the same sequence. High on both → facade. Low on both → a facade just adds indirection.

  • Does adding a facade mean the subsystem classes should be made private?
    Not necessarily — that is a separate decision. A 'transparent' facade leaves them public so advanced callers keep full power; an 'opaque' facade hides them to enforce a boundary. Hiding gives a stronger contract but makes the facade the sole path, so every unanticipated need becomes a facade change.
  • Can a subsystem have more than one facade?
    Yes, and it is often better than one giant facade. Different client groups (reporting, admin, checkout) get their own narrow, task-shaped facade over the same subsystem, which keeps each interface small and cohesive instead of producing one god-object.
  • Where does the facade sit in the dependency direction?
    Clients depend on the facade, the facade depends on the subsystem, and the subsystem must not know the facade exists. If subsystem classes call back into the facade you have created a cycle and lost the reusability the pattern was meant to protect.

A hotel concierge. You say "dinner at 8 and a taxi"; they call the restaurant, the cab firm and the kitchen. They add no restaurants to the city — but you now deal with one person instead of five. And if you insist, you can still phone the restaurant yourself.

saying these in an interview costs you the question

  • Saying a facade 'hides' the subsystem in the sense of preventing access — it is a convenience layer, not access control; enforcement needs visibility/module rules.
  • Claiming a facade adds new functionality or business rules; if it computes domain results it has become a service layer, not a facade.
  • Confusing it with Adapter — Adapter changes an interface to match an expected one; Facade simplifies a set of interfaces without being asked to match any.
  • Believing one class wrapping one class is a facade; wrapping a single collaborator with the same granularity is a delegate/wrapper, not a simplifying facade.
  • Assuming a facade must be a singleton or stateless — neither is required by the pattern.

context

open as a page

How does the Facade pattern differ from Adapter, Mediator, and Proxy, given that all four place an object in front of something else?

level: middleimportance: must knowfreq 68%

basics

~20 s

Facade simplifies many classes behind one easy entry point. Adapter converts one interface into a different one a client already expects. Mediator makes peers talk through a hub instead of each other. Proxy keeps the same interface but controls access to one object.

open as a page

A facade covers the common cases, but a caller now needs a lower-level capability the facade does not expose. What are your options, and what does each cost?

level: seniorimportance: must knowfreq 58%

basics

~20 s

Either leave the subsystem reachable so that caller uses it directly (flexible, weaker boundary), or add the capability to the facade (keeps the boundary, but the facade grows). A middle option is a deliberate escape hatch that exposes the underlying object.

open as a page

What signals tell you a facade has stopped helping and become a liability, and what would you do about each?

level: seniorimportance: should knowfreq 44%

basics

~20 s

Warning signs: it mirrors the subsystem method-for-method, it keeps growing into a god-object, it leaks internal types in its signatures, or nobody uses it because callers still import internals. Fix by resizing, splitting, or deleting it.

open as a page

How is the Facade pattern used as an architectural boundary — for module public APIs, service SDKs, or a backend-for-frontend — and what changes about the trade-offs at that scale?

level: principalimportance: should knowfreq 36%

basics

~10 s

At architecture scale, a facade becomes a module's or service's single published entry point. Everything behind it can change freely; everything the facade exposes becomes a contract you must version, deprecate and support.

open as a page

Must a facade be a single class, be stateless, or be a singleton — and how does introducing one affect testing of client code?

level: middleimportance: nice to knowfreq 26%

basics

~20 s

None of those are required. A facade can be several classes, hold state, and be created per use. For tests, clients now stub one facade instead of many collaborators, which makes their tests shorter — but the facade itself still needs integration tests.

open as a page