Environment, Toolchain, dan Workflow Go yang Benar
Materi Part 02 seri belajar Go untuk software engineer: instalasi Go, go env, module, go.mod, go.sum, command utama, linting, testing, Makefile, dan workflow lokal production-grade.
Environment, Toolchain, dan Workflow Go yang Benar
Target part ini: kamu bisa menyiapkan environment Go yang repeatable, membuat module, menjalankan build/test/lint, memahami
go env, serta memiliki workflow lokal yang cukup rapi untuk latihan dan production-style development.
Dalam framework Josh Kaufman, part ini berada pada tahap remove barriers to practice. Banyak orang gagal belajar bahasa baru bukan karena bahasanya sulit, tetapi karena loop praktiknya lambat: install tidak jelas, command tidak konsisten, dependency kacau, editor tidak siap, test tidak jalan, dan struktur project berantakan.
Go unggul karena toolchain resminya kuat. Tetapi kamu tetap perlu memahami apa yang dilakukan toolchain tersebut.
1. Tujuan Praktis Part Ini
Setelah menyelesaikan Part 02, kamu harus bisa:
- Menginstal dan memverifikasi Go.
- Memahami
go versiondango env. - Membuat module dengan
go mod init. - Menulis dan menjalankan program Go.
- Menjalankan
go fmt,go test,go vet, dango mod tidy. - Memahami fungsi
go.moddango.sum. - Menyiapkan struktur project awal.
- Membuat Makefile sederhana.
- Menyiapkan workflow editor.
- Mendiagnosis error environment umum.
Deliverable akhir part ini:
caseflow/
go.mod
cmd/
caseflow/
main.go
internal/
caseid/
caseid.go
caseid_test.go
Makefile
README.md
2. Versi Go yang Digunakan
Seri ini memakai baseline Go modern dengan prinsip:
- gunakan release stabil terbaru jika memungkinkan;
- tetap pahami kompatibilitas Go 1;
- hindari fitur eksperimental untuk fondasi;
- gunakan standard tooling resmi terlebih dahulu;
- tambahkan tool eksternal secara bertahap.
Pada 2026, Go 1.26 tersedia sebagai release stabil. Namun command go mod init pada Go 1.26 dapat membuat go.mod dengan directive go 1.25.0 secara default karena perubahan kebijakan toolchain. Jadi jangan panik jika go.mod baru tidak selalu mencantumkan versi toolchain yang sama dengan go version.
Contoh:
go version
Output mungkin:
go version go1.26.1 linux/amd64
Tetapi go.mod bisa berisi:
module example.com/caseflow
go 1.25.0
Yang penting dipahami:
go version= versi toolchain yang kamu jalankan.godirective digo.mod= minimum semantic/toolchain behavior untuk module.toolchaindirective, jika ada, bisa menyarankan toolchain tertentu.
3. Instalasi Go
Instalasi bergantung sistem operasi. Prinsipnya sama:
- Install Go dari sumber resmi atau package manager yang terpercaya.
- Pastikan binary
goada diPATH. - Verifikasi dengan
go version. - Periksa environment dengan
go env.
3.1 Linux
Jika memakai installer resmi:
wget https://go.dev/dl/go1.26.1.linux-amd64.tar.gz
sudo rm -rf /usr/local/go
sudo tar -C /usr/local -xzf go1.26.1.linux-amd64.tar.gz
Tambahkan ke shell config:
export PATH=$PATH:/usr/local/go/bin
Reload shell:
source ~/.bashrc
# atau
source ~/.zshrc
Verifikasi:
go version
3.2 macOS
Dengan installer resmi atau Homebrew:
brew install go
Verifikasi:
go version
3.3 Windows
Gunakan installer .msi resmi, lalu buka terminal baru:
go version
Jika command tidak ditemukan, periksa PATH.
4. Memahami go env
Jalankan:
go env
Command ini menampilkan konfigurasi environment Go. Jangan hafalkan semua. Fokus pada yang sering relevan.
| Variable | Fungsi |
|---|---|
GOROOT | lokasi instalasi Go |
GOPATH | workspace/cache lama dan lokasi binary install default |
GOMOD | path ke go.mod aktif, atau /dev/null jika tidak ada module |
GOMODCACHE | cache module dependency |
GOCACHE | cache build/test |
GOOS | target operating system |
GOARCH | target architecture |
GOTOOLCHAIN | aturan pemilihan toolchain |
GOPROXY | proxy module download |
GOSUMDB | checksum database untuk verifikasi module |
GOPRIVATE | pattern module privat agar tidak memakai proxy/sumdb publik |
Contoh command terarah:
go env GOROOT GOPATH GOMOD GOMODCACHE GOCACHE GOOS GOARCH GOTOOLCHAIN
Output contoh:
/usr/local/go
/home/alice/go
/home/alice/work/caseflow/go.mod
/home/alice/go/pkg/mod
/home/alice/.cache/go-build
linux
amd64
auto
5. GOROOT vs GOPATH vs Module
Banyak kebingungan Go berasal dari sejarah GOPATH.
5.1 GOROOT
GOROOT adalah lokasi instalasi Go, misalnya:
/usr/local/go
Biasanya kamu tidak perlu mengubahnya.
5.2 GOPATH
GOPATH dulu adalah workspace utama Go. Sebelum Go Modules, project sering harus berada di:
$GOPATH/src/...
Sekarang, dengan Go Modules, kamu tidak perlu menaruh project di dalam GOPATH.
Namun GOPATH masih dipakai untuk:
- default binary install path:
$GOPATH/bin; - module cache:
$GOPATH/pkg/mod.
Pastikan $GOPATH/bin masuk PATH jika kamu menginstal tool via go install.
export PATH=$PATH:$(go env GOPATH)/bin
5.3 Go Modules
Go Modules adalah model modern untuk dependency dan versioning.
Satu module ditandai oleh file:
go.mod
Contoh:
module example.com/caseflow
go 1.25.0
Dalam praktik modern:
- source code boleh ada di mana saja;
- module path menjadi identitas module;
- dependency dicatat eksplisit;
- build lebih reproducible.
6. Membuat Project caseflow
Buat directory:
mkdir caseflow
cd caseflow
Inisialisasi module:
go mod init example.com/caseflow
Output:
go: creating new go.mod: module example.com/caseflow
Lihat isi go.mod:
cat go.mod
Contoh:
module example.com/caseflow
go 1.25.0
Untuk project production nyata, module path biasanya mengikuti repository:
module github.com/acme/caseflow
Untuk latihan lokal, example.com/caseflow cukup.
7. Struktur Project Awal
Buat struktur:
mkdir -p cmd/caseflow internal/caseid
Struktur:
caseflow/
go.mod
cmd/
caseflow/
internal/
caseid/
Mengapa seperti ini?
| Path | Tujuan |
|---|---|
cmd/caseflow | entry point executable |
internal/caseid | package internal untuk validasi case ID |
go.mod | identitas module dan dependency |
internal memiliki makna khusus di Go. Package di dalam directory internal hanya bisa diimport oleh code dalam parent tree-nya. Ini berguna untuk menjaga boundary.
8. Menulis Package Pertama
Buat file:
touch internal/caseid/caseid.go
Isi internal/caseid/caseid.go:
package caseid
import (
"errors"
"strings"
)
var ErrEmpty = errors.New("case id is empty")
func Normalize(raw string) (string, error) {
id := strings.TrimSpace(raw)
if id == "" {
return "", ErrEmpty
}
return strings.ToUpper(id), nil
}
Mari bedah.
package caseid
File ini bagian dari package caseid.
var ErrEmpty = errors.New("case id is empty")
ErrEmpty diawali huruf besar, berarti exported. Package lain bisa mengecek error ini.
func Normalize(raw string) (string, error)
Function menerima string mentah dan mengembalikan normalized ID atau error.
Kenapa return error, bukan panic?
Karena input kosong adalah expected failure dari user boundary, bukan bug program.
9. Menulis Test Pertama
Buat file:
touch internal/caseid/caseid_test.go
Isi:
package caseid
import (
"errors"
"testing"
)
func TestNormalize(t *testing.T) {
tests := []struct {
name string
input string
want string
wantErr error
}{
{
name: "trims whitespace and uppercases",
input: " abc-123 ",
want: "ABC-123",
},
{
name: "rejects empty input",
input: " ",
wantErr: ErrEmpty,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := Normalize(tt.input)
if tt.wantErr != nil {
if !errors.Is(err, tt.wantErr) {
t.Fatalf("expected error %v, got %v", tt.wantErr, err)
}
return
}
if err != nil {
t.Fatalf("expected no error, got %v", err)
}
if got != tt.want {
t.Fatalf("expected %q, got %q", tt.want, got)
}
})
}
}
Jalankan:
go test ./...
Output:
ok example.com/caseflow/internal/caseid 0.002s
Hal penting:
- test berada di file
_test.go; - function test diawali
Test; testing.Tmengontrol test;- table-driven test umum di Go;
t.Runmembuat subtest;errors.Ismengecek wrapped/sentinel error.
10. Menulis Entry Point main
Buat file:
touch cmd/caseflow/main.go
Isi:
package main
import (
"errors"
"fmt"
"os"
"example.com/caseflow/internal/caseid"
)
func main() {
if err := run(os.Args[1:]); err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
}
func run(args []string) error {
if len(args) < 1 {
return errors.New("usage: caseflow <case-id>")
}
id, err := caseid.Normalize(args[0])
if err != nil {
return fmt.Errorf("normalize case id: %w", err)
}
fmt.Printf("case %s accepted for review\n", id)
return nil
}
Jalankan:
go run ./cmd/caseflow abc-123
Output:
case ABC-123 accepted for review
Jalankan tanpa argumen:
go run ./cmd/caseflow
Output:
usage: caseflow <case-id>
exit status 1
Kenapa main memanggil run?
Karena main sulit dites jika semua logic ada di sana. Dengan run(args []string) error, logic bisa diuji tanpa memanggil process exit.
Pattern ini sering dipakai untuk CLI kecil dan service startup.
11. Command Go yang Wajib Dikuasai Awal
11.1 go run
Menjalankan package command tanpa menyimpan binary manual.
go run ./cmd/caseflow abc-123
Gunakan untuk development cepat.
11.2 go build
Membangun binary.
go build ./cmd/caseflow
Output binary biasanya bernama sesuai directory command:
caseflow
Jalankan:
./caseflow abc-123
11.3 go test
Menjalankan test.
go test ./...
./... berarti semua package di module saat ini dan subdirectory-nya.
11.4 go test -race
Menjalankan test dengan race detector.
go test -race ./...
Belum terlalu relevan sampai concurrency, tetapi biasakan tahu command ini.
11.5 go fmt
Format package.
go fmt ./...
Go formatting bukan preferensi personal. Ini bagian dari budaya Go.
11.6 gofmt
Formatter level file/directory.
gofmt -w .
Biasanya go fmt ./... cukup untuk package.
11.7 go vet
Mendeteksi suspicious construct.
go vet ./...
Contoh masalah yang bisa ditemukan: format string tidak cocok dengan argumen.
11.8 go mod tidy
Membersihkan dependency module.
go mod tidy
Command ini:
- menambah dependency yang dibutuhkan;
- menghapus dependency yang tidak dipakai;
- memperbarui
go.sumjika perlu.
11.9 go list
Melihat package/module metadata.
go list ./...
Output contoh:
example.com/caseflow/cmd/caseflow
example.com/caseflow/internal/caseid
11.10 go doc
Membaca dokumentasi dari terminal.
go doc fmt.Println
12. go.mod dan go.sum
12.1 go.mod
go.mod mendefinisikan module.
Contoh sederhana:
module example.com/caseflow
go 1.25.0
Jika ada dependency:
module example.com/caseflow
go 1.25.0
require github.com/google/uuid v1.6.0
Directive penting:
| Directive | Fungsi |
|---|---|
module | nama module |
go | versi Go minimum/semantic behavior |
require | dependency module |
replace | mengganti dependency dengan path/version lain |
exclude | melarang versi tertentu |
toolchain | menyarankan toolchain Go tertentu |
tool | mencatat executable tool dependency pada Go modern |
12.2 go.sum
go.sum menyimpan checksum dependency untuk reproducibility dan integrity.
Jangan edit manual.
Commit go.mod dan go.sum ke version control.
12.3 Kapan Menjalankan go mod tidy?
Jalankan:
- setelah menambah import eksternal;
- setelah menghapus dependency;
- sebelum commit;
- di CI untuk memastikan module bersih.
Command untuk CI:
go mod tidy
git diff --exit-code go.mod go.sum
Jika ada diff, berarti developer lupa commit perubahan module.
13. Menambahkan Dependency Eksternal dengan Benar
Untuk fondasi, kita belum perlu dependency eksternal. Tetapi kamu perlu tahu workflow-nya.
Contoh menambahkan UUID:
go get github.com/google/uuid@latest
Lalu pakai:
package main
import (
"fmt"
"github.com/google/uuid"
)
func main() {
fmt.Println(uuid.NewString())
}
Rapikan:
go mod tidy
Prinsip dependency hygiene:
- Jangan menambah dependency untuk hal yang mudah dilakukan standard library.
- Periksa maintenance dan security dependency.
- Hindari dependency besar untuk fungsi kecil.
- Pin versi melalui module system.
- Commit
go.sum.
14. Makefile untuk Workflow Konsisten
Buat Makefile:
.PHONY: fmt vet test test-race build run tidy check
APP=caseflow
PKG=./...
fmt:
go fmt $(PKG)
vet:
go vet $(PKG)
test:
go test $(PKG)
test-race:
go test -race $(PKG)
build:
go build -o bin/$(APP) ./cmd/$(APP)
run:
go run ./cmd/$(APP) abc-123
tidy:
go mod tidy
check: fmt vet test
Jalankan:
make check
Kenapa Makefile masih berguna padahal Go punya toolchain bagus?
Karena Makefile menyatukan workflow tim:
- command lokal sama dengan CI;
- onboarding lebih mudah;
- tidak perlu mengingat banyak command;
- bisa menjadi documentation executable.
Jika tidak suka Makefile, gunakan just, task, atau script lain. Yang penting command-nya konsisten.
15. README Minimal
Buat README.md:
# caseflow
Learning project for production-grade Go engineering.
## Requirements
- Go 1.26+
- Make
## Commands
```bash
make check
make run
make build
Structure
cmd/caseflow executable entry point
internal/caseid case ID normalization package
README kecil lebih baik daripada tidak ada. Dokumentasi awal mencegah friction.
---
## 16. Editor Setup
Gunakan editor apa pun, tetapi pastikan fitur ini aktif:
- format on save;
- Go language server;
- test runner;
- import organization;
- diagnostics;
- debugger optional.
### 16.1 VS Code
Install extension:
```txt
Go extension by Go Team at Google
Pastikan tools terinstall lewat command palette:
Go: Install/Update Tools
Tools umum:
gopls;dlv;staticcheckoptional;goimportsoptional.
16.2 GoLand
GoLand biasanya sudah punya integration kuat:
- code navigation;
- test runner;
- debugger;
- refactoring;
- module support.
Tetap pastikan project memakai Go SDK yang benar.
16.3 Vim/Neovim
Gunakan LSP dengan gopls.
Install:
go install golang.org/x/tools/gopls@latest
Pastikan $GOPATH/bin ada di PATH.
17. Tool Eksternal yang Berguna, tetapi Jangan Terlalu Cepat
Go standard tooling sudah cukup untuk awal. Tambahkan tool eksternal saat kebutuhan nyata muncul.
| Tool | Fungsi | Kapan dipakai |
|---|---|---|
staticcheck | static analysis lebih kuat | setelah basic workflow stabil |
golangci-lint | lint aggregator | tim/project production |
gosec | security scanning | service exposed/security review |
govulncheck | vulnerability check resmi Go | dependency/security workflow |
mockgen / moq | mock generation | jika interface test mulai banyak |
air | live reload | web service development |
delve | debugger | debugging logic kompleks |
Prinsip:
Jangan mengganti pemahaman dengan tool. Tool memperkuat feedback, bukan menggantikan reasoning.
18. Private Modules dan Corporate Environment
Di environment perusahaan, dependency bisa berasal dari repository privat.
Masalah umum:
- Go mencoba mengambil module privat lewat public proxy;
- checksum lookup ke sumdb publik gagal;
- authentication Git belum siap.
Gunakan GOPRIVATE:
go env -w GOPRIVATE=github.com/acme/*
Atau beberapa domain:
go env -w GOPRIVATE=github.com/acme/*,gitlab.internal.company/*
Efeknya:
- module matching pattern tidak memakai proxy publik;
- checksum tidak dicek ke sumdb publik;
- Go memakai mekanisme VCS langsung.
Untuk environment enterprise, ini penting agar import internal tidak bocor ke service publik.
19. Cross Compilation Dasar
Go memudahkan build untuk OS/architecture lain.
Lihat target saat ini:
go env GOOS GOARCH
Build Linux binary dari macOS/Linux:
GOOS=linux GOARCH=amd64 go build -o bin/caseflow-linux-amd64 ./cmd/caseflow
Build macOS ARM:
GOOS=darwin GOARCH=arm64 go build -o bin/caseflow-darwin-arm64 ./cmd/caseflow
Build Windows:
GOOS=windows GOARCH=amd64 go build -o bin/caseflow.exe ./cmd/caseflow
Catatan:
- Cross compilation mudah selama tidak memakai cgo.
- Jika memakai cgo, toolchain C target harus tersedia.
- Untuk backend service biasa, hindari cgo kecuali diperlukan.
20. Debugging Environment Umum
20.1 go: command not found
Penyebab:
- Go belum terinstall;
- PATH belum memuat directory Go binary;
- terminal belum di-restart.
Cek:
which go
Atau Windows:
where.exe go
20.2 go.mod file not found
Penyebab:
- command dijalankan di luar module;
- belum menjalankan
go mod init.
Cek:
go env GOMOD
Jika output /dev/null, kamu sedang tidak berada di module.
20.3 Import Lokal Tidak Ditemukan
Contoh error:
package internal/caseid is not in std
Penyebab:
- import path salah.
Salah:
import "internal/caseid"
Benar:
import "example.com/caseflow/internal/caseid"
Import package dalam module tetap memakai full module path.
20.4 Test Cache Membingungkan
Go bisa cache test result.
Jalankan tanpa cache:
go test -count=1 ./...
20.5 Dependency Aneh Setelah Eksperimen
Rapikan:
go mod tidy
Bersihkan module cache jika benar-benar perlu:
go clean -modcache
Hati-hati: command ini menghapus cache module dan download ulang nanti.
21. Workflow Harian yang Disarankan
Gunakan loop kecil.
Untuk latihan:
make check
Untuk perubahan kecil:
go test ./internal/caseid
Untuk seluruh module:
go test ./...
Untuk confidence sebelum commit:
go fmt ./...
go vet ./...
go test ./...
go mod tidy
git diff
22. CI Minimal
Kita belum membuat file CI spesifik provider, tetapi workflow-nya begini:
go mod tidy
git diff --exit-code go.mod go.sum
go fmt ./...
git diff --exit-code
go vet ./...
go test ./...
Untuk GitHub Actions, bentuk sederhananya nanti bisa seperti:
name: ci
on:
push:
pull_request:
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: '1.26.x'
- run: go mod tidy
- run: git diff --exit-code go.mod go.sum
- run: go fmt ./...
- run: git diff --exit-code
- run: go vet ./...
- run: go test ./...
Kita akan bahas CI/CD lebih production-grade di Part 28. Untuk sekarang, pahami bahwa CI harus menjalankan command yang sama dengan lokal.
23. Struktur Project: Jangan Over-engineer di Hari Pertama
Struktur awal kita sengaja kecil:
caseflow/
cmd/caseflow/main.go
internal/caseid/caseid.go
internal/caseid/caseid_test.go
go.mod
Makefile
README.md
Jangan langsung membuat:
controllers/
services/
repositories/
entities/
dtos/
configs/
middlewares/
utils/
helpers/
factories/
managers/
Masalah struktur terlalu awal:
- package lahir sebelum responsibility jelas;
- dependency direction belum terbukti;
- abstraction dibuat sebelum ada pressure;
- code kecil terasa enterprise tetapi rapuh.
Go lebih nyaman dengan prinsip:
Start concrete. Extract when the boundary proves itself.
24. Package Naming Awal
Package name harus pendek, jelas, dan tidak stutter.
Buruk:
caseid.CaseIDNormalize(...)
Lebih baik:
caseid.Normalize(...)
Buruk:
utils.NormalizeCaseID(...)
Lebih baik:
caseid.Normalize(...)
Package name adalah bagian dari API. Saat menulis function exported, baca dengan package prefix.
strings.TrimSpace(...)
http.ListenAndServe(...)
caseid.Normalize(...)
Jika terdengar repetitif, nama function atau package perlu diperbaiki.
25. Latihan Terarah Part 02
Exercise 1: Buat Project dari Nol
Hapus project jika perlu, lalu ulangi dari awal tanpa copy-paste penuh.
Command:
mkdir caseflow
cd caseflow
go mod init example.com/caseflow
mkdir -p cmd/caseflow internal/caseid
Buat:
internal/caseid/caseid.gointernal/caseid/caseid_test.gocmd/caseflow/main.goMakefileREADME.md
Jalankan:
make check
make run
make build
Exercise 2: Tambah Validasi Format
Update caseid.Normalize agar hanya menerima ID dengan prefix CASE-.
Contoh valid:
CASE-123
case-abc
Contoh invalid:
ABC-123
123
Tambahkan sentinel error:
var ErrInvalidFormat = errors.New("case id format is invalid")
Tambahkan table test.
Exercise 3: Test run
Pindahkan run agar bisa dites.
Tambahkan test untuk:
- no argument;
- invalid ID;
- valid ID.
Hint: agar output bisa dites, nanti kamu bisa refactor run menerima writer. Tapi untuk sekarang cukup test error behavior.
Exercise 4: Inspect Environment
Jalankan:
go env GOROOT GOPATH GOMOD GOMODCACHE GOCACHE GOOS GOARCH GOTOOLCHAIN GOPROXY GOSUMDB GOPRIVATE
Tulis catatan singkat:
- di mana Go terinstall;
- di mana module cache;
- module aktif apa;
- target OS/architecture apa;
- apakah
GOPRIVATEperlu di environment kerja kamu.
26. Checklist Pemahaman Part 02
Kamu siap lanjut ke Part 03 jika bisa:
- menjelaskan bedanya
GOROOT,GOPATH, dan Go Modules; - membuat module baru dengan
go mod init; - menjelaskan isi dasar
go.mod; - menjelaskan fungsi
go.sum; - menjalankan
go run,go build,go test,go fmt,go vet,go mod tidy; - membuat package internal;
- mengimport package lokal dengan module path yang benar;
- membuat table-driven test sederhana;
- membuat Makefile untuk workflow lokal;
- mendiagnosis error
go.mod file not founddan import lokal salah.
27. Referensi Utama
Referensi yang menjadi dasar part ini:
- Download and install Go — https://go.dev/doc/install
- Tutorial: Get started with Go — https://go.dev/doc/tutorial/getting-started
- Tutorial: Create a Go module — https://go.dev/doc/tutorial/create-module
- How to Write Go Code — https://go.dev/doc/code
- go.mod file reference — https://go.dev/doc/modules/gomod-ref
- Managing dependencies — https://go.dev/doc/modules/managing-dependencies
- Organizing a Go module — https://go.dev/doc/modules/layout
- Go Toolchains — https://go.dev/doc/toolchain
- Command Documentation — https://go.dev/doc/cmd
- Effective Go — https://go.dev/doc/effective_go
Penutup Part 02
Part ini menghilangkan hambatan praktik. Sekarang kamu punya project kecil, module aktif, package internal, test, Makefile, dan workflow command yang stabil.
Di Part 03, kita akan masuk ke syntax, values, types, constants, zero value, declaration, conversion, dan compile-time feedback. Fokusnya bukan menghafal sintaks, tetapi memahami bagaimana Go memodelkan nilai dan tipe.
You just completed lesson 02 in start here. Use the series map if you want to review the broader track, or continue directly into the next lesson while the context is still warm.
Keep the momentum while the lesson is still fresh. Move backward for review or continue forward into the next concept.