Introducción: por qué el code review en Go no es solo una marca
\nEl code review no es un procedimiento burocrático, sino un elemento clave de la cultura de desarrollo. En Go, con su sintaxis concisa y reglas estrictas, la revisión a menudo se convierte en el primer filtro que elimina problemas en una etapa temprana. Muchos equipos que migran a Golang se enfrentan a que los viejos hábitos (por ejemplo, de Python o PHP) no funcionan: Go perdona menos errores relacionados con tipos, pero requiere atención a los detalles.
\nEn la práctica, el code review en Go resuelve tres tareas: capacitación del equipo (los novatos se integran más rápido al estilo de código), mejora de la calidad (detección de errores y antipatrones) y consistencia del código (para que el proyecto no se convierta en una "colcha de retazos"). Analicemos exactamente qué observar y cómo formular observaciones.
\n\n1. ¿Qué revisar primero?: desde sintaxis hasta errores
\nCualquier revisión comienza con lo básico. En Go hay varios "puntos críticos" que vale la pena verificar automática o manualmente.
\n\n1.1. Manejo de errores (error handling)
\nGo no usa excepciones: los errores se devuelven como valores. Un problema común: el desarrollador ignora el error devuelto usando _. Esto solo es aceptable en casos raros (por ejemplo, fmt.Println).
// Mal: se ignora el error\nresp, _ := http.Get("https://api.example.com/data")\n\n// Bien: se maneja el error\nresp, err := http.Get("https://api.example.com/data")\nif err != nil {\n log.Printf("no se pudieron obtener los datos: %v", err)\n return err\n}\ndefer resp.Body.Close()\nQué revisar:
\n- \n
- ¿Se manejan todos los errores (no solo con
_)? \n - ¿Se usa
deferpara cerrar recursos (archivos, conexiones)? \n - ¿No se "tragan" los errores en las gorutinas? \n
1.2. Nomenclatura y estilo (Go idioms)
\nGo exige brevedad: camelCase para privados, PascalCase para exportados. Evite la "notación húngara" y nombres largos.
// Mal\nfunc GetUserDataFromDatabase(userID int) (*UserData, error)\n\n// Bien\nfunc GetUser(id int) (*User, error)\nSeñales de alerta:
\n- \n
- Nombres de variables como
temp,data,val(demasiado genéricos). \n - Funciones de más de 30-40 líneas (hay que dividirlas). \n
- Falta de comentarios en funciones exportadas (es un requisito de
golint). \n
1.3. Gorutinas y sincronización
\nEsta es la parte más compleja. Los errores en código concurrente son una fuente frecuente de bugs en producción.
\n// Mal: condición de carrera (data race)\nvar counter int\nfor i := 0; i < 100; i++ {\n go func() {\n counter++ // inseguro\n }()\n}\n\n// Bien: usamos un mutex\nvar mu sync.Mutex\nvar counter int\nfor i := 0; i < 100; i++ {\n go func() {\n mu.Lock()\n counter++\n mu.Unlock()\n }()\n}\nQué revisar:
\n- \n
- ¿Hay
sync.Mutexoatomicpara datos compartidos? \n - ¿Se olvidaron de cerrar el canal (
close(ch))? \n - ¿No "fugan" gorutinas (sin
selectcon timeout)? \n
2. Revisiones arquitectónicas: desde interfaces hasta paquetes
\nDespués de la sintaxis básica, observamos la estructura del código. Go fomenta la composición, no la herencia.
\n\n2.1. Interfaces: pequeñas y del lado del consumidor
\nEn Go, las interfaces se implementan implícitamente. Una buena interfaz contiene 1-3 métodos. Verifique si el autor no intenta hacer una interfaz "todopoderosa".
\n// Mal: interfaz enorme\ntype Storage interface {\n Save(data []byte) error\n Load(id string) ([]byte, error)\n Delete(id string) error\n List() ([]string, error)\n Connect() error\