Skills Agentes

Golang Safety

Codificación defensiva en Golang para evitar panics, corrupción silenciosa de datos y bugs sutiles en tiempo de ejecución.

Solicitaread edit write glob grep bash(go:*) bash(golangci-lint:*) bash(git:*) agent
Estrellas
3.3k

en todo el repo

Actividad
51

0–100, la ruta de este skill

Actualizado
hace 4 meses

último commit aquí

Commits
5

últimos 90 días

Contexto
2.6k tok

96 tok en reposo

Paquete
4 archivos

68 KB

Instalar

Funciona con cualquier agente que lea SKILL.md

npx -y skills add samber/cc-skills-golang --skill golang-safety --agent claude-code

Se instala solo en este repositorio.

Qué hace

  • Aplica prácticas defensivas de Go: nil-safety, aserciones de tipo seguras, prevención de aliasing en slices con append
  • Detecta y corrige truncamientos silenciosos en conversiones numéricas y comparaciones incorrectas de floats
  • Revisa manejo de recursos (defer en loops) y copias defensivas de slices/mapas exportados
  • Guía diseño de zero-values seguros y uso de sync.Once para inicialización perezosa

Úsalo cuando

  • Al encontrar panics por nil, aliasing de append, acceso concurrente a mapas o problemas de comparación de floats
  • Al diseñar zero-values o revisar código para nil-safety
  • Al revisar overflow en conversiones numéricas o problemas de ciclo de vida de recursos (defer en loops)
  • Al revisar copia defensiva de slices y mapas

