Skills Plugins MCP Prompt Model 博客 我的中心

golang-patterns

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

DeepseekModel Curated skill Quality Excellent · 90 v1.0.0

Get

https://deepseekmodel.com/api/download.php?id=affaan-m-ecc-docs-es-skills-golang-patterns-skill-md&format=skill
Download .skill Standard format with system_prompt and model_config, ready for any agent framework
The actual content of the system_prompt field in the .skill file.
name golang-patterns description Patrones idiomáticos de Go, buenas prácticas y convenciones para construir aplicaciones Go robustas, eficientes y mantenibles. origin ECC 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 {
Keywords that activate this skill. Click one to copy it.

This skill does not provide trigger words.

The downloaded .skill package contains the following fields.
Field Description
formatFormat tag (skill/v1)
skill_idUnique skill ID
nameSkill name
versionVersion
descriptionDescription
categoryCategories (array)
trigger_wordsTrigger words
tagsTags
sourceSource
source_urlSource URL (this page)
exported_atExported at (set per download)
system_promptSystem prompt body
model_configModel config: provider / model / temperature / max_tokens / top_p
examplesExamples
install_guideImport guide for Coze / Dify / Claude / custom frameworks
The same skill can be exported in different platform formats.
.skill Standard format with system_prompt and model_config, ready for any agent framework Download
.skillpro Enhanced format with scripts, tools, dependencies and hooks Download
.json Plain JSON export with system_prompt and model parameters only Download
Coze Markdown with frontmatter, for Coze platform import Download
Dify Dify DSL, import directly after creating an app Download

每日精选 Skill 推荐,免费送到你邮箱

输入邮箱,每天接收一个精选 AI Agent 技能推荐。完全免费,持续更新。

验证码 --

提交后我们会发送一封确认邮件,点击邮件里的链接才会开始收信。

完全免费,取消任意时间。我们不会发送垃圾邮件。