A facade is a good idea when callers need one simple entry point to a complex subsystem. It turns into a problem when it grows big and holds its own logic.
When it helps:
- A module has many parts that work together, but most callers only want one or two high-level operations. Example: a
BillingFacadeexposeschargeSubscription(). It hides invoice creation, tax calculation, the payment adapter and receipt emails. - It works well as the public API of a module in a modular monolith (one app split into clear modules). Other modules call the facade and don't import the module's internals.
When it becomes a problem:
- It grows into a god object: one class that every caller depends on. It has dozens of methods and its own business logic, instead of passing work to the subsystem.
- It hides too much. Callers who need finer control start to go around it and import the internals anyway.
Keep a facade thin. It coordinates and passes work on. The business rules stay in the subsystem classes.
- A facade is one simple entry point over a complex subsystem.
- It works well as a module's public API and for common high-level operations.
- The risk is that it grows into a god object with its own logic.
- Keep it thin, and leave the business rules in the subsystem.
Read more