Go dirancang dengan dua janji yang menjawab keluhan lama developer: kompilasi yang cepat dan hasil berupa satu binary statis yang bisa dicopy ke server mana pun tanpa instalasi. Seluruh toolchain — kompilasi, pengujian, pemformatan, pengelolaan dependensi — tergabung dalam satu perintah go, tanpa Makefile atau pengelola package terpisah. Pada Chapter ini kita menyiapkan Go di Linux, membaca struktur module modern beserta go.mod, lalu membedah perintah-perintah dasarnya. Binary go sendiri tidak terpasang di mesin tempat materi ini diverifikasi, sehingga struktur file-nya kita bangun dan periksa secara nyata, sementara contoh eksekusinya ditampilkan sebagai contoh tampilan.

Instalasi Go #

Ada dua jalur resmi memasang Go di Linux. Jalur pertama lewat package manager — sudo apt install golang-go pada keluarga Debian — yang praktis tetapi versinya mengikuti rilis distro dan cenderung tertinggal dari upstream. Jalur kedua, yang direkomendasikan dokumentasi resmi Go, memasang tarball rilis terbaru secara manual ke /usr/local/go:

bash
sudo rm -rf /usr/local/go
sudo tar -C /usr/local -xzf go1.24.1.linux-amd64.tar.gz
echo 'export PATH=$PATH:/usr/local/go/bin' >> ~/.profile

Tiga langkah tersebut perlu dijelaskan urut-urutan. Penghapusan sudo rm -rf /usr/local/go membersihkan instalasi lama karena arsip resmi selalu berisi folder go yang utuh — menimpanya tanpa membersihkan bisa meninggalkan sisa file lama. Perintah tar -C /usr/local mengekstrak arsip hasil unduhan dari laman rilis Go (go.dev/dl) ke lokasi konvensi, dan baris echo menambahkan go ke PATH kita — sebagaimana dibahas di Chapter Compilers dan Build Tools , tanpa itu shell tidak akan menemukan perintah go. Sebagai contoh tampilan, verifikasi instalasi yang berhasil umumnya tampak seperti ini:

text
go version go1.24.1 linux/amd64

Module: Unit Proyek Modern #

Sejak 2018, proyek Go didefinisikan sebagai module: satu folder berisi file go.mod yang menyatakan nama module, versi bahasa minimal, dan daftar dependensi. Nama module biasanya mengikuti lokasi repositori; untuk latihan kita pakai domain contoh.example.com milik dokumentasi. Perintah go mod init contoh.example.com/catatan membuatnya, tetapi kita bisa menulis file ini langsung untuk melihat isinya:

bash
mkdir -p catatan/cmd/catatan
cat > catatan/go.mod << 'AKHIR'
module contoh.example.com/catatan

go 1.24
AKHIR
cat > catatan/cmd/catatan/main.go << 'AKHIR'
package main

import "fmt"

func main() {
	fmt.Println("Halo dari Go!")
}
AKHIR
cat catatan/go.mod
cat catatan/cmd/catatan/main.go

Output yang Dihasilkan:

text
module contoh.example.com/catatan

go 1.24
package main

import "fmt"

func main() {
	fmt.Println("Halo dari Go!")
}

Bedah kedua file tersebut:

  1. go.mod — baris module: nama lengkap module yang juga menjadi awalan import path semua package di dalamnya; contoh.example.com/catatan/internal/sapa nanti mengacu package di folder internal/sapa.
  2. go.mod — baris go 1.24: versi bahasa minimal yang dipakai module. Toolchain menolak fitur yang lebih baru bila angka ini lebih tua, dan mengelolanya otomatis lewat directive toolchain bila diperlukan.
  3. package main: setiap file Go dibuka dengan nama package. Paket bernama main plus fungsi main adalah titik masuk executable — padanan int main() pada C di Chapter gcc dan g++ .
  4. import "fmt": memuat package format standar; fmt.Println mencetak satu baris ke stdout.
  5. Indentasi TAB: kode di atas sengaja memakai TAB karena itulah gaya satu-satunya gofmt — pemformat resmi Go.

Konvensi folder cmd/<nama>/main.go membuat satu folder berisi satu executable; proyek dengan banyak binary tinggal menambah folder di bawah cmd/.

Perintah Dasar go #

Satu perintah go membawa seluruh alur kerja. Berikut yang paling sering dipakai sehari-hari:

PerintahPeran
go mod initmembuat go.mod baru
go run .kompilasi ke folder sementara lalu langsung menjalankan
go buildmenghasilkan binary di folder kerja
go test ./...menjalankan seluruh file _test.go
go fmt ./...memformat ulang semua file sesuai gofmt
go getmenambah dependensi ke go.mod

