[tutorial tips-dan-trik]

Cara Mengatasi Error Handling pada Golang

Saat ini Santekno akan membahas tentang penanganan Error pada bahasa Golang. Kita akan mempelajari dari penanganan yang mudah sampai beberapa implementasi yang begitu kompleks. Golang sudah menyediakan penanganan Error dengan mudah, kita bisa juga melakukan modifikasi sedikit agar Error tersebut bisa lebih mudah dipahami oleh kita sendiri dan orang yang nantinya akan berkolaborasi dengan kita. Hal yang pertama yang akan kita lakukan yaitu dengan mengkostumisasi Error bawaan dari golang.

Golang menyediakan interface sederhana untuk penanganan Error, setiap ada Error yang akan dikembalikan oleh golang mengikuti definisi interface teserbut.

type error interface{
  Error() string
}

Membuat Kustom (Custom) Error Golang

package main

import(
  "errors"
  "fmt"
)

func hitungArea(radius int)(int, error){
  if radius < 0 {
    return 0, errors.New("Tidak boleh kurang dari nol")
  }
  return radius * radius, nil
}

func main() {
  area, err := hitungArea(-1);
  if err != nil {
    fmt.Println("Terdapat kesalahan...")
    return
  } 
  
  fmt.Println(area)
}

Kode diatas, kita akan mengikuti skenario untuk menghitung area dalam sebuah lingkaran, kita perlu memastikan bahwa radius itu tidak boleh nilai-nya negatif atau bisa kita bilang kurang dari nol. Jika radius yang dikirimkan nilainya negatif maka akan nilai yang dikembalikan adalah “0” dan pesan Error yang sudah didefinisikan.

Pada fungsi hitungArea() terdapat jika dipanggil di fungsi main maka akan mengembalikan 2 nilai yaitu, pertama nilai perhitungannya dan kedua objek Error. Untuk melakukan kustomisasi Error pada fungsi hitungArea() tersebut perlu ditambahkan pengecekan, jika objek err tidak sama dengan nil maka kita akan menampilkan informasi kesalahan yang bisa kita pahami. Terbayang jika kita memiliki Error yang tidak dikustomisasi kadang kita tidak tahu sebelah mana Error itu terjadi.

Ada sedikit trik dari Santekno juga, biasanya untuk melakukan kostumisasi tersebut kita juga perlu membutuhkan informasi Error yang terdapat pada fungsi hitungArea() juga karena bisa jadi jika kita melakukan kustomisasi ini, malah Error yang aslinya kita tidak tahu maksud kesalahannya seperti apa, maka pada fungsi main kita lakukan penambahan informasi Error tersebut dengan cara seperti dibawah ini:

func main() {
  area, err := hitungArea(-1);
  if err != nil {
    fmt.Printf("Terdapat kesalahan. Err: %s", err)
    return
  } 
  
  fmt.Println(area)
}

Mengenal “Defer”

Kita akan membahas terlebih dahulu tentang defer. Lihat contoh kode dibawah ini agar bisa lebih mudah untuk memahaminya

package main

import "fmt"

func balikPesan() {
  fmt.Println("Ini contoh simple penggunaan fungsi Defer")  
}

func main() {
  defer balikPesan()
  fmt.Println("Ini baris pertama")
  fmt.Println("Ini baris kedua")
  fmt.Println("Ini baris ketiga")
}

Kode diatas kita menggunakan defer untuk memanggil fungsi balikPesan() yang kita simpan di awal sebelum kita mencetak tiap baris informasi seperti kode diatas. Seperti apakah hasil cetak kode diatas? Coba bisa ada yang bisa tebak?

Seperti inilah ketika kode diatas dijalankan

hasil mencetak defer pada golang

Meskipun dipanggil di paling atas pada main() tetapi fungsi balikPesan() tersebut dijalankan setelah baris-baris pada fungsi main() selesai. Maka fungsi balikPesan() tersebut dijalankan diakhir fungsi tersebut. Dan begitulah cara kerja dari defer pada golang.

Mengenal “Panic”

Panic biasanya digunakan untuk menghentikan program dengan informasi pesan yang sudah di kustomisasi. Ketika kita memanggil panic instruksi pada program akan menjalankan seperti berikut ini

  • Fungsi yang saat ini sedang berjalan akan diberhentikan (stop)
  • Fungsi apapun yang dipanggil dengan defer akan dijalankan terlebih dahulu
  • Eksekusi program akan berhenti

Berikut ini kode sederhana dari penggunaan panic

package main

import "fmt"

