# Go: Dasar-Dasar untuk Developer Java/Python di 2026 > Pelajari Go dengan cepat menggunakan pengalaman Java atau Python. Goroutine, channel, interface, dan pola-pola penting untuk transisi yang lancar. - Published: 2026-01-19 - Updated: 2026-04-10 - Author: SharpSkill - Tags: go, golang, concurrency, goroutines, backend - Reading time: 12 min --- Go (atau Golang) telah memantapkan posisinya sebagai bahasa pilihan untuk microservice, tool CLI, dan sistem terdistribusi. Diciptakan oleh Google pada tahun 2009, Go menggabungkan kesederhanaan Python dengan performa setara C. Bagi developer yang beralih dari Java atau Python, transisi ke Go terasa sangat mulus begitu konsep-konsep intinya dipahami. > **Mengapa Go di 2026?** > > Go menjadi fondasi Docker, Kubernetes, Terraform, dan banyak infrastruktur cloud lainnya. Kompilasi cepat, dukungan concurrency bawaan, dan deployment sebagai binary tunggal menjadikan Go ideal untuk pengembangan backend modern. ## Instalasi dan konfigurasi Go Menginstal Go mudah dan konsisten di semua platform. Tool `go` mengelola kompilasi, dependensi, dan pengujian. ```bash # install.sh # Installation on macOS with Homebrew brew install go # Installation on Linux (Ubuntu/Debian) sudo apt update && sudo apt install golang-go # Verify installation go version # go version go1.22.0 linux/amd64 ``` Struktur proyek Go mengikuti konvensi yang ketat namun sederhana. File `go.mod` mendefinisikan modul dan dependensinya. ```bash # project-setup.sh # Create a new project mkdir my-project && cd my-project go mod init github.com/user/my-project # Generated structure: # my-project/ # ├── go.mod # Module manifest # └── main.go # Entry point # Essential commands go build # Compile the project go run main.go # Compile and execute go test ./... # Run all tests go fmt ./... # Format code automatically ``` ## Program Go pertama Berikut program sederhana yang mengilustrasikan sintaks dasar Go. Perbandingan dengan Java dan Python membantu memvisualisasikan perbedaannya. ```go // main.go package main import "fmt" // Program entry point func main() { // Declaration with type inference message := "Hello, Go!" fmt.Println(message) // Explicit declaration var count int = 42 fmt.Printf("Count: %d\n", count) } ``` Hal yang langsung terlihat: tanpa titik koma, tanpa tanda kurung di sekitar kondisi, dan inferensi tipe dengan `:=`. Go mengutamakan keringkasan tanpa mengorbankan keterbacaan. ## Variabel dan tipe fundamental Go memiliki tipe statis tetapi menawarkan inferensi tipe yang sangat baik. Tipe dasar mencakup sebagian besar kasus penggunaan. ```go // types.go package main import "fmt" func main() { // Short declaration (inside functions only) name := "Alice" // string age := 30 // int height := 1.75 // float64 active := true // bool // Explicit declaration var score int = 100 var rate float64 = 3.14 // Multiple declaration var ( firstName string = "Bob" lastName string = "Smith" points int = 0 ) // Zero values (default values) var count int // 0 var text string // "" (empty string) var flag bool // false var ptr *int // nil fmt.Println(name, age, height, active) } ``` > **Zero value di Go** > > Berbeda dengan Java atau Python, Go secara otomatis menginisialisasi variabel ke "zero value"-nya: 0 untuk angka, "" untuk string, false untuk bool, nil untuk pointer dan slice. ## Fungsi dan multiple return Go memungkinkan pengembalian beberapa nilai sekaligus, fitur yang digunakan secara luas untuk penanganan error. ```go // functions.go package main import ( "errors" "fmt" ) // Simple function with typed parameters func add(a, b int) int { return a + b } // Multiple returns (idiomatic pattern for errors) func divide(a, b float64) (float64, error) { if b == 0 { return 0, errors.New("division by zero") } return a / b, nil } // Named returns func getUser(id int) (name string, age int, err error) { if id <= 0 { err = errors.New("invalid ID") return } name = "Alice" age = 30 return } // Variadic function func sum(numbers ...int) int { total := 0 for _, n := range numbers { total += n } return total } func main() { // Simple call result := add(5, 3) fmt.Println("5 + 3 =", result) // Explicit error handling quotient, err := divide(10, 3) if err != nil { fmt.Println("Error:", err) return } fmt.Printf("10 / 3 = %.2f\n", quotient) // Ignore a returned value with _ name, _, _ := getUser(1) fmt.Println("User:", name) // Variadic call total := sum(1, 2, 3, 4, 5) fmt.Println("Sum:", total) } ``` ## Struct dan method Struct adalah blok pembangun untuk tipe kustom di Go. Method diikatkan ke tipe melalui receiver. ```go // structs.go package main import "fmt" // Struct definition type User struct { ID int Username string Email string Active bool } // Constructor (convention: NewTypeName) func NewUser(id int, username, email string) *User { return &User{ ID: id, Username: username, Email: email, Active: true, } } // Method with value receiver (copy) func (u User) FullInfo() string { status := "inactive" if u.Active { status = "active" } return fmt.Sprintf("%s <%s> (%s)", u.Username, u.Email, status) } // Method with pointer receiver (modification possible) func (u *User) Deactivate() { u.Active = false } // Method with pointer receiver for modification func (u *User) UpdateEmail(newEmail string) { u.Email = newEmail } func main() { // Create with constructor user := NewUser(1, "alice", "alice@example.com") fmt.Println(user.FullInfo()) // Modify via method user.Deactivate() fmt.Println(user.FullInfo()) // Direct creation user2 := User{ ID: 2, Username: "bob", Email: "bob@example.com", } fmt.Println(user2.FullInfo()) } ``` > **Value vs Pointer Receiver** > > Gunakan pointer receiver (`*User`) ketika method mengubah state atau ketika struct berukuran besar. Gunakan value receiver (`User`) untuk method read-only pada struct ringan. ## Interface: polimorfisme implisit Interface di Go diimplementasikan secara implisit. Sebuah tipe memenuhi interface jika mengimplementasikan semua method-nya, tanpa deklarasi eksplisit. ```go // interfaces.go package main import ( "fmt" "math" ) // Interface definition type Shape interface { Area() float64 Perimeter() float64 } // Rectangle implements Shape implicitly type Rectangle struct { Width, Height float64 } func (r Rectangle) Area() float64 { return r.Width * r.Height } func (r Rectangle) Perimeter() float64 { return 2 * (r.Width + r.Height) } // Circle also implements Shape type Circle struct { Radius float64 } func (c Circle) Area() float64 { return math.Pi * c.Radius * c.Radius } func (c Circle) Perimeter() float64 { return 2 * math.Pi * c.Radius } // Function accepting the interface func PrintShapeInfo(s Shape) { fmt.Printf("Area: %.2f, Perimeter: %.2f\n", s.Area(), s.Perimeter()) } func main() { rect := Rectangle{Width: 10, Height: 5} circle := Circle{Radius: 7} // Polymorphism via interface PrintShapeInfo(rect) PrintShapeInfo(circle) // Slice of interfaces shapes := []Shape{rect, circle} for _, shape := range shapes { PrintShapeInfo(shape) } } ``` Pendekatan ini berbeda secara radikal dari Java di mana `implements` bersifat wajib. Di Go, kesesuaian bersifat struktural, bukan nominal. ## Slice dan map: koleksi dinamis Slice adalah tampilan dinamis atas array, dan map adalah hash table bawaan. ```go // collections.go package main import "fmt" func main() { // Slice: dynamic array numbers := []int{1, 2, 3, 4, 5} // Append elements numbers = append(numbers, 6, 7) // Slicing (similar to Python) subset := numbers[1:4] // [2, 3, 4] fmt.Println("Subset:", subset) // Create slice with make scores := make([]int, 0, 10) // len=0, cap=10 scores = append(scores, 100, 95, 88) // Iteration with range for index, value := range numbers { fmt.Printf("numbers[%d] = %d\n", index, value) } // Map: hash table users := map[string]int{ "alice": 30, "bob": 25, } // Add/Update users["charlie"] = 35 // Check existence age, exists := users["alice"] if exists { fmt.Println("Alice's age:", age) } // Delete delete(users, "bob") // Map iteration for name, age := range users { fmt.Printf("%s is %d years old\n", name, age) } } ``` ## Penanganan error idiomatik Go tidak memiliki exception. Error adalah nilai yang dikembalikan secara eksplisit, memaksa penanganan yang ketat. ```go // errors.go package main import ( "errors" "fmt" "os" ) // Sentinel error (for comparison) var ErrNotFound = errors.New("resource not found") var ErrInvalidInput = errors.New("invalid input") // Custom error with context type ValidationError struct { Field string Message string } func (e *ValidationError) Error() string { return fmt.Sprintf("validation failed on %s: %s", e.Field, e.Message) } // Function returning different error types func GetUser(id int) (string, error) { if id <= 0 { return "", &ValidationError{ Field: "id", Message: "must be positive", } } if id > 1000 { return "", ErrNotFound } return "Alice", nil } // Error wrapping (Go 1.13+) func ReadConfig(path string) ([]byte, error) { data, err := os.ReadFile(path) if err != nil { return nil, fmt.Errorf("reading config %s: %w", path, err) } return data, nil } func main() { // Basic pattern user, err := GetUser(-1) if err != nil { fmt.Println("Error:", err) // Type assertion for custom error var valErr *ValidationError if errors.As(err, &valErr) { fmt.Printf("Field: %s\n", valErr.Field) } // Comparison with sentinel error if errors.Is(err, ErrNotFound) { fmt.Println("User not found") } } else { fmt.Println("User:", user) } } ``` > **errors.Is dan errors.As** > > Sejak Go 1.13, `errors.Is()` digunakan untuk membandingkan dengan sentinel error dan `errors.As()` untuk mengekstrak tipe error tertentu dari rantai error yang dibungkus. ## Goroutine: concurrency ringan Goroutine adalah thread ringan yang dikelola oleh runtime Go. Memulai goroutine hanya membutuhkan beberapa KB memori. ```go // goroutines.go package main import ( "fmt" "sync" "time" ) func worker(id int, wg *sync.WaitGroup) { defer wg.Done() // Decrement counter when done fmt.Printf("Worker %d starting\n", id) time.Sleep(time.Second) fmt.Printf("Worker %d done\n", id) } func main() { var wg sync.WaitGroup // Launch 5 goroutines for i := 1; i <= 5; i++ { wg.Add(1) go worker(i, &wg) // 'go' prefix launches the goroutine } // Wait for all goroutines to complete wg.Wait() fmt.Println("All workers completed") } ``` `sync.WaitGroup` memungkinkan menunggu penyelesaian beberapa goroutine sekaligus. Ini adalah pola dasar untuk paralelisme di Go. ## Channel: komunikasi antar goroutine Channel adalah saluran bertipe untuk komunikasi antar goroutine. Channel memungkinkan sinkronisasi yang aman dan pertukaran data. ```go // channels.go package main import ( "fmt" "time" ) func producer(ch chan<- int) { for i := 1; i <= 5; i++ { fmt.Println("Producing:", i) ch <- i // Send on channel time.Sleep(100 * time.Millisecond) } close(ch) // Close channel when done } func consumer(ch <-chan int, done chan<- bool) { for value := range ch { // Iterate until closed fmt.Println("Consuming:", value) } done <- true } func main() { ch := make(chan int) // Unbuffered channel done := make(chan bool) go producer(ch) go consumer(ch, done) <-done // Wait for consumer to finish fmt.Println("All done") } ``` ### Buffered channel dan select ```go // channels_advanced.go package main import ( "fmt" "time" ) func main() { // Buffered channel (capacity 3) buffered := make(chan int, 3) buffered <- 1 buffered <- 2 buffered <- 3 // buffered <- 4 // Would block since buffer is full fmt.Println(<-buffered) // 1 // Select: channel multiplexing ch1 := make(chan string) ch2 := make(chan string) go func() { time.Sleep(100 * time.Millisecond) ch1 <- "from ch1" }() go func() { time.Sleep(200 * time.Millisecond) ch2 <- "from ch2" }() // Wait for first available message for i := 0; i < 2; i++ { select { case msg1 := <-ch1: fmt.Println("Received:", msg1) case msg2 := <-ch2: fmt.Println("Received:", msg2) case <-time.After(500 * time.Millisecond): fmt.Println("Timeout!") } } } ``` > **Filosofi Go: CSP** > > Go mengikuti model CSP (Communicating Sequential Processes): "Jangan berkomunikasi dengan berbagi memori; bagikan memori dengan berkomunikasi." Channel mencegah race condition. ## Testing di Go Go menyertakan framework testing minimalis namun efektif. File test diakhiri dengan `_test.go`. ```go // calculator.go package calculator func Add(a, b int) int { return a + b } func Divide(a, b int) (int, error) { if b == 0 { return 0, errors.New("division by zero") } return a / b, nil } ``` ```go // calculator_test.go package calculator import ( "testing" ) // Basic test func TestAdd(t *testing.T) { result := Add(2, 3) expected := 5 if result != expected { t.Errorf("Add(2, 3) = %d; want %d", result, expected) } } // Table-driven tests (recommended pattern) func TestAddTableDriven(t *testing.T) { tests := []struct { name string a, b int expected int }{ {"positive numbers", 2, 3, 5}, {"negative numbers", -2, -3, -5}, {"zero", 0, 0, 0}, {"mixed", -5, 10, 5}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { result := Add(tt.a, tt.b) if result != tt.expected { t.Errorf("Add(%d, %d) = %d; want %d", tt.a, tt.b, result, tt.expected) } }) } } // Error test func TestDivideByZero(t *testing.T) { _, err := Divide(10, 0) if err == nil { t.Error("Expected error for division by zero") } } // Benchmark func BenchmarkAdd(b *testing.B) { for i := 0; i < b.N; i++ { Add(100, 200) } } ``` Test dijalankan dengan `go test ./...` dan benchmark dengan `go test -bench=.`. ## HTTP: server web minimalis Go unggul dalam membuat server HTTP berperforma tinggi menggunakan library standarnya. ```go // server.go package main import ( "encoding/json" "log" "net/http" ) type User struct { ID int `json:"id"` Name string `json:"name"` } func main() { // Simple route http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { w.Write([]byte("Hello, Go!")) }) // JSON route http.HandleFunc("/api/users", func(w http.ResponseWriter, r *http.Request) { users := []User{ {ID: 1, Name: "Alice"}, {ID: 2, Name: "Bob"}, } w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(users) }) // Route with method http.HandleFunc("/api/user", func(w http.ResponseWriter, r *http.Request) { switch r.Method { case "GET": w.Write([]byte("Get user")) case "POST": w.Write([]byte("Create user")) default: http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) } }) log.Println("Server starting on :8080") log.Fatal(http.ListenAndServe(":8080", nil)) } ``` Server ini mampu menangani ribuan koneksi bersamaan berkat goroutine. Setiap request secara otomatis diproses dalam goroutine-nya sendiri. ## Kesimpulan Go menawarkan pendekatan pragmatis untuk pengembangan backend: sintaks sederhana, kompilasi cepat, concurrency bawaan, dan tooling yang sangat baik. Bagi developer Java atau Python, transisi memerlukan penerimaan beberapa konvensi yang berbeda (penanganan error eksplisit, generics terbatas sebelum Go 1.18), tetapi manfaat dalam performa dan kemudahan pemeliharaan langsung terasa. ### Checklist untuk memulai - ✅ Instal Go dari situs resmi atau package manager - ✅ Kuasai perintah `go build`, `go run`, `go test`, `go fmt` - ✅ Pahami perbedaan antara slice dan array - ✅ Adopsi pola `if err != nil` untuk penanganan error - ✅ Gunakan goroutine dan channel untuk concurrency - ✅ Tulis table-driven test dengan package `testing` Ekosistem Go sudah matang, dengan framework populer seperti Gin, Echo, dan Fiber untuk pengembangan web, serta tool seperti Cobra untuk CLI. Dengan fondasi yang kuat ini, mengeksplorasi topik lanjutan seperti generics (Go 1.18+), package context, dan pola-pola concurrency menjadi lebih mudah. --- Source: SharpSkill (https://sharpskill.dev), tech interview preparation for your real stack. HTML version of this page: https://sharpskill.dev/id/blog/go/go-basics-java-python-developers