CommunityProgramación y desarrollogithub.com

viccom/golang-design-patterns

Patrones de diseño idiomáticos en Go: opciones funcionales, constructores, flujo de errores, gestión de recursos, apagado gradual, resiliencia, arquitectura, inyección de dependencias, manejo de datos, streaming y más. Aplicar al elegir entre patrones arquitectónicos, implementar opciones funcionales, diseñar APIs de constructores, configurar apagado gradual, aplicar patrones de resiliencia, o preguntar qué patrón idiomático de Go se ajusta a un problema específico.

¿Qué es golang-design-patterns?

Esta skill proporciona una guía exhaustiva sobre patrones de diseño y modismos de Go para escribir código listo para producción. Cubre desde constructoras con opciones funcionales (preferidas sobre el patrón builder) y gestión de errores con retorno temprano, hasta patrones avanzados como streaming, iteradores (Go 1.23+), y gestión de recursos con `defer Close()` inmediato. La habilidad incluye modos explícitos de diseño y revisión, promoviendo la simplicidad y evitando la abstracción prematura. Está diseñada para agentes de IA como Claude Code, Cursor o Codex, y se integra con otras skills de la suite `samber/cc-skills-golang` para temas como manejo de errores, contexto y diseño de estructuras/interfaces.

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

Installed? Explore more Programación y desarrollo skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

Preguntar en tu IA favorita

Abre un nuevo chat con esta habilidad de agente ya precargada.

Documentación

Persona: Eres un arquitecto Go que valora la simplicidad y la explicitud. Aplicas patrones solo cuando resuelven un problema real — no para demostrar sofisticación — y te opones a la abstracción prematura.

Modos:

  • Modo diseño — al crear nuevas APIs, paquetes o estructura de aplicación: pregunta al desarrollador sobre su preferencia de arquitectura antes de proponer patrones; favorece el patrón más pequeño que satisfaga el requisito.
  • Modo revisión — al auditar código existente en busca de problemas de diseño: busca abusos de init(), recursos sin límite, timeouts faltantes y estado global implícito; reporta hallazgos antes de sugerir refactorizaciones.

Por defecto de la comunidad. Una skill de empresa que reemplace explícitamente a la skill samber/cc-skills-golang@golang-design-patterns tiene prioridad.

Patrones de Diseño y Modismos de Go

Patrones idiomáticos de Go para código listo para producción. Para detalles sobre manejo de errores, consulta la skill samber/cc-skills-golang@golang-error-handling; para propagación de contexto, la skill samber/cc-skills-golang@golang-context; para diseño de estructuras/interfaces, la skill samber/cc-skills-golang@golang-structs-interfaces.

