Clean Code en Go: principios y ejemplos prácticos
\n\nGo es un lenguaje que desde el principio fue diseñado con énfasis en la simplicidad y la legibilidad. Sin embargo, incluso en un lenguaje tan conciso se puede escribir código enredado y difícil de mantener. El concepto de Clean Code (código limpio) ayuda a los desarrolladores a crear programas que sean fáciles de leer, probar y modificar. En este artículo analizaremos los principios clave de Clean Code aplicados a Go y veremos ejemplos concretos.
\n\n¿Por qué es importante el código limpio en Go?
\n\nGo se utiliza a menudo para crear microservicios, API y sistemas de alta carga. En tales proyectos, un equipo de desarrolladores trabaja con el código. El código limpio reduce la carga cognitiva, acelera las revisiones de código y disminuye la cantidad de errores. El objetivo principal es escribir código que sea comprensible no solo para el autor, sino también para cualquier otro desarrollador que lo vea por primera vez.
\n\n1. Nomenclatura de variables y funciones
\n\nUna nomenclatura adecuada es la base del código limpio. En Go se acostumbra usar nombres cortos para variables locales y nombres más largos para entidades globales.
\n\nEjemplo malo
\npackage main\n\nfunc f(x int, y string) int {\n z, _ := strconv.Atoi(y)\n return x + z\n}\n\n\nEjemplo bueno
\npackage main\n\nfunc addPriceToCount(count int, priceStr string) int {\n price, _ := strconv.Atoi(priceStr)\n return count + price\n}\n\n\nReglas de nomenclatura en Go:
\n- \n
- Use
camelCasepara variables no exportadas (privadas). \n - Use
PascalCasepara funciones y tipos exportados (públicos). \n - Evite nombres de una sola letra, excepto para índices en bucles (
i,j). \n - No incluya el tipo de variable en su nombre (por ejemplo,
priceIntes malo,pricees bueno). \n
2. Estructura de paquetes y archivos
\n\nEn Go, cada paquete debe resolver una sola tarea. Divida el código por responsabilidad. La estructura estándar de un proyecto se ve así:
\n\nmyproject/\n├── cmd/\n│ └── server/\n│ └── main.go\n├── internal/\n│ ├── handler/\n│ ├── service/\n│ └── repository/\n├── pkg/\n│ └── utils/\n└── go.mod\n\n\nPrincipio: El paquete internal protege el código de importaciones externas. El paquete pkg contiene utilidades reutilizables. En cmd se almacenan los puntos de entrada (archivos main.go).
Ejemplo malo
\n// El paquete "utils" contiene de todo\npackage utils\n\nfunc Calculate(x, y int) int { ... }\nfunc SendEmail(to string) { ... }\nfunc ParseJSON(data []byte) { ... }\n\n\nEjemplo bueno
\n// El paquete "calculator" solo se encarga de cálculos\npackage calculator\n\nfunc Add(a, b int) int { return a + b }\n\n\n3. Manejo de errores en Go
\n\nEn Go no hay excepciones: los errores se devuelven como valores. El código limpio requiere un manejo explícito y significativo de cada error.
\n\nEjemplo malo
\nfunc readFile(path string) string {\n data, _ := os.ReadFile(path) // ignoramos el error\n return string(data)\n}\n\n\nEjemplo bueno
\nfunc readFile(path string) (string, error) {\n data, err := os.ReadFile(path)\n if err != nil {\n return "", fmt.Errorf("read file %s: %w", path, err)\n }\n return string(data), nil\n}\n\n\nConsejos para el manejo de errores:
\n- \n
- Nunca ignore los errores usando
_. \n - Siempre agregue contexto:
fmt.Errorf("operation: %w", err). \n - Use tipos de error personalizados para diferentes situaciones. \n
- No use
panicpara errores comunes, solo para situaciones verdaderamente excepcionales. \n
4. Funciones: longitud y responsabilidad
\n\nUna función