Scrivere buone specifiche
Raramente scrivi una specifica da una pagina vuota. Descrivi una modifica in linguaggio semplice, /opsx:propose abbozza i requisiti e gli scenari, e poi li rendi buoni. Questa pagina tratta di quest'ultima parte — come appare "buono" e come guidare l'AI verso di esso.
È il complemento di Revisione di una modifica: la revisione consiste nel cogliere i punti deboli di una bozza, la scrittura nel sapere di cosa è fatta una bozza forte.
Una specifica è comportamento, non codice
Una specifica dice cosa fa il tuo sistema fa, in termini che chiunque possa verificare — non come è costruito. È fatta di requisiti (dichiarazioni di comportamento) e scenari (esempi concreti che li dimostrano).
### Requisito: Timeout della sessione
Il sistema DEVE far scadere una sessione dopo 30 minuti di inattività.
#### Scenario: Timeout di inattività
- DATO una sessione autenticata
- QUANDO passano 30 minuti senza attività
- ALLORA la sessione viene invalidata e l'utente deve autenticarsi di nuovoTieni il come — la coda, la libreria, lo schema della tabella — in design.md o nel codice. Quando comportamento e implementazione vengono mescolati in un unico requisito, il requisito smette di essere testabile e inizia a diventare obsoleto nel momento in cui il codice cambia.
Cosa rende buono un requisito
Un buon requisito è un comportamento, espresso in modo così semplice che potresti consegnarlo a qualcun altro per testarlo.
Una dichiarazione, un
SHALL/MUST. Se un requisito ha tre clausole "e anche", in realtà sono tre requisiti. Dividili.Osservabile. Qualcuno al di fuori del codice dovrebbe essere in grado di dire se è soddisfatto. "Il sistema DEVE mostrare un banner di errore quando il caricamento supera 10 MB" è osservabile. "Il sistema DEVE gestire caricamenti di grandi dimensioni con garbo" non lo è.
La giusta forza. OpenSpec usa le parole chiave RFC 2119, e significano cose diverse:
Parola chiave Significato MUST/SHALLUn requisito rigido. Non negoziabile. SHOULDUna forte raccomandazione, con spazio per un'eccezione giustificata. MAYDavvero opzionale. Usa
MUST/SHALLdi default. UsaSHOULDsolo quando intendi davvero "a meno che non ci sia una buona ragione per non farlo."
Il test per un requisito: un tester che non ha mai visto il codice potrebbe dire se è stato soddisfatto? Se no, ha bisogno di essere affilato.
Cosa rende buono uno scenario
Gli scenari sono dove un requisito dimostra il suo valore. Ognuno è un GIVEN / WHEN / THEN concreto che potrebbe diventare un test automatizzato.
- Esercita il suo requisito. Uno scenario che semplicemente ripete il requisito con altre parole non testa nulla. Rendi una situazione specifica con un risultato specifico.
- Copri i casi che contano, non solo il percorso felice. Il login valido è facile. L'input vuoto, il token scaduto, il secondo click, la cosa che va storta — è lì che vivono i bug, e dove uno scenario vale di più.
- Dai un nome al caso nel titolo. "Scenario: Rifiuta un token scaduto" dice a un revisore cosa è coperto a colpo d'occhio; "Scenario: Test 2" non lo fa.
Un'abitudine utile: prima di approvare, chiediti qual è il caso che mi dispiacerebbe vedere rotto? — e assicurati che uno scenario lo nomini.
Scegli il tipo giusto di delta
Una modifica descrive le sue modifiche alle specifiche con tre tipi di sezione. Usare quello giusto mantiene le tue specifiche archiviate oneste:
## ADDED Requirements— comportamento completamente nuovo che non esisteva prima.## MODIFIED Requirements— comportamento già esistente che sta cambiando. Includi la versione completa; una breve nota su cosa è cambiato aiuta il revisore.## REMOVED Requirements— comportamento che sta scomparendo, con una riga sul perché.
All'archiviazione, ADDED viene aggiunto alla specifica principale, MODIFIED sostituisce la vecchia versione, e REMOVED viene eliminato da essa. Rimuovi l'ultimo requisito di una capacità e la ritiri: piuttosto che lasciare una specifica senza nulla, l'archivio elimina openspec/specs/<capability>/spec.md. Poiché è uno dei passaggi di archiviazione che rimuove un file, deve essere richiesto — aggiungi retire_capabilities: true alla modifica .openspec.yaml, insieme allo schema: di cui quel file ha già bisogno. Senza di esso l'archiviazione si interrompe e te lo dice. Il ritiro elimina l'intero file, quindi è anche rifiutato mentre la specifica contiene qualcosa al di fuori del suo titolo, ## Purpose, e dei suoi blocchi di requisiti — una sezione ## Notes, un commento sotto un requisito. L'interruzione indica quelle righe; spostale in ## Purpose o in un requisito, oppure elimina la specifica a mano. Per una specifica nel checkout del chiamante, l'output dell'archivio indica anche il git checkout che ripristina un file committato; gli store selezionati ricevono invece una guida al ripristino specifica per il checkout. Se segni una modifica reale come ADDED, ottieni due requisiti in competizione; se descrivi un nuovo comportamento come MODIFIED, non c'è nulla da sostituire. In caso di dubbio, apri la specifica corrente e vedi se il requisito è già presente.
Un'altra sezione vale la pena di essere conosciuta. Quando il tuo delta crea una capacità che non esiste ancora, aprila con ## Purpose — una frase o due su a cosa serve la capacità. L'archivio la usa come Purpose della specifica principale che crea; se la salti, ottieni un segnaposto TBD da compilare a mano. Una specifica esistente ha già un Purpose, quindi quello di un delta viene ignorato lì — modifica direttamente openspec/specs/<capability-path>/spec.md per cambiarne uno. Qui, <capability-path> è la directory relativa a specs/, come user-auth in un progetto piatto o identity/user-auth in un progetto organizzato per dominio.
Dimensiona la modifica
L'errore di scrittura più comune non è un requisito mal formulato — è una modifica che cerca di essere tre modifiche.
Una buona modifica ha un unico intento che puoi dire in una frase. "Aggiungi un interruttore per la modalità scura." "Limita la velocità dell'endpoint di login." "Migra le sessioni dai cookie." Se descrivere la modifica richiede molti "e anche", è il segnale per dividerla.
Segnali che una modifica è troppo grande:
- L'ambito della proposta sembra una lista di funzionalità non correlate.
- Rivederla richiederebbe un pomeriggio, quindi nessuno lo farà.
- Due persone non potrebbero lavorarci senza scontrarsi.
- Metà dei compiti potrebbe essere rilasciata da sola.
Modifiche più piccole sono più facili da rivedere, più facili da costruire in una sessione focalizzata, e più facili da comprendere sei mesi dopo quando l'archivio è tutto ciò che resta. Puoi sempre eseguire diverse modifiche in parallelo — vedi Modifica e iterazione e Flussi di lavoro.
Succede anche il contrario: una correzione di un errore di battitura su una riga non ha bisogno di tre requisiti e un documento di progettazione. Abbina la cerimonia alla posta in gioco.
Come guidare l'AI verso una buona bozza
Poiché /opsx:propose fa la prima bozza, la qualità di ciò che ricevi dipende dalla qualità di ciò che gli dai. Non devi scrivere requisiti a mano — devi puntare bene l'AI:
- Dichiara l'intento e il confine. "Aggiungi un interruttore per la modalità scura che segue l'impostazione del sistema al primo caricamento — non toccare l'API tema esistente." La metà fuori ambito conta tanto quanto quella dentro l'ambito.
- Nomina i casi che ti interessano. "Assicurati che ci sia uno scenario per un utente che ha già scelto un tema manualmente." L'AI copre ciò a cui punti.
- Poi modifica. È semplice Markdown. Stringi un
SHALLvago, elimina uno scenario che non testa nulla, aggiungi il caso che ha mancato — oppure chiedi all'AI: "il requisito del timeout è vago, fissalo a 30 minuti."
Bozza, affina, ripeti. Alcuni cicli di questo producono una specifica di cui ti fideresti, che è il punto principale.
Una rapida checklist
Dove andare dopo
- Revisione di una modifica — il passaggio di due minuti che coglie ciò che è sfuggito.
- Concetti — il modello più profondo dietro specifiche, modifiche e delta.
- Esempi e ricette — modifiche reali dall'inizio alla fine.