Desarrollador full stack Preguntas de entrevista & Respuestas

Las entrevistas de desarrollador full stack evalúan su capacidad para trabajar en todo el stack de la aplicación: desde el diseño de base de datos hasta la implementación de la interfaz de usuario. Espere preguntas que pongan a prueba sus conocimientos de frontend y backend, así como decisiones arquitectónicas.

Preguntas conductuales

  1. 1. Cuéntame sobre una funcionalidad que desarrollaste de extremo a extremo, desde la base de datos hasta la interfaz de usuario.

    Respuesta modelo

    Construí un feed de actividad en tiempo real para una herramienta de gestión de proyectos. En el backend, diseñé un sistema de event-sourcing con PostgreSQL: cada acción del proyecto (tarea creada, comentario añadido, estado cambiado) registraba un evento con marca de tiempo, actor, tipo de acción y metadatos. Desarrollé un endpoint de API en Node.js con paginación basada en cursor y canales WebSocket para actualizaciones en tiempo real. En el frontend, creé un componente de React con una lista virtualizada (react-window) para manejar feeds con 10K+ eventos sin problemas de rendimiento en el DOM. Los nuevos eventos aparecían en tiempo real a través de WebSocket con animaciones de inserción fluidas. También añadí filtros por tipo de evento y persona, que utilizaban un índice parcial dedicado en PostgreSQL. La funcionalidad se lanzó en 5 semanas y se convirtió en la página más visitada de la aplicación: el 78% de los usuarios activos diarios la visitaban al menos una vez por sesión.

  2. 2. Describe una situación en la que tuviste que elegir entre el frontend y el backend para implementar lógica de negocio.

    Respuesta modelo

    Necesitábamos cálculos de precios para una herramienta de presupuestos. El product manager quería actualizaciones de precio instantáneas a medida que los usuarios cambiaban cantidades y opciones. La implementación inicial puso toda la lógica de precios en el frontend de React para obtener respuesta inmediata. Funcionó hasta que descubrimos discrepancias: el frontend calculaba $1,247 pero la API de confirmación del pedido devolvía $1,251 debido a distintos métodos de redondeo. Trasladé la lógica de precios canónica al backend y creé un estimador ligero en el frontend que usaba reglas simplificadas para la respuesta inmediata, claramente etiquetado como 'precio estimado'. Al finalizar el presupuesto, el backend calculaba el precio exacto. Este patrón de 'frontend optimista, backend autoritativo' resolvió tanto el requisito de velocidad como el de exactitud. La lección: los cálculos críticos para el negocio deben tener una única fuente de verdad en el backend. El frontend puede aproximar para la UX, pero el servidor decide.

  3. 3. Cuéntame sobre una ocasión en la que mejoraste el flujo de trabajo de desarrollo de tu equipo.

    Respuesta modelo

    Nuestro equipo tenía repositorios separados de frontend y backend con ciclos de despliegue distintos. Los desarrolladores de frontend esperaban constantemente a que las APIs de backend estuvieran listas para poder integrar. Introduje dos cambios. Primero, establecí un flujo de trabajo de desarrollo API contract-first usando especificaciones OpenAPI: acordábamos el contrato de la API antes de que ninguno de los dos lados comenzara a construir, y luego los equipos de frontend y backend desarrollaban en paralelo usando la especificación como fuente de verdad. Configuré servidores mock a partir de la especificación OpenAPI para que el frontend pudiera desarrollar contra respuestas realistas antes de que el backend estuviera listo. Segundo, creé una configuración de docker-compose que ejecutaba todo el stack localmente con un solo comando, incluyendo la inicialización de la base de datos y la simulación de servicios externos. Los problemas de integración que antes aparecían en staging ahora surgían en las máquinas de los desarrolladores. El resultado: la tasa de finalización de sprints mejoró del 68% al 91% porque las dependencias entre equipos dejaron de bloquear el progreso.

  4. 4. Ponme un ejemplo de cómo gestionaste una migración de datos compleja entre sistemas.

    Respuesta modelo

    Migramos los datos de usuarios de Firebase a PostgreSQL manteniendo la aplicación React en funcionamiento. El reto: 200K usuarios con estructuras de documentos anidados que debían normalizarse en tablas relacionales. Construí un pipeline de migración en tres fases. Fase 1: diseño del esquema. Mapeé las estructuras de documentos de Firebase a tablas de PostgreSQL, normalizando arrays anidados en tablas de unión. Fase 2: operación en paralelo. La aplicación escribía en Firebase y en PostgreSQL simultáneamente mediante una capa de middleware. Las lecturas se mantenían en Firebase. Fase 3: validación y cambio. Escribí un script de reconciliación que comparaba 10K registros aleatorios entre ambas bases de datos cada noche. Tras 2 semanas sin discrepancias, cambiamos las lecturas a PostgreSQL y desactivamos las escrituras en Firebase. Tiempo total de migración: 4 semanas sin ningún tiempo de inactividad visible para el usuario. El script de reconciliación detectó 3 casos límite en la lógica de escritura dual que habrían causado pérdida de datos en una migración de una sola vez.

