dicembre 21, 2025
11 min di lettura

Domande di Intervista per Senior Backend Developer (Node.js): Guida Completa

interview
career-advice
job-search
Domande di Intervista per Senior Backend Developer (Node.js): Guida Completa
MB

Milad Bonakdar

Autore

Padroneggia lo sviluppo backend avanzato con Node.js grazie a 30 domande di intervista essenziali che coprono la progettazione del sistema, i modelli di architettura, l'ottimizzazione delle prestazioni, la scalabilità, i microservizi e la leadership. Preparazione perfetta per i colloqui da senior backend developer.


Introduzione

Questa guida completa contiene 30 domande essenziali per il colloquio che riguardano lo sviluppo backend avanzato con Node.js. Queste domande sono progettate per aiutare gli sviluppatori backend senior a prepararsi per i colloqui, trattando concetti chiave come l'Event Loop, gli Stream, la progettazione del sistema e l'ottimizzazione delle prestazioni. Ogni domanda include una risposta dettagliata, una valutazione della rarità e un livello di difficoltà.

Come sviluppatore senior, ci si aspetta che tu comprenda a fondo la natura single-threaded di Node.js e come costruire sistemi scalabili e ad alte prestazioni attorno ad essa.


Concetti Avanzati di Node.js (10 Domande)

1. Spiega in dettaglio l'Event Loop di Node.js. Quali sono le diverse fasi?

Risposta: L'Event Loop è ciò che consente a Node.js di eseguire operazioni I/O non bloccanti nonostante sia single-threaded. Delega le operazioni al kernel del sistema quando possibile.

  • Fasi:
    1. Timers: Esegue i callback pianificati da setTimeout() e setInterval().
    2. Pending Callbacks: Esegue i callback I/O rinviati all'iterazione successiva del loop.
    3. Idle, Prepare: Solo per uso interno.
    4. Poll: Recupera nuovi eventi I/O; esegue i callback relativi all'I/O. Qui è dove il loop si blocca se non ci sono altre attività.
    5. Check: Esegue i callback pianificati da setImmediate().
    6. Close Callbacks: Esegue i callback di chiusura (ad esempio, socket.on('close', ...)).

Rarità: Molto Comune Difficoltà: Difficile


2. Qual è la differenza tra process.nextTick() e setImmediate()?

Risposta:

  • process.nextTick(): Non fa parte dell'Event Loop. Si attiva immediatamente dopo il completamento dell'operazione corrente, ma prima che l'Event Loop continui. Ha una priorità più alta di setImmediate(). Un uso eccessivo può bloccare l'Event Loop (starvation).
  • setImmediate(): Fa parte della fase Check dell'Event Loop. Viene eseguito dopo la fase Poll.

Rarità: Comune Difficoltà: Media


3. Come gestisce Node.js la concorrenza se è single-threaded?

Risposta: Node.js utilizza un modello I/O non bloccante e guidato dagli eventi.

  • Thread Principale: Esegue codice JavaScript (motore V8).
  • Libuv: Una libreria C che fornisce l'Event Loop e un pool di thread (predefinito 4 thread).
  • Meccanismo: Quando viene avviata un'operazione asincrona (come I/O di file o richiesta di rete), Node.js la delega a Libuv. Libuv utilizza il suo pool di thread (per I/O di file, DNS) o meccanismi asincroni del kernel del sistema (per la rete). Quando l'operazione è completa, il callback viene inserito nella coda dell'Event Loop per essere eseguito dal thread principale.

Rarità: Comune Difficoltà: Media


4. Spiega gli Stream in Node.js e i loro tipi.

Risposta: Gli Stream sono oggetti che consentono di leggere dati da una sorgente o scrivere dati in una destinazione in blocchi continui. Sono efficienti in termini di memoria perché non è necessario caricare l'intero set di dati in memoria.

  • Tipi:
    1. Readable: Per la lettura di dati (ad esempio, fs.createReadStream).
    2. Writable: Per la scrittura di dati (ad esempio, fs.createWriteStream).
    3. Duplex: Sia leggibili che scrivibili (ad esempio, socket TCP).
    4. Transform: Stream Duplex in cui l'output viene calcolato in base all'input (ad esempio, zlib.createGzip).

Rarità: Comune Difficoltà: Media


5. Cos'è la Backpressure negli Stream e come la gestisci?

