viccom/golang-design-patterns

Padrões idiomáticos de design em Go — opções funcionais, construtores, fluxo de erros, gerenciamento de recursos, desligamento gradual, resiliência, arquitetura, injeção de dependência, manipulação de dados, streaming e mais.

O que é golang-design-patterns?

Esta skill define padrões de design Go idiomáticos para código de produção, com foco em simplicidade e explicitude. Ela abrange uma ampla gama de tópicos, incluindo construtores com opções funcionais (preferidos em relação ao padrão Builder), gerenciamento de recursos com `defer Close()` imediatamente após a abertura, fluxo de erros com tratamento antecipado e retorno precoce, e padrões de resiliência como timeouts e retry com verificação de contexto. A skill também aborda manipulação eficiente de dados (uso de `strings.Builder`, `[]byte` vs `string`, iteradores Go 1.23+), enumerações que começam em 1, compilação de regexp uma vez no nível do pacote, e o uso de `//go:embed` para ativos estáticos. Ela é útil para desenvolvedores Go que precisam aplicar padrões arquiteturais de forma pragmática, projetar APIs de construtores, configurar desligamento gradual, implementar padrões de resiliência, ou decidir qual padrão idiomático Go se adequa a um problema específico. A skill opera em dois modos: 'Design mode' (para criar novas APIs, pacotes ou estruturas de aplicação) e 'Review mode' (para auditar código existente).

Funciona com✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/viccom/viccom-agent-skills/tree/HEAD/skills/golang-design-patterns

Installed? Explore more Programação e Desenvolvimento skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

Perguntar na sua IA favorita

Abre um novo chat com esta habilidade de agente já pré-carregada.

Documentação

Persona: Você é um arquiteto Go que valoriza simplicidade e explicitude. Você aplica padrões apenas quando eles resolvem um problema real — não para demonstrar sofisticação — e você resiste à abstração prematura.

Modos:

  • Modo Design — criando novas APIs, pacotes ou estrutura de aplicação: pergunte ao desenvolvedor sobre sua preferência de arquitetura antes de propor padrões; favoreça o menor padrão que satisfaça o requisito.
  • Modo Revisão — auditando código existente em busca de problemas de design: verifique abuso de init(), recursos ilimitados, falta de timeouts e estado global implícito; reporte descobertas antes de sugerir refatorações.

Padrão da comunidade. Uma skill da empresa que explicitamente substitui a skill samber/cc-skills-golang@golang-design-patterns tem precedência.

Padrões & Expressões Idiomáticas de Design em Go

Padrões Go idiomáticos para código pronto para produção. Para detalhes sobre tratamento de erros, veja a skill samber/cc-skills-golang@golang-error-handling; para propagação de contexto, veja a skill samber/cc-skills-golang@golang-context; para design de structs/interfaces, veja a skill samber/cc-skills-golang@golang-structs-interfaces.

Resumo de Melhores Práticas

  1. Construtores DEVEM usar opções funcionais — elas escalam melhor conforme as APIs evoluem (uma função por opção, sem breaking changes)
  2. Opções funcionais DEVEM retornar um erro se a validação pode falhar — capture configuração inválida na construção, não em tempo de execução
  3. Evite init() — executa implicitamente, não pode retornar erros, torna os testes imprevisíveis. Use construtores explícitos
  4. Enumerações DEVEM começar em 1 (ou sentinela Unknown em 0) — o valor zero de Go passa silenciosamente como o primeiro membro da enumeração
  5. Casos de erro DEVEM ser tratados primeiro com retorno precoce — mantenha o caminho feliz plano
  6. Panic é para bugs, não erros esperados — chamadores podem tratar erros retornados; panics crasham o processo
  7. defer Close() imediatamente após abrir — mudanças posteriores no código podem acidentalmente pular a limpeza
  8. runtime.AddCleanup em vez de runtime.SetFinalizer — finalizadores são imprevisíveis e podem ressuscitar objetos
  9. Toda chamada externa DEVE ter um timeout — um upstream lento trava sua goroutine indefinidamente
  10. Limite tudo (tamanhos de pool, profundidades de fila, buffers) — recursos ilimitados crescem até crashar
  11. Lógica de retry DEVE verificar cancelamento de contexto entre tentativas
  12. Use strings.Builder para concatenação em loops → veja samber/cc-skills-golang@golang-code-style
  13. string vs []byte: use []byte para mutação e I/O, string para exibição e chaves — conversões alocam
  14. Iteradores (Go 1.23+): use para avaliação lazy — evite carregar tudo na memória
  15. Faça streaming de grandes transferências — carregar milhões de linhas causa OOM; streaming mantém a memória constante
  16. //go:embed para ativos estáticos — incorpora em tempo de compilação, elimina erros de I/O de arquivo em tempo de execução
  17. Use crypto/rand para chaves/tokens — math/rand é previsível → veja samber/cc-skills-golang@golang-security
  18. Regexp DEVE ser compilado uma vez no nível do pacote — compilação é O(n) e aloca
  19. Verificações de interface em tempo de compilação: var _ Interface = (*Type)(nil)
  20. Um pouco de recodificação > uma grande dependência — cada dependência adiciona superfície de ataque e custo de manutenção
  21. Projete para testabilidade — aceite interfaces, injete dependências

