Facade menyediakan antarmuka sederhana di atas subsystem yang kompleks. Client cukup panggil satu method, dibalik layar ada banyak step.
Problem yang diselesaikan:
Library besar sering punya banyak class dengan detail low-level. Kalau tiap client harus tahu semua orkestrasi, tiap tempat jadi copy-paste ritual yang sama. Facade sembunyikan kompleksitas di balik API yang ringkas, sesuai 80% use case.
Implementasi minimal — facade untuk setup upload file ke S3 dengan preview + resize:
// Subsystem complex (banyak kelas kecil)
class FileValidator {
validate(file) {
if (file.size > 5_000_000) throw new Error("Max 5MB");
if (!["image/jpeg", "image/png"].includes(file.type)) throw new Error("Only JPEG/PNG");
}
}
class ImageResizer {
async resize(file, maxWidth) {
// ...canvas manipulation, return Blob
}
}
class S3Uploader {
constructor(config) { this.config = config; }
async upload(blob, key) {
// ...presigned URL, multipart, etc
}
}
class ThumbnailGenerator {
async generate(file) {
// ...
}
}
// Facade — satu class yang orkestrasi
class MediaUploadService {
constructor(s3Config) {
this.validator = new FileValidator();
this.resizer = new ImageResizer();
this.uploader = new S3Uploader(s3Config);
this.thumbnailer = new ThumbnailGenerator();
}
async uploadImage(file, userId) {
this.validator.validate(file);
const resized = await this.resizer.resize(file, 1600);
const thumb = await this.thumbnailer.generate(file);
const key = `users/${userId}/${Date.now()}-${file.name}`;
const [fullUrl, thumbUrl] = await Promise.all([
this.uploader.upload(resized, key),
this.uploader.upload(thumb, key + "-thumb"),
]);
return { fullUrl, thumbUrl };
}
}
// Client cukup:
const media = new MediaUploadService(s3Config);
const { fullUrl, thumbUrl } = await media.uploadImage(file, user.id);
Kompleksitas validasi, resize, thumbnail, upload paralel — semua tersembunyi di satu call.
Dunia nyata di ekosistem JS/Laravel:
- jQuery
$("#foo").addClass("active")— facade di atas DOM API yang ribet (attribute, classList, browser quirks). Dulu banget ini alasan utama jQuery populer. - Laravel Facades —
Cache::get("key"),Mail::send(...),Auth::user(). Namanya "facade" bukan kebetulan: di balik layar ada service container, binding, driver — user cukup static-looking call. - Three.js
Scene— kamu tambah mesh, camera, light ke scene. Di balik layar: WebGL buffer, shader compilation, matrix math. Scene adalah facade. - Axios
axios.post(url, data)— di balik layar: XMLHttpRequest setup, interceptor chain, serialization, error handling. API ringkas. - Socket.IO
io.emit(event, data)— di balik layar: fallback transport (WebSocket → long polling), reconnection, room management.
Facade ≠ God class.
Facade yang sehat hanya orkestrasi, tidak berisi logic. Detail tetap di kelas-kelas subsystem. Kalau facade mulai tumbuh besar dan isi business rule, itu sign harus dipecah (lihat anti-pattern "God Object").
Facade vs Adapter:
- Facade — sederhanakan interface. Sumber = banyak kelas subsystem, target = satu API ringkas. Tujuan: reduksi kompleksitas.
- Adapter — translate satu interface ke interface lain. Sumber dan target jumlahnya sama, targetnya berbeda semantik.
Kapan pakai:
- Subsystem punya banyak kelas yang dipakai dalam pola yang sama berulang
- Ingin jadi "entry point" bagi library eksternal atau modul internal
- Ingin mengurangi tight coupling antara client dan detail subsystem
Kapan JANGAN pakai:
- Subsystem sudah sederhana — facade jadi layer kosong
- Facade mulai mengandung logic business yang harusnya di domain — itu code smell
- Client butuh akses fine-grained yang tidak bisa direduksi ke panggilan sederhana
Trade-off:
Facade sangat bermanfaat untuk API ergonomics dan encapsulation subsystem. Risiko: bisa jadi bottleneck (semua jalur lewat sini) atau membengkak jadi god class. Jaga facade tetap tipis dan fokus pada orkestrasi.