func jalankanPanic(){
  panic("Ini contoh pesan pada situasi Panic")
  fmt.Println("fungsi ini berjalan dengan selesai")
}

func main(){
  jalankanPanic()
  fmt.Println("fungsi main berjalan sampai selesai")
}

Kode diatas kita memanggil fungsi panic di dalam fungsi jalankanPanic(). Setelah program dijalankan, maka akan berhenti secara tiba-tiba terminated. Bisa dilihat dari hasil program diatas seperti ini

hasil mencetak panic pada golang

Program keluar pada baris ke-6 ketika menjalankan fungsi panic berjalan. Fungsi panic adalah cara lain untuk memberi tahu program tentang terjadi kesalahan dan menginstruksikan untuk mengakhiri dengan pesan kesalahan khusus.

Menambahkan “Defer” ke dalam fungsi “Panic”

Seperti yang telah dijelaskan, setiap kali fungsi panic dijalankan fungsi yang menggunakan defer akan dijalankan terlebih dahulu sampai selesai. Mari kita lihat contoh kode programnya dibawah ini

package main

import "fmt"

func lakukanRecovery(){
  fmt.Println("Fungsi ini untuk melakukan recovery")
}

func jalankanPanic(){
  defer lakukanRecovery()
  panic("Ini contoh pesan pada situasi Panic")
  fmt.Println("fungsi ini berjalan dengan selesai")
}

func main(){
  jalankanPanic()
  fmt.Println("fungsi main berjalan sampai selesai")
}

Bagaimanakah hasil program diatas setelah dijalankan? Penasaran? Sesuai informasi yang disinggung diatas, hasilnya adalah fungsi dibawah defer akan dijalankan terlebih dahulu, mari kita lihat dibawah ini

hasil mencetak panic pada golang

Pada baris ke-11, panic berjalan, maka fungsi defer akan dijalankan terlebih dahulu sebelum diberhentikan. Begitu panic muncul, maka akan mencari semua fungsi defer agar dijalankan sebelum diberhentikan.

Menggunakan “Recovery”

Setelah situasi panic terjadi, maka program akan berhenti. Sejatinya di dunia nyata, aplikasi yang berhenti karena kesalahan itu tidak baik. Maka perlu mekanisme untuk melakukan pemulihan dari kesalahan tersebut. Kita perlu mengkondisikan pemulihan untuk menghindari pemberhentian aplikasi yang tidak diinginkan.

Fungsi defer selalu dijalankan saat fungsi itu sedang terjadi panic atau tidak terjadi panic Maka kita akan membuat skenario pemulihan (recovery) di dalam fungsi defer.

Mendeteksi situasi panic

Dalam fungsi defer kita harus melakukan pengecekan apakah eksekusi fungsi mengalami panic atau tidak. Untuk mendeteksi ini, kita akan menjalankan fungsi recover(). Setelah kita menjalan kan fungsi tersebut, kita akan mendapatkan informasi pesan kesalahan yang sama dengan nilai parameter yang diteruskan ke fungsi panic. Pesan tersebut akan dikembalikan sebagai output fungsi dari recover() lalu tidak akan mengijinkan untuk di hentikan tetapi akan terkontrol dan fungsi yang memanggil itu akan berjalan secara normal. Kita lihat langsung contoh programnya

package main

import "fmt"

func lakukanRecovery() {
	if pesanRecover := recover(); pesanRecover != nil {
		fmt.Println(pesanRecover)
	}
	fmt.Println("Fungsi ini untuk melakukan recovery")
}

func jalankanPanic() {
	defer lakukanRecovery()
	panic("Ini contoh pesan pada situasi Panic")
	fmt.Println("fungsi ini berjalan dengan selesai")
}

func main() {
	jalankanPanic()
	fmt.Println("fungsi main berjalan sampai selesai")
}

Setelah dijalankan program diatas, maka hasilnya program tersebut akan memberikan pesan informasi panic tetapi program tetap berjalan sampai akhir tanpa program tersebut berhenti. Bisa dilihat dibawah ini

hasil mencetak panic, defer recovery pada golang

Kesimpulan

Penanganan kesalahan pada golang memang terlihat berbeda dibandingkan dengan bahasa lain. Maka perlu kita tahu beberapa hal yg harus diperhatikan untuk melakukan penanganan Error tersebut. Mekanisme untuk recovery pun harus kita pikirkan bagaimana agar program kita tetap terus berjalan tidak berhenti seketika jika terjadi kesalahan yang mengakibatkan situasi panic.

comments powered by Disqus