Kenapa Generic di Golang Adalah Fitur yang Wajib Dikuasai Setiap Engineer
3 min read

Kenapa Generic di Golang Adalah Fitur yang Wajib Dikuasai Setiap Engineer

Dalam dunia software engineering modern, kode yang reusable, aman, dan mudah dirawat bukan lagi sekadar keinginan, tetapi kebutuhan. Salah satu fitur yang mengubah paradigma penulisan kode di Golang adalah Generic. Dengan Generic, engineer bisa menulis kode sekali namun dapat digunakan untuk berbagai tipe data tanpa kehilangan type safety.

Artikel ini akan membahas secara mendalam tentang Generic, termasuk konsep, masalah yang diselesaikan, implementasi di Golang, dan kapan sebaiknya digunakan.


Mengapa Generic Penting

Tanpa Generic, engineer sering terjebak dalam salah satu dari dua masalah:

  1. Duplikasi Kode: Menulis fungsi atau struktur data yang sama untuk tiap tipe data.
  2. Interface{} / any: Menggunakan tipe umum yang mengorbankan type safety dan readability.

Generic memecahkan kedua masalah ini dengan:

  • Menyediakan type safety compile-time
  • Memungkinkan kode reusable dan ekspresif
  • Mengurangi duplikasi dan error runtime

Bagi engineer yang mengelola library, API, atau sistem backend besar, memahami Generic adalah keharusan.


Konsep Generic

Generic memungkinkan penggunaan type parameter daripada tipe konkret. Di Golang 1.18+, Generic diperkenalkan dengan sintaks sederhana namun kuat.

Type Parameter

Fungsi generic didefinisikan menggunakan tanda kurung siku []:

func Print[T any](value T) {
    fmt.Println(value)
}
  • T adalah nama type parameter
  • any adalah alias interface{}

Constraint

Constraint menentukan tipe data yang bisa digunakan:

type Number interface {
    ~int | ~int64 | ~float64
}
  • ~int → tipe dasar int dan turunannya
  • | → union type

Implementasi Generic di Golang

Generic Function

Contoh fungsi Max:

type Ordered interface {
    ~int | ~int64 | ~float64 | ~string
}

func Max[T Ordered](a, b T) T {
    if a > b {
        return a
    }
    return b
}

Penggunaan:

Max(10, 20)
Max("a", "b")

✔ Type-safe, tanpa duplikasi, tanpa casting

Generic Struct

Contoh wrapper response:

type Response[T any] struct {
    Data  T
    Error error
}

Penggunaan:

resp := Response[int]{
    Data:  200,
    Error: nil,
}

Cocok untuk:

  • API response
  • Repository pattern
  • Service layer

Generic Utility Function

Contoh Map function:

func Map[T any, R any](items []T, fn func(T) R) []R {
    result := make([]R, len(items))
    for i, v := range items {
        result[i] = fn(v)
    }
    return result
}

Penggunaan:

nums := []int{1, 2, 3}
strings := Map(nums, func(n int) string {
    return strconv.Itoa(n)
})

Generic pada Repository Pattern

Untuk backend, generic sangat cocok untuk repository base:

type Repository[T any] interface {
    FindByID(id string) (T, error)
    Save(entity T) error
}

Implementasi spesifik bisa tetap dilakukan per model, tapi kontrak repository tetap reusable.


Kapan Menggunakan Generic

✅ Ideal

  • Logika independen dari tipe data
  • Pola berulang (collection, wrapper, utility)
  • Menjaga type safety
  • Library atau shared module

Contoh: collection utils, DTO wrapper, cache abstraction, repository base

❌ Sebaiknya Dihindari

  • Digunakan sekali saja
  • Membuat kode lebih sulit dibaca
  • Logic sangat spesifik terhadap domain

Generic bukan pengganti design yang buruk, tetapi alat untuk meningkatkan kualitas kode.


Perbandingan Generic vs Interface

AspekInterfaceGeneric
FokusPerilaku (behavior)Tipe (type)
PolimorfismeRuntimeCompile-time
Type SafetyLebih lemahLebih kuat
OverheadBisa adaMinimal

Rule of thumb: gunakan interface untuk behavior, gunakan generic untuk data & algoritma.


Kesimpulan

Generic adalah fitur kunci di Golang yang wajib dipahami engineer modern. Dengan Generic, kode menjadi:

  • Lebih bersih
  • Lebih aman
  • Lebih reusable
  • Lebih ekspresif

Memahami kapan dan bagaimana menggunakan Generic akan membuat Anda menulis kode yang lebih profesional dan siap untuk skala besar.