Impara a creare specifiche delle feature da codice leggendo il comportamento reale da route e componenti, quindi producendo una spec vivente e una lista di gap.

Le persone hanno opinioni diverse su cosa faccia un'app perché ricordano versioni differenti. Support ricorda l'ultimo ticket arrabbiato. Sales ricorda il percorso della demo. Gli ingegneri ricordano cosa la feature doveva fare. Chiedi a tre persone e ottieni tre risposte sicure, e nessuna corrisponde alla build corrente.
Col tempo, il codice diventa l'unica fonte che rimane aggiornata. La doc deriva, i ticket si chiudono e le patch rapide si accumulano. Una route riceve una nuova regola di validazione. Un toggle nell'interfaccia cambia un default. Un handler inizia a restituire errori diversi. Nessuno aggiorna la spec perché sembra opzionale, e ogni cambiamento sembra troppo piccolo per essere documentato.
Questo genera problemi prevedibili. I team rilasciano cambiamenti che rompono edge case che non sapevano esistessero. QA testa il percorso felice e perde regole sepolte negli handler. I nuovi membri copiano il comportamento dall'UI senza capire i vincoli reali. Gli stakeholder discutono opinioni invece di riferirsi a un comportamento condiviso.
Un buon risultato non è un documento perfetto. È chiarezza condivisa. Tutti dovrebbero essere in grado di rispondere: "Cosa succede se faccio X?" e "Cosa garantisce il sistema?" senza indovinare. Ottieni meno sorprese, cicli di revisione più brevi e meno momenti del tipo "Aspetta, lo fa già" perché il team sta guardando la stessa verità.
Quando una spec corrisponde al codice, diventa sicuro pianificare cambiamenti. Puoi vedere cosa è stabile, cosa è accidentale e cosa manca prima del rilascio.
Una spec vivente è una descrizione breve e modificabile di ciò che l'app fa oggi. Non è un documento una tantum. Cambia ogni volta che cambia il comportamento, così il team può fidarsi.
Quando si parla di feature spec scritte dal codice (per esempio usando Claude Code), l'obiettivo è semplice: leggere il comportamento reale da route, handler e schermate, poi scriverlo in linguaggio semplice.
Una spec vivente utile si concentra su ciò che gli utenti vedono e su cosa il sistema promette. Dovrebbe coprire:
Non dovrebbe invece coprire come è organizzato il codice. Se inizi a nominare file e piani di refactor, stai scivolando in dettagli di implementazione. Evita:
Una lista di gap è separata. È un piccolo elenco di discrepanze e incognite che trovi scrivendo la spec.
Esempio: una route rifiuta file oltre 10MB, ma l'UI dice 25MB. È un gap finché il team non decide quale regola è quella vera e aggiorna o codice o spec.
Parti piccolo. Se provi a documentare tutta l'app, finirai con una pila di note di cui nessuno si fiderà. Scegli una fetta che gli utenti riescono a descrivere in una frase, tipo "invitare un collega", "checkout" o "reset password". Buoni scope sono un singolo ambito funzionale, un modulo o un percorso utente dall'entry point al risultato.
Scegli il punto di partenza in base a dove risiede la verità:
Prima di leggere il codice, raccogli qualche input così le incongruenze saltano subito all'occhio: eventuale documentazione API esistente, vecchie note di prodotto, ticket di supporto e i "pain point" noti di cui la gente si lamenta. Queste cose non sovrascrivono il codice, ma ti aiutano a notare stati mancanti come errori, edge case e permessi.
Mantieni il formato della spec noioso e coerente. I team si allineano più velocemente quando ogni spec si legge allo stesso modo.
Usa questa struttura ripetutamente e le tue feature spec resteranno leggibili, comparabili e facili da aggiornare.
Inizia dai punti di ingresso server. Route e handler mostrano "cosa fa l'app" in termini concreti: chi può chiamarla, cosa devono inviare, cosa ricevono e cosa cambia nel sistema.
Elenca le route nello scope e mappa ognuna a un intento utente. Non scrivere "POST /api/orders." Scrivi "Effettuare un ordine" o "Salva bozza." Se non riesci a nominare l'intento in parole semplici, quello è già un gap della spec.
Mentre leggi ogni handler, cattura input e regole di validazione come requisiti rivolti all'utente. Includi campi obbligatori, formati ammessi e le regole che provocano errori reali. Per esempio: "Email deve essere valida", "Quantity deve essere almeno 1", "La data di inizio non può essere nel passato."
Scrivi i controlli di auth e ruolo allo stesso modo. Invece di "middleware: requireAdmin," documenta: "Solo gli admin possono cancellare qualsiasi ordine. Gli utenti normali possono cancellare solo il proprio ordine entro 10 minuti." Se il codice controlla ownership, feature flag o confini di tenant, includili anche.
Poi annota output e risultati. Cosa restituisce il successo (un ID creato, un oggetto aggiornato)? Come appaiono i fallimenti comuni (401 non autenticato, 403 non autorizzato, 404 non trovato, 409 conflitto, 422 errore di validazione)?
Infine, registra gli effetti collaterali perché fanno parte del comportamento: record creati o aggiornati, email o notifiche inviate, eventi pubblicati, job in background messi in coda e tutto ciò che innesca altri flussi. Questi dettagli prevengono sorprese quando i team faranno affidamento sulla spec in seguito.
Le route ti dicono cosa l'app può fare. I componenti ti dicono cosa gli utenti sperimentano realmente. Tratta l'UI come parte del contratto: cosa appare, cosa viene bloccato e cosa succede quando qualcosa va storto.
Inizia trovando le schermate di ingresso per la feature. Cerca il componente pagina, il layout wrapper e alcuni componenti "decision" che controllano fetch, permessi e navigazione. Lì di solito vive il comportamento reale.
Mentre leggi i componenti, cattura le regole percepibili dagli utenti: quando le azioni sono disabilitate, passi obbligatori, campi condizionali, stati di loading e come appaiono gli errori (errori inline sui campi vs toast, retry automatico, pulsanti "riprovare"). Nota anche il comportamento di stato e caching come dati obsoleti mostrati per primi, update ottimistici, o timestamp "ultimo salvataggio".
Fai attenzione ai flow nascosti che modificano silenziosamente ciò che gli utenti vedono. Cerca feature flag, bucket di esperimenti e gate riservati agli admin. Nota anche redirect silenziosi, come inviare utenti non loggati al login o utenti senza accesso a una schermata di upgrade.
Un esempio concreto: in una schermata "Change Email", documenta che Save rimane disabilitato finché l'email non è valida, appare uno spinner durante la richiesta, il successo mostra un banner di conferma e gli errori di validazione backend vengono renderizzati sotto l'input. Se il codice mostra una flag come newEmailFlow, nota entrambe le varianti e cosa cambia.
Scrivi ogni flow UI come brevi passi (cosa fa l'utente, cosa fa l'UI in risposta) e mantieni condizioni ed errori vicini al passo che li riguarda. Questo mantiene la spec leggibile e aiuta a individuare i gap.
Le note grezze da route e componenti sono utili, ma difficili da discutere. Riscrivi ciò che hai osservato in una spec che un PM, un designer, QA e un ingegnere possano leggere e approvare.
Un pattern pratico è una user story per ogni route o schermata. Mantienila piccola e specifica. Per esempio: "Come utente autenticato, posso resettare la password così da riottenere accesso." Se il codice mostra comportamenti diversi per ruolo (admin vs user), dividili in storie separate invece di nasconderli in note a piè di pagina.
Poi scrivi criteri di accettazione che rispecchiano i percorsi reali del codice, non l'ideale prodotto. Se l'handler restituisce 401 quando manca il token, quello è un criterio. Se l'UI disabilita l'invio finché un campo non è valido, quello è un criterio.
Includi regole sui dati in linguaggio semplice, soprattutto quelle che causano sorprese: limiti, ordinamenti, unicità, campi obbligatori. "Gli username devono essere unici (verificato al salvataggio)" è più chiaro di "indice unico."
Gli edge case spesso fanno la differenza tra un bel documento e uno utile. Evidenzia stati vuoti, valori nulli, retry, timeout e cosa vede l'utente quando una chiamata API fallisce.
Quando incontri incognite, segnala invece di indovinare:
Quei marker si trasformano in rapide domande al team invece che in assunzioni silenziose.
Una lista di gap non è una seconda Jira. È un breve elenco basato su evidenze di dove codice e comportamento desiderato non combaciano, o dove nessuno riesce a spiegare chiaramente cosa sia "corretto". Fatto bene, diventa uno strumento per raggiungere accordi, non una lotta di pianificazione.
Sii rigoroso su cosa conta come gap:
Quando registri un gap, includi tre parti per mantenerlo ancorato:
L'evidenza è ciò che impedisce che la lista diventi opinioni. Per esempio: "POST /checkout/apply-coupon accetta coupon scaduti, ma CouponBanner.tsx li blocca in UI. Impatto: ricavi e confusione utente. Tipo: bug o decisione mancante (confermare regola voluta)."
Mantienila corta. Imposta un limite, per esempio 10 elementi nella prima passata. Se trovi 40 problemi, raggruppali in pattern (incoerenze di validazione, controlli di permessi, stati vuoti) e conserva solo gli esempi principali.
Evita date e pianificazioni dentro la lista di gap. Se serve ownership, tienila leggera: annota chi dovrebbe decidere (prodotto) o chi può verificare il comportamento (engineering), poi sposta la pianificazione reale nel backlog.
Scegli uno scope piccolo e ad alto traffico: checkout con codici promo e opzioni di spedizione. L'obiettivo non è riscrivere tutto il prodotto, ma catturare cosa l'app fa oggi.
Inizia dalle route backend. Qui di solito emergono le regole. Potresti trovare route come POST /checkout/apply-promo, GET /checkout/shipping-options e POST /checkout/confirm.
Da quegli handler, scrivi il comportamento in parole semplici:
Poi controlla i componenti UI. Un PromoCodeInput potrebbe aggiornare i totali solo dopo una risposta di successo e mostrare gli errori inline sotto l'input. Un componente ShippingOptions potrebbe selezionare automaticamente l'opzione più economica al primo caricamento e triggerare un refresh completo del totale quando l'utente la cambia.
Ora hai una spec leggibile e una piccola lista di gap. Per esempio: i messaggi di errore differiscono tra il route del promo e l'UI ("Invalid code" vs "Not eligible"), e nessuno riesce a indicare una regola chiara per l'arrotondamento delle tasse (per riga vs totale ordine).
In pianificazione, il team concorda prima sulla realtà, poi decide cosa cambiare. Invece di discutere opinioni, revisioni comportamenti documentati, si sceglie una incoerenza da correggere e si lascia il resto come "comportamento attuale noto" fino a quando non vale la pena rivederlo.
Una spec aiuta solo se il team concorda che rispecchia la realtà. Fai una breve lettura con un ingegnere e una persona di prodotto. Mantienila concentrata: 20–30 minuti su cosa gli utenti possono fare e cosa il sistema fa in risposta.
Durante la lettura, trasforma le affermazioni in domande sì/no. "Quando un utente raggiunge questa route, restituiamo sempre 403 se non ha sessione?" "Questo stato vuoto è intenzionale?" Questo separa il comportamento voluto da ciò che è entrato accidentalmente nel tempo.
Concordate il lessico prima di modificare qualsiasi cosa. Usa le parole che gli utenti vedono nell'UI (etichette dei bottoni, titoli di pagina, messaggi). Aggiungi nomi interni solo quando aiutano gli ingegneri a trovare il codice (nomi di route, nomi di componenti). Questo evita discrepanze come prodotto che dice "Workspace" mentre la spec usa "Org."
Per mantenerla aggiornata, rendi ownership e cadenza esplicite:
Se usi uno strumento come Koder.ai, snapshot e rollback possono aiutare a confrontare il "prima" e il "dopo" quando aggiorni una spec, specialmente dopo un grande refactor.
Il modo più rapido per perdere fiducia in una spec è descrivere il prodotto che vorresti, non quello che hai. Applica una regola ferma: ogni affermazione deve essere supportata da qualcosa che puoi indicare nel codice o in una schermata reale.
Un'altra trappola è copiare la forma del codice nel documento. Una spec che recita "Controller -> Service -> Repository" non è una spec, è una mappa delle cartelle. Scrivi in termini user-facing: cosa attiva l'azione, cosa vede l'utente, cosa viene salvato e come appaiono gli errori.
I permessi e i ruoli sono spesso ignorati fino alla fine, poi tutto si rompe. Aggiungeteli presto, anche se sono disordinati. Indicate quali ruoli possono visualizzare, creare, modificare, cancellare, esportare o approvare, e dove la regola è applicata (solo UI, solo API o entrambi).
Non saltare i percorsi non felici. Il comportamento reale si nasconde in retry, fallimenti parziali e regole basate sul tempo come scadenze, cooldown, job schedulati o limiti "una volta al giorno". Considerali comportamenti di prima classe.
Un modo rapido per far emergere gap è controllare:
Infine, mantieni la lista gap in movimento. Ogni gap dovrebbe essere etichettato come: "unknown, needs decision", "bug, fix" o "missing feature, plan." Se nulla viene etichettato, la lista si blocca e la spec smette di essere "vivente."
Fai una rapida passata per chiarezza, copertura e azionabilità. Qualcuno che non l'ha scritta dovrebbe capire cosa la feature fa oggi e cosa rimane poco chiaro.
Leggi la spec come un nuovo collega al primo giorno. Se può riassumere la feature in un minuto, sei vicino. Se continua a chiedere "dove inizia?" o "qual è il percorso felice?" stringi l'apertura.
Controlla:
Ogni gap dovrebbe essere specifico e testabile. Invece di "Gestione errori poco chiara," scrivi: "Se il provider di pagamento restituisce 402, l'UI mostra un toast generico; confermare messaggio desiderato e comportamento di retry." Aggiungi una singola azione successiva (chiedere a prodotto, aggiungere un test, ispezionare i log) e nota chi dovrebbe rispondere.
Scegli una area funzionale e limita il tempo a 60 minuti. Scegli qualcosa di piccolo ma reale (login, checkout, ricerca, una schermata admin). Scrivi una frase di scope: cosa è incluso e cosa è escluso.
Esegui il workflow una volta end-to-end: scorri le route/handler principali, segui il flow UI principale e annota comportamenti osservabili (input, output, validazione, stati di errore). Se rimani bloccato, registra la domanda come gap e vai avanti.
Quando hai finito, condividi la spec dove il team può commentare e stabilisci una regola: ogni cambiamento di comportamento rilasciato deve aggiornare la spec nello stesso intervallo di consegna, anche se sono cinque righe.
Tieni i gap separati dal backlog. Raggruppali in "comportamento sconosciuto", "comportamento incoerente" e "test mancanti", poi rivedili brevemente ogni settimana per decidere cosa è importante ora.
Se la stesura e l'iterazione sembrano lente, un builder chat-based come Koder.ai può aiutarti a ottenere una prima versione rapidamente. Descrivi la feature, incolla frammenti chiave o nomi di route, affina la formulazione in conversazione ed esporta il sorgente quando serve. L'obiettivo è velocità e chiarezza condivisa, non un processo più grande.
Inizia con una piccola porzione visibile all'utente (per esempio “reset password” o “invita un collega”). Leggi prima le route/handler per catturare regole e risultati, poi il flow UI per descrivere cosa vedono realmente gli utenti (stati disabilitati, errori, redirect). Scrivilo con un template coerente e registra gli "unknown" in una lista gap separata.
Di default: tratta il comportamento attuale del codice come fonte di verità e documentalo.
Se il comportamento sembra accidentale o incoerente, non "correggerlo" nella spec: segnala invece un gap con prove (dove l'hai visto e cosa fa), poi prendi una decisione per aggiornare il codice o la spec.
Mantienila noiosa e ripetibile. Un template pratico è:
Questo mantiene le spec leggibili e rende più facile individuare le discrepanze.
Scrivi le regole come requisiti visibili all'utente, non come note di codice.
Esempi:
Indica cosa causa un errore e cosa vede l'utente quando succede.
Concentrati su ciò che è osservabile:
Gli effetti collaterali sono importanti perché influenzano altre feature e le aspettative di support/ops.
Se l'UI blocca qualcosa che l'API permette (o viceversa), registralo come gap finché non viene presa una decisione.
Registra:
Poi concordate una regola unica e aggiornate sia codice che spec per allinearli.
Mantieni la lista gap breve e basata su evidenze. Ogni voce dovrebbe avere:
Evita di trasformarla in un backlog o di programmarne direttamente il rilascio.
Documentali esplicitamente invece di nasconderli.
Includi:
Sono spesso la fonte di sorprese e bug.
Breve: una lettura di 20–30 minuti con un ingegnere e una persona di prodotto.
Trasforma le affermazioni in controlli sì/no (per esempio: “Restituiamo sempre 403 quando non autorizzati?”). Allineate il vocabolario usando le parole visibili nell'UI (etichette e messaggi) così tutti intendono la stessa cosa.
Tieni la spec vicina al codice e rendi gli aggiornamenti parte del rilascio.
Default pratici:
L'obiettivo è piccole modifiche frequenti, non un grande rewrite.