opção

Padrões idiomáticos do Go, melhores práticas e convenções para a criação de aplicativos em Go robustos, eficientes e fáceis de manter.

...Expandir tudo
41
Tempo atualizado 29 de Junho de 2026

Sobre golang-patterns

golang-patterns é uma skill de IA reutilizável focada em um fluxo de trabalho específico. nome: golang-patterns

A habilidade reúne instruções, convenções e orientações específicas para cada tarefa, para que um agente possa executar o trabalho de forma mais consistente. descrição: Padrões idiomáticos do Go, melhores práticas e convenções para a criação de aplicativos em Go robustos, eficientes e fáceis de manter. Padrões idiomáticos do Go e melhores práticas para a criação de aplicativos robustos, eficientes e fáceis de manter. - Escrever novo código em Go

Na prática, esta habilidade é mais adequada para usuários que precisam de execução repetível com menos etapas de configuração e menos ambiguidade. - Refatoração de código Go existente - Projeto de pacotes/módulos Go O Go privilegia a simplicidade em detrimento da sofisticação. O código deve ser óbvio e fácil de ler. // Bom: Claro e direto

Perguntas frequentes

Em que o “ golang-patterns ” ajuda?

golang-patterns Ajuda os agentes a seguirem um fluxo de trabalho focado, descrito na documentação de origem, reduzindo a ambiguidade e mantendo a execução alinhada com a tarefa pretendida.

Quando essa skill deve ser usada?

Use-a quando a tarefa corresponder ao fluxo de trabalho, domínio ou regras operacionais descritas na documentação da habilidade, especialmente quando a execução consistente for importante.

Quais são as principais limitações?

A habilidade é limitada pela qualidade e pelo escopo de suas instruções de origem. Se a documentação subjacente estiver incompleta, o agente ainda pode precisar de contexto adicional ou validação manual.

Ver no GitHub

Go Development Patterns

Idiomatic Go patterns and best practices for building robust, efficient, and maintainable applications.

When to Activate

  • Writing new Go code
  • Reviewing Go code
  • Refactoring existing Go code
  • Designing Go packages/modules

Core Principles

1. Simplicity and Clarity

Go favors simplicity over cleverness. Code should be obvious and easy to read.

// Good: Clear and directfunc GetUser(id string) (*User, error) {    user, err := db.FindUser(id)    if err != nil {        return nil, fmt.Errorf("get user %s: %w", id, err)    }    return user, nil}// Bad: Overly cleverfunc GetUser(id string) (*User, error) {    return func() (*User, error) {        if u, e := db.FindUser(id); e == nil {            return u, nil        } else {            return nil, e        }    }()}

2. Make the Zero Value Useful

Design types so their zero value is immediately usable without initialization.

// Good: Zero value is usefultype Counter struct {    mu    sync.Mutex    count int // zero value is 0, ready to use}func (c *Counter) Inc() {    c.mu.Lock()    c.count++    c.mu.Unlock()}// Good: bytes.Buffer works with zero valuevar buf bytes.Bufferbuf.WriteString("hello")// Bad: Requires initializationtype BadCounter struct {    counts map[string]int // nil map will panic}

3. Accept Interfaces, Return Structs

Functions should accept interface parameters and return concrete types.

// Good: Accepts interface, returns concrete typefunc ProcessData(r io.Reader) (*Result, error) {    data, err := io.ReadAll(r)    if err != nil {        return nil, err    }    return &Result{Data: data}, nil}// Bad: Returns interface (hides implementation details unnecessarily)func ProcessData(r io.Reader) (io.Reader, error) {    // ...}

Error Handling Patterns

Error Wrapping with Context

// Good: Wrap errors with contextfunc LoadConfig(path string) (*Config, error) {    data, err := os.ReadFile(path)    if err != nil {        return nil, fmt.Errorf("load config %s: %w", path, err)    }    var cfg Config    if err := json.Unmarshal(data, &cfg); err != nil {        return nil, fmt.Errorf("parse config %s: %w", path, err)    }    return &cfg, nil}

Custom Error Types

// Define domain-specific errorstype ValidationError struct {    Field   string    Message string}func (e *ValidationError) Error() string {    return fmt.Sprintf("validation failed on %s: %s", e.Field, e.Message)}// Sentinel errors for common casesvar (    ErrNotFound     = errors.New("resource not found")    ErrUnauthorized = errors.New("unauthorized")    ErrInvalidInput = errors.New("invalid input"))

Error Checking with errors.Is and errors.As