No lo uses cuando

    Qué lo activa

    Di cualquiera de estas frases y el agente debería cargar este skill.

    • “Revisa este código Go por posibles nil panics”
    • “¿Por qué mi slice se corrompe después de usar append?”
    • “Ayúdame a diseñar zero-values seguros para esta struct”
    • “Revisa si hay overflow en estas conversiones de int64 a int32”

    SKILL.md

    En inglés

    Persona: You are a defensive Go engineer. You treat every untested assumption about nil, capacity, and numeric range as a latent crash waiting to happen.

    Go Safety: Correctness & Defensive Coding

    Prevents programmer mistakes — bugs, panics, and silent data corruption in normal (non-adversarial) code. Security handles attackers; safety handles ourselves.

    Best Practices Summary

    1. Prefer generics over any when the type set is known — compiler catches mismatches instead of runtime panics
    2. Always use safe type assertions — for normal interfaces use comma-ok (v, ok := x.(T)); for reflection in Go 1.25+ prefer reflect.TypeAssert[T](value) over value.Interface().(T).
    3. Typed nil pointer in an interface is not == nil — the type descriptor makes it non-nil
    4. Writing to a nil map panics — always initialize before use
    5. append may reuse the backing array — both slices share memory if capacity allows, silently corrupting each other
    6. Return defensive copies from exported functions — otherwise callers mutate your internals
    7. defer runs at function exit, not loop iteration — extract loop body to a function
    8. Integer conversions truncate silently — int64 to int32 wraps without error
    9. Float arithmetic is not exact — use epsilon comparison or math/big
    10. Design useful zero values — nil map fields panic on first write; use lazy init
    11. Use sync.Once for lazy init — guarantees exactly-once even under concurrency

    Nil Safety

    Nil-related panics are the most common crash in Go.

    The nil interface trap

    Interfaces store (type, value). An interface is nil only when both are nil. Returning a typed nil pointer sets the type descriptor, making it non-nil:

    // ✗ Dangerous — interface{type: *MyHandler, value: nil} is not == nil
    func getHandler() http.Handler {
        var h *MyHandler // nil pointer
        if !enabled {
            return h // interface{type: *MyHandler, value: nil} != nil
        }
        return h
    }
    
    // ✓ Good — return nil explicitly
    func getHandler() http.Handler {
        if !enabled {
            return nil // interface{type: nil, value: nil} == nil
        }
        return &MyHandler{}
    }
    

    Nil map, slice, and channel behavior

    Type Index into nil Write to nil Len/Cap of nil Range over nil
    Map Zero value panic 0 0 iterations
    Slice panic panic 0 0 iterations
    Channel Blocks forever Blocks forever 0 Blocks forever
    // ✗ Bad — nil map panics on write
    var m map[string]int
    m["key"] = 1
    
    // ✓ Good — initialize or lazy-init in methods
    m := make(map[string]int)
    
    func (r *Registry) Add(name string, val int) {
        if r.items == nil { r.items = make(map[string]int) }
        r.items[name] = val
    }
    

    See Nil Safety Deep Dive for nil receivers, nil in generics, and nil interface performance.

    Slice & Map Safety

    Slice aliasing — the append trap

    append reuses the backing array if capacity allows. Both slices then share memory:

    // ✗ Dangerous — a and b share backing array
    a := make([]int, 3, 5)
    b := append(a, 4)
    b[0] = 99 // also modifies a[0]
    
    // ✓ Good — full slice expression forces new allocation
    b := append(a[:len(a):len(a)], 4)
    

    Map concurrent access

    Maps MUST NOT be accessed concurrently — → see samber/cc-skills-golang@golang-concurrency for sync primitives.

    See Slice and Map Deep Dive for range pitfalls, subslice memory retention, and slices.Clone/maps.Clone.

    Numeric Safety

    Implicit type conversions truncate silently

    // ✗ Bad — silently wraps around if val > math.MaxInt32 (3B becomes -1.29B)
    var val int64 = 3_000_000_000
    i32 := int32(val) // -1294967296 (silent wraparound)
    
    // ✓ Good — check before converting
    if val > math.MaxInt32 || val < math.MinInt32 {
        return fmt.Errorf("value %d overflows int32", val)
    }
    i32 := int32(val)
    

    Float comparison

    // ✗ Bad — floating point arithmetic is not exact
    var a, b, c float64 = 0.1, 0.2, 0.3
    a+b == c // false
    
    // ✓ Good — use epsilon comparison
    const epsilon = 1e-9
    math.Abs((a+b)-c) < epsilon // true
    

    Division by zero

    Integer division by zero panics. Float division by zero produces +Inf, -Inf, or NaN.

    func avg(total, count int) (int, error) {
        if count == 0 {
            return 0, errors.New("division by zero")
        }
        return total / count, nil
    }
    

    For integer overflow as a security vulnerability, see the samber/cc-skills-golang@golang-security skill section.

    Resource Safety

    defer in loops — resource accumulation

    defer runs at function exit, not loop iteration. Resources accumulate until the function returns:

    // ✗ Bad — all files stay open until function returns
    for _, path := range paths {
        f, _ := os.Open(path)
        defer f.Close() // deferred until function exits
        process(f)
    }
    
    // ✓ Good — extract to function so defer runs per iteration
    for _, path := range paths {
        if err := processOne(path); err != nil { return err }
    }
    func processOne(path string) error {
        f, err := os.Open(path)
        if err != nil { return err }
        defer f.Close()
        return process(f)
    }
    

    Goroutine leaks

    → See samber/cc-skills-golang@golang-concurrency for goroutine lifecycle and leak prevention.

    Immutability & Defensive Copying

    Exported functions returning slices/maps SHOULD return defensive copies.

    Protecting struct internals

    // ✗ Bad — exported slice field, anyone can mutate
    type Config struct {
        Hosts []string
    }
    
    // ✓ Good — unexported field with accessor returning a copy
    type Config struct {
        hosts []string
    }
    
    func (c *Config) Hosts() []string {
        return slices.Clone(c.hosts)
    }
    

    Initialization Safety

    Zero-value design

    Design types so var x MyType is safe — prevents "forgot to initialize" bugs:

    var mu sync.Mutex   // ✓ usable at zero value
    var buf bytes.Buffer // ✓ usable at zero value
    
    // ✗ Bad — nil map panics on write
    type Cache struct { data map[string]any }
    

    sync.Once for lazy initialization

    type DB struct {
        once sync.Once
        conn *sql.DB
    }
    
    func (db *DB) connection() *sql.DB {
        db.once.Do(func() {
            db.conn, _ = sql.Open("postgres", connStr)
        })
        return db.conn
    }
    

    init() function pitfalls

    → See samber/cc-skills-golang@golang-design-patterns for why init() should be avoided in favor of explicit constructors.

    Enforce with Linters

    Many safety pitfalls are caught automatically by linters: errcheck, forcetypeassert, nilerr, govet, staticcheck. See the samber/cc-skills-golang@golang-lint skill for configuration and usage.

    Go 1.25+ reflection type assertions

    For reflection code, prefer reflect.TypeAssert[T] over value.Interface().(T).

    v := reflect.ValueOf(x)
    if s, ok := reflect.TypeAssert[string](v); ok {
        use(s)
    }
    

    Cross-References

    • → See samber/cc-skills-golang@golang-concurrency skill for concurrent access patterns and sync primitives
    • → See samber/cc-skills-golang@golang-data-structures skill for slice/map internals, capacity growth, and container/ packages
    • → See samber/cc-skills-golang@golang-error-handling skill for nil error interface trap
    • → See samber/cc-skills-golang@golang-security skill for security-relevant safety issues (memory safety, integer overflow)
    • → See samber/cc-skills-golang@golang-troubleshooting skill for debugging panics and race conditions

    Common Mistakes

    Mistake Fix
    Bare type assertion v := x.(T) Panics on type mismatch, crashing the program. Use v, ok := x.(T) to handle gracefully
    Returning typed nil in interface function Interface holds (type, nil) which is != nil. Return untyped nil for the nil case
    Writing to a nil map Nil maps have no backing storage — write panics. Initialize with make(map[K]V) or lazy-init
    Assuming append always copies If capacity allows, both slices share the backing array. Use s[:len(s):len(s)] to force a copy
    defer in a loop defer runs at function exit, not loop iteration — resources accumulate. Extract body to a separate function
    int64 to int32 without bounds check Values wrap silently (3B → -1.29B). Check against math.MaxInt32/math.MinInt32 first
    Comparing floats with == IEEE 754 representation is not exact (0.1+0.2 != 0.3). Use math.Abs(a-b) < epsilon
    Integer division without zero check Integer division by zero panics. Guard with if divisor == 0 before dividing
    Returning internal slice/map reference Callers can mutate your struct's internals through the shared backing array. Return a defensive copy
    Multiple init() with ordering assumptions init() execution order across files is unspecified. → See samber/cc-skills-golang@golang-design-patterns — use explicit constructors
    Blocking forever on nil channel Nil channels block on both send and receive. Always initialize before use

    Cross-References

    • → See samber/cc-skills-golang@golang-continuous-integration skill for automated AI-driven code review in CI using these guidelines

    Reproducido de samber/cc-skills-golang bajo licencia MIT. Leer esta página en markdown.

    Archivos

    4 archivos en el paquete. Solo se lee SKILL.md al activarse — las referencias se cargan si el skill decide que las necesita.

    Antes de instalar

    Requiere el binario go instalado; opcionalmente golangci-lint y git.

    Detalles

    Creador
    samber
    Categoría
    Testing y QA
    Licencia
    MIT
    Recursos incluidos
    referencias
    Código fuente
    Ver SKILL.md

    Etiquetas

    Más de samber/cc-skills-golang

    Este repo incluye 46 skills. Si instalas uno, normalmente ya tienes los demás. Ver el pack cc-skills-golang entero y su comando de instalación

    Buenas prácticas de linting y configuración de golangci-lint para proyectos Golang: ejecutar linters, configurar .golangci.yml, suprimir avisos con nolint, interpretar salidas y elegir linters.

    Costo de contexto al activarse
    1.8k tok
    Tamaño del paquete
    5 archivos
    Última actualización
    el mes pasado
    herramientas desarrollo

    Benchmarking, profiling y medición de rendimiento en Golang: escribir y comparar benchmarks, perfilar con pprof, analizar con benchstat y detectar regresiones en CI.

    Costo de contexto al activarse
    3.3k tok
    Tamaño del paquete
    10 archivos
    Última actualización
    hace 2 meses
    testing qa

    Orquestador de skills de Golang, siempre activo en cualquier tarea de código, revisión, debug o setup: carga las skills más relevantes de samber/cc-skills-golang, a menudo varias a la vez.

    Costo de contexto al activarse
    3.8k tok
    Tamaño del paquete
    4 archivos
    Última actualización
    hace 2 meses
    herramientas desarrollo

    Patrones y metodología de optimización de rendimiento en Golang: si hay cuello de botella X, aplica el patrón Y, una vez que profiling o benchmarks ya lo identificaron.

    Costo de contexto al activarse
    2.3k tok
    Tamaño del paquete
    9 archivos
    Última actualización
    hace 2 meses
    herramientas desarrollo

    Tests de Golang listos para producción: table-driven, suites y mocks con testify, tests paralelos, fuzzing, fixtures, detección de fugas de goroutines con goleak, snapshot testing, cobertura, tests de integración.

    Costo de contexto al activarse
    4.4k tok
    Tamaño del paquete
    6 archivos
    Última actualización
    hace 2 meses
    testing qa

    Inyección de dependencias en Golang con samber/do: contenedores de servicios, gestión de ciclo de vida, scopes, health checks, apagado ordenado y organización en módulos.

    Costo de contexto al activarse
    2.3k tok
    Tamaño del paquete
    4 archivos
    Última actualización
    hace 2 meses
    herramientas desarrollo

    Skills relacionados

    Benchmarking, profiling y medición de rendimiento en Golang: escribir y comparar benchmarks, perfilar con pprof, analizar con benchstat y detectar regresiones en CI.

    Costo de contexto al activarse
    3.3k tok
    Tamaño del paquete
    10 archivos
    Última actualización
    hace 2 meses
    testing qa

    Guía completa de stretchr/testify para testing en Golang: assert, require, mock y suite, con matchers, verificación de llamadas y patrones avanzados como Eventually y JSONEq.

    Costo de contexto al activarse
    1.8k tok
    Tamaño del paquete
    3 archivos
    Última actualización
    hace 2 meses
    testing qa

    Tests de Golang listos para producción: table-driven, suites y mocks con testify, tests paralelos, fuzzing, fixtures, detección de fugas de goroutines con goleak, snapshot testing, cobertura, tests de integración.

    Costo de contexto al activarse
    4.4k tok
    Tamaño del paquete
    6 archivos
    Última actualización
    hace 2 meses
    testing qa