Facade Pattern #
Dalam sistem yang berkembang, kompleksitas sering kali muncul bukan karena satu komponen yang rumit, tetapi karena banyaknya subsistem yang saling berinteraksi. Setiap subsistem mungkin memiliki API sendiri, dependensi sendiri, dan urutan pemanggilan yang tidak sederhana. Facade Pattern hadir untuk menyederhanakan interaksi ini dengan menyediakan satu antarmuka terpadu.
Facade Pattern adalah salah satu Structural Design Pattern yang sangat sering digunakan di dunia nyata, terutama pada aplikasi backend, integrasi library, dan sistem legacy.
Apa itu Facade Pattern? #
Facade Pattern adalah design pattern yang menyediakan antarmuka sederhana (facade) untuk sekumpulan interface yang lebih kompleks di dalam suatu subsistem.
Facade tidak menghilangkan kompleksitas, tetapi menyembunyikannya dari client. Client cukup berinteraksi dengan facade tanpa perlu memahami detail internal subsistem.
Secara sederhana:
Facade = pintu depan yang rapi untuk sistem yang rumit di belakangnya.
Tujuan Pattern #
Tujuan utama penggunaan Facade Pattern adalah:
Menyederhanakan penggunaan subsistem Client tidak perlu tahu urutan pemanggilan atau detail implementasi.
Mengurangi coupling antara client dan subsistem Client bergantung pada facade, bukan langsung ke banyak komponen.
Meningkatkan readability dan maintainability Kode client menjadi lebih bersih dan fokus pada use-case.
Isolasi perubahan Perubahan di subsistem tidak memengaruhi client selama facade tetap stabil.
Kapan Cocok Digunakan? #
Facade Pattern sangat cocok digunakan ketika:
- Sistem memiliki banyak subsistem dengan API kompleks
- Client harus memanggil banyak komponen secara berurutan untuk satu use-case
- Ingin menyediakan API tingkat tinggi (high-level API)
- Bekerja dengan library pihak ketiga atau legacy system
- Ingin memisahkan business logic orchestration dari detail teknis
Contoh Kasus Nyata #
- Service pembayaran (validasi user, cek saldo, debit, logging, notifikasi)
- Proses order (inventory, pricing, discount, payment, shipping)
- Wrapper SDK untuk API eksternal
Struktur Pattern #
Komponen utama:
Facade Kelas/struct yang menyediakan API sederhana
Subsystem Classes Kelas-kelas kompleks yang melakukan pekerjaan sebenarnya
Client Menggunakan facade, bukan subsistem langsung
Client → Facade → Subsystems
Contoh Implementasi (Golang) #
Studi Kasus: Proses Checkout #
Checkout membutuhkan beberapa subsistem:
- UserService
- InventoryService
- PaymentService
- NotificationService
Tanpa facade, client harus mengatur semuanya sendiri.
Subsystem Implementation #
package checkout
import "fmt"
type UserService struct{}
func (u *UserService) ValidateUser(userID string) error {
fmt.Println("Validating user", userID)
return nil
}
type InventoryService struct{}
func (i *InventoryService) CheckStock(productID string) error {
fmt.Println("Checking stock for product", productID)
return nil
}
type PaymentService struct{}
func (p *PaymentService) Pay(userID string, amount float64) error {
fmt.Println("Processing payment for", userID)
return nil
}
type NotificationService struct{}
func (n *NotificationService) SendReceipt(userID string) {
fmt.Println("Sending receipt to", userID)
}
Facade Implementation #
package checkout
type CheckoutFacade struct {
userService *UserService
inventoryService *InventoryService
paymentService *PaymentService
notificationService *NotificationService
}
func NewCheckoutFacade() *CheckoutFacade {
return &CheckoutFacade{
userService: &UserService{},
inventoryService: &InventoryService{},
paymentService: &PaymentService{},
notificationService: &NotificationService{},
}
}
func (c *CheckoutFacade) Checkout(userID, productID string, amount float64) error {
if err := c.userService.ValidateUser(userID); err != nil {
return err
}
if err := c.inventoryService.CheckStock(productID); err != nil {
return err
}
if err := c.paymentService.Pay(userID, amount); err != nil {
return err
}
c.notificationService.SendReceipt(userID)
return nil
}
Client Code #
func main() {
checkout := checkout.NewCheckoutFacade()
err := checkout.Checkout("user-1", "product-1", 150_000)
if err != nil {
panic(err)
}
}
Client sekarang hanya tahu satu method: Checkout().
Facade Pattern vs Pattern Lain #
Facade vs Adapter #
- Facade: menyederhanakan sistem kompleks
- Adapter: mengubah interface agar kompatibel
Facade vs Mediator #
- Facade: satu arah (client → subsistem)
- Mediator: komunikasi dua arah antar objek
Kelebihan dan Kekurangan #
Kelebihan #
- API lebih sederhana
- Client code lebih bersih
- Mengurangi coupling
Kekurangan #
- Risiko facade menjadi terlalu besar
- Bisa menyembunyikan performa atau side-effect
Best Practices #
Facade Bukan God Object #
Facade bertugas mengorkestrasi, bukan mengimplementasikan logic berat.
❌ Salah:
- Semua business logic dipindahkan ke facade
✅ Benar:
- Logic tetap di subsistem
- Facade hanya memanggil dan mengatur alur
Jangan Memaksa Semua Akses Lewat Facade #
Subsystem tetap boleh diakses langsung jika dibutuhkan oleh use-case khusus.
Facade adalah opsional convenience layer, bukan pembatas mutlak.
Gunakan Interface untuk Subsystem #
Agar mudah di-test dan di-mock.
type PaymentService interface {
Pay(userID string, amount float64) error
}
Ini sangat membantu untuk unit test facade.
Facade Cocok untuk Boundary Layer #
Gunakan facade di:
- Application service
- Use-case layer
- API handler
- Command / job processor
Hindari menaruh facade di layer domain murni jika tidak perlu.
Penutup #
Facade Pattern adalah solusi elegan untuk menghadapi kompleksitas sistem tanpa harus mengubah struktur internalnya. Dengan menyediakan antarmuka yang sederhana dan fokus pada use-case, facade membantu menjaga kode tetap bersih, terstruktur, dan mudah dirawat.
Dalam Golang, facade sangat natural digunakan karena Go mendorong komposisi dan eksplisit orchestration. Digunakan dengan bijak, Facade Pattern adalah salah satu pattern paling praktis dan bernilai tinggi di dunia software engineering.