func HandleError(err error) {    // Check for specific error    if errors.Is(err, sql.ErrNoRows) {        log.Println("No records found")        return    }    // Check for error type    var validationErr *ValidationError    if errors.As(err, &validationErr) {        log.Printf("Validation error on field %s: %s",            validationErr.Field, validationErr.Message)        return    }    // Unknown error    log.Printf("Unexpected error: %v", err)}

Never Ignore Errors

// Bad: Ignoring error with blank identifierresult, _ := doSomething()// Good: Handle or explicitly document why it's safe to ignoreresult, err := doSomething()if err != nil {    return err}// Acceptable: When error truly doesn't matter (rare)_ = writer.Close() // Best-effort cleanup, error logged elsewhere

Concurrency Patterns

Worker Pool

func WorkerPool(jobs <-chan Job, results chan<- Result, numWorkers int) {    var wg sync.WaitGroup    for i := 0; i < numWorkers; i++ {        wg.Add(1)        go func() {            defer wg.Done()            for job := range jobs {                results <- process(job)            }        }()    }    wg.Wait()    close(results)}

Context for Cancellation and Timeouts

func FetchWithTimeout(ctx context.Context, url string) ([]byte, error) {    ctx, cancel := context.WithTimeout(ctx, 5*time.Second)    defer cancel()    req, err := http.NewRequestWithContext(ctx, "GET", url, nil)    if err != nil {        return nil, fmt.Errorf("create request: %w", err)    }    resp, err := http.DefaultClient.Do(req)    if err != nil {        return nil, fmt.Errorf("fetch %s: %w", url, err)    }    defer resp.Body.Close()    return io.ReadAll(resp.Body)}

Graceful Shutdown

func GracefulShutdown(server *http.Server) {    quit := make(chan os.Signal, 1)    signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)    <-quit    log.Println("Shutting down server...")    ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)    defer cancel()    if err := server.Shutdown(ctx); err != nil {        log.Fatalf("Server forced to shutdown: %v", err)    }    log.Println("Server exited")}

errgroup for Coordinated Goroutines