Preguntas técnicas

  1. 1. ¿Cómo diseñarías un editor de documentos colaborativo en tiempo real?

    Respuesta modelo

    El desafío principal es la resolución de conflictos cuando varios usuarios editan simultáneamente. Usaría Transformación Operacional (OT) o CRDTs (Conflict-free Replicated Data Types). Los CRDTs son más modernos y no requieren un servidor central para la resolución de conflictos, lo que los hace más resilientes. Arquitectura: el frontend usa un editor de texto enriquecido (Tiptap/ProseMirror) con una biblioteca CRDT (Yjs) que gestiona las ediciones locales de forma optimista. Los cambios se propagan a través de WebSocket a un servidor Node.js que los envía a todos los clientes conectados. El servidor también persiste el estado del documento en PostgreSQL como un CRDT serializado con cada cambio (con debounce para evitar escrituras excesivas). Para la presencia: cada cliente envía la posición del cursor y la selección a través del canal WebSocket, y los demás clientes renderizan cursores de colores. Para el soporte offline: Yjs gestiona la fusión cuando un cliente se reconecta, aplicando sus cambios offline al estado actual del documento. Consideraciones de escalabilidad: usar Redis Pub/Sub para difundir cambios entre múltiples instancias del servidor, particionar las conexiones WebSocket por ID de documento e implementar carga diferida para documentos muy largos.

  2. 2. Explica el renderizado en el servidor frente al renderizado en el cliente. ¿Cuándo elegirías cada uno?

    Respuesta modelo

    Renderizado en el cliente (CSR): el servidor envía una estructura HTML mínima, el JavaScript se descarga y renderiza la página en el navegador. Ventajas: transiciones de página fluidas, menor carga en el servidor, ideal para paneles autenticados. Desventajas: carga inicial más lenta (página en blanco hasta que el JS se ejecuta), SEO deficiente (los motores de búsqueda pueden no ejecutar el JS), peores Core Web Vitals. Renderizado en el servidor (SSR): el servidor renderiza el HTML completo para cada solicitud. Ventajas: primer renderizado de contenido rápido, excelente SEO, funciona sin JavaScript. Desventajas: mayor carga en el servidor, las recargas de página completa se sienten más lentas, más difícil implementar funcionalidades interactivas. Elijo CSR para aplicaciones autenticadas (paneles de control, paneles de administración, herramientas SaaS) donde el SEO no importa y la interactividad es lo principal. Elijo SSR para contenido público (sitios de marketing, blogs, páginas de productos de e-commerce) donde el SEO y el tiempo de carga inicial son críticos. Los frameworks modernos (Next.js, Nuxt, Remix) permiten combinar ambos: SSR para la carga inicial con hidratación del lado del cliente para la interactividad. La Generación de Sitio Estático (SSG) es aún mejor para contenido que no cambia por solicitud.

  3. 3. ¿Cómo gestionas la autenticación en una aplicación full stack?

    Respuesta modelo

    Implemento autenticación basada en JWT con una estrategia de tokens específica. El token de acceso (JWT) tiene vida corta (15 minutos), contiene la identidad del usuario y sus roles, y se envía en el encabezado Authorization. El token de actualización tiene vida larga (7 días), es opaco (no JWT), se almacena en una cookie HTTP-only Secure SameSite y se mapea a un registro en la base de datos para poder revocarlo. El flujo: el usuario inicia sesión, el servidor valida las credenciales, devuelve el token de acceso en el cuerpo de la respuesta y establece la cookie de token de actualización. El frontend almacena el token de acceso en memoria (no en localStorage, ya que es vulnerable a XSS). Cuando el token de acceso expira, el frontend llama silenciosamente al endpoint de actualización, que valida la cookie y devuelve un nuevo token de acceso. Al cerrar sesión, ambos tokens se invalidan en el servidor. Para OAuth (Google, GitHub), utilizo el flujo de código de autorización: redirigir al proveedor, recibir el código en el callback, intercambiar el código por tokens del proveedor en el servidor, crear o vincular la cuenta de usuario, y emitir nuestro propio JWT. Nunca confío directamente en los tokens del lado del cliente de los proveedores OAuth.

  4. 4. ¿Cuál es tu enfoque para el manejo de errores en todo el stack?

    Respuesta modelo

    Implemento el manejo de errores en cuatro capas. API de backend: todos los errores devuelven un formato JSON consistente con código de estado, código de error (legible por máquina), mensaje (legible por humanos) y un campo de detalles opcional. Uso los códigos de estado HTTP correctamente: 400 para validación, 401 para autenticación, 403 para autorización, 404 para no encontrado, 409 para conflictos, 500 para errores del servidor. Nunca expongo trazas de pila ni detalles internos en las respuestas de producción. Capa de servicio del backend: try/catch alrededor de llamadas externas y operaciones de base de datos, con tipos de error específicos (NotFoundError, ValidationError, ConflictError) que se mapean a respuestas HTTP. Los errores no gestionados llegan a un manejador de errores global que registra el error completo y devuelve un 500 genérico. Capa de API del frontend: un cliente de API centralizado que gestiona errores comunes: el 401 dispara la actualización del token, el 403 muestra acceso denegado, el 429 muestra un mensaje de límite de tasa, el 500 muestra un error genérico con opción de reintento. Interfaz de usuario del frontend: los error boundaries capturan errores de renderizado, las notificaciones toast gestionan errores no bloqueantes y la validación en línea gestiona los errores de formulario. Cada error se registra: los errores del servidor en logging estructurado (Pino), los errores del cliente en un servicio de seguimiento de errores (Sentry).