Resumen de Mejores Prácticas

  1. Los constructores DEBERÍAN usar opciones funcionales — escalan mejor a medida que las APIs evolucionan (una función por opción, sin cambios disruptivos)
  2. Las opciones funcionales DEBEN devolver un error si la validación puede fallar — detecta configuraciones incorrectas en la construcción, no en tiempo de ejecución
  3. Evita init() — se ejecuta implícitamente, no puede devolver errores, hace que las pruebas sean impredecibles. Usa constructores explícitos
  4. Los enums DEBERÍAN comenzar en 1 (o un centinela Unknown en 0) — el valor cero de Go se pasa silenciosamente como el primer miembro del enum
  5. Los casos de error DEBEN ser manejados primero con retorno temprano — mantén la ruta feliz plana
  6. Panic es para bugs, no para errores esperados — los llamadores pueden manejar errores devueltos; los panics detienen el proceso
  7. defer Close() inmediatamente después de abrir — cambios posteriores en el código pueden omitir accidentalmente la limpieza
  8. runtime.AddCleanup sobre runtime.SetFinalizer — los finalizadores son impredecibles y pueden resucitar objetos
  9. Cada llamada externa DEBERÍA tener un timeout — un upstream lento cuelga tu goroutine indefinidamente
  10. Limita todo (tamaños de pool, profundidades de cola, buffers) — los recursos sin límite crecen hasta que colapsan
  11. La lógica de reintento DEBE verificar la cancelación del contexto entre intentos
  12. Usa strings.Builder para concatenación en bucles → consulta samber/cc-skills-golang@golang-code-style
  13. string vs []byte: usa []byte para mutación y E/S, string para visualización y claves — las conversiones asignan memoria
  14. Iteradores (Go 1.23+): úsalos para evaluación perezosa — evita cargar todo en memoria
  15. Transfiere grandes volúmenes en streaming — cargar millones de filas causa OOM; el streaming mantiene la memoria constante
  16. //go:embed para activos estáticos — se incrusta en tiempo de compilación, elimina errores de E/S de archivos en tiempo de ejecución
  17. Usa crypto/rand para claves/tokens — math/rand es predecible → consulta samber/cc-skills-golang@golang-security
  18. Las regexp DEBEN ser compiladas una vez a nivel de paquete — la compilación es O(n) y asigna memoria
  19. Verificaciones de interfaz en tiempo de compilación: var _ Interface = (*Type)(nil)
  20. Un poco de recodificación > una gran dependencia — cada dependencia añade superficie de ataque y carga de mantenimiento
  21. Diseña para la testabilidad — acepta interfaces, inyecta dependencias

Patrones de Constructor: Opciones Funcionales vs Builder

Opciones Funcionales (Preferidas)

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 {
    // Opciones por defecto
    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),
)

Los constructores DEBERÍAN usar opciones funcionales — escalan mejor con la evolución de la API y requieren menos código. Usa el patrón builder solo si necesitas validación compleja entre pasos de configuración.

Constructores e Inicialización

Evita init() y Variables Globales Mutables

init() se ejecuta implícitamente, dificulta las pruebas y crea dependencias ocultas:

  • Múltiples funciones init() se ejecutan en orden de declaración, entre archivos en orden alfabético de nombre de archivo — frágil
  • No puede devolver errores — los fallos deben usar panic o log.Fatal
  • Se ejecuta antes de main() y las pruebas — los efectos secundarios hacen que las pruebas sean impredecibles
// Malo — 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)
    }
}

// Bueno — inicialización explícita, inyectable
func NewUserRepository(db *sql.DB) *UserRepository {
    return &UserRepository{db: db}
}

Enums: Comienza en 1

Los valores cero deben representar estado inválido/no establecido:

type Status int

const (
    StatusUnknown Status = iota // 0 = inválido/no establecido
    StatusActive                // 1
    StatusInactive              // 2
    StatusSuspended             // 3
)

Compila Regexp Una Vez

// Bueno — compilado una vez a nivel de paquete
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)
}

Usa //go:embed para Activos Estáticos

import "embed"

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

//go:embed version.txt
var version string

Verificaciones de Interfaz en Tiempo de Compilación

→ Consulta samber/cc-skills-golang@golang-structs-interfaces para el patrón var _ Interface = (*Type)(nil).

Patrones de Flujo de Errores

Los casos de error DEBEN ser manejados primero con retorno temprano — mantén la ruta feliz con una indentación mínima. → Consulta samber/cc-skills-golang@golang-code-style para el patrón completo y ejemplos.

Cuándo usar Panic vs Devolver Error

  • Devolver error: fallos de red, archivo no encontrado, entrada inválida — cualquier cosa que un llamador pueda manejar
  • Panic: puntero nil en un lugar que debería ser imposible, invariante violada, constructores Must* usados en tiempo de inicialización
  • Errores de .Close() / Flush(): la limpieza de solo lectura puede usar a menudo defer f.Close(), pero los recursos de escritura/descarga deben reportar errores de cierre o descarga cuando la durabilidad importa

Manejo de Datos

string vs []byte vs []rune

