What problem does the Facade design pattern solve, and what does a facade actually add to a system?
answer
- Unified higher-level interface over a subsystem
- Adds convenience, not capability
- Clients depend on one type, not ten
- Subsystem stays reachable — not a security wall
- One-way: client → facade → subsystem
basics
~20 sFacade 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 sFacade 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// 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
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.
Add the coupling argument and the one-way dependency rule, and separate Facade from Adapter and Mediator explicitly.
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.
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.