Preguntas situacionales

  1. 1. Estás desarrollando una nueva funcionalidad y debes decidir si usar una arquitectura monolítica o de microservicios. ¿Cómo decides?

    Respuesta modelo

    Empezaría con un monolito a menos que haya una razón de peso para no hacerlo. Los microservicios añaden complejidad operacional (red, despliegue, monitorización, depuración de sistemas distribuidos) que solo se justifica a partir de ciertos tamaños de equipo y requisitos de escala. Elegiría un monolito cuando: el equipo tiene menos de 10 ingenieros, el producto está en una fase previa al ajuste producto-mercado (la iteración rápida importa más que la escalabilidad) y no hay necesidad inmediata de escalar o desplegar componentes específicos de forma independiente. Elegiría microservicios cuando: distintos componentes tienen necesidades de escalado muy diferentes (un procesador de imágenes intensivo en CPU frente a una API ligera), los equipos necesitan desplegar de forma independiente (más de 10 ingenieros, varios squads) o el dominio se descompone de forma natural en contextos delimitados distintos. La solución pragmática intermedia: construir un monolito modular con fronteras internas claras. Si un módulo necesita convertirse en un servicio más adelante, la separación es limpia. Esto evita la complejidad de los sistemas distribuidos manteniendo la opción de dividir cuando la necesidad sea real.

  2. 2. El diseñador quiere una animación compleja que funcione en móvil, pero te preocupa el rendimiento. ¿Cómo lo gestionas?

    Respuesta modelo

    Primero haría un prototipo en lugar de especular. Construiría la animación usando transformaciones CSS y opacidad (que están aceleradas por GPU y no provocan reflujo del layout) y la probaría en un dispositivo Android de gama media representativo, no en mi MacBook Pro. Si funciona a 60fps en ese dispositivo, lo lanzo. Si no, diagnosticaría el cuello de botella usando el panel de rendimiento de Chrome DevTools: ¿es layout thrashing, operaciones de pintura o bloqueo del hilo principal? Luego propondría alternativas según el problema específico. Quizás podríamos usar la Web Animations API para una mejor programación de fotogramas. Quizás reducimos el número de elementos animados. Quizás usamos will-change para promover capas a la GPU. Quizás la animación se reproduce solo una vez en lugar de de forma continua. Le presentaría al diseñador un espectro de opciones: 'Aquí está la animación completa a 30fps en móvil. Aquí está una versión simplificada a 60fps. Aquí está una alternativa estática.' Que elija el compromiso. A menudo los diseñadores prefieren la versión simple y fluida a la compleja y entrecortada.

  3. 3. Observas que el frontend hace 15 llamadas a la API al cargar la página. ¿Cómo lo optimizas?

    Respuesta modelo

    Primero entendería por qué: ¿son estas llamadas independientes o tienen dependencias? ¿Son todas necesarias para el renderizado inicial? Mis estrategias de optimización en orden de impacto: Primero, identificar las llamadas que no son necesarias para el renderizado inicial y diferirlas: cargar datos debajo del pliegue al hacer scroll, cargar paneles secundarios al interactuar. Esto podría reducir las llamadas iniciales de 15 a 5. Segundo, agrupar llamadas relacionadas: si estamos obteniendo perfil de usuario, configuración de usuario y notificaciones de usuario por separado, crear un endpoint BFF (Backend for Frontend) que devuelva todos los datos del usuario en una sola llamada. Tercero, usar GraphQL o un patrón de API compuesta si la fragmentación es un problema sistémico: dejar que el frontend solicite exactamente los datos que necesita en una sola llamada. Cuarto, cachear de forma agresiva: usar el patrón stale-while-revalidate de React Query para datos que no cambian con frecuencia. Quinto, precargar: si es probable que el usuario navegue de la página A a la página B, comenzar a obtener los datos de la página B al pasar el cursor. Mediría el impacto: tiempo total de carga de página, Tiempo hasta Interactividad y número de solicitudes de red.

  4. 4. Un cliente solicita una funcionalidad que le funcionaría pero que introduciría deuda técnica en la plataforma. ¿Cómo lo gestionas?

    Respuesta modelo

    Cuantificaría la deuda en lugar de simplemente etiquetarla como 'deuda técnica'. ¿Qué se romperá específicamente o qué será más difícil? ¿Cuántas funcionalidades futuras se ven afectadas? ¿Cuál es el coste de mantenimiento durante 12 meses? Luego propondría alternativas. Opción A: construirlo de la manera 'correcta': tarda más pero no añade deuda. Opción B: construir la versión del cliente detrás de un feature flag como extensión personalizada, con un plan para generalizarla cuando otros clientes necesiten una funcionalidad similar. Opción C: construir la versión rápida con una deuda documentada, un plazo comprometido para la refactorización y la aceptación del product owner de que esto genera un coste de mantenimiento. Presentaría el compromiso de forma clara: 'Podemos lanzar en 2 semanas con el enfoque C, pero ralentizará la Funcionalidad X el próximo trimestre en 1 semana y la Funcionalidad Y en 3 días.' Generalmente, cuando se cuantifica el coste derivado, la decisión se vuelve obvia. Si el negocio decide que la velocidad vale la deuda, es una decisión legítima, pero debe ser explícita.

