Depuración de código Go: de principiante a profesional en una tarde

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

Por qué falla tu código Go y cómo solucionarlo sin dolor de cabeza

\n\n

Escribiste un código Go que, según tu opinión, es perfecto. La compilación fue genial, las pruebas están en verde... pero en producción todo se va al traste. ¿Te suena? Bienvenido al mundo real del desarrollo, donde los bugs no son errores de principiantes, sino parte del crecimiento profesional. Hoy analizaremos la depuración de código Go para que no solo encuentres errores, sino que prevengas su aparición en la etapa de escritura.

\n\n

Go es un lenguaje que le brinda al desarrollador potentes herramientas de depuración directamente "de fábrica". Pero muchos solo usan fmt.Println y se preguntan sinceramente por qué sus gorutinas se comportan como gatos sobre un tejado de zinc caliente. Arreglemos esto de una vez por todas.

\n\n

Técnica n.º 1: Print inteligente: cuando log.Fatal no es necesario

\n\n

Sí, sé lo que dirás: "¿Para qué necesito delve si puedo imprimir una variable?" Y tendrás razón en el 80% de los casos. Pero el problema no es fmt.Println, sino cómo lo usas.

\n\n

Pasando de Println al registro estructurado

\n\n

En lugar de poner decenas de prints, usa el paquete log o slog (disponible desde Go 1.21):

\n\n
package main\n\nimport (\n    "log/slog"\n    "os"\n)\n\nfunc main() {\n    logger := slog.New(slog.NewTextHandler(os.Stdout, nil))\n    \n    // En lugar de fmt.Println("error:", err)\n    if err := doSomething(); err != nil {\n        logger.Error("la operación falló", \n            "error", err,\n            "module", "data_processor",\n            "attempt", 3,\n        )\n    }\n}\n
\n\n

Este enfoque te proporciona registros estructurados que son fáciles de analizar, filtrar y examinar. En producción, esto te salvará de llamadas nocturnas.

\n\n

Truco: compilación condicional para registros de depuración

\n\n

Para no saturar la producción, usa build tags:

\n\n
//go:build debug\n\npackage main\n\nvar debug = true\n
\n\n
//go:build !debug\n\npackage main\n\nvar debug = false\n
\n\n

Ejecuta con el flag -tags debug y obtienes registros detallados. Sin el flag, producción limpia.

\n\n

Técnica n.º 2: Delve: tu detective personal para Go

\n\n

Si la depuración con print es una bicicleta, Delve es un Tesla. Este depurador está creado específicamente para Go y entiende gorutinas, interfaces e incluso generics. La instalación es sencilla:

\n\n
go install github.com/go-delve/delve/cmd/dlv@latest\n
\n\n

Puntos de interrupción que saben pensar

\n\n

Delve permite establecer no solo breakpoints, sino puntos condicionales:

\n\n
(dlv) break main.go:25 if userID == 42\n(dlv) continue\n
\n\n

El depurador se detendrá solo cuando userID sea igual a 42. Imagina cuánto tiempo ahorra esto al depurar bucles.

\n\n

Investigación de gorutinas

\n\n

Lo más aterrador en Go son los deadlocks y las race conditions. Delve muestra todas las gorutinas activas:

\n\n
(dlv) goroutines\n  Goroutine 1 - User: ./main.go:10 main.main (0x109a5b6)\n  Goroutine 2 - User: ./main.go:15 main.worker (0x109a6c8)\n* Goroutine 3 - User: ./main.go:22 main.worker (0x109a6c8)\n
\n\n

El asterisco muestra la gorutina actual. Cambia entre ellas:

\n\n
(dlv) goroutine 2\n(dlv) stack\n
\n\n

Trabajo con memoria: viendo lo que hay dentro

\n\n

El comando locals muestra todas las variables locales, y print muestra sus valores con tipos:

\n\n
(dlv) locals\ndata = []int len: 100000, cap: 100000\nresult = map[string]int ["error": 5, "success": 99995]\n(dlv) print data[0:5]\n[]int len: 5, cap: 100000, [42, 17, 89, 3, 256]\n
\n\n

Técnica n.º 3: Creación de perfiles con pprof: encuentra los cuellos de botella

\n\n

¿Tu código funciona, pero es lento? pprof es el perfilador integrado de Go. Te mostrará dónde "se ralentiza" el programa y dónde consume memoria.

\n\n

Añadiendo un endpoint HTTP

Blogs

Book Recommendations