Domande da colloquio
Domande da colloquio per Software Engineer
Esercitati con domande su programmazione, strutture dati, algoritmi, system design, debugging, test, produzione e collaborazione. Usa questa selezione mirata insieme alla guida completa per Guida al colloquio per Software Engineer.
19 domande
6 categorie
Software Engineer
Aggiornata a maggio 2026
Array, stringhe e tabelle hash
Questi fondamenti valutano indici, frequenze, due puntatori, finestre scorrevoli e precisione dell’implementazione.
Approccio — Memorizzare il complemento in una tabella hash
Scorrerei l’array una sola volta. Per ogni x verificherei se target − x è già presente in una tabella hash. In tal caso restituirei il suo indice e quello corrente; altrimenti salverei x con il relativo indice. Ogni elemento viene elaborato una volta: O(n) tempo e O(n) spazio. Chiarirei prima se esiste esattamente una soluzione e se un indice può essere riutilizzato.
Possibili domande di approfondimento
Come gestiresti i duplicati?
Come risolveresti senza spazio aggiuntivo?
Cosa cambia se l’array è ordinato?
Approccio — Finestra scorrevole con ultimo indice osservato
Manterrei una finestra [left, right] senza duplicati e l’ultimo indice di ogni carattere. Se un carattere ricompare nella finestra, sposterei left a lastSeen + 1. Aggiornerei poi l’indice e il massimo. Left non deve mai arretrare. Il tempo è O(n) e lo spazio O(k), dove k è l’alfabeto.
Possibili domande di approfondimento
Perché left può soltanto avanzare?
Come gestiresti Unicode?
Come restituiresti anche la sottostringa?
Approccio — Creare una chiave canonica per ogni parola
Creerei per ogni parola una chiave canonica e raggrupperei le chiavi uguali in una tabella hash. La chiave può essere la stringa ordinata oppure, con un alfabeto fisso, un vettore di frequenze. Con l’ordinamento, il tempo è O(n · m log m); con le frequenze, O(n · m), dove m è la lunghezza.
Possibili domande di approfondimento
Quale soluzione è migliore per stringhe molto lunghe?
Come gestiresti le maiuscole?
Come renderesti deterministico l’output?
Liste concatenate, alberi e grafi
Qui contano disciplina nell’uso dei puntatori, invarianti ricorsive, ordine di attraversamento e gestione sicura dei nodi visitati.
Approccio — Tre puntatori: precedente, corrente e successivo
Inizializzerei prev a null e current alla testa. A ogni iterazione salverei current.next, farei puntare current.next a prev e avanzerei entrambi i puntatori. Alla fine prev è la nuova testa. L’invariante è che prev punta sempre alla parte già invertita. Tempo O(n), spazio O(1).
Possibili domande di approfondimento
Come sarebbe la soluzione ricorsiva?
Cosa succede con una lista vuota?
Come invertiresti solo un intervallo?
Approccio — Propagare limiti inferiore e superiore validi
Confrontare soltanto i figli non basta. Attraverserei ricorsivamente l’albero passando l’intervallo consentito: a sinistra, il valore corrente diventa il limite superiore; a destra, quello inferiore. Se un nodo viola l’intervallo, l’albero non è valido. Chiarirei la regola per i duplicati. Tempo O(n), spazio O(h) per la ricorsione.
Possibili domande di approfondimento
Perché non basta confrontare i figli diretti?
Come funzionerebbe un attraversamento inorder?
Come eviteresti l’overflow nei limiti?
Approccio — BFS per livelli di distanza
Tratterei ogni cella attraversabile come un nodo ed eseguirei BFS dall’inizio. Contrassegnerei una cella quando la inserisco in coda per evitare duplicati. Il primo arrivo alla destinazione è minimo grazie all’ordine per livelli. Per restituire il percorso, salverei i predecessori. Tempo e spazio O(righe · colonne).
Possibili domande di approfondimento
Come restituiresti il percorso?
Cosa cambia con celle pesate?
Come gestiresti più punti di partenza?
Approccio — Associare ogni nodo originale al suo clone
Userei DFS o BFS e una tabella che associa ogni nodo originale al suo clone. Creerei e salverei il clone alla prima visita, quindi clonerei i vicini. Salvarlo prima evita cicli infiniti e conserva i vicini condivisi. Tempo e spazio O(V + E).
Possibili domande di approfondimento
Perché salvare il clone prima di attraversare i vicini?
Come cloneresti un grafo non connesso?
Quali test coprono cicli e cappi?
Programmazione dinamica e backtracking
L’aspetto essenziale è definire con precisione lo stato, formulare una transizione completa e potare correttamente i rami non validi.
Approccio — DP bottom-up per tutti gli importi
Definirei dp[a] come il numero minimo di monete per l’importo a. Imposterei dp[0] = 0 e il resto su infinito. Per ogni importo e moneta c ≤ a, aggiornerei dp[a] = min(dp[a], dp[a − c] + 1). Se l’obiettivo resta infinito, non può essere composto. Tempo O(importo · monete), spazio O(importo).
Possibili domande di approfondimento
Come ricostruiresti le monete utilizzate?
Cosa cambia se le monete sono limitate?
Perché un approccio greedy non funziona sempre?
Approccio — DP per posizione finale e ottimizzazione con ricerca binaria
La soluzione di base definisce dp[i] come la lunghezza massima che termina in i. Per ogni j < i con nums[j] < nums[i], aggiorna dp[i], ottenendo O(n²). La soluzione ottimizzata conserva il minor valore finale possibile per ogni lunghezza e lo sostituisce mediante ricerca binaria, raggiungendo O(n log n).
Possibili domande di approfondimento
Come restituiresti la sottosequenza?
Perché tails non rappresenta necessariamente la sottosequenza effettiva?
Come gestiresti valori uguali?
Approccio — Generare soltanto prefissi validi
Costruirei la stringa un passaggio alla volta. Si può aggiungere una parentesi aperta finché open < n e una chiusa solo se close < open. Quando la lunghezza raggiunge 2n, la combinazione è valida. Poiché non si creano mai prefissi non validi, lo spazio di ricerca viene potato in anticipo.
Possibili domande di approfondimento
Qual è la dimensione asintotica dell’output?
Come lo formuleresti in modo iterativo?
Quali casi base sono importanti?
Colloqui di progettazione di sistemi
Questi colloqui valutano la maturità tecnica. Per i profili senior contano compromessi, colli di bottiglia, affidabilità, osservabilità e responsabilità operativa.
Approccio — Requisiti → API → generazione ID → archiviazione → reindirizzamento → scala
L’utente invia un URL lungo e riceve un codice; il reindirizzamento deve essere rapido. Le API principali sono createShortUrl e redirect. Il record contiene codice, destinazione, utente, creazione, scadenza e stato. I codici possono derivare da ID sequenziali in Base62 oppure essere generati casualmente con rilevamento delle collisioni. La lettura usa una cache davanti al database, convalida stato e scadenza e risponde con 301 o 302. Le analisi vengono elaborate in modo asincrono tramite coda. Su larga scala aggiungerei cache edge, sharding per codice, rate limit e controllo degli abusi.
Possibili domande di approfondimento
Come genereresti codici univoci?
Quando useresti 301 invece di 302?
Come registreresti le analisi senza rallentare il servizio?
Approccio — Utenti → pubblicazioni → fanout → ranking → lettura → coerenza
Ipotizzerei un feed di account seguiti. Gli oggetti centrali sono utente, follow, pubblicazione, contenuto, voce del feed e interazione. I servizi di pubblicazione, grafo, feed e ranking lavorano con cache, object storage e code. Il fanout in scrittura consente letture rapide ma è costoso per gli account enormi. Il fanout in lettura riduce le scritture ma aumenta la latenza. Un approccio ibrido distribuisce in scrittura gli account normali e gestisce quelli grandi in lettura. Considererei inoltre freschezza, privacy, errori delle code, invalidazione della cache e spam.
Possibili domande di approfondimento
Come gestiresti account con milioni di follower?
Come ordineresti le pubblicazioni?
Cosa succede se la coda di fanout è in ritardo?
Approccio — Connessioni → flusso dei messaggi → archiviazione → consegna → affidabilità
I client mantengono una connessione WebSocket con i gateway. All’invio, il gateway autentica, usa una chiave di idempotenza, salva il messaggio, pubblica un evento e lo consegna ai destinatari connessi. Gli utenti offline ricevono una notifica push e si sincronizzano dall’ultimo punto visualizzato. Il modello include conversazione, partecipante, messaggio, consegna, lettura e dispositivo. Le chiavi evitano i duplicati, le sequenze per conversazione garantiscono l’ordine, mentre conferme e tentativi ripetuti assicurano la consegna. Gli allegati vanno nell’object storage. Monitorerei latenza, tasso di consegna, connessioni, riconnessioni, coda ed errori di scrittura.
Possibili domande di approfondimento
Come garantiresti l’ordine?
Come supporteresti più dispositivi?
Cosa memorizzeresti per le conferme di lettura?
Debugging, test e preparazione alla produzione
Questi scenari distinguono chi scrive codice da chi gestisce software in modo responsabile.
Approccio — Convalidare il segnale → delimitare l’ambito → esaminare le modifiche → scomporre le dipendenze → mitigare
Confermerei il segnale su più sistemi di monitoraggio ed esaminerei p50, p95, p99 ed endpoint. Segmentare per regione, zona, versione, host, client, tipo e dipendenza aiuta a delimitare il problema. Esaminerei deployment, configurazione, migrazioni, traffico, feature flag, cache e interruzioni downstream. I trace scompongono la latenza; controllerei anche database, hit rate, coda, CPU, memoria, garbage collection e pool. In presenza di impatto, mitigherei prima di dimostrare la causa perfetta tramite rollback, disattivazione di un flag, scalabilità o esclusione di una dipendenza lenta.
Possibili domande di approfondimento
Cosa faresti se aumentasse soltanto p99?
Come decideresti un rollback?
Quali dashboard ti servirebbero?
Approccio — Casi normali → limiti → input non validi → invarianti
Chiarirei tipi, combinazioni, scadenza, minimo, idoneità, arrotondamento, imposte e spedizione. Gli unit test coprirebbero nessuno sconto, percentuale, importo fisso, minimo esatto e inferiore, scaduto, utente non idoneo e cumulo. Le invarianti sono: il prezzo non è mai negativo, lo sconto non supera l’importo idoneo, una promozione scaduta non si applica e lo stesso input produce lo stesso risultato. Se influisce sui pagamenti, aggiungerei test di integrazione e registrerei la motivazione di ogni decisione.
Possibili domande di approfondimento
Come testeresti l’arrotondamento valutario?
Cosa succede se il servizio promozioni non è disponibile?
Quali casi sono unitari e quali di integrazione?
Approccio — Correttezza → manutenibilità → rischio → chiarezza
Esaminerei in quest’ordine: risolve correttamente il problema? È manutenibile e presenta confini chiari? Quali rischi introduce per migrazione, concorrenza, sicurezza, prestazioni, compatibilità o osservabilità? I test coprono la modifica? Distinguerei i blocchi dai suggerimenti. Correttezza, sicurezza o migrazione possono bloccare; il gusto personale no. Una review deve migliorare sia il codice sia la velocità del team, non dimostrare superiorità.
Possibili domande di approfondimento
Come risolveresti un disaccordo?
Quando un commento è bloccante?
Come eviteresti ritardi inutili?
Domande comportamentali e di collaborazione
Questi round affrontano responsabilità, collaborazione, decisioni tecniche, ambiguità e apprendimento. Le risposte migliori includono conseguenze tecniche reali.
Approccio — Contesto → opzioni → compromessi → decisione → risultato
Sceglierei una decisione con alternative reali: sviluppare o acquistare, SQL o NoSQL, correzione rapida o riprogettazione, coerenza o disponibilità. Spiegherei contesto, vincoli e opzioni. Indicherei il compromesso e le evidenze determinanti: traffico, scadenza di un cliente, incidenti, capacità o roadmap. Concluderei con risultato e apprendimento. Una risposta matura può ammettere cosa farei diversamente oggi.
Possibili domande di approfondimento
Chi non era d’accordo?
Quali informazioni avrebbero cambiato la decisione?
Come hai misurato il successo?
Approccio — Incidente → impatto → risposta → causa → prevenzione
Inizierei dall’impatto: cosa non ha funzionato, chi ne ha risentito e quanto era grave. Descriverei poi il mio contributo a rilevamento, triage, rollback, mitigazione, comunicazione o analisi della causa. Durante l’incidente, ripristinare il servizio conta più che dimostrare una teoria. Spiegherei come ho usato log, metriche, trace, flag, rollback o dipendenze. Dopo la mitigazione, descriverei causa e prevenzione: test migliori, rollout sicuro, monitoraggio o runbook, senza cercare colpevoli.
Possibili domande di approfondimento
Come hai comunicato durante l’incidente?
Quale avviso lo avrebbe rilevato prima?
Cosa ha cambiato il team in seguito?
Approccio — Obiettivo condiviso → vincoli → opzioni → compromessi → decisione
Per prima cosa allineerei l’obiettivo per l’utente e l’azienda. Molti conflitti nascono da ipotesi diverse. Spiegherei con precisione il vincolo tecnico: complessità, affidabilità, tempistica, manutenzione, sicurezza o prestazioni. Invece di limitarmi a dire no, proporrei opzioni: un MVP più piccolo, un processo manuale temporaneo, una feature flag, lavoro per fasi o un design più semplice. In presenza di rischi importanti, documenterei alternative, conseguenze e raccomandazione. L’obiettivo non è far vincere Ingegneria, ma consentire al team di prendere una decisione consapevole.
Possibili domande di approfondimento
Cosa faresti se Prodotto insistesse sull’opzione rischiosa?
Come spiegheresti il debito tecnico?
Quando porteresti la questione al livello superiore?
Esercitati dal vivo con le risposte
Interview Pilot suggerisce risposte in tempo reale durante i colloqui, aiutandoti a rispondere con chiarezza.