Este texto describe cómo prepararse para una entrevista de trabajo como desarrollador Go (Go: ¿Qué hay Debajo del Capó y Por qué Deberías Aprenderlo como Segundo Lenguaje?), dependiendo del nivel de experiencia (Middle, Middle+ y Senior). Se incluyen ejemplos de preguntas y soluciones.
Una entrevista desarrollador Go puede ser un reto en cualquier nivel. En esta guía pretende prepararte para el éxito con ejemplos de preguntas, ejercicios prácticos y consejos.
Consejos: Entrevista desarrollador Go

¿Qué preguntan al contratar a un desarrollador Go de nivel Middle?
La entrevista se divide en dos partes: una presentación personal y preguntas prácticas.
- Parte 1: Presentación personal
Se te pedirá que hables sobre ti, tu experiencia en proyectos, tu formación y las tareas que has realizado.
- Parte 2: Preguntas prácticas
- Conocimientos generales del lenguaje Go: Se espera que conozcas los siguientes 14 puntos:
- Concurrencia: goroutines y canales (base del lenguaje).
- Sistema de tipos e interfaces (tipado estático).
- Gestión de memoria y punteros.
- Manejo de errores (error handling).
- Trabajo con paquetes y módulos (go mod).
- Pruebas (paquete testing integrado).
- Trabajo con cadenas de texto y UTF-8.
- Slices y maps (características de su implementación).
- Reflection y etiquetas de estructuras.
- Depuración y perfilado (pprof).
- Trabajo con archivos e IO.
- Contextos (context.Context).
- Trabajo con JSON/XML (paquetes encoding).
- Generación de código (go generate).
- Solución de problemas prácticos: Deberás resolver problemas utilizando algoritmos básicos. A continuación se muestra un ejemplo:
Ejemplo: Implementar un limitador de velocidad simple en Go
Se debe implementar un limitador de velocidad que restrinja el número de solicitudes por segundo. La solución debe ser segura para la concurrencia y ocupar poco código.
Criterios de evaluación:
- Seguridad para la concurrencia de la implementación.
- Eficiencia al eliminar solicitudes obsoletas (O(1)).
- Funcionamiento correcto con ventanas de tiempo.
- Limpieza del código y uso de las expresiones idiomáticas de Go.
- Presencia de pruebas.
Solución (en Go):
// rate_limiter.go
package main
import (
"sync"
"time"
)
type RateLimiter struct {
window time.Duration
maxReq int
reqs []time.Time
mutex sync.Mutex
timeFunc func() time.Time
}
func NewRateLimiter(window time.Duration, maxRequests int) *RateLimiter {
return &RateLimiter{
window: window,
maxReq: maxRequests,
reqs: make([]time.Time, 0),
timeFunc: time.Now,
}
}
func (rl *RateLimiter) Allow() bool {
rl.mutex.Lock()
defer rl.mutex.Unlock()
now := rl.timeFunc()
cutoff := now.Add(-rl.window)
// Eliminamos solicitudes obsoletas
for i, t := range rl.reqs {
if t.After(cutoff) {
rl.reqs = rl.reqs[i:]
break
}
}
if len(rl.reqs) < rl.maxReq {
rl.reqs = append(rl.reqs, now)
return true
}
return false
}
// rate_limiter_test.go
package main
import (
"sync"
"testing"
"time"
)
func TestRateLimiter(t *testing.T) {
// Creamos una función de tiempo ficticia para pruebas deterministas
fakeTime := time.Now()
limiter := &RateLimiter{
window: time.Second,
maxReq: 3,
reqs: make([]time.Time, 0),
timeFunc: func() time.Time { return fakeTime },
}
var wg sync.WaitGroup
allowed := 0
denied := 0
var mu sync.Mutex
// Realizamos 5 solicitudes de forma concurrente
for i := 0; i < 5; i++ {
wg.Add(1)
go func() {
defer wg.Done()
isAllowed := limiter.Allow()
mu.Lock()
defer mu.Unlock()
if isAllowed {
allowed++
return
}
denied++
}()
}
wg.Wait()
if allowed != 3 || denied != 2 {
t.Errorf("Se esperaban 3 permitidas y 2 denegadas, se obtuvieron %d permitidas y %d denegadas", allowed, denied)
}
}
- Experiencia en la implementación de guías de estilo: Se te preguntará sobre tus experiencias implementando guías de estilo, los objetivos de su implementación y los resultados obtenidos.
- Conocimiento de patrones de diseño básicos: Se espera que conozcas y puedas aplicar patrones de diseño básicos en Go.
Categoría | Patrón | Descripción |
---|---|---|
Patrones de concurrencia en Go | Worker Pool | Gestión de un pool de goroutines para el procesamiento paralelo de tareas. Permite limitar el número de tareas que se ejecutan simultáneamente. |
Fan-out/Fan-in | Distribución del trabajo entre varios workers (fan-out) y recolección de resultados (fan-in). Útil para el procesamiento paralelo de datos. | |
Pipeline | Procesamiento secuencial de datos a través de una cadena de goroutines. Cada etapa procesa los datos y los pasa a la siguiente. | |
Patrones de diseño clásicos (GoF) | Decorator | Añadir comportamiento a los objetos sin modificar su estructura. En Go se implementa mediante composición y embedding. |
Composite | Composición de objetos en estructuras en forma de árbol. Permite trabajar de manera uniforme con objetos individuales y con sus composiciones. | |
Adapter | Conversión de la interfaz de un objeto a la interfaz esperada por el cliente. Útil para integrar interfaces incompatibles. | |
Strategy | Encapsulación de una familia de algoritmos y su intercambiabilidad. Permite elegir el algoritmo en tiempo de ejecución. | |
Observer | Mecanismo de suscripción para notificar cambios. En Go se implementa a través de canales. | |
Command | Encapsulación de una solicitud como objeto. Permite parametrizar a los clientes con diferentes solicitudes. | |
Patrones idiomáticos de Go | Functional Options | Forma idiomática de configuración en Go. Permite crear APIs flexibles con parámetros opcionales. |
¿Qué preguntan al contratar a un desarrollador Go de nivel Middle+?
Las preguntas evaluarán tus conocimientos técnicos, experiencia, habilidades y cualidades personales.
- Conocimiento de construcciones específicas del lenguaje: Por ejemplo, comprensión y aplicación de interfaces.
- Uso idiomático del lenguaje: Escribir código Go de forma eficiente y legible.
- Diseño e implementación de un pequeño servicio: Capacidad para diseñar y construir un servicio pequeño y funcional.
- Experiencia en proyectos: Descripción de proyectos en los que has participado, tu rol y las tareas que has realizado.
- Conocimiento de herramientas básicas: otel, gRPC, Protobuf, HTTP(s), etc.
- Conceptos básicos de redes y transmisión de datos:
- Modelo OSI y TCP/IP.
- Protocolos de capa de transporte (TCP/UDP).
- Protocolos HTTP/HTTPS.
- gRPC y Protocol Buffers.
- WebSockets.
- Trabajo con sockets.
- Concurrencia en operaciones de red.
- Seguridad de las conexiones de red.
- Prácticas de testing: Conocimiento y aplicación de diferentes tipos de pruebas (unitarias, funcionales, de estrés, de rendimiento, fuzzing).
- Uso de linters: Aplicación de linters localmente y en entornos CI/CD.
- Herramientas de perfilado y depuración: Dominio de herramientas para el análisis de rendimiento y la depuración de código.
- Importancia de las herramientas de observabilidad: Comprensión de la importancia de implementar herramientas de observabilidad.
- Participación en revisiones de código: Experiencia en la revisión de código de tus compañeros.
- Principios de diseño de sistemas: Conocimiento y aplicación de los principios de diseño de sistemas.
- Documentación: Cómo documentas tu código (¿a través del código o de una wiki?), cómo mantienes la documentación actualizada y cómo evitas la obsolescencia.
- Escritura de código limpio y legible: Capacidad para escribir código simple y claro, sin construcciones innecesarias. Ejemplo de código limpio vs. código complejo:
package main
import (
"fmt"
"os"
"strings"
)
// Ejemplo de función de un programador principiante
func ProcessDataBeginner(input string) ([]string, error) {
// Comprobación redundante
if input == "" {
err := fmt.Errorf("entrada vacía")
return nil, err
}
// Varias variables para una operación simple
var result []string
var temp string
var i int
for i = 0; i < len(input); i++ {
if input[i] != ',' {
temp += string(input[i])
} else {
if temp != "" {
result = append(result, temp)
temp = ""
}
}
}
// Lógica duplicada
if temp != "" {
result = append(result, temp)
}
// Manejo de errores incorrecto
if len(result) == 0 {
return result, fmt.Errorf("no hay datos")
}
return result, nil
}
// Ejemplo de función de un desarrollador experimentado
func ProcessDataExpert(input string) ([]string, error) {
// Comprobación única
if input == "" {
return nil, fmt.Errorf("entrada vacía")
}
// Mínimo de variables, legibilidad
return strings.Split(input, ","), nil
}
func main() {
// Ejemplo de uso
input := "go,java,python,cpp"
// Llamada a la versión principiante
result1, err1 := ProcessDataBeginner(input)
fmt.Println("Versión principiante:", result1, err1)
// Llamada a la versión experta
result2, err2 := ProcessDataExpert(input)
fmt.Println("Versión experta: ", result2, err2)
}
¿Qué preguntan al contratar a un desarrollador Go de nivel Senior?
Al contratar a un desarrollador Go para una posición Senior se formulan preguntas que verifican los conocimientos técnicos, la experiencia laboral, las habilidades y las cualidades personales del candidato.
Ante todo, un Senior es un desarrollador independiente, y sus decisiones deben ser óptimas.
- Saber diseñar la arquitectura de aplicaciones.
- Tener experiencia trabajando con sistemas distribuidos.
- Demostrar habilidades de depuración y perfilado.
- Hablar sobre su experiencia: en qué proyectos participó, su rol y su aporte.
- Conocer el conjunto básico: OpenTelemetry (OTel), gRPC, Protobuf, HTTP(s), entre otros.
- Explicar qué prácticas de testing aplica en el trabajo (pruebas unitarias, funcionales, de estrés, de rendimiento, fuzzing).
- Ser capaz de crear rápidamente prototipos y validar conceptos.
- Contar cuál ha sido su grado de participación en revisiones de código de sus colegas.
- Entender y aplicar principios de diseño de sistemas.
- Saber —o al menos estar dispuesto a— ayudar a los compañeros y compartir su experiencia. Contar un ejemplo personal.
Los Seniors también deben aplicar activamente herramientas basadas en IA en su trabajo: agentes de IA, revisiones automáticas con modelos, asistentes de IA, generación de documentación, generación de pruebas, búsqueda de vulnerabilidades, etc.
Asimismo, en una entrevista un Senior debe demostrar amplitud de conocimientos, erudición y compromiso. Por ejemplo, explicar qué novedades aparecieron en las dos últimas versiones del lenguaje, cómo aplicarlas de manera útil o qué traerá de nuevo y práctico la próxima versión de Go.
Las respuestas muestran el grado de interés y profundidad del candidato en el área, así como su disposición y motivación para seguir desarrollándose.
Cómo prepararse para la entrevista: consejo del experto
- Presta atención a la concurrencia (goroutines, canales, paquete
sync
), interfaces, gestión de memoria y manejo de errores. Revisa las diferencias entremap
yslice
, y el funcionamiento dedefer
,panic
yrecover
. - Resuelve problemas de algoritmos y patrones concurrentes. Escribe código Go limpio teniendo en cuenta lo siguiente:
- La complejidad asintótica en tiempo y memoria debe ser óptima para el tipo de problema que resuelvas.
- Uso eficiente de los recursos.
- Trabajo correcto con contextos.
- Optimización de asignaciones (Middle+).
- Pruebas (Middle+).
- Estudia el funcionamiento interno: el planificador de goroutines, el recolector de basura, los mecanismos de gestión de memoria y los principios de construcción de sistemas distribuidos y tolerantes a fallos.