Source profileQuality 64/100Review permissions

affaan-m/ECC/docs/es/skills/golang-patterns/SKILL.md

golang-patterns

Patrones idiomáticos de Go, buenas prácticas y convenciones para construir aplicaciones Go robustas, eficientes y mantenibles.

Source repository stars
234,327
Declared platforms
0
Static risk flags
3
Last source update
2026-07-27
Source checked
2026-07-28

Decision brief

What it does—and where it fits

Patrones idiomáticos de Go y buenas prácticas para construir aplicaciones robustas, eficientes y mantenibles.

Best for

    Not for

    • Tasks that require unconfirmed production actions or broad system permissions.
    • Environments where the pinned source and install steps cannot be inspected.

    Compatibility matrix

    Platform support, with evidence labels

    PlatformStatusEvidenceWhat to check
    CodexNot declaredNo explicit evidencePortability before use
    Claude CodeNot declaredNo explicit evidencePortability before use
    CursorNot declaredNo explicit evidencePortability before use
    Gemini CLINot declaredNo explicit evidencePortability before use
    Open the compatibility checker

    Installation

    Inspect first. Install second.

    The source command is displayed only when detected. A safe inspection prompt is always available so your agent can explain every action before execution.

    Source-detected install commandSource
    npx skills add https://github.com/affaan-m/ECC --skill "docs/es/skills/golang-patterns"
    Safe inspection promptEditorial

    Inspect the Agent Skill "golang-patterns" from https://github.com/affaan-m/ECC/blob/4e973d3eaf92d97f8d2e2d8abb39d8bdc8711b38/docs/es/skills/golang-patterns/SKILL.md at commit 4e973d3eaf92d97f8d2e2d8abb39d8bdc8711b38. List every install step, command, network request, credential, file read/write, external action, and rollback step. Explain whether it fits my task. Do not install or execute anything until I approve.

    Workflow

    What the source asks the agent to do

    1. 01

      Cuándo Activar

      Escribir nuevo código Go

      Escribir nuevo código GoRevisar código GoRefactorizar código Go existente
    2. 02

      Principios Fundamentales

      Go favorece la simplicidad sobre la astucia. El código debe ser obvio y fácil de leer.

      Go favorece la simplicidad sobre la astucia. El código debe ser obvio y fácil de leer.Diseñar tipos para que su valor cero sea inmediatamente usable sin inicialización.Las funciones deben aceptar parámetros de interfaz y retornar tipos concretos.
    3. 03

      1. Simplicidad y Claridad

      Go favorece la simplicidad sobre la astucia. El código debe ser obvio y fácil de leer.

      Go favorece la simplicidad sobre la astucia. El código debe ser obvio y fácil de leer.
    4. 04

      2. Hacer que el Valor Cero Sea Útil

      Diseñar tipos para que su valor cero sea inmediatamente usable sin inicialización.

      Diseñar tipos para que su valor cero sea inmediatamente usable sin inicialización.
    5. 05

      3. Aceptar Interfaces, Retornar Structs

      Las funciones deben aceptar parámetros de interfaz y retornar tipos concretos.

      Las funciones deben aceptar parámetros de interfaz y retornar tipos concretos.

    Permission review

    Static risk signals and limitations

    Reads files

    low · line 94

    The documentation asks the agent to read local files, directories, or repositories.

    data, err := os.ReadFile(path)

    Network access

    medium · line 205

    The documentation includes network, browsing, or remote request actions.

    return nil, fmt.Errorf("fetch %s: %w", url, err)

    Network access

    medium · line 269

    The documentation includes network, browsing, or remote request actions.

    data, _ := fetch(url)

    Runs scripts

    medium · line 570

    The documentation asks the agent to run terminal commands or scripts.

    go build ./...

    Runs scripts

    medium · line 571

    The documentation asks the agent to run terminal commands or scripts.

    go run ./cmd/myapp

    Evidence record

    Why each signal appears

    EvidenceSourceComputedTestedEditorial
    SignalValueEvidence typeMeaning
    Quality score64/100ComputedDocumentation, specificity, maintenance, and trust rules
    Repository stars234,327SourceRepository attention, not individual Skill quality
    Compatibility0 platformsSourceDeclared in the catalog source record
    Usage guideautomated source guideEditorialGenerated or reviewed according to the visible evidence level

    Pinned source

    Provenance and original SKILL.md

    Repository
    affaan-m/ECC
    Skill path
    docs/es/skills/golang-patterns/SKILL.md
    Commit
    4e973d3eaf92d97f8d2e2d8abb39d8bdc8711b38
    License
    MIT
    Collected
    2026-07-28
    Default branch
    main
    View the original SKILL.md

    Patrones de Desarrollo Go

    Patrones idiomáticos de Go y buenas prácticas para construir aplicaciones robustas, eficientes y mantenibles.

    Cuándo Activar

    • Escribir nuevo código Go
    • Revisar código Go
    • Refactorizar código Go existente
    • Diseñar paquetes/módulos Go

    Principios Fundamentales

    1. Simplicidad y Claridad

    Go favorece la simplicidad sobre la astucia. El código debe ser obvio y fácil de leer.

    // Bien: Claro y directo
    func 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
    }
    
    // Mal: Demasiado ingenioso
    func 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. Hacer que el Valor Cero Sea Útil

    Diseñar tipos para que su valor cero sea inmediatamente usable sin inicialización.

    // Bien: El valor cero es útil
    type Counter struct {
        mu    sync.Mutex
        count int // el valor cero es 0, listo para usar
    }
    
    func (c *Counter) Inc() {
        c.mu.Lock()
        c.count++
        c.mu.Unlock()
    }
    
    // Bien: bytes.Buffer funciona con el valor cero
    var buf bytes.Buffer
    buf.WriteString("hello")
    
    // Mal: Requiere inicialización
    type BadCounter struct {
        counts map[string]int // el mapa nil causará panic
    }
    

    3. Aceptar Interfaces, Retornar Structs

    Las funciones deben aceptar parámetros de interfaz y retornar tipos concretos.

    // Bien: Acepta interfaz, retorna tipo concreto
    func ProcessData(r io.Reader) (*Result, error) {
        data, err := io.ReadAll(r)
        if err != nil {
            return nil, err
        }
        return &Result{Data: data}, nil
    }
    
    // Mal: Retorna interfaz (oculta detalles de implementación innecesariamente)
    func ProcessData(r io.Reader) (io.Reader, error) {
        // ...
    }
    

    Patrones de Manejo de Errores

    Wrapping de Errores con Contexto

    // Bien: Envolver errores con contexto
    func 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
    }
    

    Tipos de Error Personalizados

    // Definir errores específicos del dominio
    type ValidationError struct {
        Field   string
        Message string
    }
    
    func (e *ValidationError) Error() string {
        return fmt.Sprintf("validation failed on %s: %s", e.Field, e.Message)
    }
    
    // Errores centinela para casos comunes
    var (
        ErrNotFound     = errors.New("resource not found")
        ErrUnauthorized = errors.New("unauthorized")
        ErrInvalidInput = errors.New("invalid input")
    )
    

    Verificación de Errores con errors.Is y errors.As

    func HandleError(err error) {
        // Verificar error específico
        if errors.Is(err, sql.ErrNoRows) {
            log.Println("No records found")
            return
        }
    
        // Verificar tipo de error
        var validationErr *ValidationError
        if errors.As(err, &validationErr) {
            log.Printf("Validation error on field %s: %s",
                validationErr.Field, validationErr.Message)
            return
        }
    
        // Error desconocido
        log.Printf("Unexpected error: %v", err)
    }
    

    Nunca Ignorar Errores

    // Mal: Ignorar error con identificador en blanco
    result, _ := doSomething()
    
    // Bien: Manejar o documentar explícitamente por qué es seguro ignorar
    result, err := doSomething()
    if err != nil {
        return err
    }
    
    // Aceptable: Cuando el error realmente no importa (raro)
    _ = writer.Close() // Limpieza de mejor esfuerzo, error registrado en otro lugar
    

    Patrones de Concurrencia

    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 para Cancelación y 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)
    }
    

    Apagado Graceful

    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 para Goroutines Coordinadas

    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 // Capturar variables del bucle
            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
    }
    

    Evitar Goroutine Leaks

    // Mal: Goroutine leak si el context es cancelado
    func leakyFetch(ctx context.Context, url string) <-chan []byte {
        ch := make(chan []byte)
        go func() {
            data, _ := fetch(url)
            ch <- data // Bloquea para siempre si no hay receptor
        }()
        return ch
    }
    
    // Bien: Maneja correctamente la cancelación
    func safeFetch(ctx context.Context, url string) <-chan []byte {
        ch := make(chan []byte, 1) // Canal con buffer
        go func() {
            data, err := fetch(url)
            if err != nil {
                return
            }
            select {
            case ch <- data:
            case <-ctx.Done():
            }
        }()
        return ch
    }
    

    Diseño de Interfaces

    Interfaces Pequeñas y Enfocadas

    // Bien: Interfaces de un solo método
    type Reader interface {
        Read(p []byte) (n int, err error)
    }
    
    type Writer interface {
        Write(p []byte) (n int, err error)
    }
    
    type Closer interface {
        Close() error
    }
    
    // Componer interfaces según se necesite
    type ReadWriteCloser interface {
        Reader
        Writer
        Closer
    }
    

    Definir Interfaces Donde Se Usan

    // En el paquete consumidor, no en el proveedor
    package service
    
    // UserStore define lo que este servicio necesita
    type UserStore interface {
        GetUser(id string) (*User, error)
        SaveUser(user *User) error
    }
    
    type Service struct {
        store UserStore
    }
    
    // La implementación concreta puede estar en otro paquete
    // No necesita conocer esta interfaz
    

    Comportamiento Opcional con Type Assertions

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

    Organización de Paquetes

    Layout Estándar del Proyecto

    myproject/
    ├── cmd/
    │   └── myapp/
    │       └── main.go           # Punto de entrada
    ├── internal/
    │   ├── handler/              # Handlers HTTP
    │   ├── service/              # Lógica de negocio
    │   ├── repository/           # Acceso a datos
    │   └── config/               # Configuración
    ├── pkg/
    │   └── client/               # Cliente de API pública
    ├── api/
    │   └── v1/                   # Definiciones de API (proto, OpenAPI)
    ├── testdata/                 # Fixtures de prueba
    ├── go.mod
    ├── go.sum
    └── Makefile
    

    Nomenclatura de Paquetes

    // Bien: Corto, minúsculas, sin guiones bajos
    package http
    package json
    package user
    
    // Mal: Verboso, mayúsculas mixtas, o redundante
    package httpHandler
    package json_parser
    package userService // Sufijo 'Service' redundante
    

    Evitar Estado a Nivel de Paquete

    // Mal: Estado global mutable
    var db *sql.DB
    
    func init() {
        db, _ = sql.Open("postgres", os.Getenv("DATABASE_URL"))
    }
    
    // Bien: Inyección de dependencias
    type Server struct {
        db *sql.DB
    }
    
    func NewServer(db *sql.DB) *Server {
        return &Server{db: db}
    }
    

    Diseño de Structs

    Patrón de Opciones Funcionales

    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, // por defecto
            logger:  log.Default(),    // por defecto
        }
        for _, opt := range opts {
            opt(s)
        }
        return s
    }
    
    // Uso
    server := NewServer(":8080",
        WithTimeout(60*time.Second),
        WithLogger(customLogger),
    )
    

    Embedding para Composición

    type Logger struct {
        prefix string
    }
    
    func (l *Logger) Log(msg string) {
        fmt.Printf("[%s] %s\n", l.prefix, msg)
    }
    
    type Server struct {
        *Logger // Embedding - Server obtiene el método Log
        addr    string
    }
    
    func NewServer(addr string) *Server {
        return &Server{
            Logger: &Logger{prefix: "SERVER"},
            addr:   addr,
        }
    }
    
    // Uso
    s := NewServer(":8080")
    s.Log("Starting...") // Llama al Logger.Log embebido
    

    Memoria y Rendimiento

    Pre-asignar Slices Cuando Se Conoce el Tamaño

    // Mal: El slice crece múltiples veces
    func processItems(items []Item) []Result {
        var results []Result
        for _, item := range items {
            results = append(results, process(item))
        }
        return results
    }
    
    // Bien: Asignación única
    func processItems(items []Item) []Result {
        results := make([]Result, 0, len(items))
        for _, item := range items {
            results = append(results, process(item))
        }
        return results
    }
    

    Usar sync.Pool para Asignaciones Frecuentes

    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)
        // Procesar...
        return buf.Bytes()
    }
    

    Evitar Concatenación de Strings en Bucles

    // Mal: Crea muchas asignaciones de string
    func join(parts []string) string {
        var result string
        for _, p := range parts {
            result += p + ","
        }
        return result
    }
    
    // Bien: Asignación única con strings.Builder
    func join(parts []string) string {
        var sb strings.Builder
        for i, p := range parts {
            if i > 0 {
                sb.WriteString(",")
            }
            sb.WriteString(p)
        }
        return sb.String()
    }
    
    // Mejor: Usar la librería estándar
    func join(parts []string) string {
        return strings.Join(parts, ",")
    }
    

    Integración con Herramientas Go

    Comandos Esenciales

    # Build y ejecutar
    go build ./...
    go run ./cmd/myapp
    
    # Pruebas
    go test ./...
    go test -race ./...
    go test -cover ./...
    
    # Análisis estático
    go vet ./...
    staticcheck ./...
    golangci-lint run
    
    # Gestión de módulos
    go mod tidy
    go mod verify
    
    # Formato
    gofmt -w .
    goimports -w .
    

    Configuración Recomendada de Linter (.golangci.yml)

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

    Referencia Rápida: Modismos de Go

    ModismoDescripción
    Aceptar interfaces, retornar structsLas funciones aceptan parámetros de interfaz, retornan tipos concretos
    Los errores son valoresTratar errores como valores de primera clase, no como excepciones
    No comunicarse compartiendo memoriaUsar canales para coordinación entre goroutines
    Hacer que el valor cero sea útilLos tipos deben funcionar sin inicialización explícita
    Un poco de copia es mejor que una pequeña dependenciaEvitar dependencias externas innecesarias
    Claro es mejor que inteligentePriorizar legibilidad sobre astucia
    gofmt no es favorito de nadie pero sí amigo de todosSiempre formatear con gofmt/goimports
    Retornar tempranoManejar errores primero, mantener el camino feliz sin indentar

    Anti-Patrones a Evitar

    // Mal: Retornos naked en funciones largas
    func process() (result int, err error) {
        // ... 50 líneas ...
        return // ¿Qué se está retornando?
    }
    
    // Mal: Usar panic para control de flujo
    func GetUser(id string) *User {
        user, err := db.Find(id)
        if err != nil {
            panic(err) // No hacer esto
        }
        return user
    }
    
    // Mal: Pasar context en struct
    type Request struct {
        ctx context.Context // El context debería ser el primer parámetro
        ID  string
    }
    
    // Bien: Context como primer parámetro
    func ProcessRequest(ctx context.Context, id string) error {
        // ...
    }
    
    // Mal: Mezclar receptores de valor y puntero
    type Counter struct{ n int }
    func (c Counter) Value() int { return c.n }    // Receptor de valor
    func (c *Counter) Increment() { c.n++ }        // Receptor de puntero
    // Elegir un estilo y ser consistente
    

    Recuerda: El código Go debe ser aburrido de la mejor manera — predecible, consistente y fácil de entender. Ante la duda, mantenerlo simple.

    Alternatives

    Compare before choosing