Go language fundamentals, concurrency, error handling, and project patterns.
// Spawn goroutine
go func() {
result := process(data)
resultChan <- result
}()
// Unbuffered channel (synchronous)
ch := make(chan int)
// Buffered channel
ch := make(chan int, 100)
// Send and receive
ch <- value // Send
value := <-ch // Receive
// Select for multiplexing
select {
case msg := <-msgChan:
handle(msg)
case <-time.After(5 * time.Second):
return errors.New("timeout")
case <-ctx.Done():
return ctx.Err()
}
Patterns:
// Return errors, don't panic
func fetchUser(id int) (*User, error) {
user, err := db.FindUser(id)
if err != nil {
return nil, fmt.Errorf("fetch user %d: %w", id, err)
}
return user, nil
}
// Error wrapping (Go 1.13+)
if errors.Is(err, sql.ErrNoRows) {
return nil, ErrNotFound
}
// Type assertion for custom errors
var apiErr *APIError
if errors.As(err, &apiErr) {
log.Printf("API error: %d", apiErr.Code)
}
// Sentinel errors
var ErrNotFound = errors.New("not found")
Rules:
fmt.Errorf("operation: %w", err)errors.Is and errors.As for comparisonpanic for recoverable errors// Small interfaces
type Reader interface {
Read(p []byte) (n int, err error)
}
type Writer interface {
Write(p []byte) (n int, err error)
}
// Composition
type ReadWriter interface {
Reader
Writer
}
// Accept interfaces, return structs
func ProcessData(r Reader) (*Result, error) {
data, err := io.ReadAll(r)
// ...
return &Result{}, nil
}
Best Practices:
interface{} sparingly; prefer generics (Go 1.18+)// Pass context as first parameter
func fetchData(ctx context.Context, id int) (*Data, error) {
// Respect cancellation
select {
case <-ctx.Done():
return nil, ctx.Err()
default:
}
// Use context with HTTP requests
req, _ := http.NewRequestWithContext(ctx, "GET", url, nil)
return client.Do(req)
}
// Add timeout
ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
defer cancel()
// Add values (use sparingly)
ctx = context.WithValue(ctx, requestIDKey, reqID)
Rules:
project/
├── cmd/
│ └── myapp/
│ └── main.go # Entry point
├── internal/ # Private packages
│ ├── handler/
│ ├── service/
│ └── repository/
├── pkg/ # Public packages
├── api/ # API definitions (proto, OpenAPI)
├── configs/
├── go.mod
└── go.sum
Conventions:
internal/ prevents external importscmd/ for multiple entry points// Table-driven tests
func TestAdd(t *testing.T) {
tests := []struct {
name string
a, b int
expected int
}{
{"positive", 1, 2, 3},
{"negative", -1, -1, -2},
{"zero", 0, 0, 0},
}
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)
}
})
}
}
// Parallel tests
func TestParallel(t *testing.T) {
t.Parallel()
// ...
}
// Benchmarks
func BenchmarkProcess(b *testing.B) {
for i := 0; i < b.N; i++ {
Process(data)
}
}
make([]T, 0, expectedLen)sync.Poolgo tool pprof before optimizinggo build -gcflags='-m' to check heap escapesstrings.Builder not + concatenationSearch for places (restaurants, cafes, etc.) via Google Places API proxy on localhost.
Interact with GitHub using the `gh` CLI. Use `gh issue`, `gh pr`, `gh run`, and `gh api` for issues, PRs, CI runs, and advanced queries.
Create or update AgentSkills. Use when designing, structuring, or packaging skills with scripts, references, and assets.
Start voice calls via the OpenClaw voice-call plugin.
Notion API for creating and managing pages, databases, and blocks.
Gemini CLI for one-shot Q&A, summaries, and generation.
Category:developer