Skip to content
Back to skills

Go Idioms

ASecurity

Idiomatic Go patterns for errors, interfaces, concurrency, and packages. Use when: - Writing or reviewing Go code - Designing interfaces or package structure - Implementing concurrency patterns - Handling errors and context propagation - Structuring Go projects Keywords: Go, golang, error wrapping, interface design, goroutine, channel, context, package design, dependency injection, race condition

  • 666 stars
  • 0 votes
  • 0 copies
  • 4 views
  • Added February 8, 2026
toolsgosqlapi

Works with

  • cli
  • api

Security analysis

A100/100

Scanned February 12, 2026

npx -y skills add majiayu000/claude-skill-registry --skill go-idioms --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Go Idioms?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Go Idioms
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/majiayu000-go-idioms/badge)](https://www.skillsdirectory.com/skills/majiayu000-go-idioms)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: go-idioms
description: |
  Idiomatic Go patterns for errors, interfaces, concurrency, and packages. Use when:
  - Writing or reviewing Go code
  - Designing interfaces or package structure
  - Implementing concurrency patterns
  - Handling errors and context propagation
  - Structuring Go projects
  Keywords: Go, golang, error wrapping, interface design, goroutine, channel,
  context, package design, dependency injection, race condition
---

# Go Idioms

Boring, explicit, race-safe Go. Accept interfaces, return structs.

## Error Handling

**Always wrap with context at package boundaries:**
```go
// Use %w to preserve error chain
return fmt.Errorf("fetching user %s: %w", userID, err)

// Check wrapped errors
if errors.Is(err, sql.ErrNoRows) { ... }

var paymentErr *PaymentError
if errors.As(err, &paymentErr) { ... }
```

Never: `%v` (loses type), raw errors from exported functions, generic context.

## Interface Design

**Define interfaces in consuming package, not provider:**
```go
// notification/sender.go (consumer defines interface)
type EmailSender interface {
    Send(ctx context.Context, to, subject, body string) error
}

// email/client.go (provider implements)
type Client struct { ... }
func (c *Client) Send(ctx context.Context, to, subject, body string) error { ... }
```

**Small interfaces (1-3 methods). Compose larger from smaller:**
```go
type Reader interface { Read(p []byte) (n int, err error) }
type Writer interface { Write(p []byte) (n int, err error) }
type ReadWriter interface { Reader; Writer }
```

**Compile-time verification:**
```go
var _ EmailSender = (*Client)(nil)
```

## Concurrency

**Always propagate context:**
```go
func FetchData(ctx context.Context) ([]byte, error) {
    select {
    case <-ctx.Done():
        return nil, ctx.Err()
    case result := <-dataChan:
        return result, nil
    }
}
```

**Bounded concurrency (semaphore):**
```go
sem := make(chan struct{}, 10)
for _, item := range items {
    sem <- struct{}{}
    go func(item Item) {
        defer func() { <-sem }()
        process(item)
    }(item)
}
```

**Race safety:** Always run `go test -race ./...`

## Package Design

```
internal/
  user/          # Domain: single purpose
    user.go
    service.go
    repository.go
  order/         # Another domain
  app/           # Dependency wiring
cmd/
  api/           # Entry points
```

**Rules:**
- Single purpose per package
- No generic names (utils, helpers, common)
- No circular dependencies
- Export only what's necessary

## Dependency Injection

```go
// Constructor accepts interfaces
func NewUserService(repo UserRepository, mailer EmailSender) *UserService {
    return &UserService{repo: repo, mailer: mailer}
}

// Wire in app/ package
func NewApp() *App {
    repo := postgres.NewUserRepo(db)
    mailer := sendgrid.NewClient(apiKey)
    userSvc := user.NewUserService(repo, mailer)
    return &App{UserService: userSvc}
}
```

## Anti-Patterns

- Goroutines without cancellation path (leaks)
- Monolithic interfaces (10+ methods)
- Framework-like inheritance patterns
- Reflection when explicit types work
- Global singletons for dependencies
- Generic everything (overuse of generics)
- `interface{}` / `any` without justification

## Embrace Boring

- Explicit error handling at each step
- Standard library first (`map`, `[]T`, `sort.Slice`)
- Table-driven tests
- Struct composition, not inheritance
- Clear, verbose code over clever code

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.