/ 8 min read
Menjadi Profesional: Mengorganisir Kode & Menangani Error - Becoming Gopher
Selamat datang kembali di petualangan Becoming Gopher! Sejauh ini, kita sudah mengumpulkan semua ‘alat’ dan ‘jurus sakti’—mulai dari struct
, interface
, hingga menaklukkan pointer
. Kita sudah bisa membangun fitur-fitur yang kompleks.
Tapi, membangun fitur saja tidak cukup. Seorang Gopher profesional tidak hanya menulis kode yang berjalan, tapi juga kode yang bersih, terorganisir, dan tangguh saat menghadapi masalah. Inilah yang membedakan proyek main-main dengan aplikasi kelas produksi.
Di babak ini, kita akan fokus pada dua pilar profesionalisme dalam Go:
- Mengorganisir Kode: Bagaimana cara menata file kita ke dalam
package
yang rapi, mengontrol apa yang bisa diakses dari luar dengan access modifier, dan menjaga kode tetap konsisten. - Menangani Error: Bagaimana cara Go menangani kesalahan dengan elegan? Kita akan belajar cara membuat, mengembalikan, dan memeriksa error secara idiomatis, termasuk membuat tipe error kita sendiri.
Ini adalah langkah kita untuk naik kelas. Siap untuk mulai berpikir seperti seorang software engineer? Mari kita tata proyek kita!
Mengorganisir Kode Seperti Profesional
Seiring proyek kita tumbuh, menaruh semua file dalam satu folder akan menjadi mimpi buruk. Go menyediakan sistem package
untuk menjaga semuanya tetap rapi.
gofmt
- Polisi Gaya Otomatis
Sebelum kita menata file, mari kita tata dulu kode di dalamnya. Go punya filosofi kuat tentang konsistensi. gofmt
adalah alat bawaan yang secara otomatis memformat kodemu sesuai standar resmi.
# Memformat semua file .go di folder saat ini dan subfoldernyago fmt ./...
Komentar - Menulis Catatan pada Kode
Setelah menjaga kode tetap rapi dengan gofmt
, alat selanjutnya untuk profesionalisme adalah komentar. Komentar adalah teks di dalam kode yang akan diabaikan oleh compiler, tujuannya murni untuk dibaca oleh manusia.
Ada sebuah pepatah terkenal: “Komentar terbaik adalah kode yang tidak butuh komentar.” Artinya, kita harus berusaha menulis kode yang jelas. Namun, komentar tetap sangat berguna untuk:
- Menjelaskan logika bisnis atau algoritma yang kompleks.
- Memberi catatan
TODO
untuk pengembangan selanjutnya. - Menonaktifkan sementara baris kode saat debugging.
Go memiliki dua jenis komentar:
1. Komentar Satu Baris (//
)
// Menghitung total skor berdasarkan data yang adatotalSkor := hitungSkor(data)
2. Komentar Multi Baris (/* ... */
)
/*Fungsi ini adalah bagian dari proses autentikasi.Ia akan menerima token, memvalidasinya ke server,dan mengembalikan profil pengguna jika valid.*/func autentikasiPengguna(token string) { // ...}
Di dunia Go, ini bukan pilihan, tapi keharusan. gofmt
mengakhiri semua perdebatan gaya penulisan dan membuat kode Go mudah dibaca oleh siapa saja.
Package
- Lemari Arsip untuk Kode
Package adalah cara Go mengelompokkan kode ke dalam unit-unit logis. Secara fisik, satu package adalah satu folder. Tujuannya adalah untuk memecah kode berdasarkan fungsinya (misal: user
, produk
, pembayaran
).
Setiap program Go yang bisa dieksekusi harus punya package main
dan func main()
sebagai titik masuknya.
import
- Memanggil Bantuan dari Luar
Untuk menggunakan kode dari package
lain (baik itu standard library seperti fmt
atau package buatan kita sendiri), kita harus menggunakan import
.
package main
// Mengimpor package lokal bernama 'mathutil'import ( "fmt" "namamodul/mathutil" // ganti 'namamodul' dengan nama di go.mod Anda)
func main() { hasil := mathutil.Add(5, 3) fmt.Println(hasil)}
Struktur folder
namamodul/├── go.mod├── main.go└── mathutil/ └── add.go
Access Modifier
- Penjaga Pintu Public & Private
Di Go, tidak ada kata kunci public
atau private
. Aturannya sederhana dan jenius: kapitalisasi nama.
- Nama yang diawali Huruf Besar (
Add
,Book
) bersifat Exported (publik) dan bisa diakses dari package lain. - Nama yang diawali huruf kecil (
add
,book
) bersifat unexported (privat) dan hanya bisa diakses dari dalam package yang sama.
package user
// Diekspor, bisa diakses dari luartype User struct { Name string age int // tidak diekspor}
// Dieksporfunc (u *User) GetAge() int { return u.age}
// tidak dieksporfunc (u *User) validate() { // ...}
init()
- Ritual Persiapan Otomatis
Terkadang kita perlu menjalankan kode persiapan saat sebuah package pertama kali digunakan (misalnya, membuka koneksi database). Go menyediakan fungsi spesial init()
untuk ini.
Fungsi init()
akan dijalankan otomatis sekali oleh Go saat package diimpor, tanpa perlu kita panggil.
package config
import "fmt"
var APIKey string
func init() { fmt.Println("Paket config diinisialisasi...") // Logika untuk membaca file .env atau sejenisnya APIKey = "RAHASIA123"}
Menangani Error dengan Elegan
Inilah salah satu filosofi Go yang paling membedakannya dari bahasa lain.
Di banyak bahasa, error adalah sebuah ‘ledakan’ (exception) yang menghentikan segalanya. Di Go, error adalah sebuah nilai biasa yang dikembalikan oleh fungsi, sama seperti string
atau int
. Pola umumnya adalah fungsi mengembalikan (hasil, error)
.
error
- Kontrak Kesalahan Universal
Go memiliki interface bawaan yang sangat sederhana untuk ini:
type error interface { Error() string}
Setiap tipe yang memiliki method Error() string
secara otomatis dianggap sebagai sebuah error
.
Cara Dasar Membuat dan Memeriksa Error
Pola paling umum adalah memeriksa apakah error
yang dikembalikan bernilai nil
(tidak ada error) atau tidak.
import ( "errors" "fmt" "strconv")
func ubahKeAngka(teks string) (int, error) { if teks == "" { // 1. Membuat error sederhana return 0, errors.New("teks tidak boleh kosong") }
angka, err := strconv.Atoi(teks) if err != nil { // 2. Membungkus error yang ada dengan konteks tambahan return 0, fmt.Errorf("gagal mengubah teks '%s': %w", teks, err) }
return angka, nil // Sukses, error bernilai nil}
func main() { // Memanggil fungsi dan langsung memeriksa error-nya if hasil, err := ubahKeAngka("abc"); err != nil { fmt.Println("Terjadi kesalahan:", err) } else { fmt.Println("Berhasil:", hasil) }}
Studi Kasus: Error Kustom yang Informatif
Terkadang, pesan error string
saja tidak cukup. Kita butuh error
yang lebih terstruktur. Karena error
adalah interface, kita bisa membuat struct kita sendiri untuk menjadi tipe error
kustom.
Bayangkan kita punya fungsi FindUser
. Ia bisa gagal karena dua alasan: input tidak valid (validation error) atau data tidak ada (not found error).
package main
import ( "errors" "fmt")
// 1. Sentinel Error: sebuah variabel error global untuk kasus spesifik.var ErrNotFound = errors.New("data tidak ditemukan")
// 2. Custom Error Type: sebuah struct untuk error yang lebih detail.type ValidationError struct { Field string Msg string}
// Agar ValidationError dianggap 'error', ia harus punya method Error()func (e ValidationError) Error() string { return fmt.Sprintf("validasi gagal pada field '%s': %s", e.Field, e.Msg)}
// Fungsi yang bisa mengembalikan berbagai jenis errorfunc FindUser(name string) (string, error) { if name == "" { return "", ValidationError{Field: "name", Msg: "tidak boleh kosong"} } if name == "Budi" { return "Budi Ditemukan", nil } return "", ErrNotFound // Kembalikan sentinel error}
func main() { // Memeriksa jenis error yang kembali _, err := FindUser("") if err != nil { var vErr ValidationError // Gunakan errors.As untuk memeriksa apakah error-nya bertipe ValidationError if errors.As(err, &vErr) { fmt.Printf("Error Validasi! Field: %s, Pesan: %s\n", vErr.Field, v.Msg) } }
_, err = FindUser("Joko") if err != nil { // Gunakan errors.Is untuk memeriksa apakah error-nya adalah ErrNotFound if errors.Is(err, ErrNotFound) { fmt.Println("Error: Pengguna yang dicari memang tidak ada.") } }}
Gunakan errors.Is()
untuk membandingkan sebuah error dengan variabel error spesifik (sentinel). Gunakan errors.As()
untuk memeriksa apakah sebuah error adalah tipe struct kustom tertentu dan mengekstrak nilainya.
Petualangan Hari Ini Selesai!
Luar biasa! Kita sudah sampai di penghujung materi inti. Hari ini kita telah mengambil langkah besar dari sekadar coder menjadi software engineer. Kita tidak hanya menulis kode, tapi juga memikirkan cara menata dan membuatnya tangguh.
Singkatnya, kita sudah belajar:
- Cara menjaga kode tetap rapi dan terorganisir dengan
package
,import
, dangofmt
. - Filosofi error handling di Go sebagai nilai, bukan exception.
- Teknik menangani error secara profesional, mulai dari membuat error sederhana hingga tipe error kustom yang kaya informasi menggunakan
errors.Is
danerrors.As
.
Dengan semua pengetahuan ini, ransel petualangan kita sudah penuh. Hanya ada satu hal yang tersisa: menggunakannya! Di postingan terakhir dari seri “Becoming Gopher” ini, kita akan merangkum semuanya dengan membangun proyek pertama kita dan melihat sekilas ke mana arah perjalanan kita selanjutnya.