Fatal
Dalam pengembangan aplikasi Go, kita sering melihat log.Fatal digunakan untuk menghentikan program ketika terjadi error. Namun, penggunaan log.Fatal yang tersebar di berbagai tempat dapat membuat kode sulit diuji dan dikelola. Bab ini akan membahas pola penggunaan log.Fatal yang disiplin dan terpusat.
📂 Kode Lengkap Bab Ini: Seluruh kode yang dibahas di bab ini tersedia di GitHub:
7.1 Memahami log.Fatal
Fungsi log.Fatal di Go melakukan dua hal sekaligus:
Mencetak pesan error ke log
Memanggil
os.Exit(1)untuk menghentikan program secara paksa
log.Fatal("something went wrong")
// Sama seperti:
// log.Print("something went wrong")
// os.Exit(1)Karakteristik penting:
defertidak akan dieksekusi setelahlog.FatalKode setelah
log.Fataltidak akan pernah berjalanTidak ada kesempatan untuk melakukan cleanup (menutup koneksi database, dll)
7.2 Kapan Menggunakan log.Fatal
log.Fatal sebaiknya hanya digunakan untuk error yang:
Terjadi di awal program (belum ada resource yang perlu dibersihkan)
Tidak mungkin dipulihkan (unrecoverable)
Membuat state program tidak valid untuk melanjutkan eksekusi
Contoh penggunaan yang tepat:
File konfigurasi tidak ditemukan
Port server sudah digunakan oleh proses lain
Koneksi database gagal sama sekali
Lokasi yang tepat untuk log.Fatal:
func init()– inisialisasi package-level variablefunc main()– entry point aplikasi
7.3 Masalah dengan log.Fatal yang Tersebar
Pada bab-bab sebelumnya, kita memiliki log.Fatal di berbagai tempat:
Masalah dengan pendekatan ini:
Sulit diuji –
log.Fatalakan menghentikan testCleanup tidak berjalan –
defer db.Close()tidak terpanggilTidak jelas aliran error – bercampur antara return error dan fatal
7.4 Pola: Memisahkan logika dari eksekusi
Solusi yang direkomendasikan adalah memindahkan semua logika ke fungsi run() error, lalu hanya main() yang memanggil log.Fatal jika run() mengembalikan error.
Pola ini memiliki keuntungan:
Semua error dikembalikan sebagai nilai biasa (
return error)defertetap berjalan dengan benarFungsi
run()bisa diuji secara unitHanya satu
log.Fataldi seluruh program (dimain)
7.5 Implementasi: CLI
Berikut implementasi pola run() error pada cmd/cli/main.go:
Perhatikan perubahan:
log.Fatalfdihapus dari dalamrun(), diganti denganreturn fmt.Errorf(...)Hanya
main()yang memilikilog.FatalfMenggunakan
%wuntuk wrapping error (mempertahankan rantai error)
7.6 Implementasi: Server
cmd/server/main.go juga mengikuti pola yang sama:
Perhatikan perubahan penting:
log.Fatalfdi dalamselectdiubah menjadireturn fmt.Errorf(...)Server error sekarang dikembalikan sebagai nilai error dari
run()main()tetap hanya memiliki SATUlog.Fatalf
7.7 Perbandingan Sebelum dan Sesudah
Jumlah log.Fatal
2+ (tersebar)
1 (hanya di main())
Error handling
Campuran (return & fatal)
Konsisten (return error)
Testability
Sulit (fatal hentikan test)
Mudah (run() bisa di-test)
Cleanup (defer)
Tidak jalan setelah fatal
Jalan selalu
Error wrapping
Tidak konsisten
Menggunakan %w
7.8 Error Wrapping dengan %w
%wPerhatikan penggunaan %w (bukan %v) saat membungkus error:
Dengan %w, kita bisa menggunakan errors.Is() dan errors.As() nantinya untuk memeriksa tipe error tertentu.
Ringkasan Bab 7
Di bab ini kita telah belajar:
Apa itu
log.Fatal– Mencetak log +os.Exit(1)Kapan menggunakannya – Hanya di
init()ataumain(), untuk error yang tidak bisa dipulihkanPola
run() error– Memisahkan logika dari eksekusiSatu
log.Fatal– Hanya dimain(), memanggilrun()dan handle errorError wrapping – Menggunakan
%wuntuk mempertahankan rantai error
Manfaat yang kita peroleh:
✅ Semua error ditangani secara konsisten (
return error)✅
deferselalu berjalan (koneksi database tertutup dengan benar)✅ Fungsi
run()bisa diuji secara unit✅ Aliran kode lebih jelas dan mudah dilacak
Yang akan datang:
Saat ini
run()sudah cukup rapi, tapi masih bisa dikelompokkan lagiBab selanjutnya: Bootstrap – mengorganisir inisialisasi aplikasi (config, database, dependency injection) dalam satu tempat yang terstruktur
Last updated