SwadhyAI Notes

All Low-Level Design notes

Structural · many familiar types

Facade

A is a structural pattern that gives callers one simple entry point into a group of classes that already have working APIs. The facade sequences those classes so the rest of the app does not have to remember every step.

A concrete example: checkout needs Inventory, Payable, InvoiceService, and Mailer. Controllers should call CheckoutFacade.placeOrder(cart) instead of wiring those four steps themselves.

Inventory

reserve(lines)

Payable

pay(total, id)

InvoiceService

issue(cart, paid)

Mailer

sendReceipt(email, invoice)

One entry point

CheckoutFacade.placeOrder(cart)

The rest of the app does not call the four services directly.

Controller / API

one collaborator, not four

Core question

Can I give callers one simple door so they never have to orchestrate the messy rooms behind it?

The classes behind the door keep their interfaces. You are not translating a foreign SDK — that is Adapter. You are hiding how many objects it takes to finish a use case. fits this well: a controller talks to the facade, not to every service inside it.

The sequence — still four objects

Facade does not delete Inventory. It stops every controller from remembering the order of steps. Each step still lives where the data lives.

  1. 01

    Reserve

    inventory.reserve(cart.lines()) — stock is Inventory’s job.

  2. 02

    Charge

    payment.pay(cart.total(), cart.id()) — money is Payable’s job (maybe an adapter behind it).

  3. 03

    Invoice

    invoices.issue(cart, paid) — documents are not the payment SDK’s job.

  4. 04

    Mail

    mailer.sendReceipt(cart.email(), invoice) — SMTP is not checkout policy.

Java sketch: one door into checkout

Keep the facade . It sequences calls. It should not become a CheckoutManager that owns pricing formulas, SQL, and HTML.

java
class CheckoutFacade {
  private final Inventory inventory;
  private final Payable payment;
  private final InvoiceService invoices;
  private final Mailer mailer;

  CheckoutFacade(Inventory inventory, Payable payment,
                 InvoiceService invoices, Mailer mailer) {
    this.inventory = inventory;
    this.payment = payment;
    this.invoices = invoices;
    this.mailer = mailer;
  }

  Receipt placeOrder(Cart cart) {
    inventory.reserve(cart.lines());
    PaymentResult paid = payment.pay(cart.total(), cart.id());
    Invoice invoice = invoices.issue(cart, paid);
    mailer.sendReceipt(cart.email(), invoice);
    return new Receipt(invoice.id(), paid);
  }
}

// controller: return checkout.placeOrder(cart);
// not: inventory.reserve; payment.pay; invoices.issue; mailer.send

Thin door (the pattern)

  • Delegates every step to a collaborator that already owns it.
  • placeOrder is a use-case verb, not a vague process(Object).
  • The rest of the app imports CheckoutFacade, not the four internals.
  • Tests can replace one facade or inject four fakes at the constructor — both are honest.

named Facade

  • Computes tax, writes JDBC, and builds MIME in the same class.
  • Grows a private method per new product rule.
  • Callers still sneak around it to “just reserve once.”
  • You hid a Manager, not a subsystem.

Same idea in another domain: hotel check-in

Reservations, billing, and housekeeping already have fine APIs. The pain is that every kiosk would have to remember the check-in sequence. The front desk does not rename those APIs. It stops the guest from meeting them one by one.

java
class HotelFrontDesk {
  private final Reservations rooms;
  private final Billing billing;
  private final Housekeeping housekeeping;

  KeyCard checkIn(Guest guest, Dates stay) {
    Room room = rooms.allocate(stay);
    billing.openFolio(guest, room);
    housekeeping.prepare(room);
    return room.keyCard();
  }
}

A subsystem, not a rename

SmellCount of types behind the wrapPattern
Caller must remember four stepsMany, all already yoursFacade
SDK method names do not match PayableOne foreign classAdapter
Need log + retry on the same NotifierOne, same interfaceDecorator
Do not load the 12MB image yetOne, same interface, delayed creationProxy

A “StripeFacade” that only renames charge to pay is an adapter with a louder name. Facade is for a . They can compose: the facade’s Payable field may be a Stripe adapter. That is healthy. See Adapter vs Facade.

Common mistakes

A God object named Facade

If CheckoutFacade computes tax, writes SQL, and formats HTML, you hid a Manager. The pattern only sequences objects that already know their jobs.

Calling a one-class rename a Facade

Wrapping StripeClient so it looks like Payable is Adapter. Wrapping EmailNotifier to log is Decorator. Facade is a cluster of classes, not a single awkward method list.

Callers still import the internals

If the controller also calls inventory.reserve “just this once,” the door was decoration. The rest of the app should import the facade, not the five internals.

A method named process(Object)

Name the use case: placeOrder, checkIn, startSession, renderPage. Vague verbs often hide a god object.

How to explain this in an interview

“Inventory, Payable, Invoice, and Mailer already have fine APIs. The controller should not know the sequence, so CheckoutFacade.placeOrder sequences them. This is not an adapter — we did not change a foreign signature. Payable might still be a Stripe adapter behind the door.”
  1. List the four calls a naive checkout controller would make. Draw the facade method that replaces them.
  2. Where does tax policy live if the facade must stay thin?
  3. Logging framework: Logger facade in front of appenders and formatters — or a decorator on one appender? When is each honest?

Takeaway

Facade gives many familiar classes one simpler method. Sequence the work; do not absorb all the policy. One SDK with the wrong method names is Adapter, not a facade.