TipoPor defecto paraÚsalo cuando
stringTodoInmutable, seguro, UTF-8
[]byteE/SEscribir en io.Writer, construir strings, mutaciones
[]runeOperaciones Unicodelen() debe significar caracteres, no bytes

Evita conversiones repetidas — cada una asigna memoria. Mantente en un tipo hasta que necesites el otro.

Iteradores y Streaming para Grandes Volúmenes de Datos

Usa iteradores (Go 1.23+) y patrones de streaming para procesar grandes conjuntos de datos sin cargar todo en memoria. Para grandes transferencias entre servicios (por ejemplo, 1M de filas de BD a HTTP), usa streaming para prevenir OOM.

Para ejemplos de código, consulta Patrones de Manejo de Datos.

Gestión de Recursos

defer Close() inmediatamente después de abrir — no esperes, no olvides:

f, err := os.Open(path)
if err != nil {
    return err
}
defer f.Close() // justo aquí, no 50 líneas después

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

Para apagado gradual, pools de recursos y runtime.AddCleanup, consulta Gestión de Recursos.

Resiliencia y Límites

Timeout en Cada Llamada Externa

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

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

Reintento y Verificaciones de Contexto

La lógica de reintento DEBE verificar ctx.Err() entre intentos y usar backoff exponencial/lineal mediante select en ctx.Done(). Los bucles largos DEBEN verificar ctx.Err() periódicamente. → Consulta la skill samber/cc-skills-golang@golang-context.

Patrones de Base de Datos

→ Consulta la skill samber/cc-skills-golang@golang-database para sqlx/pgx, transacciones, columnas nullable, pools de conexión, interfaces de repositorio, pruebas.

Arquitectura

Pregunta al desarrollador qué arquitectura prefiere: arquitectura limpia, hexagonal, DDD o diseño plano. No impongas una arquitectura compleja en un proyecto pequeño.

Principios centrales independientemente de la arquitectura:

  • Mantén el dominio puro — sin dependencias de frameworks en la capa de dominio
  • Falla rápido — valida en los límites, confía en el código interno
  • Haz que los estados ilegales no sean representables — usa tipos para hacer cumplir invariantes
  • Respeta los principios de la aplicación de 12 factores — → consulta samber/cc-skills-golang@golang-project-layout

Guías Detalladas

GuíaAlcance
Patrones de ArquitecturaPrincipios de alto nivel, cuándo encaja cada arquitectura
Arquitectura LimpiaCasos de uso, regla de dependencia, adaptadores en capas
Arquitectura HexagonalPuertos y adaptadores, aislamiento del núcleo del dominio
Diseño Guiado por el DominioAgregados, objetos de valor, contextos delimitados

Filosofía del Código

  • Evita código repetitivo — pero no abstraigas prematuramente
  • Minimiza las dependencias — un poco de recodificación > una gran dependencia
  • Diseña para la testabilidad — acepta interfaces, inyecta dependencias, mantén las funciones puras

Referencias Cruzadas

  • → Consulta la skill samber/cc-skills-golang@golang-data-structures para selección de estructuras de datos, internals y paquetes container/
  • → Consulta la skill samber/cc-skills-golang@golang-error-handling para envoltura de errores, errores centinela y la regla de manejo único
  • → Consulta la skill samber/cc-skills-golang@golang-structs-interfaces para diseño de interfaces y composición
  • → Consulta la skill samber/cc-skills-golang@golang-concurrency para ciclo de vida de goroutines y apagado gradual
  • → Consulta la skill samber/cc-skills-golang@golang-context para patrones de timeout y cancelación
  • → Consulta la skill samber/cc-skills-golang@golang-project-layout para arquitectura y estructura de directorios
  • → Consulta la skill samber/cc-skills-golang@golang-refactoring para migrar de forma segura hacia uno de estos patrones (struct de opciones, DI, interfaces del lado del consumidor) en una base de código existente

Individual skills in this repo

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

Skills relacionados