Tema: go
-
Elegir Go o Rust para un nuevo servicio: un procedimiento de decisión sin benchmarks
Decidir entre Go y Rust para un servicio a partir de propiedades documentadas de cada lenguaje y de las limitaciones del equipo, en lugar de a partir del folclore de los benchmarks: el modelo de gestión de memoria, el estilo de manejo de errores y de concurrencia, la forma de la carga de trabajo, las bibliotecas con las que el servicio debe comunicarse, y quién lo mantendrá dentro de dos años.
-
Cancelación y plazos en Go con context.Context
Propagar un context.Context desde la solicitud entrante a través de cada llamada que pueda bloquear, derivar contextos hijos con WithTimeout o WithCancel, llamar siempre a la función cancel, y comprobar ctx.Done() en los bucles, de modo que la desconexión de un cliente o un plazo cumplido detengan todo el árbol de goroutines en lugar de dejarlas en ejecución.
-
Tiempo transcurrido en Go: la serialización pierde el componente de reloj monótono
Mantener separada la medición local de duración de las marcas de tiempo persistidas y de las políticas de plazos entre procesos.
-
Interfaces de Go: satisfacción implícita y el nil que no es nil
Un tipo de Go satisface una interfaz simplemente por tener sus métodos; no se declara nada. Eso hace que las interfaces pequeñas definidas en el punto de uso sean baratas, pero un valor de interfaz es un par de tipo y valor, de modo que un puntero nil almacenado en una interfaz error no es igual a nil.
-
Aliasing con append en Go: probar tanto la ruta de capacidad sobrante como la de reasignación
Hacer explícita la propiedad de un slice cuando hacer append sobre una vista puede modificar el almacenamiento observado en otro lugar.
-
Manejo de errores en Go: envolver con %w, errors.Is y errors.As
Las funciones de Go devuelven los errores como valores ordinarios; se añade contexto con fmt.Errorf y el verbo %w para que el original siga siendo accesible, y después se comprueba la cadena con errors.Is para los valores centinela y errors.As (o la versión genérica errors.AsType) para los tipos, en lugar de comparar cadenas o usar ==.
-
Goroutines, canales y el paquete sync: panorama de la concurrencia en Go
Una sentencia go ejecuta una llamada a función de forma concurrente sobre una pila barata y ampliable; los canales transfieren valores entre goroutines y bloquean hasta que ambos extremos están listos; sync.WaitGroup, Mutex y Once cubren los casos en los que compartir memoria es más sencillo. Una condición de carrera es un error cuyo resultado el modelo de memoria solo restringe en parte, y el detector -race es la herramienta para encontrarla.
-
¿Cuánto más tarda un ingeniero que viene de un lenguaje dinámico en ser productivo en Rust que en Go, y qué conceptos explican la diferencia?
Pregunta abierta: suele decirse que Go se aprende rápido y que Rust es exigente, y la encuesta State of Rust 2024 indica que alrededor del 31 % de quienes no usan Rust citan la dificultad percibida; pero pocas fuentes miden el tiempo hasta un primer cambio integrado, hasta revisar código sin supervisión o qué conceptos (ownership, lifetimes, async, traits) consumen ese tiempo en ingenieros que llegan de Python, Ruby o JavaScript.
-
Pruebas basadas en tablas en Go con subpruebas
Escribe una única función de prueba que recorra un slice de casos con nombre y ejecute cada uno con t.Run: los casos pasan a ser datos, se puede elegir uno con go test -run 'TestX/name', y t.Parallel, t.Helper y t.Cleanup mantienen el bucle rápido y legible.
-
Cobertura del detector de condiciones de carrera de Go: una ejecución limpia no dice nada sobre las rutas que no se ejecutan
Relaciona los resultados de go test -race con las rutas concurrentes que realmente se ejercitan, incluidos el arranque y el apagado.
-
Traits de Rust frente a interfaces de Go: impl explícito frente a satisfacción implícita
Ambos lenguajes abstraen comportamiento sin jerarquías de clases, pero en Go un tipo satisface una interfaz con solo tener los métodos, mientras que en Rust implementa un trait únicamente mediante un bloque impl explícito sujeto a la regla de huérfanos. Además, Rust distingue entre genéricos en tiempo de compilación (monomorfizados) y objetos trait dyn (despacho dinámico), una elección que Go toma en lugar del programador.
-
Módulos de Go: go.mod, go.sum y el sufijo de versión mayor
Un módulo de Go es un árbol versionado de paquetes descrito por go.mod; el comando go elige las versiones de las dependencias mediante selección de versión mínima, verifica las descargas con go.sum y exige un sufijo del tipo /v2 en la ruta del módulo para toda versión mayor superior a 1, de modo que las versiones incompatibles tengan rutas de importación distintas.
-
Copia de mutex en Go: mantener la identidad del bloqueo junto con el estado que protege
Revisa los receptores por valor, las asignaciones y las operaciones sobre contenedores que pueden copiar una estructura con un mutex activo.
Legible por máquina: JSON