Consejos para la entrevista

No intente ser igual de profundo en todo. Tenga un lado fuerte (frontend o backend) y demuestre competencia sólida en el otro. Prepárese para escribir código tanto en un framework frontend como en un lenguaje backend durante la entrevista.

Practica estas preguntas con IA

Prueba una entrevista simulada gratis

Practica estas preguntas con IA

Preguntas frecuentes

¿Cómo prepararse para una entrevista full stack?
Cubra ambos lados: frontend (React/Vue, HTML/CSS, gestión de estado) y backend (diseño de API, modelado de base de datos, autenticación). Prepare también el diseño de sistemas full stack.
¿Las entrevistas full stack favorecen el frontend o el backend?
Depende de la empresa. Las startups quieren habilidades equilibradas. Las empresas grandes pueden tener roles inclinados hacia un lado.
¿Son importantes los conocimientos de DevOps?
Cada vez más. Los desarrolladores full stack deben poder desplegar su propio código, configurar pipelines CI/CD y resolver problemas en producción.
¿Debo construir un proyecto de portafolio?
Un proyecto full stack bien construido es evidencia convincente de sus capacidades. Elija algo con autenticación, base de datos, UI responsive y despliegue.

Puestos relacionados

Artículos relacionados

Usamos cookies para analizar el tráfico del sitio web y mejorar tu experiencia. Puedes cambiar tus preferencias en cualquier momento. Cookie Policy