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.
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
| Platform | Status | Evidence | What to check |
|---|---|---|---|
| Codex | Not declared | No explicit evidence | Portability before use |
| Claude Code | Not declared | No explicit evidence | Portability before use |
| Cursor | Not declared | No explicit evidence | Portability before use |
| Gemini CLI | Not declared | No explicit evidence | Portability before use |
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.
npx skills add https://github.com/affaan-m/ECC --skill "docs/es/skills/golang-patterns"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
- 01
Cuándo Activar
Escribir nuevo código Go
Escribir nuevo código GoRevisar código GoRefactorizar código Go existente - 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. - 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. - 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. - 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
The documentation asks the agent to read local files, directories, or repositories.
data, err := os.ReadFile(path)Network access
The documentation includes network, browsing, or remote request actions.
return nil, fmt.Errorf("fetch %s: %w", url, err)Network access
The documentation includes network, browsing, or remote request actions.
data, _ := fetch(url)Runs scripts
The documentation asks the agent to run terminal commands or scripts.
go build ./...Runs scripts
The documentation asks the agent to run terminal commands or scripts.
go run ./cmd/myappEvidence record
Why each signal appears
| Signal | Value | Evidence type | Meaning |
|---|---|---|---|
| Quality score | 64/100 | Computed | Documentation, specificity, maintenance, and trust rules |
| Repository stars | 234,327 | Source | Repository attention, not individual Skill quality |
| Compatibility | 0 platforms | Source | Declared in the catalog source record |
| Usage guide | automated source guide | Editorial | Generated 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
| Modismo | Descripción |
|---|---|
| Aceptar interfaces, retornar structs | Las funciones aceptan parámetros de interfaz, retornan tipos concretos |
| Los errores son valores | Tratar errores como valores de primera clase, no como excepciones |
| No comunicarse compartiendo memoria | Usar canales para coordinación entre goroutines |
| Hacer que el valor cero sea útil | Los tipos deben funcionar sin inicialización explícita |
| Un poco de copia es mejor que una pequeña dependencia | Evitar dependencias externas innecesarias |
| Claro es mejor que inteligente | Priorizar legibilidad sobre astucia |
| gofmt no es favorito de nadie pero sí amigo de todos | Siempre formatear con gofmt/goimports |
| Retornar temprano | Manejar 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
affaan-m/ECC
golang-patterns
Go-specific design patterns and best practices including functional options, small interfaces, dependency injection, concurrency patterns, error handling, and package organization. Use when working with Go code to apply idiomatic Go patterns.
affaan-m/ECC
golang-patterns
Idiomatic Go patterns, best practices, and conventions for building robust, efficient, and maintainable Go applications.
affaan-m/ECC
golang-patterns
Review golang-patterns's use cases, installation, workflow, and original source instructions.
affaan-m/ECC
golang-patterns
Review golang-patterns's use cases, installation, workflow, and original source instructions.