Il benchmark delle refactor svela il rischio N+1 nel tuo repo Windsurf

VibeInspect.ai · 22 agosto 2026 · 6 min di lettura
- windsurf
- vibe-coding
- query-n-plus-one
- performance
- audit-codice
Il codice che compila non è ancora un sistema che regge
Un nuovo benchmark dedicato alle refactor su larga scala mostra un limite concreto degli agenti di coding: il modello migliore ha raggiunto un resolve rate del 41,2% su 170 casi reali, distribuiti tra sette linguaggi. Il test è stato costruito per misurare cambiamenti ampi, distribuiti su più file e con vincoli di comportamento più severi rispetto ai benchmark più semplici.
La notizia completa è Most coding agent benchmarks skip large-scale refactoring. Not this one..
Il dato non dice che gli agenti siano inutili. Dice una cosa più scomoda: quando il comportamento dipende da relazioni distribuite nel codice, il risultato può sembrare corretto localmente e restare sbagliato a livello di sistema.
Per chi ha spedito un prodotto generato con un coding agent, il rischio non è soltanto una refactor incompleta. È anche una regressione invisibile nelle prestazioni: una pagina che funziona con dieci record e diventa lenta quando il database contiene migliaia di elementi.
Il caso concreto di oggi è uno solo: query N+1.
Cosa significa se il tuo codice l’ha scritto Windsurf
Windsurf può aiutarti a costruire rapidamente dashboard, cataloghi, pannelli amministrativi e pagine con dati relazionati. Il codice può essere pulito, tipizzato e accompagnato da test verdi.
Il problema N+1 nasce quando il backend esegue una query per ottenere una lista e poi una query aggiuntiva per ogni elemento della lista.
Esempio concettuale: recuperi 100 ordini con una query. Poi, dentro un ciclo, chiedi separatamente il cliente associato a ciascun ordine. Il risultato è una query iniziale più 100 query successive. Con dieci ordini può sembrare tutto normale. Con mille ordini, ogni richiesta moltiplica il lavoro sul database e aumenta la latenza.
In un repo costruito o ampliato con Windsurf, il problema può apparire in forme diverse:
- una relazione caricata dentro un ciclo;
- una funzione di accesso al database chiamata da un mapper per ogni riga;
- un componente server che recupera dettagli individuali durante il rendering;
- un resolver GraphQL che esegue query separate per ogni elemento;
- un endpoint che restituisce una lista senza pre-caricare le relazioni necessarie;
- una pagina che usa cache solo per il caso singolo, ma non per il caricamento di massa.
Non significa che Windsurf abbia scritto codice “sbagliato”. Significa che l’agente può ottimizzare la correttezza del singolo passaggio senza vedere il costo aggregato dell’intero percorso.
La schermata funziona. I dati sono corretti. Il sistema però può fare centinaia di chiamate dove ne servivano una o due.
Perché ora ti serve un audit: il verdetto sul percorso dati
Il benchmark sulle refactor complesse mette in evidenza la differenza tra modificare codice e comprendere davvero le dipendenze di un sistema. Una query N+1 è proprio questo tipo di problema: raramente vive in una sola riga.
Per il tuo repo Windsurf, l’audit deve rispondere a una domanda precisa:
un percorso che restituisce una collezione può moltiplicare le query o le chiamate esterne in proporzione al numero di elementi?
Per arrivare al verdetto bisogna seguire il flusso completo:
- quale endpoint o pagina avvia la richiesta;
- quale query carica la collezione principale;
- quali funzioni vengono chiamate per ogni elemento;
- se quelle funzioni interrogano di nuovo il database o un servizio esterno;
- se le relazioni vengono caricate in modo aggregato;
- se esistono limiti, paginazione e filtri;
- quale comportamento emerge quando il numero di record cresce.
Il verdetto utile non è “ci sono molte query”. È più concreto: il percorso mantiene il numero di chiamate sotto controllo rispetto alla dimensione dell’input, oppure il costo cresce elemento per elemento in un flusso raggiungibile dagli utenti.
VibeInspect prende il repository ZIP, lo analizza con specialisti AI e restituisce un PDF con score e verdetto. Nel piano Diagnostic il report include evidenze riferite a file e righe. Non esegue un test di carico e non modifica il codice: ti aiuta però a capire dove il comportamento del repo può degradare prima che il problema emerga dai grafici di produzione.
Il nemico non è avere usato Windsurf. È non sapere se una pagina apparentemente semplice esegue una query per ogni riga che mostra.
Le evidenze che distinguono un N+1 reale da un falso allarme
Un ciclo vicino a una query non dimostra sempre un problema. Può lavorare su dati già caricati in memoria. L’evidenza nasce dal collegamento tra iterazione, accesso ai dati e numero di chiamate.
Cerca soprattutto queste combinazioni:
- Query dentro un ciclo. Una funzione come
findByIdogetDetailschiamata per ogni elemento è il segnale più diretto. - Relazione caricata dopo il fetch principale. La lista viene recuperata correttamente, ma ogni relazione viene risolta separatamente.
- Serializzazione con accesso implicito ai dati. Un mapper o un serializer può attivare lazy loading senza che la query sia evidente nel controller.
- Resolver o componenti ripetuti. Un componente riutilizzato in una lista può eseguire la stessa richiesta per ogni card o riga.
- Chiamate esterne nel loop. Il problema non riguarda soltanto SQL: anche API, storage o servizi di arricchimento possono moltiplicare le richieste.
- Assenza di paginazione. Se l’endpoint carica l’intera collezione, l’effetto N+1 può diventare proporzionale a tutto il dataset.
- Test solo con fixture piccole. Dieci record non mostrano il comportamento che emerge con centinaia o migliaia di elementi.
L’audit deve collegare queste evidenze con il percorso utente. Un N+1 su una pagina interna e poco usata non ha lo stesso peso di un endpoint pubblico richiamato a ogni apertura della dashboard.
Cosa un linter non vede
Un linter può segnalare una variabile inutilizzata, un import errato, una promessa non gestita o una regola di stile violata. Può individuare alcune chiamate sospette, ma non dimostra il costo totale del flusso.
Non vede, da solo, che:
- una query corretta viene eseguita centinaia di volte nella stessa richiesta;
- una relazione viene risolta durante il rendering di ogni elemento;
- un resolver GraphQL genera una query per nodo;
- un endpoint restituisce tutti i record senza un limite ragionevole;
- la cache evita il problema in sviluppo ma non in produzione;
- il database è veloce con pochi dati e satura quando la collezione cresce;
- una refactor ha spostato l’accesso ai dati in un helper apparentemente innocuo.
Nemmeno i test del caso nominale bastano. Un test può verificare che ogni ordine mostri il nome del cliente. Non dice quante query sono state eseguite per produrre quel risultato, né come cambia il comportamento con 1.000 ordini.
Il linter controlla la forma locale. L’audit ricostruisce il rapporto tra input, chiamate e costo.
Cosa fare questa settimana
Scegli una sola pagina o API che restituisce una lista: ordini, utenti, prodotti, eventi o ticket.
Poi misura e annota:
- numero medio di elementi restituiti;
- query eseguite durante una richiesta;
- chiamate esterne effettuate;
- relazioni caricate per ogni elemento;
- presenza di paginazione e limiti;
- latenza con dataset piccolo e dataset realistico.
Nel repository, segui il percorso dalla route fino alla query. Cerca cicli, mapper, resolver e componenti che chiamano funzioni di accesso ai dati. Non fermarti al controller: il problema può essere nascosto in un helper o in un caricamento implicito.
Se non sai indicare quale funzione determina il numero di query rispetto al numero di record, non partire da un’altra refactor generata dall’AI. Ti serve prima un verdetto sul repo.
Carica lo ZIP su VibeInspect.ai. Per questo caso sceglierei il piano Diagnostic, perché il problema è tecnico e hai bisogno di evidenze su file, righe e percorso dati.
L’obiettivo non è dimostrare che Windsurf abbia scritto codice “brutto”. È sapere se il tuo prodotto continua a rispondere quando la lista cresce, oppure se ogni nuovo record aggiunge un altro giro di lavoro nascosto.
Domande frequenti
Che cos’è un problema N+1?
È un antipattern in cui il sistema esegue una query iniziale per una collezione e poi una query aggiuntiva per ogni elemento. Il numero di chiamate cresce con la dimensione dell’input.
Windsurf può generare un N+1?
Il rischio dipende dal repository concreto. Un agente può creare un flusso corretto per pochi record ma inefficiente quando una relazione viene caricata separatamente per ogni elemento.
Perché un linter non basta per trovare un N+1?
Perché il problema riguarda il comportamento aggregato del percorso dati: query, cicli, resolver, caricamento delle relazioni e dimensione dell’input. Non è sempre dimostrabile con una regola locale.
Come si verifica un possibile N+1?
Bisogna seguire il flusso dalla route alla query, contare le chiamate con dataset realistici e controllare se il numero di accessi cresce elemento per elemento.
Quale piano VibeInspect scegliere?
Il piano Diagnostic, perché restituisce evidenze riferite a file e righe sul percorso dati, sulle query ripetute e sui punti in cui il costo può crescere con il numero di record.