Risposta: La backpressure si verifica quando uno stream Readable invia dati più velocemente di quanto lo stream Writable possa elaborarli. Se non gestita, l'utilizzo della memoria aumenterà fino al crash del processo.

  • Gestione:
    • .pipe(): Il modo più semplice. Gestisce automaticamente la backpressure mettendo in pausa lo stream Readable quando il buffer dello stream Writable è pieno e riprendendolo quando si svuota.
    • Manuale: Ascolta l'evento drain sullo stream Writable e metti in pausa/riprendi manualmente lo stream Readable.

Rarità: Media Difficoltà: Difficile


6. Come funziona il modulo cluster?

Risposta: Poiché Node.js è single-threaded, viene eseguito su un singolo core della CPU. Il modulo cluster consente di creare processi figlio (worker) che condividono la stessa porta del server.

  • Processo Master: Gestisce i worker.
  • Processi Worker: Ognuno esegue un'istanza della tua applicazione.
  • Vantaggio: Consente di utilizzare tutti i core della CPU disponibili, aumentando la velocità di trasmissione.

Rarità: Comune Difficoltà: Media


7. Worker Threads vs modulo Cluster: quando usare quale?

Risposta:

  • Cluster: Crea processi separati. Ognuno ha il proprio spazio di memoria e istanza V8. Ideale per scalare server HTTP (I/O bound).
  • Worker Threads: Crea thread all'interno di un singolo processo. Condividono la memoria (tramite SharedArrayBuffer). Ideale per attività ad alta intensità di CPU (ad esempio, elaborazione di immagini, crittografia) per evitare di bloccare l'Event Loop principale.

Rarità: Media Difficoltà: Difficile


8. Come gestisci le eccezioni non gestite e i rejection di promise non gestiti?

Risposta:

  • Eccezione Non Gestita: Ascolta process.on('uncaughtException', cb). Di solito è meglio registrare l'errore e riavviare il processo (utilizzando un gestore di processi come PM2) perché lo stato dell'applicazione potrebbe essere corrotto.
  • Rejection Non Gestito: Ascolta process.on('unhandledRejection', cb).
  • Best Practice: Usa sempre blocchi try/catch e .catch() sulle promise.

Rarità: Comune Difficoltà: Facile


9. Qual è il ruolo di package-lock.json?

Risposta: Descrive l'albero esatto che è stato generato, in modo che le installazioni successive siano in grado di generare alberi identici, indipendentemente dagli aggiornamenti delle dipendenze intermedie. Assicura che il tuo progetto funzioni esattamente allo stesso modo su ogni macchina (CI/CD, altri sviluppatori).

Rarità: Comune Difficoltà: Facile


10. Spiega il concetto di Middleware in Express.js.

Risposta: Le funzioni middleware sono funzioni che hanno accesso all'oggetto richiesta (req), all'oggetto risposta (res) e alla successiva funzione middleware nel ciclo richiesta-risposta dell'applicazione (next).

  • Compiti: Eseguire codice, modificare gli oggetti req/res, terminare il ciclo richiesta-risposta, chiamare il middleware successivo.
  • Ordine: Vengono eseguite sequenzialmente nell'ordine in cui sono definite.

Rarità: Comune Difficoltà: Facile


Progettazione del Sistema e Architettura (10 Domande)

11. Come progetteresti un'applicazione di chat in tempo reale?

Risposta:

  • Protocollo: WebSockets (utilizzando socket.io o ws) per la comunicazione full-duplex.
  • Backend: Node.js è ideale grazie alla sua natura guidata dagli eventi che gestisce molte connessioni simultanee.
  • Scaling:
    • Redis Pub/Sub: Se hai più istanze del server, un utente connesso al Server A deve inviare un messaggio a un utente sul Server B. Redis Pub/Sub funge da message broker per trasmettere messaggi tra i server.
  • Database:
    • Messaggi: NoSQL (MongoDB/Cassandra) per un'elevata velocità di scrittura.
    • Utenti: Relazionale (PostgreSQL) o NoSQL.

Rarità: Molto Comune Difficoltà: Difficile


12. Microservizi in Node.js: schemi di comunicazione.

Risposta:

  • Sincrono: HTTP/REST o gRPC. Buono per semplici richieste/risposte.
  • Asincrono: Code di messaggi (RabbitMQ, Kafka, SQS). Buono per disaccoppiare i servizi e gestire i picchi di carico.
  • Event-Driven: I servizi emettono eventi, altri ascoltano.

Rarità: Comune Difficoltà: Media


13. Come gestisci le transazioni distribuite (Saga Pattern)?