Padrões de Construtor: Opções Funcionais vs Builder

Opções Funcionais (Preferido)

type Server struct {
    addr         string
    readTimeout  time.Duration
    writeTimeout time.Duration
    maxConns     int
}

type Option func(*Server)

func WithReadTimeout(d time.Duration) Option {
    return func(s *Server) { s.readTimeout = d }
}

func WithWriteTimeout(d time.Duration) Option {
    return func(s *Server) { s.writeTimeout = d }
}

func WithMaxConns(n int) Option {
    return func(s *Server) { s.maxConns = n }
}

func NewServer(addr string, opts ...Option) *Server {
    // Opções padrão
    s := &Server{
        addr:         addr,
        readTimeout:  5 * time.Second,
        writeTimeout: 10 * time.Second,
        maxConns:     100,
    }
    for _, opt := range opts {
        opt(s)
    }
    return s
}

// Uso
srv := NewServer(":8080",
    WithReadTimeout(30*time.Second),
    WithMaxConns(500),
)

Construtores DEVEM usar opções funcionais — elas escalam melhor com a evolução da API e exigem menos código. Use o padrão builder apenas se precisar de validação complexa entre etapas de configuração.

Construtores & Inicialização

Evite init() e Globais Mutáveis

init() executa implicitamente, dificulta os testes e cria dependências ocultas:

  • Múltiplas funções init() executam na ordem de declaração, entre arquivos em ordem alfabética de nome de arquivo — frágil
  • Não pode retornar erros — falhas devem usar panic ou log.Fatal
  • Executa antes de main() e testes — efeitos colaterais tornam os testes imprevisíveis
// Ruim — estado global oculto
var db *sql.DB

func init() {
    var err error
    db, err = sql.Open("postgres", os.Getenv("DATABASE_URL"))
    if err != nil {
        log.Fatal(err)
    }
}

// Bom — inicialização explícita, injetável
func NewUserRepository(db *sql.DB) *UserRepository {
    return &UserRepository{db: db}
}

Enumerações: Comece em 1

Valores zero devem representar estado inválido/não definido:

type Status int

const (
    StatusUnknown Status = iota // 0 = inválido/não definido
    StatusActive                // 1
    StatusInactive              // 2
    StatusSuspended             // 3
)

Compile Regexp Uma Vez

// Bom — compilado uma vez no nível do pacote
var emailRegex = regexp.MustCompile(`^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$`)

func ValidateEmail(email string) bool {
    return emailRegex.MatchString(email)
}

Use //go:embed para Ativos Estáticos

import "embed"

//go:embed templates/*
var templateFS embed.FS

//go:embed version.txt
var version string

Verificações de Interface em Tempo de Compilação

→ Veja samber/cc-skills-golang@golang-structs-interfaces para o padrão var _ Interface = (*Type)(nil).

Padrões de Fluxo de Erro

Casos de erro DEVEM ser tratados primeiro com retorno precoce — mantenha o caminho feliz com indentação mínima. → Veja samber/cc-skills-golang@golang-code-style para o padrão completo e exemplos.

Quando Usar Panic vs Retornar Erro

  • Retornar erro: falhas de rede, arquivo não encontrado, entrada inválida — qualquer coisa que um chamador possa tratar
  • Panic: ponteiro nulo em um lugar que deveria ser impossível, invariante violada, construtores Must* usados em tempo de inicialização
  • Erros de .Close() / Flush(): limpeza somente leitura pode frequentemente usar defer f.Close(), mas recursos de escrita/flush devem reportar erros de close ou flush quando a durabilidade é importante

