Go Series: Safer Enum

Enum di Go

Go tidak mendukung enums secara bawaan, tetapi ada cara untuk menirunya. Banyak solusi yang terlihat jelas ternyata kurang ideal. Berikut beberapa ide untuk membuat enums lebih aman secara desain.

iota

Go menyediakan iota untuk enumerasi.

const (
    Guest = iota // 0
    Member       // 1
    Moderator    // 2
    Admin        // 3
)

Masalah Utama:

  • Nilai iota mudah berubah jika urutan diubah.

  • Rentan kesalahan seperti nilai negatif atau angka tidak valid.

  • Tidak ada validasi otomatis.

Contoh masalah:

func CreateUser(role int) error { ... }

CreateUser(-1) // Masih bisa dijalankan!

❌ Anti-pattern: Enums Integer Hindari penggunaan iota untuk enums yang bukan angka berurutan atau flags.


Sentinel Values

Tambahkan nilai eksplisit untuk zero-value.

type Role uint

const (
    Unknown Role = iota // 0
    Guest               // 1
    Member              // 2
    Admin               // 3
)

func CreateUser(r Role) error {
    if r == Unknown {
        return errors.New("role tidak valid")
    }
    return nil
}

βœ… Taktik: Sentinel Eksplisit Gunakan variabel khusus (seperti Unknown) untuk merepresentasikan nilai default yang tidak valid.


Slugs (String Enums)

Gunakan string untuk enums agar lebih deskriptif.

type Role string

const (
    Guest     Role = "guest"
    Member    Role = "member"
    Moderator Role = "moderator"
    Admin     Role = "admin"
)

Keuntungan:

  • Nilai mudah dipahami di log, API, atau database.

  • Contoh: {"error": "user-not-found"} lebih jelas daripada {"error": 404}.

βœ… Taktik: Slugs Gunakan string dengan format konsisten (camelCase, snake_case, dll) untuk memudahkan parsing.


Enums Berbasis Struct

Enkapsulasi enums dalam struct untuk keamanan ekstra.

type Role struct {
    slug string
}

var (
    Guest     = Role{"guest"}
    Member    = Role{"member"}
    Moderator = Role{"moderator"}
    Admin     = Role{"admin"}
)

// Constructor untuk validasi
func FromString(s string) (Role, error) {
    switch s {
    case Guest.slug:
        return Guest, nil
    case Member.slug:
        return Member, nil
    // ...
    default:
        return Role{}, errors.New("role tidak dikenal")
    }
}

Keuntungan:

  • Tidak bisa membuat nilai invalid dari luar package (karena field slug tidak diekspor).

  • Validasi otomatis saat pembuatan objek.

βœ… Taktik: Struct-based Enums Gunakan struct untuk menjamin validitas nilai enum saat kompilasi.


Perbandingan Solusi

Metode
Keamanan
Deskriptif
Validasi Otomatis

iota

Rendah

❌

❌

Sentinel Values

Sedang

❌

βœ… (Parsial)

Slugs (String)

Sedang

βœ…

❌

Struct-based

Tinggi

βœ…

βœ…


Kesimpulan

  1. Hindari enums integer kecuali untuk urutan atau flags.

  2. Gunakan string (slugs) untuk enums yang perlu deskriptif.

  3. Pertimbangkan struct-based enums untuk logika bisnis kritis yang membutuhkan validasi ketat.

Dengan pendekatan ini, kode Anda menjadi lebih aman, mudah dipelihara, dan kurang rentan terhadap kesalahan logika.

Last updated