Entriamo in un fase in cui la qualità dell'output prodotto da Cursor diventa più variabile, e la supervisione umana diventa più importante. Cursor cerca nel progetto tutti i componenti che importano da userSlice o che usano useSelector e useDispatch con riferimenti allo stato utente, e li aggiorna per usare il nuovo store Zustand.
Aggiornamento dei componenti consumatori
Proseguendo nel nostro progetto, il prossimo passaggio restituisce quanto segue:
// Prima — con Redux
import { useSelector, useDispatch } from 'react-redux';
import { updatePreferences, fetchUserProfile } from '../store/userSlice';
const UserSettings = () => {
const dispatch = useDispatch();
const preferences = useSelector((state: RootState) => state.user.preferences);
const loading = useSelector((state: RootState) => state.user.loading);
const handleSave = (newPrefs: Partial) => {
dispatch(updatePreferences(newPrefs));
};
return ( /* ... */ );
};
A questo:
// Dopo — con Zustand
import { useUserStore } from '../store/useUserStore';
const UserSettings = () => {
const preferences = useUserStore((state) => state.preferences);
const loading = useUserStore((state) => state.loading);
const updatePreferences = useUserStore((state) => state.updatePreferences);
const handleSave = (newPrefs: Partial) => {
updatePreferences(newPrefs);
};
return ( /* ... */ );
};
Questo tipo di sostituzione, Cursor la esegue in modo preciso e consistente. Il problema emerge quando i componenti usano selettori con logica derivata — per esempio useSelector con un selettore reselect che combina più campi dello stato, perché lì Cursor tende a inlineare la logica nel componente invece di proporre un selettore Zustand equivalente, producendo codice funzionalmente corretto ma architetturalmente degradato.
I punti ciechi dell'agente di Cursor: dove la supervisione è obbligatoria
Lavorare con Cursor su un refactoring di questa portata mette in luce tre categorie di problemi ricorrenti che è importante conoscere prima di iniziare, non per scoraggiarsi dall'usare lo strumento, ma per sapere dove concentrare l'attenzione durante la review.
Il primo riguarda la gestione del middleware Redux. Se il tuo store usa middleware personalizzati, per il logging, per la persistenza con redux-persist, per la sincronizzazione con un WebSocket, Cursor tende a non migrarli automaticamente perché richiedono decisioni architetturali che vanno oltre la mappatura diretta. Spesso li omette silenziosamente, producendo uno store Zustand funzionante ma privato di funzionalità che prima erano presenti. Una review attenta del diff, file per file, è l'unico modo per intercettare queste omissioni.
Il secondo problema riguarda i test. Se hai test unitari sulle action creator o sui reducer Redux (e dovresti averli) Cursor generalmente non li migra, perché il modello di testing di Zustand è sufficientemente diverso da richiedere una riscrittura non banale. Nella migliore delle ipotesi te lo dice esplicitamente. Nella peggiore lascia i test esistenti puntare a moduli che non esistono più, e la build di test smette di funzionare senza che sia ovvio il perché.
Il terzo problema è più sottile e riguarda la gestione dello stato globale condiviso tra store. In un'applicazione Redux matura, è comune avere thunk che leggono lo stato di una slice diversa tramite getState().
In Zustand questo pattern si implementa diversamente — attraverso l'importazione diretta di altri store o tramite il middleware subscribeWithSelector. Cursor a volte risolve questo in modo creativo ma non idiomatico, producendo accoppiamenti impliciti che funzionano ma che rendono il codice più difficile da ragionare.
Il valore reale: non la velocità, ma la riduzione dell'attrito cognitivo
C'è una tendenza a misurare il valore degli agenti AI in termini di velocità. Ad esempio: quante ore risparmio usando Cursor invece di scrivere tutto a mano? È una metrica comprensibile ma parziale, perché non cattura il vantaggio più importante che questi strumenti offrono su un refactoring complesso.
Il vero valore di Cursor in un contesto come questo non è che fa il lavoro più velocemente. Abbassa invece la soglia di attrito cognitivo che rende certi refactoring procrastinabili indefinitamente. Sapere che puoi delegare la parte meccanica, la mappatura uno a uno tra Redux e Zustand, la ricerca e sostituzione dei pattern di useSelector, la generazione dello store con la firma corretta, cambia la percezione del task da "progetto di due giorni" a "pomeriggio con supervisione attiva".
Questo non significa che il lavoro umano sparisca. Significa che si concentra dove conta davvero: nelle decisioni architetturali che l'agente non può prendere autonomamente, nella gestione dei casi limite, nella review critica dell'output, e nei test che verificano che il sistema si comporti ancora correttamente dopo la migrazione.
Un pattern di lavoro che funziona in pratica
Dopo diverse sessioni di refactoring con agenti su codice React, emerge un pattern operativo che bilancia l'autonomia dell'agente con il controllo necessario. Si inizia con un branch dedicato e un commit iniziale che fotografa lo stato del codebase prima di qualsiasi modifica. Si fornisce a Cursor un task granulare, una slice alla volta, non l'intero store, con vincoli espliciti su cosa non toccare. Si revisiona ogni batch di modifiche come una pull request, con attenzione particolare ai file che l'agente ha modificato senza che fossero nel perimetro dichiarato del task. Si eseguono i test dopo ogni batch, non solo alla fine. E si mantiene un file di note sulle decisioni architetturali prese durante il processo. Perché quella conoscenza non è catturata da nessuna parte nell'output dell'agente.
È un processo più strutturato rispetto a semplicemente aprire il Composer e scrivere "migra tutto a Zustand". Ma è anche un processo che, con quella struttura, produce risultati affidabili su codebase reali. L'unica metrica che conta quando si parla di codice in produzione.
Cosa cambia nel ruolo dello sviluppatore con Cursor?
C'è una domanda che emerge naturalmente da questo tipo di esperienza, e vale la pena affrontarla senza eufemismi. Se un agente come Cursor può eseguire la parte meccanica di un refactoring complesso, cosa rimane al developer?
Rimane tutto quello che conta. Rimane la decisione di migrare da Redux a Zustand in primo luogo, che non è ovvia e dipende dal contesto del progetto. Rimane la definizione dell'architettura dello store Zustand, che l'agente replica ma non inventa. Rimane la valutazione critica dell'output, che richiede di capire Zustand abbastanza bene da riconoscere quando l'agente ha fatto una scelta subottimale. Rimane la gestione dei casi limite: il middleware non migrato, il selettore derivato inlinato nel componente, il test che punta a un modulo inesistente.
In sintesi, rimane il mestiere del developer. Quello che cambia è la distribuzione del tempo tra lavoro meccanico e lavoro intellettuale. Gli agenti comprimono il primo. Il secondo rimane e diventa più visibile, più centrale, e in un certo senso più richiesto di prima. Supervisionare un agente richiede una comprensione del dominio più solida di quella necessaria per eseguire il task "a mano".
Se vuoi aggiornamenti su Cursor: quando la supervisione è obbligatoria inserisci la tua email nel box qui sotto: