Prepárate para entrevistas de Software Engineer con patrones de programación, estructuras de datos, algoritmos, diseño de sistemas, depuración, pruebas y preguntas de comportamiento.
Las entrevistas para Software Engineers evalúan si piensas con claridad, escribes código correcto, explicas compensaciones, analizas casos límite y colaboras de forma fiable.
3–6
rondas de entrevista habituales
45–60 min
de duración por ronda de código
6+
patrones esenciales de programación
4–8 sem.
de preparación recomendada
Qué evalúan los entrevistadores
—
Descomposición: ¿conviertes un enunciado ambiguo en un algoritmo concreto?
—
Estructuras de datos: ¿eliges una representación adecuada a las restricciones?
—
Corrección: ¿consideras casos límite, invariantes y fallos?
—
Calidad: ¿escribes código legible y mantenible bajo presión?
—
Complejidad: ¿explicas tiempo y espacio sin optimizar antes de tiempo?
—
Producción: ¿consideras fiabilidad, escala, pruebas y riesgo operativo?
—
Comunicación: ¿razonas en voz alta y respondes bien a las indicaciones?
Haz visible tu razonamiento
No programes veinte minutos en silencio. Explica primero el enfoque, los supuestos, un ejemplo y los casos límite. Se evalúa tanto el camino como el resultado.
Proceso de entrevista para Software Engineers
Los procesos habituales incluyen selección, una prueba técnica inicial, varias rondas de código, diseño de sistemas para perfiles sénior y conversaciones de colaboración y comportamiento.
Fases habituales
1
Entrevista con selección: confirma nivel, ubicación, rango salarial, permiso de trabajo y encaje.
2
Prueba técnica inicial: normalmente una tarea de código, a veces con depuración o fundamentos.
3
Rondas de programación: entre dos y cuatro problemas algorítmicos o prácticos.
4
Diseño de sistemas: para perfiles sénior, con arquitectura, escala, datos, API y resiliencia.
5
Comportamiento o valores: examina responsabilidad, colaboración, conflicto y madurez técnica.
6
Debrief: se integran señales de resolución, código, diseño y trabajo en equipo.
Entrevista de programación
Entrevista de diseño de sistemas
Pregunta central
¿Resuelves correctamente en código un problema acotado?
¿Diseñas un sistema fiable con restricciones reales?
Señal sólida
Algoritmo claro, implementación limpia, casos probados y complejidad correcta
Buenas API y modelos, plan de escala, compensaciones y fallos
Error habitual
Programar antes de aclarar entradas y casos límite
Dibujar cajas sin explicar flujo, responsabilidades ni restricciones
Mejor preparación
Reconocer patrones y ejecutar con limpieza
Comprender arquitecturas y razonar compensaciones en voz alta
No importa solo cuántos problemas resolviste
Cientos de ejercicios aportan poco si no explicas el enfoque, pruebas el código o eliges bien bajo presión. La calidad de la práctica supera a la cantidad.
Fundamentos de las entrevistas de programación
Un proceso repetible evita precipitarse, ayuda a encontrar un enfoque sólido y permite que el entrevistador siga tu razonamiento.
Un proceso fiable
1
Aclara entrada, salida, restricciones, duplicados, orden, nulos y comportamiento límite.
2
Resuelve manualmente un ejemplo pequeño e identifica la transformación.
3
Empieza por fuerza bruta si ayuda y explica qué podría almacenarse, ordenarse o recorrer de otra forma.
4
Elige patrón y estructura y declara la invariante que garantiza la corrección.
5
Escribe código claro, con nombres comprensibles y sin trucos innecesarios.
6
Prueba un caso normal, límites y un caso que cuestione tus supuestos.
7
Explica tiempo y espacio, incluida ordenación, pila recursiva y estructuras auxiliares.
Conceptos esenciales
Invariante
Condición que permanece cierta durante el algoritmo y permite justificar su corrección.
Complejidad amortizada
Coste medio a lo largo de una secuencia de operaciones, como en tablas hash o arrays dinámicos.
Espacio de búsqueda
Conjunto de respuestas o estados posibles explorado mediante búsqueda binaria, backtracking, BFS o DP.
Estado
Información necesaria en un punto del algoritmo para tomar la siguiente decisión.
✓ Recomendado
—
Aclarar restricciones antes de elegir un enfoque
—
Explicar invariantes, no solo detalles de implementación
—
Validar el algoritmo con ejemplos antes de programar
—
Probar entradas vacías, un solo valor, duplicados, negativos y límites
—
Refactorizar solo cuando mejora claridad o corrección
✗ Evita
—
Empezar a programar inmediatamente
—
Ocultar incertidumbre guardando silencio
—
Aplicar un patrón memorizado que no encaja
—
Ignorar overflow, mutación, orden o duplicados
—
Declarar complejidad antes de considerar todas las operaciones
Arrays, strings y tablas hash
Estos fundamentos evalúan índices, frecuencias, dos punteros, sliding windows e implementación precisa.
Enfoque — Guardar el complemento en una tabla hash
Recorrería el array una vez. Para cada x comprobaría si target − x ya está en una tabla hash. Si está, devolvería su índice y el actual; si no, guardaría x con su índice. Cada elemento se procesa una vez: O(n) de tiempo y O(n) de espacio. Antes aclararía si existe exactamente una solución y si puede reutilizarse un índice.
Posibles preguntas de seguimiento
¿Cómo tratarías duplicados?
¿Cómo resolverías sin espacio adicional?
¿Qué cambia si el array está ordenado?
Enfoque — Sliding window con último índice visto
Mantendría una ventana [left, right] sin duplicados y el último índice de cada carácter. Si aparece de nuevo dentro de la ventana, movería left a lastSeen + 1. Después actualizaría el índice y el máximo. Left nunca debe retroceder. El tiempo es O(n) y el espacio O(k), donde k es el alfabeto.
Posibles preguntas de seguimiento
¿Por qué left solo puede avanzar?
¿Cómo tratarías Unicode?
¿Cómo devolverías también el substring?
Enfoque — Crear una clave canónica por palabra
Crearía para cada palabra una clave canónica y agruparía claves iguales en una tabla hash. La clave puede ser la cadena ordenada o, con alfabeto fijo, un vector de frecuencias. Ordenando, el tiempo es O(n · m log m); con frecuencias, O(n · m), donde m es la longitud.
Posibles preguntas de seguimiento
¿Qué solución es mejor para strings muy largos?
¿Cómo tratarías mayúsculas?
¿Cómo harías determinista la salida?
Listas enlazadas, árboles y grafos
Aquí importan la disciplina de punteros, invariantes recursivas, orden de recorrido y tratamiento seguro de nodos visitados.
Enfoque — Tres punteros: anterior, actual y siguiente
Inicializaría prev en null y current en la cabeza. En cada iteración guardaría current.next, apuntaría current.next a prev y avanzaría ambos punteros. Al final prev es la nueva cabeza. La invariante es que prev siempre apunta a la parte ya invertida. Tiempo O(n), espacio O(1).
Posibles preguntas de seguimiento
¿Cómo sería la solución recursiva?
¿Qué ocurre con una lista vacía?
¿Cómo invertirías solo un tramo?
Enfoque — Propagar límites inferior y superior válidos
Comparar solo con los hijos no basta. Recorrería recursivamente pasando el rango permitido: a la izquierda, el valor actual se convierte en límite superior; a la derecha, en inferior. Si un nodo viola el rango, el árbol no es válido. Aclararía la regla para duplicados. Tiempo O(n), espacio O(h) por la recursión.
Posibles preguntas de seguimiento
¿Por qué no basta comparar hijos directos?
¿Cómo funcionaría un recorrido inorder?
¿Cómo evitarías overflow en los límites?
Enfoque — BFS por niveles de distancia
Trataría cada celda transitable como nodo y ejecutaría BFS desde el inicio. Marcaría una celda al encolarla para no duplicarla. El primer acceso al destino es mínimo por el orden en niveles. Para devolver el camino, guardaría predecesores. Tiempo y espacio O(filas · columnas).
Posibles preguntas de seguimiento
¿Cómo devolverías el camino?
¿Qué cambia con celdas ponderadas?
¿Cómo tratarías varios puntos iniciales?
Enfoque — Mapear cada nodo original a su clon
Usaría DFS o BFS y una tabla que asigna cada original a su clon. Crearía y guardaría el clon en la primera visita y luego clonaría vecinos. Guardarlo antes evita bucles en ciclos y preserva vecinos compartidos. Tiempo y espacio O(V + E).
Posibles preguntas de seguimiento
¿Por qué guardar el clon antes de recorrer vecinos?
¿Cómo clonarías un grafo no conexo?
¿Qué pruebas cubren ciclos y self-loops?
Programación dinámica y backtracking
Lo esencial es definir con precisión el estado, formular una transición completa y podar correctamente ramas inválidas.
Enfoque — DP bottom-up para todas las cantidades
Definiría dp[a] como el mínimo de monedas para la cantidad a. Establecería dp[0] = 0 y el resto en infinito. Para cada cantidad y moneda c ≤ a, actualizaría dp[a] = min(dp[a], dp[a − c] + 1). Si el objetivo sigue en infinito, no puede formarse. Tiempo O(cantidad · monedas), espacio O(cantidad).
Posibles preguntas de seguimiento
¿Cómo reconstruirías las monedas utilizadas?
¿Qué cambia si las monedas son limitadas?
¿Por qué greedy no siempre funciona?
Enfoque — DP por posición final y optimización con búsqueda binaria
La solución básica define dp[i] como la longitud máxima que termina en i. Para todo j < i con nums[j] < nums[i], actualiza dp[i], con O(n²). La solución optimizada guarda el menor final posible para cada longitud y lo sustituye mediante búsqueda binaria, logrando O(n log n).
Posibles preguntas de seguimiento
¿Cómo devolverías la subsecuencia?
¿Por qué tails no es necesariamente la subsecuencia real?
¿Cómo tratarías valores iguales?
Enfoque — Generar solo prefijos válidos
Construiría la cadena paso a paso. Puede añadirse apertura mientras open < n y cierre solo si close < open. Cuando la longitud llega a 2n, la combinación es válida. Como nunca se crean prefijos inválidos, se poda pronto el espacio de búsqueda.
Posibles preguntas de seguimiento
¿Cuál es el tamaño asintótico de la salida?
¿Cómo lo formularías iterativamente?
¿Qué casos base importan?
Entrevistas de diseño de sistemas
Estas entrevistas evalúan madurez técnica. En perfiles sénior importan compensaciones, cuellos de botella, fiabilidad, observabilidad y responsabilidad operativa.
Un proceso práctico
1
Aclarar requisitos funcionales y exclusiones deliberadas.
2
Aclarar escala, latencia, disponibilidad, consistencia, durabilidad, privacidad, coste y regiones.
3
Estimar usuarios, solicitudes por segundo, almacenamiento, ancho de banda, hot keys y relación lectura/escritura.
4
Definir API y modelos de datos antes de detallar la arquitectura.
5
Diseñar clientes, balanceo, servicios, bases, colas, cachés, object storage y procesos de fondo.
6
Identificar cuellos y fallos, como saturación de base, cola atrasada o caída regional.
7
Comparar SQL/NoSQL, síncrono/asíncrono y consistencia/disponibilidad.
8
Cerrar con monitorización, rollout, seguridad, rate limits, recuperación y evolución.
Enfoque — Requisitos → API → generación de ID → almacenamiento → redirección → escala
El usuario envía una URL larga y recibe un código; la redirección debe ser rápida. Las API principales son createShortUrl y redirect. El registro contiene código, destino, usuario, creación, caducidad y estado.
Los códigos pueden derivarse de ID secuenciales en Base62 o generarse aleatoriamente con detección de colisiones. La lectura usa caché delante de la base, valida estado y caducidad y responde 301 o 302. La analítica se procesa de forma asíncrona mediante cola. A escala añadiría edge cache, sharding por código, rate limits y control de abuso.
Asumiría un feed de cuentas seguidas. Los objetos centrales son usuario, follow, publicación, contenido, entrada de feed e interacción. Servicios de publicación, grafo, feed y ranking trabajan con caché, object storage y colas.
Fanout al escribir permite lecturas rápidas, pero es caro para cuentas enormes. Fanout al leer reduce escrituras y aumenta latencia. Un enfoque híbrido distribuye cuentas normales al escribir y trata las grandes al leer. También consideraría frescura, privacidad, fallos de cola, invalidación de caché y spam.
Posibles preguntas de seguimiento
¿Cómo tratarías cuentas con millones de seguidores?
Los clientes mantienen WebSocket con gateways. Al enviar, el gateway autentica, usa una clave de idempotencia, guarda el mensaje, publica un evento y entrega a receptores conectados. Los usuarios offline reciben push y sincronizan desde el último punto visto.
El modelo incluye conversación, participante, mensaje, entrega, lectura y dispositivo. Las claves evitan duplicados, las secuencias por conversación ordenan y los acknowledgements y reintentos aseguran entrega. Los adjuntos van a object storage. Vigilaría latencia, tasa de entrega, conexiones, reconexiones, cola y fallos de escritura.
Posibles preguntas de seguimiento
¿Cómo garantizarías el orden?
¿Cómo soportarías varios dispositivos?
¿Qué guardarías para confirmaciones de lectura?
Depuración, pruebas y preparación para producción
Estos escenarios distinguen a quien escribe código de quien opera software con responsabilidad.
Confirmaría la señal en varios monitores y revisaría p50, p95, p99 y endpoints. Segmentar por región, zona, versión, host, cliente, tipo y dependencia ayuda a acotar.
Revisaría despliegues, configuración, migraciones, tráfico, feature flags, caché y caídas downstream. Los traces descomponen latencia; también comprobaría base de datos, hit rate, cola, CPU, memoria, GC y pools. Si hay impacto, mitigaría antes de demostrar la causa perfecta mediante rollback, desactivar flag, escalar o evitar una dependencia lenta.
Aclararía tipos, combinaciones, caducidad, mínimo, elegibilidad, redondeo, impuestos y envío. Los unit tests cubrirían sin descuento, porcentaje, cantidad fija, mínimo exacto y por debajo, caducado, usuario no elegible y acumulación.
Las invariantes: el precio nunca es negativo, el descuento no supera el importe elegible, una promoción caducada no aplica y la misma entrada produce el mismo resultado. Si afecta a pagos, añadiría integración y registraría la razón de cada decisión.
Revisaría en orden: ¿resuelve correctamente el problema? ¿Es mantenible y tiene límites claros? ¿Qué riesgos introduce en migración, concurrencia, seguridad, rendimiento, compatibilidad u observabilidad? ¿Las pruebas cubren el cambio?
Separaría bloqueos de sugerencias. Corrección, seguridad o migración pueden bloquear; el gusto no. Una review debe mejorar código y velocidad del equipo, no demostrar superioridad.
Posibles preguntas de seguimiento
¿Cómo resolverías un desacuerdo?
¿Cuándo es bloqueante un comentario?
¿Cómo evitarías retrasos innecesarios?
Preguntas de comportamiento y colaboración
Estas rondas abordan responsabilidad, colaboración, decisiones técnicas, ambigüedad y aprendizaje. Las mejores respuestas incluyen consecuencias técnicas reales.
Utiliza historias específicas de ingeniería
Una historia sólida identifica la decisión técnica, la compensación, las personas, el resultado y el cambio posterior. Evita historias genéricas aplicables a cualquier puesto.
Elegiría una decisión con alternativas reales: construir o comprar, SQL o NoSQL, parche rápido o rediseño, consistencia o disponibilidad. Explicaría contexto, restricciones y opciones.
Nombraría la compensación y qué evidencia decidió: tráfico, fecha de cliente, incidentes, capacidad o roadmap. Terminaría con resultado y aprendizaje. Una respuesta madura puede admitir qué haría distinto hoy.
Comenzaría por el impacto: qué falló, quién sufrió y gravedad. Después describiría mi contribución a detección, triaje, rollback, mitigación, comunicación o causa.
Durante el incidente, restaurar importa más que probar una teoría. Explicaría cómo utilicé logs, métricas, traces, flags, rollbacks o dependencias. Tras mitigar, detallaría causa y prevención: mejores pruebas, rollout seguro, monitorización o runbooks, sin buscar culpables personales.
Primero alinearía el objetivo de usuario y negocio. Muchos conflictos nacen de supuestos distintos. Explicaría con precisión la restricción técnica: complejidad, fiabilidad, plazo, mantenimiento, seguridad o rendimiento.
En lugar de decir solo no, ofrecería opciones: MVP menor, proceso manual temporal, feature flag, trabajo escalonado o diseño más simple. Ante riesgos importantes, documentaría alternativas, consecuencias y recomendación. El objetivo no es que Ingeniería gane, sino una decisión consciente del equipo.
Posibles preguntas de seguimiento
¿Qué harías si Producto insiste en la opción arriesgada?
¿Cómo explicarías deuda técnica?
¿Cuándo escalarías?
Estrategia de preparación para Software Engineers
Combina patrones, simulacros, diseño de sistemas, historias y soltura en tu lenguaje. El objetivo es velocidad fiable, no solo reconocimiento.
Plan de preparación de seis semanas
1
Semana 1: arrays, strings, hash, dos punteros, sliding windows, stacks, queues y complejidad.
Semana 3: programación dinámica y backtracking; definir estados antes de programar.
4
Semana 4: problemas mixtos cronometrados y revisión por patrón, bug, límite, comunicación o ritmo.
5
Semana 5: si aplica, diseño con requisitos, API, datos, escala, fallos y compensaciones.
6
Semana 6: simulacros, historias de comportamiento y profundización en proyectos técnicos.
Prioridades según la empresa
—
Grandes tecnológicas: corrección, diseño de sistemas, comportamiento y consistencia entre rondas.
—
Startups: ejecución práctica, depuración, responsabilidad, producto y ambigüedad.
—
Infraestructura: sistemas distribuidos, fiabilidad, redes, almacenamiento, concurrencia y operación.
—
IA: pipelines de datos, serving de modelos, evaluación, latencia, fiabilidad e integración.
—
Fintech y salud: corrección, seguridad, privacidad, auditabilidad, cumplimiento y rollout prudente.
No practiques solo tus temas favoritos
Evitar grafos, DP, recursión o diseño revela esa debilidad bajo presión. Registra errores por tema y practica lo que te hace lento o inseguro.
Idea clave
Las respuestas sólidas combinan claridad algorítmica, implementación limpia, criterio de producción y colaboración. No se trata de memorizar, sino de derivar una solución correcta desde principios básicos bajo restricciones.
Practica estas preguntas en directo
Interview Pilot te sugiere respuestas en tiempo real durante entrevistas reales para ayudarte a responder con claridad.