Ekosistem Go menuntut pengujian sebagai warga kelas satu: file berakhiran _test.go otomatis dianggap test, dan framework testing adalah pustaka standar — tidak ada dependensi pihak ketiga untuk sekadar menguji. Kita tambahkan satu package dengan test ke module sebelumnya, lalu periksa struktur akhirnya:

bash
mkdir -p catatan/cmd/catatan catatan/internal/sapa
cat > catatan/go.mod << 'AKHIR'
module contoh.example.com/catatan

go 1.24
AKHIR
cat > catatan/cmd/catatan/main.go << 'AKHIR'
package main

import "fmt"

func main() {
	fmt.Println("Halo dari Go!")
}
AKHIR
cat > catatan/internal/sapa/sapa.go << 'AKHIR'
package sapa

// Sapa mengembalikan sapaan untuk nama yang diberikan.
func Sapa(nama string) string {
	return "Halo, " + nama + "!"
}
AKHIR
cat > catatan/internal/sapa/sapa_test.go << 'AKHIR'
package sapa

import "testing"

func TestSapa(t *testing.T) {
	got := Sapa("Budi")
	want := "Halo, Budi!"
	if got != want {
		t.Errorf("Sapa(%q) = %q, ingin %q", "Budi", got, want)
	}
}
AKHIR
cd catatan
tree

Output yang Dihasilkan:

text
.
├── cmd
│   └── catatan
│       └── main.go
├── go.mod
└── internal
    └── sapa
        ├── sapa.go
        └── sapa_test.go

5 directories, 4 files

Dua hal penting dari struktur tersebut:

  1. internal/sapa/: folder bernama internal istimewa — package di dalamnya hanya boleh diimpor oleh module yang sama, sehingga sapa otomatis terlindung dari pemakaian pihak luar.
  2. sapa_test.go berada sefolder dengan kodenya: test fungsi Sapa ditulis di file test pada package yang sama; prefiks Test menandai fungsi test, dan t.Errorf mencatat kegagalan tanpa menghentikan test lain.

Sebagai contoh tampilan, sesi kerja dengan perintah-perintah di atas pada mesin ber-Go biasanya tampak seperti ini:

console
$ go run .
Halo dari Go!
$ go test ./...
ok      contoh.example.com/catatan      0.012s
$ go build
$ ls
catatan  cmd  go.mod  internal

Perhatikan bahwa go build menghasilkan binary catatan — nama diambil dari elemen terakhir path module. Pesan ok dari go test menandai seluruh package lolos, dan angka waktunya bervariasi di tiap mesin.

GOPATH: Masa Lalu yang Masih Terasa #

Sebelum module ada, semua kode Go wajib tinggal di dalam satu folder kerja bernama GOPATH — biasanya ~/go — dengan struktur kaku src/, pkg/, dan bin/. Era itu berlalu, tetapi dua warisannya masih relevan. Pertama, variabel GOPATH masih menentukan lokasi module cache: dependensi yang diunduh go get disimpan di ~/go/pkg/mod dan dibagi pakai oleh semua proyek — bukan disalin per proyek seperti node_modules. Kedua, perintah go install some.tool/cmd/tool@latest meletakkan binary alat di ~/go/bin; folder itu perlu ditambahkan ke PATH agar alatnya bisa dipanggil dari mana saja. Jadi mekanisme PATH dari bab-bab awal section ini tetap jadi kunci: folder ~/go/bin di PATH kita, dan seluruh pemasangan alat Go berjalan tanpa root.

Binary Tunggal: Keunggulan Saat Deploy #

Hasil go build adalah satu file executable yang berisi program dan seluruh dependensinya. Tanpa CGO, binary Go bahkan sepenuhnya statis — ldd akan menjawab not a dynamic executable — kontras dengan binary C di Chapter sebelumnya yang menautkan libc.so.6 secara dinamis. Implikasinya besar untuk deployment: copy satu file ke server melalui scp, beri hak eksekusi, dan program siap jalan — tidak perlu interpreter Python, runtime Node, atau folder node_modules di server. Go juga bisa menyilang-kompilasi: pasangan variabel GOOS=windows GOARCH=amd64 pada saat go build menghasilkan binary untuk sistem lain langsung dari Linux, sesuatu yang dulu hanya mimpi di toolchain C.

Dengan compiler, interpreter, dan runtime yang telah kita jelajahi, pola besar Linux sebagai rumah development sudah terlihat: toolchain terpusat di PATH, versi terisolasi per user, dan pustaka per proyek. Chapter berikutnya menutup tur bahasa dengan ekosistem yang paling tua wujud kerjanya: Java dan JVM-nya.