Risposta: Nei microservizi, una transazione potrebbe estendersi a più servizi. È difficile garantire ACID.

  • Saga Pattern: Una sequenza di transazioni locali. Ogni transazione locale aggiorna il database e pubblica un evento o un messaggio per attivare la transazione locale successiva nella saga.
  • Compensazione: Se una transazione locale fallisce, la saga esegue una serie di transazioni di compensazione che annullano le modifiche apportate dalle transazioni locali precedenti.

Rarità: Media Difficoltà: Difficile


14. Spiega il pattern Circuit Breaker.

Risposta: Impedisce a un'applicazione di tentare ripetutamente di eseguire un'operazione che probabilmente fallirà (ad esempio, chiamare un microservizio inattivo).

  • Stati:
    • Closed: Le richieste passano attraverso.
    • Open: Le richieste falliscono immediatamente (fast fail) senza chiamare il servizio.
    • Half-Open: Consente a un numero limitato di richieste di verificare se il servizio si è ripreso.

Rarità: Media Difficoltà: Media


15. Come proteggi un'API Node.js?

Risposta:

  • Helmet: Imposta vari header HTTP per proteggere l'app.
  • Rate Limiting: Usa express-rate-limit per prevenire DDoS/Brute force.
  • Input Validation: Usa librerie come Joi o Zod.
  • Authentication: JWT o OAuth2.
  • CORS: Configura correttamente per consentire solo domini affidabili.
  • NoSQL Injection: Sanitizza gli input contro l'iniezione MongoDB.

Rarità: Comune Difficoltà: Media


16. Cos'è Serverless e come si adatta a Node.js?

Risposta: Serverless (ad esempio, AWS Lambda) ti consente di eseguire codice senza provisioning o gestione di server.

  • Adattamento Node.js: Node.js è eccellente per serverless grazie al suo rapido tempo di avvio (cold start) e alla sua natura leggera.
  • Casi d'uso: Endpoint API, elaborazione di eventi (caricamenti S3), attività pianificate.

Rarità: Media Difficoltà: Media


17. Spiega GraphQL vs REST. Quando usare GraphQL?

Risposta:

  • REST: Endpoint multipli, over-fetching o under-fetching dei dati.
  • GraphQL: Endpoint singolo, il client chiede esattamente ciò di cui ha bisogno.
  • Usa GraphQL: Quando hai requisiti di dati complessi, più client (web, mobile) che necessitano di forme di dati diverse o per ridurre i round trip di rete.

Rarità: Comune Difficoltà: Media


18. Come implementi la Caching in Node.js?

Risposta:

  • In-Memory: node-cache (buono per una singola istanza, ma i dati vengono persi al riavvio e non vengono condivisi).
  • Distribuito: Redis (standard industriale).
  • Strategie: Cache-Aside, Write-Through.
  • HTTP Caching: Usa gli header ETag, Cache-Control.

Rarità: Comune Difficoltà: Media


19. Database Connection Pooling.

Risposta: Aprire una nuova connessione al database per ogni richiesta è costoso.

  • Pooling: Mantiene una cache di connessioni al database che possono essere riutilizzate.
  • Node.js: Librerie come pg (PostgreSQL) o mongoose gestiscono automaticamente il pooling. È necessario configurare la dimensione del pool in base al carico di lavoro e ai limiti del DB.

Rarità: Media Difficoltà: Media


20. Come gestisci il caricamento di file in Node.js?

Risposta:

  • Multipart/form-data: La codifica standard per il caricamento di file.
  • Librerie: multer (middleware per Express), formidable, busboy.
  • Storage: Non archiviare i file nel filesystem del server (statelessness). Carica su storage cloud come AWS S3. Trasmetti il file direttamente a S3 per evitare di caricarlo in memoria.

Rarità: Comune Difficoltà: Media


Prestazioni & Testing (10 Domande)

21. Come esegui il debug di una perdita di memoria in Node.js?

Risposta:

  • Sintomi: Aumento dell'utilizzo della memoria nel tempo (RSS), eventuale crash.
  • Strumenti:
    • Node.js Inspector: Flag --inspect, connettiti con Chrome DevTools.
    • Heap Snapshots: Scatta snapshot e confrontali per trovare oggetti che non vengono garbage collected.
    • process.memoryUsage(): Monitora programmaticamente.

Rarità: Comune Difficoltà: Difficile


22. Profilazione delle applicazioni Node.js.

Risposta: La profilazione aiuta a identificare i colli di bottiglia della CPU.

  • Profiler Integrato: node --prof app.js. Genera un file di log. Elaboralo con node --prof-process isolate-0x...log.
  • Clinic.js: Una suite di strumenti (clinic doctor, clinic flame, clinic bubbleprof) per diagnosticare problemi di prestazioni.

