Hermes Wiki

Facade Pattern

Concept

Facade puts one simplified interface in front of a subsystem made up of many interacting classes, so callers get a single entry point instead of needing to know which of the subsystem's objects to call, in what order, and with what arguments carried between the calls. The facade class doesn't add new capability — everything it exposes, the subsystem could already do if a caller wired it up directly — it just packages the subsystem's common sequences of operations into a small number of methods that hide the coordination logic. Booking a trip, for instance, might genuinely require creating a reservation, charging a payment, decrementing inventory, and sending a confirmation — four different subsystems, each with its own object and API. A BookingFacade.bookTrip(...) method sequences those four calls internally; every caller elsewhere in the codebase gets one method call instead of reimplementing that four-step sequence (and its error handling) at every call site that needs to book a trip.

Facade differs from most of the other structural patterns in that it doesn't wrap a single object behind a matching interface (Decorator, Proxy) or unify a family of interchangeable objects behind a shared interface (Composite, Bridge) — it sits in front of a whole subsystem of different objects and offers a narrower, purpose-built interface that doesn't need to structurally mirror anything underneath it. The subsystem's original, full interfaces are still there and still directly usable for callers who need finer-grained control; the facade is an additional, optional simplification layered on top, not a replacement.

Tradeoffs

Approach Benefit Cost
Facade (single simplified entry point) Callers get one method instead of coordinating N subsystem objects; the correct sequencing/error-handling logic lives in one place instead of being duplicated at every call site Can become a "god object" if every subsystem operation gets bolted onto it over time; hides subsystem power from callers who genuinely need finer control, unless the subsystem's own interfaces stay reachable alongside it
No facade — callers use subsystem objects directly Full access to every subsystem capability, no extra abstraction layer to maintain Every call site must get the coordination sequence right; a bug fix to that sequence (e.g. "always check inventory before charging payment") has to be found and applied everywhere it was duplicated
Push the coordination logic into one of the subsystem's own classes (no separate facade class) One fewer class in the codebase Conflates "this class does X" with "this class also orchestrates X, Y, and Z," muddying that class's own responsibility and making it a de facto facade without being named or documented as one

When to use / when not to

  • Use when a subsystem has multiple objects/steps that are almost always used together in the same sequence, and scattering that sequencing knowledge across call sites would duplicate it and risk drift when it changes.
  • Especially valuable at integration boundaries — wrapping a third-party SDK or a legacy subsystem with an awkward, chatty API behind an interface shaped for how this codebase actually needs to use it.
  • Don't add one when a subsystem is already used one way, from one call site — the facade would just be an extra layer of indirection with no call sites benefiting from the simplification.
  • Don't let a facade become the only way to reach the subsystem if some callers legitimately need lower-level control (e.g. an admin tool that needs to inspect or override one step of a normally-atomic sequence) — keep the subsystem's original interfaces reachable rather than deleting them once the facade exists.

Common pitfall

Letting a facade accumulate every operation any caller ever needed from the subsystem, until it becomes a second, parallel "God object" API surface that itself needs its own internal organization — at which point the facade has stopped being a simplification and become just another subsystem to learn. This tends to happen gradually: each individual addition looks reasonable ("callers need this one more coordinated operation too"), but there's no natural limit unless someone is actively asking whether a given method actually represents coordination across multiple subsystem objects (facade's actual job) versus just being a passthrough to one subsystem method that didn't need wrapping in the first place.

Engineering Lens

Facade is one of the easier patterns to justify in review because its value is almost entirely at the boundary, not internally — the question worth asking isn't "should this subsystem have a simplified interface" (usually yes, if it's used from more than one place) but "is this class still doing coordination, or has it become a dumping ground." A useful discipline: a method belongs on the facade if removing it would force some caller to re-implement multi-step coordination logic themselves; a method that just forwards a single call to a single subsystem object with no added sequencing doesn't need to live on the facade at all — that caller can and should just call the subsystem directly.

  • Composite Pattern — both hide internal structure behind a simpler surface, but Composite unifies interchangeable same-interface nodes while Facade coordinates different subsystem objects that don't share an interface
  • Proxy — both add an indirection layer in front of something else, but Proxy matches the wrapped object's own interface exactly (to control access), while Facade deliberately offers a narrower, different interface than the subsystem underneath

Sources

Hermes Wiki