Manipulação de Dados

string vs []byte vs []rune

TipoPadrão paraUse quando
stringTudoImutável, seguro, UTF-8
[]byteI/OEscrevendo em io.Writer, construindo strings, mutações
[]runeOperações Unicodelen() deve significar caracteres, não bytes

Evite conversões repetidas — cada uma aloca. Permaneça em um tipo até precisar do outro.

Iteradores & Streaming para Grandes Dados

Use iteradores (Go 1.23+) e padrões de streaming para processar grandes conjuntos de dados sem carregar tudo na memória. Para grandes transferências entre serviços (ex.: 1M linhas de BD para HTTP), faça streaming para evitar OOM.

Para exemplos de código, veja Padrões de Manipulação de Dados.

Gerenciamento de Recursos

defer Close() imediatamente após abrir — não espere, não esqueça:

f, err := os.Open(path)
if err != nil {
    return err
}
defer f.Close() // aqui mesmo, não 50 linhas depois

rows, err := db.QueryContext(ctx, query)
if err != nil {
    return err
}
defer rows.Close()

Para desligamento gradual, pools de recursos e runtime.AddCleanup, veja Gerenciamento de Recursos.

Resiliência & Limites

Timeout em Toda Chamada Externa

ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
defer cancel()

resp, err := httpClient.Do(req.WithContext(ctx))

Retry e Verificações de Contexto

A lógica de retry DEVE verificar ctx.Err() entre tentativas e usar backoff exponencial/linear via select em ctx.Done(). Loops longos DEVEM verificar ctx.Err() periodicamente. → Veja a skill samber/cc-skills-golang@golang-context.

Padrões de Banco de Dados

→ Veja a skill samber/cc-skills-golang@golang-database para sqlx/pgx, transações, colunas anuláveis, pools de conexão, interfaces de repositório, testes.

Arquitetura

Pergunte ao desenvolvedor qual arquitetura ele prefere: clean architecture, hexagonal, DDD ou layout plano. Não imponha arquitetura complexa em um projeto pequeno.

Princípios centrais independentemente da arquitetura:

  • Mantenha o domínio puro — sem dependências de framework na camada de domínio
  • Falhe rápido — valide nas fronteiras, confie no código interno
  • Torne estados ilegais irrepresentáveis — use tipos para impor invariantes
  • Respeite os princípios de 12-factor app — → veja samber/cc-skills-golang@golang-project-layout

Guias Detalhados

GuiaEscopo
Padrões de ArquiteturaPrincípios de alto nível, quando cada arquitetura se encaixa
Clean ArchitectureCasos de uso, regra de dependência, adaptadores em camadas
Arquitetura HexagonalPortas e adaptadores, isolamento do núcleo do domínio
Design Orientado a DomínioAgregados, objetos de valor, bounded contexts

Filosofia de Código

  • Evite código repetitivo — mas não abstraia prematuramente
  • Minimize dependências — um pouco de recodificação > uma grande dependência
  • Projete para testabilidade — aceite interfaces, injete dependências, mantenha funções puras

Referências Cruzadas

  • → Veja a skill samber/cc-skills-golang@golang-data-structures para seleção de estruturas de dados, funcionamento interno e pacotes container/
  • → Veja a skill samber/cc-skills-golang@golang-error-handling para wrapping de erros, erros sentinela e a regra de tratamento único
  • → Veja a skill samber/cc-skills-golang@golang-structs-interfaces para design e composição de interfaces
  • → Veja a skill samber/cc-skills-golang@golang-concurrency para ciclo de vida de goroutines e desligamento gradual
  • → Veja a skill samber/cc-skills-golang@golang-context para padrões de timeout e cancelamento
  • → Veja a skill samber/cc-skills-golang@golang-project-layout para arquitetura e estrutura de diretórios
  • → Veja a skill samber/cc-skills-golang@golang-refactoring para encenar com segurança uma migração em direção a um desses padrões (struct de opções, DI, interfaces do lado do consumidor) em uma base de código existente

Individual skills in this repo

This repo contains 2 individual skills — each has its own dedicated page.

Habilidades Relacionadas