Bootstrap
Seiring berkembangnya framework, kita akan menambahkan berbagai komponen: Redis, OpenTelemetry, HTTP client, message queue, dan lain-lain. Jika semua inisialisasi dilakukan langsung di run(), fungsi tersebut akan menjadi sangat panjang dan sulit dikelola.
Bootstrap adalah pola untuk memusatkan semua inisialisasi aplikasi dalam satu tempat, sehingga run() hanya fokus pada orchestration (mengatur alur) bukan construction (membangun komponen).
📂 Kode Lengkap Bab Ini: Seluruh kode yang dibahas di bab ini tersedia di GitHub:
8.1 Masalah dengan Inisialisasi Langsung
Saat ini, run() melakukan dua tanggung jawab sekaligus:
func run() error {
// Tanggung jawab 1: Inisialisasi komponen
cfg, err := config.LoadConfig() // ← inisialisasi
db, err := database.OpenDB(cfg) // ← inisialisasi
// Tanggung jawab 2: Orchestration
userRepository := repository.NewUserRepository(db)
userService := service.NewUsers(userRepository)
userHandler := handler.NewUserHandler(userService)
// ... server setup dan graceful shutdown
}Masalah ke depan:
Setiap komponen baru (Redis, cache, telemetry) akan menambah panjang
run()Inisialisasi dan cleanup tersebar (database di sini, nanti Redis di sana)
Sulit mengatur urutan inisialisasi yang benar (misal: logger harus sebelum yang lain)
Testing jadi sulit karena harus menginisialisasi semua komponen
8.2 Solusi: Struct App sebagai Container
Kita buat struct App yang menjadi container untuk semua dependency aplikasi:
Prinsip:
Semua inisialisasi terjadi di fungsi
NewApp()Appberisi semua komponen yang sudah siap pakaiCleanupberisi fungsi untuk menutup resource (database, koneksi, dll)run()cukup memanggilNewApp()dandefer app.Cleanup()
8.3 Implementasi Bootstrap
Buat file internal/bootstrap/app.go:
Catatan: Cleanup function memastikan resource dibersihkan dalam urutan yang benar (LIFO - Last In First Out) ketika dipanggil di defer.
8.4 Update Server Main
Sekarang cmd/server/main.go menjadi lebih bersih. Semua inisialisasi komponen diambil alih oleh bootstrap.NewApp():
8.5 Perbandingan Sebelum dan Sesudah
Lokasi inisialisasi
Tersebar di run()
Terpusat di bootstrap.NewApp()
Penambahan komponen baru
Mengubah run()
Mengubah bootstrap.NewApp()
Cleanup resource
Tersebar (hanya database)
Terpusat di Cleanup()
Testability
Sulit mock komponen
Mudah (bisa buat App terpisah untuk test)
Tanggung jawab run()
Inisialisasi + orchestrasi
Hanya orchestrasi
8.6 Diagram Alur Bootstrap
8.7 Update CLI Main (Opsional)
Untuk konsistensi, cmd/cli/main.go juga bisa menggunakan bootstrap:
8.8 Manfaat untuk Testing (Preview)
Testing memang bleum dibahas di bab ini, tapi sebagai preview saja untuk menjelaskan keuntungan pemakaian bootstrap. Dengan pola bootstrap, testing menjadi lebih mudah karena kita bisa membuat App terpisah untuk test:
Ringkasan Bab 8
Di bab ini kita telah belajar:
Masalah – Inisialisasi komponen yang tersebar membuat
run()panjang dan sulit dikelolaSolusi – Bootstrap pattern dengan struct App sebagai container dependency
Implementasi – Fungsi
NewApp()yang menginisialisasi semua komponen sekaligusCleanup – Fungsi Cleanup untuk membersihkan resource dalam urutan yang benar
Testability – Bootstrap memudahkan pembuatan test dengan dependency yang bisa diganti
Manfaat yang kita peroleh:
✅
run()sekarang hanya fokus pada orchestrasi (setup server, graceful shutdown)✅ Penambahan komponen baru (Redis, logger, dll) hanya mengubah
bootstrap.NewApp()✅ Cleanup resource terpusat dan terjamin
✅ Lebih mudah di-test karena dependency bisa diganti
✅ CLI dan server berbagi inisialisasi yang sama
Yang akan datang:
Saat ini logging masih menggunakan
log.PrintfstandarBab selanjutnya: Logging – membangun logging terstruktur untuk memudahkan observabilitas
Last updated
Was this helpful?