Episode ini membongkar cara Go bekerja di balik layar: runtime, garbage collector, scheduler goroutine, dan proses kompilasi. Kalian juga mengenal paket standar utama serta bagaimana package, module, dan go mod membentuk arsitektur project.

Di episode 1 kalian tahu mengapa Go ada. Sekarang saatnya membongkar bagaimana Go bekerja di balik layar. Memahami runtime dan arsitektur project bukan sekadar pengetahuan teori — ini menentukan keputusan desain ketika kalian menulis aplikasi produksi.
Episode 2 menjelaskan tiga lapisan: runtime Go yang terdiri dari garbage collector dan scheduler goroutine, paket standar utama yang menjadi tulang punggung hampir semua aplikasi, dan sistem module yang membentuk struktur project. Di akhir episode, kalian akan melihat peta lengkap bagaimana sebuah program Go dibangun dari kode menjadi binary.
Go memakai garbage collector (GC) untuk mengelola memori heap secara otomatis. Kalian mengalokasikan memori tanpa harus membebaskannya secara manual seperti C atau C++. GC Go menggunakan algoritma tricolor concurrent mark-sweep yang berjalan paralel dengan program, sehingga jeda (pause) per siklus sangat singkat — biasanya di bawah satu milidetik.
Scheduler Go memetakan banyak goroutine ke sejumlah thread OS yang lebih kecil. Model ini disebut M:N scheduling: M goroutine berjalan di atas N thread. Scheduler membagi waktu lewat kerja sama (cooperative), memindahkan goroutine dari thread saat ia memanggil operasi pemblokiran seperti I/O, sehingga satu goroutine yang menunggu tidak menghentikan goroutine lain.
package main
import (
"fmt"
"runtime"
)
func main() {
fmt.Println("goroutine aktif:", runtime.NumGoroutine())
go func() {
fmt.Println("goroutine baru")
}()
fmt.Println("maksimum CPU:", runtime.NumCPU())
}Go dikompilasi langsung menjadi machine code, bukan bytecode yang diinterpretasi. Compiler mengolah package, melakukan type checking, lalu menghasilkan binary statis. Tidak ada VM yang perlu diinstal di mesin target. Inilah mengapa binary Go bisa langsung dijalankan di container minimal sekalipun.
Tiga paket yang paling sering dipakai: fmt untuk formatting dan I/O berbasis teks, io untuk interface pembacaan dan penulisan, serta os untuk akses sistem operasi seperti argumen, environment variable, dan file. Kombinasi ketiganya menjadi dasar hampir semua program.
package main
import (
"fmt"
"os"
)
func main() {
if len(os.Args) > 1 {
fmt.Println("argumen pertama:", os.Args[1])
}
fmt.Fprintf(os.Stdout, "PID proses: %d\n", os.Getpid())
}context membawa nilai ber-skope-request sekaligus mekanisme pembatalan dan deadline untuk operasi async. sync menyediakan primitif sinkronisasi: Mutex, WaitGroup, dan Once. Ketiga paket ini akan kalian dalami di episode 10 dan 12.
Sebuah package adalah kumpulan file Go di direktori yang sama, dengan deklarasi package di baris pertama. Package main menghasilkan binary yang bisa dieksekusi; package lain adalah library yang di-import. Identifier yang diawali huruf kapital diekspor, sementara huruf kecil bersifat privat.
package greeter
func Halo(nama string) string {
return "Halo, " + nama
}
func rahasia() string {
return "fungsi privat"
}Sebuah module adalah unit distribusi yang menyatukan banyak package, didefinisikan lewat file go.mod. Perintah go mod init membuatnya, go mod tidy menyinkronkan dependensi, dan go mod vendor mengunduh semua dependency ke direktori lokal. go.mod mencatat versi Go dan dependency beserta checksum-nya. Coba jalankan go mod init github.com/contoh/modul di direktori kosong untuk melihat isi file yang dihasilkan.
go mod init github.com/nama/belajar-go
go mod tidy
cat go.modGo mengizinkan definisi metode pada tipe melalui receiver. Ini adalah cara Go menerapkan konsep seperti method pada class, tanpa perlu class itu sendiri.
package main
import "fmt"
type Persegi struct {
Panjang int
Lebar int
}
func (p Persegi) Luas() int {
return p.Panjang * p.Lebar
}
func main() {
s := Persegi{Panjang: 4, Lebar: 3}
fmt.Println("luas:", s.Luas())
}Go tidak punya inheritance. Sebagai gantinya, Go memakai interface dan composition. Interface didefinisikan oleh kumpulan metode, dan sebuah tipe secara implisit memenuhinya jika memiliki metode yang sesuai — tanpa deklarasi eksplisit. Sementara itu, struct bisa digabung (embedded) satu sama lain untuk membangun perilaku kompleks dari komponen sederhana.
package main
import "fmt"
type Deskriptor interface {
Deskripsi() string
}
type Dasar struct {
Nama string
}
func (d Dasar) Deskripsi() string {
return "objek bernama " + d.Nama
}
type Lanjutan struct {
Dasar
Versi int
}
func main() {
var d Deskriptor = Lanjutan{Dasar: Dasar{Nama: "aplikasi"}, Versi: 2}
fmt.Println(d.Deskripsi())
}Alur lengkap membangun aplikasi Go: compiler membaca package utama, mengikuti semua import, melakukan type checking, lalu menghasilkan binary. Perintah go build ./... mengompilasi semua package dalam module, sementara go install menempatkan binary ke direktori bin dari GOPATH.
go build -o app ./...
ls -la appBiner hasil build bisa diuji, dikirim ke registry container, atau langsung dijalankan di server. Proses ini yang membuat Go menjadi pilihan utama untuk deploy ke Kubernetes dan platform cloud lainnya — kita akan membahasnya mendalam di episode 16.
Episode 2 memetakan arsitektur Go: runtime dengan garbage collector dan scheduler goroutine, kompilasi sekali menjadi binary statis, paket standar utama, sistem module lewat go mod, serta konsep interface, metode, dan composition yang menggantikan inheritance.
Inti yang harus dibawa pulang:
Di episode 3 selanjutnya kalian akan menulis program Go pertama — struktur file, deklarasi package, import, tipe data dasar, variabel, konstanta, fungsi dengan multiple return values, dan error handling idiomatik. Semua yang kita bahas di episode ini akan langsung dipraktikkan dengan kode nyata.