import "golang.org/x/sync/errgroup"func FetchAll(ctx context.Context, urls []string) ([][]byte, error) {    g, ctx := errgroup.WithContext(ctx)    results := make([][]byte, len(urls))    for i, url := range urls {        i, url := i, url // Capture loop variables        g.Go(func() error {            data, err := FetchWithTimeout(ctx, url)            if err != nil {                return err            }            results[i] = data            return nil        })    }    if err := g.Wait(); err != nil {        return nil, err    }    return results, nil}

Avoiding Goroutine Leaks

// Bad: Goroutine leak if context is cancelledfunc leakyFetch(ctx context.Context, url string) <-chan []byte {    ch := make(chan []byte)    go func() {        data, _ := fetch(url)        ch <- data // Blocks forever if no receiver    }()    return ch}// Good: Properly handles cancellationfunc safeFetch(ctx context.Context, url string) <-chan []byte {    ch := make(chan []byte, 1) // Buffered channel    go func() {        data, err := fetch(url)        if err != nil {            return        }        select {        case ch <- data:        case <-ctx.Done():        }    }()    return ch}

Interface Design

Small, Focused Interfaces

// Good: Single-method interfacestype Reader interface {    Read(p []byte) (n int, err error)}type Writer interface {    Write(p []byte) (n int, err error)}type Closer interface {    Close() error}// Compose interfaces as neededtype ReadWriteCloser interface {    Reader    Writer    Closer}

Define Interfaces Where They're Used

// In the consumer package, not the providerpackage service// UserStore defines what this service needstype UserStore interface {    GetUser(id string) (*User, error)    SaveUser(user *User) error}type Service struct {    store UserStore}// Concrete implementation can be in another package// It doesn't need to know about this interface

Optional Behavior with Type Assertions

type Flusher interface {    Flush() error}func WriteAndFlush(w io.Writer, data []byte) error {    if _, err := w.Write(data); err != nil {        return err    }    // Flush if supported    if f, ok := w.(Flusher); ok {        return f.Flush()    }    return nil}

Package Organization

Standard Project Layout

myproject/├── cmd/│   └── myapp/│       └── main.go           # Entry point├── internal/│   ├── handler/              # HTTP handlers│   ├── service/              # Business logic│   ├── repository/           # Data access│   └── config/               # Configuration├── pkg/│   └── client/               # Public API client├── api/│   └── v1/                   # API definitions (proto, OpenAPI)├── testdata/                 # Test fixtures├── go.mod├── go.sum└── Makefile

Package Naming

// Good: Short, lowercase, no underscorespackage httppackage jsonpackage user// Bad: Verbose, mixed case, or redundantpackage httpHandlerpackage json_parserpackage userService // Redundant 'Service' suffix

Avoid Package-Level State

// Bad: Global mutable statevar db *sql.DBfunc init() {    db, _ = sql.Open("postgres", os.Getenv("DATABASE_URL"))}// Good: Dependency injectiontype Server struct {    db *sql.DB}func NewServer(db *sql.DB) *Server {    return &Server{db: db}}

Struct Design

Functional Options Pattern

type Server struct {    addr    string    timeout time.Duration    logger  *log.Logger}type Option func(*Server)func WithTimeout(d time.Duration) Option {    return func(s *Server) {        s.timeout = d    }}func WithLogger(l *log.Logger) Option {    return func(s *Server) {        s.logger = l    }}func NewServer(addr string, opts ...Option) *Server {    s := &Server{        addr:    addr,        timeout: 30 * time.Second, // default        logger:  log.Default(),    // default    }    for _, opt := range opts {        opt(s)    }    return s}// Usageserver := NewServer(":8080",    WithTimeout(60*time.Second),    WithLogger(customLogger),)

Embedding for Composition

type Logger struct {    prefix string}func (l *Logger) Log(msg string) {    fmt.Printf("[%s] %s", l.prefix, msg)}type Server struct {    *Logger // Embedding - Server gets Log method    addr    string}func NewServer(addr string) *Server {    return &Server{        Logger: &Logger{prefix: "SERVER"},        addr:   addr,    }}// Usages := NewServer(":8080")s.Log("Starting...") // Calls embedded Logger.Log

Memory and Performance

Preallocate Slices When Size is Known

// Bad: Grows slice multiple timesfunc processItems(items []Item) []Result {    var results []Result    for _, item := range items {        results = append(results, process(item))    }    return results}// Good: Single allocationfunc processItems(items []Item) []Result {    results := make([]Result, 0, len(items))    for _, item := range items {        results = append(results, process(item))    }    return results}

Use sync.Pool for Frequent Allocations

var bufferPool = sync.Pool{    New: func() interface{} {        return new(bytes.Buffer)    },}func ProcessRequest(data []byte) []byte {    buf := bufferPool.Get().(*bytes.Buffer)    defer func() {        buf.Reset()        bufferPool.Put(buf)    }()    buf.Write(data)    // Process...    return buf.Bytes()}

Avoid String Concatenation in Loops

// Bad: Creates many string allocationsfunc join(parts []string) string {    var result string    for _, p := range parts {        result += p + ","    }    return result}// Good: Single allocation with strings.Builderfunc join(parts []string) string {    var sb strings.Builder    for i, p := range parts {        if i > 0 {            sb.WriteString(",")        }        sb.WriteString(p)    }    return sb.String()}// Best: Use standard libraryfunc join(parts []string) string {    return strings.Join(parts, ",")}

Go Tooling Integration

Essential Commands

# Build and rungo build ./...go run ./cmd/myapp# Testinggo test ./...go test -race ./...go test -cover ./...# Static analysisgo vet ./...staticcheck ./...golangci-lint run# Module managementgo mod tidygo mod verify# Formattinggofmt -w .goimports -w .

Recommended Linter Configuration (.golangci.yml)

linters:  enable:    - errcheck    - gosimple    - govet    - ineffassign    - staticcheck    - unused    - gofmt    - goimports    - misspell    - unconvert    - unparamlinters-settings:  errcheck:    check-type-assertions: true  govet:    check-shadowing: trueissues:  exclude-use-default: false

Quick Reference: Go Idioms

IdiomDescription
Accept interfaces, return structsFunctions accept interface params, return concrete types
Errors are valuesTreat errors as first-class values, not exceptions
Don't communicate by sharing memoryUse channels for coordination between goroutines
Make the zero value usefulTypes should work without explicit initialization
A little copying is better than a little dependencyAvoid unnecessary external dependencies
Clear is better than cleverPrioritize readability over cleverness
gofmt is no one's favorite but everyone's friendAlways format with gofmt/goimports
Return earlyHandle errors first, keep happy path unindented

Anti-Patterns to Avoid

// Bad: Naked returns in long functionsfunc process() (result int, err error) {    // ... 50 lines ...    return // What is being returned?}// Bad: Using panic for control flowfunc GetUser(id string) *User {    user, err := db.Find(id)    if err != nil {        panic(err) // Don't do this    }    return user}// Bad: Passing context in structtype Request struct {    ctx context.Context // Context should be first param    ID  string}// Good: Context as first parameterfunc ProcessRequest(ctx context.Context, id string) error {    // ...}// Bad: Mixing value and pointer receiverstype Counter struct{ n int }func (c Counter) Value() int { return c.n }    // Value receiverfunc (c *Counter) Increment() { c.n++ }        // Pointer receiver// Pick one style and be consistent

Remember: Go code should be boring in the best way - predictable, consistent, and easy to understand. When in doubt, keep it simple.

Todos os arquivos

1 arquivos
SKILL.md 13.7k
Ver

Instalar golang-patterns

Baixe e descompacte os arquivos de habilidades no diretório .claude/skills/.

Baixar ZIP

Clone o repositório e copie os arquivos da habilidade para o seu projeto.

git clone https://github.com/affaan-m/ECC/blob/main/skills/golang-patterns/SKILL.md # Copy SKILL.md to your .claude/skills/ directory

Copiar Copiar
Configuração rápida: Copie a pasta da habilidade para .claude/skills/. O Claude detectará e utilizará automaticamente a habilidade

Habilidades relacionadas

golang-structs-interfaces
Tempo atualizado 29 de Junho de 2026
OR