golangSOLID di Go

1. Single Responsibility Principle (SRP)

Prinsip: Satu class/module hanya memiliki satu tanggung jawab. Aplikasi Dunia Nyata: Sistem manajemen pengguna di aplikasi e-commerce.

// ❌ Melanggar SRP: User struct menangani data & validasi
type User struct {
    Name  string
    Email string
}

func (u *User) Save() error {
    // Logika simpan ke database
    return nil
}

func (u *User) ValidateEmail() bool {
    // Logika validasi email
    return strings.Contains(u.Email, "@")
}

// ✅ Memenuhi SRP: Pemisahan tanggung jawab
type User struct {
    Name  string
    Email string
}

type UserRepository struct{} // Tanggung jawab: akses data
func (r *UserRepository) Save(u *User) error { /* ... */ }

type UserValidator struct{} // Tanggung jawab: validasi
func (v *UserValidator) ValidateEmail(u *User) bool { /* ... */ }

Keuntungan:

  • Perubahan validasi tidak memengaruhi logika penyimpanan data.

  • Kode lebih mudah di-maintain dan diuji.


2. Open/Closed Principle (OCP)

Prinsip: Software entities terbuka untuk ekstensi, tetapi tertutup untuk modifikasi. Aplikasi Dunia Nyata: Sistem pembayaran dengan metode pembayaran yang beragam.

Keuntungan:

  • Tambah metode pembayaran baru (misal: GoPay) tanpa ubah kode PaymentProcessor.

  • Kode lebih fleksibel terhadap perubahan bisnis.


3. Liskov Substitution Principle (LSP)

LSP adalah prinsip ke-3 dari SOLID. Intinya:

Sebuah subclass atau implementasi harus bisa menggantikan superclass/interface tanpa mengubah perilaku yang diharapkan dalam program.

Artinya, kalau kita punya fungsi yang bekerja dengan interface X, maka semua implementasi dari interface X harus bisa dipakai tanpa bikin bug atau perilaku aneh.


Analogi sederhana

Bayangkan ada interface Bird dengan method Fly(). Kalau kita punya Sparrow (burung pipit), dia bisa terbang. Kalau kita tambahkan Penguin, dia tidak bisa terbang.

Kalau kita masukkan Penguin ke dalam fungsi yang ekspektasinya semua Bird bisa Fly(), pasti ada masalah → inilah pelanggaran LSP.


Contoh di Golang

Contoh yang Melanggar LSP

Kenapa ini melanggar LSP? Karena Penguin secara konsep tidak sesuai dengan kontrak Bird yang punya Fly(). Ketika dipakai, malah menyebabkan error → program tidak bisa bekerja dengan substitusi Penguin.


Contoh yang Benar (Mematuhi LSP) Pisahkan interface berdasarkan kemampuan:

Dengan memisahkan interface, Penguin tetap bisa jadi Bird tanpa memaksa punya Fly(). Program lebih aman dan konsisten dengan LSP.


Inti LSP

  1. Gunakan interface kecil dan spesifik (mirip Interface Segregation Principle).

  2. Jangan memaksa implementasi melanggar kontrak interface.

  3. Fungsi yang menerima interface harus bekerja untuk semua implementasinya tanpa perlu tahu implementasi spesifiknya.


Jadi kunci LSP di Golang: jangan bikin interface yang memaksa implementasi melakukan hal yang tidak cocok dengan nature-nya.


Mau saya bikinkan contoh lain yang lebih ke use-case real (misalnya transaksi pembayaran, user repository, dsb.) biar lebih kebayang selain contoh "Bird"?


4. Interface Segregation Principle (ISP)

Prinsip: Klien tidak boleh dipaksa bergantung pada interface yang tidak digunakan. Aplikasi Dunia Nyata: Sistem IoT dengan device yang memiliki fitur berbeda.

Keuntungan:

  • Device hanya implementasi fitur yang dimiliki.

  • Menghindari "noise" dari metode tidak relevan.


5. Dependency Inversion Principle (DIP)

Prinsip:

  • High-level module tidak bergantung pada low-level module.

  • Keduanya bergantung pada abstraksi (interface).

  • Abstraksi tidak bergantung pada detail.

Aplikasi Dunia Nyata: Service layer yang bergantung pada repository.

Keuntungan:

  • Mudah ganti database (misal dari MySQL ke PostgreSQL) tanpa ubah OrderService.

  • Kode lebih mudah diuji (bisa mock OrderRepository).


Kesimpulan: Manfaat SOLID di Go

  1. Maintainability: Perubahan pada satu fitur tidak memengaruhi fitur lain (SRP, ISP).

  2. Extensibility: Tambah fitur baru tanpa ubah kode existing (OCP, DIP).

  3. Reliability: Substitusi komponen aman tanpa error (LSP).

  4. Testability: Dependency injection (DIP) memudahkan pembuatan unit test.

  5. Scalability: Arsitektur modular mendukung pertumbuhan aplikasi.

Best Practice di Go:

  • Gunakan interface untuk abstraksi (OCP, DIP, ISP).

  • Hindari struct dengan tanggung jawab ganda (SRP).

  • Pastikan implementasi interface konsisten (LSP).

  • Lakukan dependency injection melalui constructor/parameter.

Last updated