Errores comunes en Go y cómo evitarlos: Organización de código y proyecto

Organización de código y proyecto en Go

Sombreado no intencional de variables

El sombreado de vraiables ocurre cuando una variable local oculta a una variable del mismo nombre en un alcance exterior. En Go, el operador := se usa para declarar y asignar variables, mientras que = solo asigna. Un error común es usar := dentro de un bloque, creando una variable nueva en lugar de modificar la existente.

var contador int
contador, err := procesar() // Asigna a la variable existente en el mismo alcance
var contador int
if condicion {
    contador, err := procesar() // Crea una variable nueva, ocultando la exterior
}

Para evitar esto, use = para asignar a la variable exterior, o reestructure el código. Las herramientas como GoLand pueden resaltar estos problemas automáticamente.

Anidamiento innecesario de código

El exceso de anidamiento dificulta la legibilidad. En lugar de anidar bloques condicionales, use retornos tempranos para mantener el camino feliz alineado a la izquierda.

func procesarMal() {
    var datos []byte
    datos, err := leerEntrada(nil)
    if err != nil {
        return
    } else {
        // Código anidado innecesariamente
    }
}

func procesarBien() {
    var datos []byte
    datos, err := leerEntrada(nil)
    if err != nil {
        return // Retorno temprano en caso de error
    }
    // Continuación sin anidamiento
}

Uso inadecuado de la función init

La función init se ejecuta al importar un paquete, pero su uso excesivo puede limitar el manejo de errores y complicar las pruebas. Por ejemplo, inicializar una base de datos en init puede obligar a que el programa falle si hay un error, en lugar de dejar que el usuario decida.

var baseDatos *sql.DB
func init() {
    fuente := os.Getenv("MYSQL_SOURCE")
    db, err := sql.Open("mysql", fuente)
    if err != nil {
        log.Panic(err)
    }
    baseDatos = db
}

Una alternativa mejor es usar una función de inicialización diferida con manejo de errores explícito.

var baseDatos *sql.DB
var inicializar sync.Once

func ObtenerDB() (*sql.DB, error) {
    var err error
    inicializar.Do(func() {
        baseDatos, err = sql.Open("", "")
    })
    if err != nil {
        return nil, err
    }
    return baseDatos, nil
}

Sobreuso de getters y setters

En Go, no es necesario usar getters y setters como en otros lenguajes. Si no hay lógica adicional, acceda a los campos directamente. Use setters solo cuando sea necesario, por ejemplo, para validar datos o registrar cambios. El nombre del getter debe omitir "Get": en lugar de GetEdad(), use Edad().

Polución de interfaces

Las interfaces deben descubrirse, no crearse. Evite definir interfaces innecesarias. Mantenga las interfaces del lado del cliente para abstraer comportamientos específicos, y evite que las funciones devuelvan interfaces en lugar de implementaciones concretas.

Uso de any

El tipo any debe usarse solo cuando sea necesario aceptar o devolver cualquier tipo, como en json.Marshal. De lo contrario, reduce la expresividad del código y puede ocultar errores de compilación.

Uso de genéricos

Los genéricos en Go 1.18 ayudan a reducir código repetitivo, pero deben usarse con moderación. No los utilice prematuramente; introdúzcalos solo cuando haya una necesidad concreta para evitar complejidad innecesaria.

Problemas con la incrustación de tipos

La incrustación de tipos puede simplificar el código, pero puede causar problemas de visibilidad si algunos campos deberían permanecer ocultos. Use esta característica con cuidado.

Patrón de opciones funcionales

Para inicializar estructuras con múltiples parámetros, use el patrón de opciones funcionales. Esto mejora la legibilidad y mantiene la API flexible.

Organización del proyecto

Siga convenciones establecidas, como el layout de proyecto de Go, para estructurar su código. Evite crear paquetes genéricos como util; en su lugar, cree paquetes con nombres descriptivos.

package stringset
func Nuevo(...string) map[string]struct{} { ... }
func Ordenar(map[string]struct{}) []string { ... }

Colisiones de nombres

Evite que los nombres de variables colidan con los nombres de paquetes. Use nombres únicos o alias de importación para resolver conflictos.

Documentación del código

Documente todos los elementos exportados para ayudar a los usuarios y mantenedores a entender el propósito del código.

Uso de linters

Utilice herramientas de análisis estático como linters y formateadores para mejorar la calidad y consistencia del código.

Resumen de mejores prácticas:

  • Evite el sombreado de variables para prevenir errores de referencia.
  • Minimice el anidamiento para mejorar la legibilidad.
  • Use funciones específicas para inicialización en lugar de init.
  • Sea práctico con getters y setters; no los fuerce innecesariamente.
  • Descubra abstracciones en lugar de crearlas prematuramente.
  • Mantenga las interfaces del lado del cliente.
  • Las funciones deben devolver implementaciones concretas, no interfaces.
  • Use any solo cuando sea esencial.
  • Emplee genéricos cuando haya una necesidad real.
  • Use la incrustación de tipos con precaución.
  • Aplique el patrón de opciones funcionales para parámetros complejos.
  • Siga estructuras de proyecto estándar.
  • Nombre los paquetes de manera significativa, evitando utilidades genéricas.
  • Resuelva colisiones de nombres con alias o nombres únicos.
  • Documente el código exportado.
  • Utilice linters y formateadores para mantener la calidad.

Etiquetas: Go golang variable shadowing init function interfaces

Publicado el 6-16 19:01