Start HereOrdered learning track

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.

12 min read2355 words
PrevNext
Lesson 0235 lesson track0106 Start Here
#go#golang#toolchain#modules+2 more

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:

  1. Menginstal dan memverifikasi Go.
  2. Memahami go version dan go env.
  3. Membuat module dengan go mod init.
  4. Menulis dan menjalankan program Go.
  5. Menjalankan go fmt, go test, go vet, dan go mod tidy.
  6. Memahami fungsi go.mod dan go.sum.
  7. Menyiapkan struktur project awal.
  8. Membuat Makefile sederhana.
  9. Menyiapkan workflow editor.
  10. 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.
  • go directive di go.mod = minimum semantic/toolchain behavior untuk module.
  • toolchain directive, jika ada, bisa menyarankan toolchain tertentu.

3. Instalasi Go

Instalasi bergantung sistem operasi. Prinsipnya sama:

  1. Install Go dari sumber resmi atau package manager yang terpercaya.
  2. Pastikan binary go ada di PATH.
  3. Verifikasi dengan go version.
  4. 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.

VariableFungsi
GOROOTlokasi instalasi Go
GOPATHworkspace/cache lama dan lokasi binary install default
GOMODpath ke go.mod aktif, atau /dev/null jika tidak ada module
GOMODCACHEcache module dependency
GOCACHEcache build/test
GOOStarget operating system
GOARCHtarget architecture
GOTOOLCHAINaturan pemilihan toolchain
GOPROXYproxy module download
GOSUMDBchecksum database untuk verifikasi module
GOPRIVATEpattern 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?

PathTujuan
cmd/caseflowentry point executable
internal/caseidpackage internal untuk validasi case ID
go.modidentitas 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.T mengontrol test;
  • table-driven test umum di Go;
  • t.Run membuat subtest;
  • errors.Is mengecek 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.sum jika 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:

DirectiveFungsi
modulenama module
goversi Go minimum/semantic behavior
requiredependency module
replacemengganti dependency dengan path/version lain
excludemelarang versi tertentu
toolchainmenyarankan toolchain Go tertentu
toolmencatat 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:

  1. Jangan menambah dependency untuk hal yang mudah dilakukan standard library.
  2. Periksa maintenance dan security dependency.
  3. Hindari dependency besar untuk fungsi kecil.
  4. Pin versi melalui module system.
  5. 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;
  • staticcheck optional;
  • goimports optional.

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.

ToolFungsiKapan dipakai
staticcheckstatic analysis lebih kuatsetelah basic workflow stabil
golangci-lintlint aggregatortim/project production
gosecsecurity scanningservice exposed/security review
govulncheckvulnerability check resmi Godependency/security workflow
mockgen / moqmock generationjika interface test mulai banyak
airlive reloadweb service development
delvedebuggerdebugging 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.go
  • internal/caseid/caseid_test.go
  • cmd/caseflow/main.go
  • Makefile
  • README.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 GOPRIVATE perlu 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 found dan import lokal salah.

27. Referensi Utama

Referensi yang menjadi dasar part ini:


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.

Lesson Recap

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.

Continue The Track

Keep the momentum while the lesson is still fresh. Move backward for review or continue forward into the next concept.