Preguntas de entrevista Intermedio Ingeniero Fullstack
En qué se centra una entrevista Intermedio de Ingeniero Fullstack, las preguntas que enfrentarás y cómo practicarlas con feedback de IA al instante.
Qué se espera en el nivel Intermedio
Se espera entrega autónoma de extremo a extremo y buenos compromisos cliente/servidor.
Preguntas de ejemplo para entrevista de Ingeniero Fullstack
- Técnica¿Cómo decides qué lógica corresponde al cliente y cuál al servidor?Lo que cubre una buena respuesta
- Seguridad: lógica sensible en servidor
- Rendimiento: client-side reduce latencia
- Estado: servidor maneja estado compartido
- Offline: cliente puede funcionar desconectado
Ver respuesta de ejemplo
La decisión se basa en varios criterios. Primero, la seguridad: toda lógica que maneje datos sensibles o reglas de negocio críticas debe ejecutarse en el servidor, pues el cliente puede ser manipulado. Segundo, el rendimiento: operaciones que requieren interactividad inmediata (como validación de formularios) se hacen en cliente para evitar latencia. Tercero, el estado compartido: si varios usuarios necesitan ver los mismos datos actualizados, el servidor debe ser la fuente de verdad. Por ejemplo, en un ecommerce, el cálculo de impuestos va en servidor, mientras que la animación de carrito va en cliente. Un error común es delegar lógica de precios al cliente, exponiendo la aplicación a fraudes.
- TécnicaExplica cómo funcionan la autenticación y las sesiones de extremo a extremo.Lo que cubre una buena respuesta
- JWT vs sesiones tradicionales
- Flujo: login → token → middleware de verificación
- Almacenamiento seguro (httpOnly, secure flag)
- Renovación de tokens y expiración
- Protección contra CSRF y XSS
Ver respuesta de ejemplo
La autenticación extremo a extremo comienza cuando el cliente envía credenciales al servidor. Este valida, genera un token (JWT) o una cookie de sesión firmada, y lo devuelve. El cliente lo almacena de forma segura (httpOnly, Secure, SameSite). Cada petición posterior incluye el token (en header Authorization o cookie). El servidor extrae y verifica la firma, extrayendo el usuario. Para sesiones, el servidor guarda el estado en una base de datos o Redis. Un patrón común es JWT con token de acceso corto y refresh token largo. El error típico es incluir datos sensibles en el payload del JWT sin encriptación. Además, hay que proteger contra CSRF usando tokens anti-CSRF en formularios.
- Técnica¿Cómo optimizarías una página lenta que depende de una API lenta?Lo que cubre una buena respuesta
- Caching: service worker, CDN, SWR
- Carga perezosa y skeleton screens
- Pre-fetching de datos
- Compresión y paginación de API
- Optimistic UI y retry exponencial
Ver respuesta de ejemplo
Primero, identifico si el cuello de botella es la API o el frontend. Para una API lenta, implemento caching: en el cliente con Service Workers (Cache API) o librerías como React Query/SWR para mantener datos frescos. También uso CDN para assets estáticos. En la UI, aplico carga perezosa (lazy loading) para componentes no críticos y skeleton screens mientras espera. Pre-fetching predictivo (basado en navegación) mejora la percepción. Para la API, optimizo con paginación, compresión (gzip), y limito campos innecesarios. Finalmente, implemento optimistic UI: actualizo la vista de inmediato y revierto en caso de error. Un error común es cachear todo sin estrategia de invalidación, causando datos obsoletos.
- ProgramaciónConstruye una pequeña funcionalidad CRUD: esquema, endpoint de API y un formulario de UI.Lo que cubre una buena respuesta
- Schema SQL con campos id, title, completed
- REST: GET, POST, PUT, DELETE
- UI con formulario y listado
- Validación básica y manejo de errores
Ver respuesta de ejemplo
Voy a diseñar un CRUD de tareas. El esquema en SQL: CREATE TABLE tasks (id SERIAL PRIMARY KEY, title TEXT NOT NULL, completed BOOLEAN DEFAULT false). El endpoint API RESTful en Express: GET /tasks (devuelve array), POST /tasks (crea), PUT /tasks/:id (actualiza), DELETE /tasks/:id (elimina). La UI en React tiene un formulario controlado para agregar tarea y una lista con botones de completar/eliminar. Uso fetch para las peticiones, mostrando estado de carga y errores. Validación: título no vacío en cliente y servidor. La complejidad temporal es O(1) para operaciones individuales en base de datos indexada. El error común es no sanitizar entrada, exponiendo a inyección SQL.
Solución de referenciajavascript // Esquema SQL // CREATE TABLE tasks (id SERIAL PRIMARY KEY, title TEXT NOT NULL, completed BOOLEAN DEFAULT false); // Endpoint API (Express) const express = require('express'); const { Pool } = require('pg'); const app = express(); app.use(express.json()); const pool = new Pool({ connectionString: process.env.DATABASE_URL }); app.get('/tasks', async (req, res) => { const result = await pool.query('SELECT * FROM tasks ORDER BY id'); res.json(result.rows); }); app.post('/tasks', async (req, res) => { const { title } = req.body; if (!title || title.trim() === '') return res.status(400).json({ error: 'Title required' }); const result = await pool.query('INSERT INTO tasks (title) VALUES ($1) RETURNING *', [title]); res.status(201).json(result.rows[0]); }); app.put('/tasks/:id', async (req, res) => { const { id } = req.params; const { completed } = req.body; const result = await pool.query('UPDATE tasks SET completed = $1 WHERE id = $2 RETURNING *', [completed, id]); if (result.rows.length === 0) return res.status(404).json({ error: 'Not found' }); res.json(result.rows[0]); }); app.delete('/tasks/:id', async (req, res) => { const { id } = req.params; await pool.query('DELETE FROM tasks WHERE id = $1', [id]); res.status(204).send(); }); // UI (React) import React, { useState, useEffect } from 'react'; function Tasks() { const [tasks, setTasks] = useState([]); const [newTitle, setNewTitle] = useState(''); useEffect(() => { fetchTasks(); }, []); const fetchTasks = async () => { const res = await fetch('/tasks'); setTasks(await res.json()); }; const addTask = async () => { if (!newTitle.trim()) return; const res = await fetch('/tasks', { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({ title: newTitle }) }); const task = await res.json(); setTasks([...tasks, task]); setNewTitle(''); }; const toggleTask = async (id, completed) => { const res = await fetch(`/tasks/${id}`, { method: 'PUT', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({ completed: !completed }) }); const updated = await res.json(); setTasks(tasks.map(t => t.id === id ? updated : t)); }; const deleteTask = async (id) => { await fetch(`/tasks/${id}`, { method: 'DELETE' }); setTasks(tasks.filter(t => t.id !== id)); }; return ( <div> <input value={newTitle} onChange={e => setNewTitle(e.target.value)} placeholder='New task' /> <button onClick={addTask}>Add</button> <ul> {tasks.map(t => ( <li key={t.id}> <span style={{textDecoration: t.completed ? 'line-through' : 'none'}}>{t.title}</span> <button onClick={() => toggleTask(t.id, t.completed)}>Toggle</button> <button onClick={() => deleteTask(t.id)}>Delete</button> </li> ))} </ul> </div> ); } export default Tasks; - ProgramaciónImplementa actualizaciones optimistas de UI con reversión en caso de fallo.Lo que cubre una buena respuesta
- Actualización inmediata del estado local
- Se guarda el estado anterior para revertir
- Petición al servidor en segundo plano
- Reversión automática en caso de fallo
- Manejo de errores y retroalimentación al usuario
Ver respuesta de ejemplo
Implemento un patrón donde la UI se actualiza instantáneamente, optimistamente, antes de la respuesta del servidor. Almaceno el estado anterior (usando useState o useReducer) y envío la petición. Si la respuesta falla (error de red o servidor), revierto al estado guardado y muestro una notificación de error. Esto mejora la percepción de velocidad. Es crucial que la operación sea idempotente o que el servidor maneje conflictos (ej. versionado). La complejidad temporal es O(1) en el frontend, y la latencia depende de la red. Un error común es no considerar que la reversión puede causar incongruencias si el usuario realizó otras acciones intermedias.
Solución de referenciajavascript import React, { useState, useCallback } from 'react'; function OptimisticTodo() { const [todos, setTodos] = useState([ { id: 1, text: 'Comprar leche', done: false }, { id: 2, text: 'Terminar reporte', done: true }, ]); const toggleTodo = useCallback(async (id) => { const previousTodos = [...todos]; const todo = todos.find(t => t.id === id); if (!todo) return; // Optimistic update setTodos(todos.map(t => t.id === id ? { ...t, done: !t.done } : t)); try { const response = await fetch(`/api/todos/${id}`, { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ done: !todo.done }), }); if (!response.ok) throw new Error('Error del servidor'); // Opcional: actualizar con respuesta del servidor const updated = await response.json(); setTodos(todos.map(t => t.id === id ? updated : t)); } catch (error) { // Revertir en caso de fallo setTodos(previousTodos); alert('Error al actualizar: ' + error.message); } }, [todos]); return ( <ul> {todos.map(todo => ( <li key={todo.id}> <span style={{ textDecoration: todo.done ? 'line-through' : 'none' }}>{todo.text}</span> <button onClick={() => toggleTodo(todo.id)}> {todo.done ? 'Desmarcar' : 'Marcar'} </button> </li> ))} </ul> ); } export default OptimisticTodo; - Diseño de sistemasDiseña un sistema de comentarios con actualizaciones en tiempo real y moderación.Lo que cubre una buena respuesta
- WebSockets para tiempo real
- Cola de moderación con prioridades
- Base de datos relacional para persistencia
- Caché para comentarios populares
- Escalabilidad: particionado por post
Ver respuesta de ejemplo
El sistema requiere que los comentarios aparezcan en tiempo real y que los moderadores revisen contenido ofensivo. Uso WebSockets (Socket.io) para notificaciones push. Cuando un usuario publica un comentario, el servidor lo inserta en una cola de moderación (Redis) con un nivel de confianza. Si el comentario supera un umbral de seguridad (mediante IA o reglas), se aprueba automáticamente y se transmite a todos los clientes en el mismo post. Caso contrario, queda pendiente para revisión manual. La base de datos (PostgreSQL) guarda los comentarios con estado (pendiente/aprobado/rechazado). Para alta carga, cacheo los comentarios aprobados de posts populares en Redis (LRU). El flujo: cliente envía POST /comment -> servidor añade a cola -> proceso de aprobación -> broadcast. Escalo horizontalmente con un balanceador y agrego una capa de CDN para contenido estático. Un error común es no manejar la reconexión de WebSockets ni la sincronización de estado.
- ConductualCuéntame de una funcionalidad que entregaste enteramente por tu cuenta.Lo que cubre una buena respuesta
- Propiedad completa del feature
- Diseño e implementación individual
- Tecnologías usadas y desafíos
- Métricas de éxito y resultado
Ver respuesta de ejemplo
En mi proyecto anterior, desarrollé completamente un sistema de notificaciones push en tiempo real. Identifiqué la necesidad de alertar a los usuarios sobre eventos críticos (pedidos, mensajes). Implementé el backend con Node.js y Redis para la cola de eventos, y WebSockets (Socket.io) para la comunicación en vivo. En el frontend, construí un componente de notificaciones con React, que mostraba alertas animadas y persistía el historial. El principal desafío fue manejar la concurrencia: múltiples usuarios recibiendo notificaciones sin saturar el servidor. Solucioné usando grupos de sockets por usuario y límite de conexiones por IP. El resultado fue una reducción del 80% en el tiempo de entrega de notificaciones (de 10 segundos a menos de 1), mejorando la retención de usuarios. Aprendí a depurar problemas de WebSockets y a optimizar queries de Redis.
- Conductual¿Cómo decides en qué parte de la pila profundizar?Lo que cubre una buena respuesta
- Análisis de brechas de habilidades
- Valor de negocio y urgencia
- Preferencias personales e intereses
- Tendencias tecnológicas actuales
- Feedback del equipo y mentorship
Ver respuesta de ejemplo
Para decidir en qué parte de la pila profundizar, primero evalúo dónde hay mayor necesidad en el equipo o en el proyecto. Si el frontend tiene deudas técnicas que afectan la velocidad de desarrollo, priorizo mejorar en React y TypeScript. Segundo, considero mi interés personal: si disfruto más la lógica de negocio, me inclino hacia backend. Tercero, miro las tendencias del mercado; por ejemplo, aprender GraphQL o NestJS puede abrir oportunidades. También busco feedback de mi mentor sobre áreas donde pueda tener mayor impacto. Un enfoque es pasar un tiempo dedicado a cada capa (por ejemplo, 3 meses en frontend, 3 en backend) y luego decidir. El error común es solo profundizar en lo que ya se sabe, evitando salir de la zona de confort. Mi filosofía es 'T-shaped': tener una especialización (profundidad) pero con conocimiento amplio de toda la pila (amplitud).
Qué evalúan los entrevistadores
Oficio de frontend
Estado de componentes, renderizado y UI responsive y accesible.
Backend y APIs
Diseño de endpoints, autenticación, validación y modelado de datos.
Pensamiento de extremo a extremo
Dónde poner la lógica, la caché y la frontera cliente/servidor.
Bases de datos
Diseño de esquemas, consultas y ajuste básico de rendimiento.
Entrega
Pruebas, CI/CD y lanzamientos seguros detrás de flags.
Cómo prepararte
- Elige un área de profundidad y señálala con claridad: los generalistas que profundizan en algo destacan.
- Narra todo el ciclo de vida de una petición para demostrar comprensión de extremo a extremo.
- No descuides las pruebas ni el despliegue; las entrevistas de fullstack examinan la entrega, no solo el código.
Preguntas frecuentes
¿Las entrevistas de fullstack son más difíciles que las especializadas?
Son más amplias, no necesariamente más difíciles: cambias algo de profundidad por cobertura de extremo a extremo, pero aún necesitas profundidad real en al menos una capa.
¿En qué debo centrarme para una entrevista de fullstack?
En poder construir una pequeña funcionalidad a través de esquema, API y UI, y explicar con claridad los compromisos cliente/servidor.
¿A los puestos fullstack les preguntan diseño de sistemas?
Sí, normalmente diseño pragmático de funcionalidades de producto que tocan tanto el frontend como el backend, en lugar de pura infraestructura.
Practica preguntas de Ingeniero Fullstack con feedback instantáneo de IA
Offersly realiza una entrevista simulada adaptada a tu currículum y al puesto objetivo, y luego puntúa cada respuesta por relevancia, profundidad, claridad y corrección.