Rarità: Media Difficoltà: Difficile


23. Spiega la regola "Non bloccare l'Event Loop".

Risposta: Poiché c'è solo un thread, se esegui un'operazione sincrona a lunga esecuzione (ad esempio, calcolo pesante, lettura sincrona di file, regex complessa), l'Event Loop si ferma. Nessun'altra richiesta può essere elaborata.

  • Soluzione: Partiziona il calcolo (setImmediate), usa Worker Threads o delega a un microservizio.

Rarità: Molto Comune Difficoltà: Facile


24. Unit Testing vs Integration Testing in Node.js.

Risposta:

  • Unit Testing: Test di singole funzioni/moduli in isolamento. Mock delle dipendenze. (Strumenti: Jest, Mocha, Chai).
  • Integration Testing: Test di come i moduli lavorano insieme (ad esempio, endpoint API + Database). (Strumenti: Supertest).

Rarità: Comune Difficoltà: Facile


25. Cos'è TDD (Test Driven Development)?

Risposta: Un processo di sviluppo in cui scrivi il test prima del codice.

  1. Scrivi un test che fallisce (Red).
  2. Scrivi il codice minimo per superare il test (Green).
  3. Riorganizza il codice (Refactor).

Rarità: Media Difficoltà: Media


26. Come gestisci il logging in un'app Node.js di produzione?

Risposta:

  • Non usare console.log: È sincrono (bloccante) quando si scrive su un terminale/file in alcuni casi e manca di struttura.
  • Usa un Logger: Winston, Bunyan o Pino.
  • Struttura: Formato JSON per una facile analisi da parte degli strumenti di gestione dei log (ELK Stack, Datadog).
  • Livelli: Error, Warn, Info, Debug.

Rarità: Comune Difficoltà: Facile


27. Spiega il Semantic Versioning (SemVer).

Risposta: Formato: MAJOR.MINOR.PATCH (ad esempio, 1.2.3).

  • MAJOR: Modifiche API incompatibili.
  • MINOR: Funzionalità retrocompatibile.
  • PATCH: Correzioni di bug retrocompatibili.
  • ^ vs ~: ^1.2.3 si aggiorna a <2.0.0. ~1.2.3 si aggiorna a <1.3.0.

Rarità: Comune Difficoltà: Facile


28. Cosa sono le Variabili d'Ambiente e come le gestisci?

Risposta:

  • Scopo: Configurazione che varia tra gli ambienti (Dev, Staging, Prod) come URL DB, chiavi API.
  • Utilizzo: process.env.VARIABLE_NAME.
  • Gestione: File .env (utilizzando il pacchetto dotenv) per lo sviluppo locale. In produzione, impostale nel sistema operativo o nelle impostazioni del container/piattaforma.

Rarità: Comune Difficoltà: Facile


29. Come distribuisci un'applicazione Node.js?

Risposta:

  • Process Manager: PM2 (mantiene l'app attiva, gestisce i riavvii, i log).
  • Reverse Proxy: Nginx (gestisce SSL, file statici, bilanciamento del carico) -> App Node.js.
  • Containerizzazione: Docker (standard).
  • Orchestrazione: Kubernetes.
  • CI/CD: GitHub Actions, Jenkins.

Rarità: Comune Difficoltà: Media


30. Cos'è Event Emitter?

Risposta: Il modulo events è il cuore dell'architettura event-driven di Node.js.

  • Utilizzo:
    const EventEmitter = require('events');
    const myEmitter = new EventEmitter();
    myEmitter.on('event', () => console.log('an event occurred!'));
    myEmitter.emit('event');
  • Molti moduli core lo estendono: fs.ReadStream, net.Server, http.Server.

Rarità: Comune Difficoltà: Facile

Newsletter subscription

Consigli di carriera settimanali che funzionano davvero

Ricevi le ultime idee direttamente nella tua casella di posta

Decorative doodle

Il Tuo Prossimo Colloquio Dista Solo un Curriculum

Crea un curriculum professionale e ottimizzato in pochi minuti. Non servono competenze di design—solo risultati comprovati.

Crea il mio curriculum

Condividi questo post

Raddoppia le Tue Chiamate per Colloqui

I candidati che personalizzano il loro curriculum in base alla descrizione del lavoro ottengono 2,5 volte più colloqui. Usa la nostra IA per personalizzare automaticamente il tuo CV per ogni singola candidatura istantaneamente.