go-programming-expert · diff
v4.4.2 to v4.4.2
305 added, 205 removed. Audit A to A.
---
name: go-programming-expert
- description: "Expert-level skill for Go programming (Go 1.25+). Covers high-performance microservices, concurrency patterns, sqlc, net/http, Gin/Echo/Fiber, gRPC, and testing in English and Indonesian."
+ description: "Expert-level skill for Go programming (Go 1.24+ / 1.25+). Covers Swiss Table maps, weak pointers, synctest concurrency testing, tool directives, sqlc, net/http, and microservices in English and Indonesian."
author: "Roedy Rustam"
version: "4.4.2"
---
- # Go Programming Expert (Go 1.25 Edition)
+ # Go Programming Expert (Go 1.24 / 1.25 Edition)
[English](#english) | [Bahasa Indonesia](#bahasa-indonesia)
---
<a name="english"></a>
## English
### Orchestration & Integration
Connects and orchestrates with domain skills:
- **API Design & Protocols**: `api-design-expert`, `openapi-swagger-codegen-expert`, and `spec-driven-development-expert` for gRPC/protobuf contract design, REST endpoints, and RFC 9457 Problem Details.
- **Data Persistence**: `database-orm-expert` for sqlc type-safe query generation, `pgx/v5` connection pooling, and transactional data integrity.
- **Realtime & Streaming**: `sse-websocket-streaming-expert` for goroutine-backed streaming pipelines and low-latency WebSocket hubs.
- - **Testing & Quality**: `autonomous-tdd-debugger`, `e2e-testing-expert`, and `anti-slop` for executing `go test -v ./...`, table-driven tests, and enforcing strict Go error checking (`if err != nil`).
+ - **Testing & Quality**: `autonomous-tdd-debugger`, `e2e-testing-expert`, and `anti-slop` for executing `go test -v ./...`, synthetic clock testing via `testing/synctest`, and strict error checking (`if err != nil`).
- **Orchestration**: `brainstorming` and `zero-to-prod-orchestrator` (Phase 4: Backend & APIs).
### Description
- Expert-level Go development for building high-performance microservices, APIs, and CLI tools. Covers **Go 1.25** features (range-over-func iterators, generic type aliases, weak pointers), structured logging with `slog`, `net/http` with the new ServeMux patterns, Gin/Echo/Fiber frameworks, sqlc for type-safe SQL, gRPC, and production testing patterns.
+ Expert-level Go development for building high-performance microservices, concurrent pipelines, and production CLI tools. Covers **Go 1.24+ and 1.25** features (Swiss Table maps, weak pointers, `testing/synctest` deterministic concurrency testing, `tool` directives in `go.mod`), structured logging with `slog`, enhanced ServeMux pattern routing, sqlc type-safe SQL, and robust worker pools.
### Trigger Conditions
- - Writing Go 1.24+ / 1.25+ microservices or APIs.
- - Implementing concurrency patterns with goroutines, channels, and `sync` primitives.
- - Using structured logging with `log/slog`.
- - Building HTTP servers with `net/http` ServeMux (Go 1.22+) or Gin/Echo/Fiber.
- - Writing type-safe SQL with **sqlc** or using **GORM**.
- - Implementing gRPC services with protobuf.
- - Writing Go tests with the standard `testing` package + `testify`.
+ - Writing Go 1.24+ / 1.25+ microservices, APIs, or high-throughput distributed workers.
+ - Utilizing Go 1.24+ Swiss Table optimizations, weak pointers (`weak.Pointer`), or generic type aliases.
+ - Running deterministic concurrency tests using `testing/synctest` without flaky `time.Sleep`.
+ - Managing tool dependencies using the official `tool` directive in `go.mod`.
+ - Writing type-safe SQL with **sqlc** or connection-pooled PostgreSQL with **pgx/v5**.
+ - Building HTTP servers using standard `net/http` ServeMux method & wildcard routing.
- ### Go 1.25 — Key Features
+ ---
- #### Range-Over-Func (Go 1.22 → Stable in 1.24/1.25)
- Range over custom iterators — enables functional-style collection operations:
+ ### Go 1.24 / 1.25 Core Architectural Features
+
+ #### 1. Go 1.24+ Tool Dependencies in `go.mod`
+ Go 1.24 standardizes executable developer tooling dependencies directly in `go.mod`, eliminating legacy `tools.go` boilerplate:
+ ```bash
+ # Add a tool dependency
+ go get -tool github.com/sqlc-dev/sqlc/cmd/sqlc@latest
+ go get -tool github.com/golangci/golangci-lint/cmd/golangci-lint@latest
+
+ # Run the tool directly
+ go tool sqlc generate
+ go tool golangci-lint run
+ ```
```go
- // Define an iterator function
- func Fibonacci() iter.Seq[int] {
- return func(yield func(int) bool) {
- a, b := 0, 1
- for {
- if !yield(a) {
- return
- }
- a, b = b, a+b
- }
+ // go.mod snippet
+ tool (
+ github.com/sqlc-dev/sqlc/cmd/sqlc
+ github.com/golangci/golangci-lint/cmd/golangci-lint
+ )
+ ```
+
+ #### 2. Weak Pointers (`weak.Pointer`) & In-Memory Caching
+ Go 1.24 introduces `weak.Make()` and `weak.Pointer` to reference heap objects without preventing the Garbage Collector from freeing them:
+ ```go
+ package cache
+
+ import (
+ "sync"
+ "weak"
+ )
+
+ type Session struct {
+ UserID string
+ AuthToken string
+ }
+
+ type WeakSessionCache struct {
+ mu sync.RWMutex
+ store map[string]weak.Pointer[Session]
+ }
+
+ func NewWeakSessionCache() *WeakSessionCache {
+ return &WeakSessionCache{
+ store: make(map[string]weak.Pointer[Session]),
}
}
- // Range over it naturally
- for n := range Fibonacci() {
- if n > 100 {
- break
+ func (c *WeakSessionCache) Set(key string, session *Session) {
+ c.mu.Lock()
+ defer c.mu.Unlock()
+ c.store[key] = weak.Make(session)
+ }
+
+ func (c *WeakSessionCache) Get(key string) (*Session, bool) {
+ c.mu.RLock()
+ defer c.mu.RUnlock()
+
+ ptr, ok := c.store[key]
+ if !ok {
+ return nil, false
}
- fmt.Println(n)
+
+ // Dereference: returns nil if GC reclaimed the session
+ val := ptr.Value()
+ if val == nil {
+ return nil, false
+ }
+ return val, true
}
```
- #### Generic Type Aliases (Go 1.24/1.25)
+ #### 3. Deterministic Concurrency Testing with `testing/synctest`
+ Go 1.24 introduces `testing/synctest` (GOEXPERIMENT=synctest) to test concurrent code with virtual clocks:
```go
- // Type alias with generic parameters
- type Set[T comparable] = map[T]struct{}
- type Result[T any] = struct{ Value T; Err error }
+ package queue_test
- // Usage
- var s Set[string] = make(map[string]struct{})
- ```
+ import (
+ "context"
+ "testing"
+ "testing/synctest"
+ "time"
+ )
- #### Weak Pointers (Go 1.24/1.25)
- ```go
- import "weak"
+ func TestWorkerTimeout(t *testing.T) {
+ synctest.Run(func() {
+ ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
+ defer cancel()
- // Weak pointer — does not prevent GC collection
- ptr := weak.Make(&myStruct{})
- if val := ptr.Value(); val != nil {
- // Still alive
+ resultChan := make(chan string, 1)
+
+ go func() {
+ // Virtual time advances instantaneously when all goroutines in the bubble are idle
+ time.Sleep(10 * time.Second)
+ resultChan <- "completed"
+ }()
+
+ select {
+ case res := <-resultChan:
+ t.Fatalf("unexpected success: %s", res)
+ case <-ctx.Done():
+ // Successfully verified timeout without waiting 5 real seconds!
+ t.Log("Worker timed out deterministically")
+ }
+ })
}
```
- ### Structured Logging with `log/slog`
+ #### 4. Range-Over-Func Iterators (Go 1.24+ Standard)
+ Stream sequence processing with zero slice allocations:
```go
- package main
+ package iterator
- import (
- "log/slog"
- "os"
- )
+ import "iter"
- func main() {
- // Production JSON logger
- logger := slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{
- Level: slog.LevelInfo,
- AddSource: true, // include file:line
- }))
- slog.SetDefault(logger)
+ type Transaction struct {
+ ID string
+ Amount int64
+ Failed bool
+ }
- slog.Info("server started", "port", 8080, "env", "production")
- slog.Error("database connection failed", "error", err, "host", dbHost)
-
- // Grouped context
- reqLogger := logger.WithGroup("request").With(
- "trace_id", traceID,
- "user_id", userID,
- )
- reqLogger.Info("handler called", "method", r.Method, "path", r.URL.Path)
+ // Custom iterator filtering successful transactions
+ func SuccessfulTransactions(txs []Transaction) iter.Seq[Transaction] {
+ return func(yield func(Transaction) bool) {
+ for _, tx := range txs {
+ if !tx.Failed {
+ if !yield(tx) {
+ return // Stop iteration early if consumer breaks
+ }
+ }
+ }
+ }
}
+
+ // Consumer loop
+ func TotalRevenue(txs []Transaction) int64 {
+ var total int64
+ for tx := range SuccessfulTransactions(txs) {
+ total += tx.Amount
+ }
+ return total
+ }
```
- ### HTTP Server — net/http ServeMux (Go 1.22+)
- Go 1.22 upgraded the standard ServeMux with method-based routing and path parameters — reducing the need for external routers:
+ #### 5. HTTP Microservice with `net/http` ServeMux & `log/slog`
+ Zero-dependency HTTP server with method routing, path parameters, and structured JSON telemetry:
```go
package main
import (
"encoding/json"
- "net/http"
"log/slog"
+ "net/http"
+ "os"
)
+ type UserResponse struct {
+ ID string `json:"id"`
+ Role string `json:"role"`
+ }
+
func main() {
- mux := http.NewServeMux()
+ logger := slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{Level: slog.LevelInfo}))
+ slog.SetDefault(logger)
- // Method + path pattern matching (Go 1.22+)
- mux.HandleFunc("GET /api/users", listUsers)
- mux.HandleFunc("POST /api/users", createUser)
- mux.HandleFunc("GET /api/users/{id}", getUser) // path params
- mux.HandleFunc("DELETE /api/users/{id}", deleteUser)
+ mux := http.NewServeMux()
- slog.Info("starting server", "addr", ":8080")
- http.ListenAndServe(":8080", mux)
- }
+ // Method and path parameter matching
+ mux.HandleFunc("GET /health", func(w http.ResponseWriter, r *http.Request) {
+ w.WriteHeader(http.StatusOK)
+ w.Write([]byte(`{"status":"healthy"}`))
+ })
- func getUser(w http.ResponseWriter, r *http.Request) {
- id := r.PathValue("id") // Extract path parameter
- user := map[string]string{"id": id, "name": "Gopher"}
- w.Header().Set("Content-Type", "application/json")
- json.NewEncoder(w).Encode(user)
- }
- ```
+ mux.HandleFunc("GET /api/v1/users/{id}", func(w http.ResponseWriter, r *http.Request) {
+ userID := r.PathValue("id")
+ slog.Info("retrieving user profile", "user_id", userID, "remote_addr", r.RemoteAddr)
- ### Type-Safe SQL with sqlc
- ```bash
- # Install sqlc
- go install github.com/sqlc-dev/sqlc/cmd/sqlc@latest
+ w.Header().Set("Content-Type", "application/json")
+ json.NewEncoder(w).Encode(UserResponse{ID: userID, Role: "member"})
+ })
- # sqlc.yaml
- version: "2"
- sql:
- - engine: "postgresql"
- queries: "queries/"
- schema: "schema/"
- gen:
- go:
- package: "db"
- out: "internal/db"
- emit_json_tags: true
- emit_interface: true
+ slog.Info("starting production server", "port", 8080)
+ if err := http.ListenAndServe(":8080", mux); err != nil {
+ slog.Error("server exited", "error", err)
+ os.Exit(1)
+ }
+ }
```
+ #### 6. Type-Safe SQL with sqlc & pgx/v5
```sql
-- queries/users.sql
-- name: GetUser :one
- SELECT * FROM users WHERE id = $1 LIMIT 1;
-
- -- name: ListUsers :many
- SELECT * FROM users ORDER BY created_at DESC LIMIT $1 OFFSET $2;
+ SELECT id, name, email, created_at FROM users WHERE id = $1 LIMIT 1;
-- name: CreateUser :one
- INSERT INTO users (name, email) VALUES ($1, $2) RETURNING *;
- ```
-
- ```go
- // Generated type-safe Go code (used in handlers)
- user, err := queries.GetUser(ctx, userID) // Fully typed!
- users, err := queries.ListUsers(ctx, db.ListUsersParams{Limit: 20, Offset: 0})
- ```
-
- ### Concurrency Patterns
-
- #### errgroup for Parallel Work
- ```go
- import "golang.org/x/sync/errgroup"
-
- g, ctx := errgroup.WithContext(context.Background())
-
- g.Go(func() error { return fetchA(ctx) })
- g.Go(func() error { return fetchB(ctx) })
-
- if err := g.Wait(); err != nil {
- // First error from any goroutine
- return fmt.Errorf("parallel fetch: %w", err)
- }
- ```
-
- #### Worker Pool Pattern
- ```go
- func workerPool(jobs <-chan Job, results chan<- Result, numWorkers int) {
- var wg sync.WaitGroup
- for range numWorkers {
- wg.Add(1)
- go func() {
- defer wg.Done()
- for job := range jobs {
- results <- process(job)
- }
- }()
- }
- wg.Wait()
- close(results)
- }
+ INSERT INTO users (name, email) VALUES ($1, $2) RETURNING id, name, email, created_at;
```
- ### Testing Best Practices
```go
- package user_test
+ // Consuming generated sqlc code
+ package handler
import (
- "testing"
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
+ "context"
+ "example/internal/db"
+ "github.com/jackc/pgx/v5/pgxpool"
)
- func TestGetUser(t *testing.T) {
- t.Parallel() // Always parallelize independent tests
-
- // Table-driven tests
- tests := []struct{
- name string
- userID string
- want *User
- wantErr bool
- }{
- {"valid user", "user-123", &User{ID: "user-123"}, false},
- {"not found", "missing", nil, true},
- }
+ type UserHandler struct {
+ queries *db.Queries
+ pool *pgxpool.Pool
+ }
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- t.Parallel()
- got, err := GetUser(context.Background(), tt.userID)
- if tt.wantErr {
- require.Error(t, err)
- return
- }
- require.NoError(t, err)
- assert.Equal(t, tt.want.ID, got.ID)
- })
+ func (h *UserHandler) Create(ctx context.Context, name, email string) (*db.User, error) {
+ user, err := h.queries.CreateUser(ctx, db.CreateUserParams{
+ Name: name,
+ Email: email,
+ })
+ if err != nil {
+ return nil, err
}
+ return &user, nil
}
```
---
<a name="bahasa-indonesia"></a>
## Bahasa Indonesia
### Integrasi Orkestrasi
Terhubung dan mengorkestrasi bersama skill domain:
- **Desain & Protokol API**: `api-design-expert`, `openapi-swagger-codegen-expert`, dan `spec-driven-development-expert` untuk kontrak gRPC/protobuf, endpoint REST, dan spesifikasi RFC 9457 Problem Details.
- **Persistensi Data**: `database-orm-expert` untuk pembuatan query type-safe via sqlc, connection pooling `pgx/v5`, dan integritas transaksi database.
- **Realtime & Streaming**: `sse-websocket-streaming-expert` untuk pipeline streaming berbasis channel goroutine dan hub WebSocket berlatensi rendah.
- - **Pengujian & Kualitas**: `autonomous-tdd-debugger`, `e2e-testing-expert`, dan `anti-slop` untuk eksekusi `go test -v ./...`, table-driven tests, dan penegakan penanganan error ketat (`if err != nil`).
+ - **Pengujian & Kualitas**: `autonomous-tdd-debugger`, `e2e-testing-expert`, dan `anti-slop` untuk eksekusi `go test -v ./...`, pengujian jam sintetis dengan `testing/synctest`, dan penegakan penanganan error ketat (`if err != nil`).
- **Orkestrator Utama**: `brainstorming` dan `zero-to-prod-orchestrator` (Fase 4: Backend & APIs).
### Deskripsi
- Panduan Go tingkat ahli untuk membangun microservices, API, dan CLI tool berkinerja tinggi. Mencakup fitur **Go 1.25** (range-over-func, generic type alias, weak pointer), structured logging dengan `slog`, ServeMux `net/http` dengan pola baru (Go 1.22+), framework Gin/Echo/Fiber, sqlc untuk SQL type-safe, gRPC, dan pola pengujian produksi.
+ Panduan Go tingkat ahli untuk membangun microservices, pipeline konkurensi, dan CLI tool berkinerja tinggi. Mencakup fitur **Go 1.24+ dan 1.25** (optimasi hash map Swiss Table, weak pointer, pengujian deterministik `testing/synctest`, direktif `tool` di `go.mod`), structured logging dengan `slog`, ServeMux `net/http` dengan pola pencocokan rute modern, sqlc untuk SQL type-safe, dan worker pool tangguh.
### Kondisi Pemicu
- - Menulis microservices atau API Go 1.24+/1.25+.
- - Mengimplementasikan pola konkurensi dengan goroutine, channel, dan primitif `sync`.
- - Menggunakan structured logging dengan `log/slog`.
- - Membangun HTTP server dengan ServeMux `net/http` (Go 1.22+) atau Gin/Echo/Fiber.
- - Menulis SQL type-safe dengan **sqlc** atau GORM.
- - Mengimplementasikan layanan gRPC dengan protobuf.
+ - Menulis microservices atau backend API Go 1.24+/1.25+ berthroughput tinggi.
+ - Menggunakan optimasi hash map Swiss Table, weak pointer (`weak.Pointer`), atau generic type alias.
+ - Menjalankan pengujian konkurensi deterministik menggunakan `testing/synctest` tanpa `time.Sleep` yang rapuh.
+ - Mengelola dependensi perkakas pengembang secara resmi melalui direktif `tool` di `go.mod`.
+ - Menulis SQL type-safe dengan **sqlc** atau koneksi database PostgreSQL dengan **pgx/v5**.
- ### Go 1.25 — Fitur Utama
+ ---
- #### Range-Over-Func (Stabil di 1.24/1.25)
- Go 1.24/1.25 menstabilkan range over iterator function — memungkinkan koleksi gaya fungsional yang idiomatis tanpa mengekspos slice internal.
+ ### Fitur Arsitektur Inti Go 1.24 / 1.25
- #### Generic Type Alias
- Go 1.24/1.25 memungkinkan alias tipe dengan parameter generic, meningkatkan komposibilitas tipe.
+ #### 1. Direktif Perkakas `tool` di `go.mod` (Standar Go 1.24+)
+ Go 1.24 menstandardisasi pelacakan perkakas dependensi biner langsung di dalam `go.mod`, menghapus trik lawas `tools.go`:
+ ```bash
+ # Menambahkan dependensi tool
+ go get -tool github.com/sqlc-dev/sqlc/cmd/sqlc@latest
+ go get -tool github.com/golangci/golangci-lint/cmd/golangci-lint@latest
- #### Weak Pointer
- `weak.Make()` membuat pointer lemah yang tidak mencegah GC mengumpulkan objek — berguna untuk cache.
+ # Menjalankan tool langsung
+ go tool sqlc generate
+ go tool golangci-lint run
+ ```
- ### Structured Logging dengan `log/slog`
- Paket `log/slog` bawaan Go (sejak 1.21) mendukung output JSON terstruktur, level log, dan pengelompokan atribut. Gunakan sebagai standar logging di semua proyek Go baru.
+ #### 2. Weak Pointer (`weak.Pointer`) untuk Cache Memori Ramah GC
+ Go 1.24 menyediakan `weak.Make()` dan `weak.Pointer` untuk menunjuk memori tanpa menghalangi Garbage Collector membersihkannya:
+ ```go
+ package cache
- ### HTTP Server — net/http ServeMux (Go 1.22+)
- ServeMux Go 1.22 mendukung pencocokan berdasarkan metode HTTP dan parameter path — mengurangi kebutuhan router eksternal untuk API sederhana.
+ import (
+ "sync"
+ "weak"
+ )
- ### SQL Type-Safe dengan sqlc
- `sqlc` menghasilkan kode Go yang fully typed dari query SQL dan skema database — menghilangkan kebutuhan ORM untuk sebagian besar kasus.
+ type SesiPengguna struct {
+ UserID string
+ AuthToken string
+ }
- ### Pola Konkurensi
+ type CacheSesiWeak struct {
+ mu sync.RWMutex
+ store map[string]weak.Pointer[SesiPengguna]
+ }
- #### errgroup
- Gunakan `errgroup.WithContext()` dari `golang.org/x/sync/errgroup` untuk menjalankan goroutine paralel dan mengumpulkan error pertama secara aman.
+ func NewCacheSesiWeak() *CacheSesiWeak {
+ return &CacheSesiWeak{
+ store: make(map[string]weak.Pointer[SesiPengguna]),
+ }
+ }
- #### Worker Pool
- Gunakan pola worker pool dengan channel untuk memproses pekerjaan secara paralel dengan jumlah goroutine yang terkendali.
+ func (c *CacheSesiWeak) Set(kunci string, sesi *SesiPengguna) {
+ c.mu.Lock()
+ defer c.mu.Unlock()
+ c.store[kunci] = weak.Make(sesi)
+ }
- ### Best Practices Pengujian
- - Gunakan `t.Parallel()` untuk semua test independen.
- - Gunakan table-driven tests untuk menguji banyak skenario dengan kode minimal.
- - Gunakan `testify/assert` dan `testify/require` untuk assertion yang ekspresif.
+ func (c *CacheSesiWeak) Get(kunci string) (*SesiPengguna, bool) {
+ c.mu.RLock()
+ defer c.mu.RUnlock()
+
+ ptr, ada := c.store[kunci]
+ if !ada {
+ return nil, false
+ }
+
+ // Dereferensi: mengembalikan nil jika GC telah mengumpulkan memori sesi
+ nilai := ptr.Value()
+ if nilai == nil {
+ return nil, false
+ }
+ return nilai, true
+ }
+ ```
+
+ #### 3. Pengujian Konkurensi Determinis Menggunakan `testing/synctest`
+ Go 1.24 memperkenalkan `testing/synctest` untuk menguji alur waktu asinkron dengan jam virtual seketika:
+ ```go
+ package antrean_test
+
+ import (
+ "context"
+ "testing"
+ "testing/synctest"
+ "time"
+ )
+
+ func TestBatasWaktuPekerja(t *testing.T) {
+ synctest.Run(func() {
+ ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
+ defer cancel()
+
+ hasilChan := make(chan string, 1)
+
+ go func() {
+ // Waktu virtual maju seketika saat seluruh goroutine menganggur
+ time.Sleep(10 * time.Second)
+ hasilChan <- "sukses"
+ }()
+
+ select {
+ case hasil := <-hasilChan:
+ t.Fatalf("alur gagal: menerima data di luar batas waktu %s", hasil)
+ case <-ctx.Done():
+ // Berhasil diverifikasi tanpa menunggu 5 detik waktu riil!
+ t.Log("Pekerja berhasil timeout secara deterministik")
+ }
+ })
+ }
+ ```
+
+ #### 4. Iterator Range-Over-Func
+ Pemrosesan koleksi secara streaming tanpa alokasi memori berlebih:
+ ```go
+ package iterator
+
+ import "iter"
+
+ type Transaksi struct {
+ ID string
+ Nominal int64
+ Gagal bool
+ }
+
+ func TransaksiSukses(daftar []Transaksi) iter.Seq[Transaksi] {
+ return func(yield func(Transaksi) bool) {
+ for _, tx := range daftar {
+ if !tx.Gagal {
+ if !yield(tx) {
+ return
+ }
+ }
+ }
+ }
+ }
+ ```