Skip to content

Escrevendo Boas Especificações ​

Você raramente escreve uma especificação em uma página em branco. Você descreve uma mudança em linguagem simples, o /opsx:propose elabora os requisitos e cenários, e então você os aperfeiçoa. Esta página trata dessa última parte — o que "bom" significa e como orientar a IA nessa direção.

Ela é a companheira de Revisando uma Mudança: revisar é identificar os pontos fracos de um rascunho, escrever é saber do que um rascunho forte é feito.

Uma especificação é comportamento, não código ​

Uma especificação diz o que seu sistema faz, em termos que qualquer pessoa possa verificar — não como ele é construído. Ela é composta por requisitos (declarações de comportamento) e cenários (exemplos concretos que os comprovam).

markdown
### Requirement: Session Timeout
The system SHALL expire a session after 30 minutes of inactivity.

#### Scenario: Idle timeout
- GIVEN an authenticated session
- WHEN 30 minutes pass with no activity
- THEN the session is invalidated and the user must re-authenticate

Mantenha o como — a fila, a biblioteca, o esquema da tabela — em design.md ou no código. Quando comportamento e implementação se misturam em um único requisito, o requisito deixa de ser testável e começa a ficar desatualizado no momento em que o código muda.

O que torna um bom requisito ​

Um bom requisito é um único comportamento, declarado de forma tão clara que você poderia entregá-lo a outra pessoa para testar.

  • Uma declaração, um SHALL/MUST. Se um requisito tem três cláusulas de "e também", são na verdade três requisitos. Separe-os.

  • Observável. Alguém fora do código deve ser capaz de dizer se ele se cumpre. "O sistema DEVE exibir um banner de erro quando o upload exceder 10 MB" é observável. "O sistema DEVE lidar com uploads grandes de forma adequada" não é.

  • A força adequada. O OpenSpec usa as palavras-chave do RFC 2119, e elas significam coisas diferentes:

    Palavra-chaveSignificado
    MUST / SHALLUm requisito rígido. Inegociável.
    SHOULDUma recomendação forte, com margem para uma exceção justificada.
    MAYGenuinamente opcional.

    Use MUST/SHALL por padrão. Use SHOULD apenas quando você realmente quer dizer "a menos que haja um bom motivo para não".

O teste para um requisito: um testador que nunca viu o código conseguiria dizer se ele passou? Se não, ele precisa ser afiado.

O que torna um bom cenário ​

Os cenários são onde um requisito justifica sua existência. Cada um é um GIVEN / WHEN / THEN concreto que poderia se tornar um teste automatizado.

  • Ele exercita seu requisito. Um cenário que apenas reafirma o requisito com outras palavras não testa nada. Torne-o uma situação específica com um resultado específico.
  • Cubra os casos que importam, não apenas o caminho feliz. O login válido é fácil. A entrada vazia, o token expirado, o segundo clique, a coisa que dá errado — são esses os lugares onde os bugs vivem, e onde um cenário vale mais.
  • Nomeie o caso no título. "Scenario: Rejects an expired token" diz a um revisor o que está coberto de relance; "Scenario: Test 2" não diz.

Um hábito útil: antes de aprovar, pergunte qual é o caso que eu ficaria chateado de ver quebrado? — e certifique-se de que um cenário o nomeia.

Escolha o tipo de delta adequado ​

Uma mudança descreve suas edições nas especificações com três tipos de seção. Usar o certo mantém suas especificações arquivadas honestas:

  • ## ADDED Requirements — comportamento totalmente novo que não existia antes.
  • ## MODIFIED Requirements — comportamento que já existia e está mudando. Inclua a nova versão completa; uma breve nota sobre o que mudou ajuda o revisor.
  • ## REMOVED Requirements — comportamento que está sendo removido, com uma linha explicando por quê.

No arquivamento, ADDED é adicionado à especificação principal, MODIFIED substitui a versão antiga e REMOVED é removido dela. Remova o último requisito de uma capacidade e ela é aposentada: em vez de deixar uma especificação vazia, o arquivamento exclui openspec/specs/<capability>/spec.md. Como esse é o único passo de arquivamento que remove um arquivo, ele precisa ser solicitado — adicione retire_capabilities: true ao .openspec.yaml da mudança, junto com o schema: que esse arquivo já precisa. Sem isso, o arquivamento é abortado e informa você. A aposentadoria exclui o arquivo inteiro, então também é recusada enquanto a especificação contém algo fora do título, ## Purpose e seus blocos de requisitos — uma seção ## Notes, um comentário sob um requisito. O abortamento nomeia essas linhas; mova-as para ## Purpose ou para um requisito, ou exclua a especificação manualmente. Para uma especificação no checkout do chamador, a saída do arquivamento também nomeia o git checkout que restaura um arquivo commitado; stores selecionados recebem orientações de recuperação escopadas ao checkout. Se você marcar uma mudança real como ADDED, acabará com dois requisitos em conflito; se descrever comportamento novo como MODIFIED, não há nada para substituir. Na dúvida, abra a especificação atual e veja se o requisito já está lá.

Há mais uma seção que vale a pena conhecer. Quando seu delta cria uma capacidade que ainda não existe, abra-o com ## Purpose — uma ou duas frases sobre para que serve a capacidade. O arquivamento a usa como o Purpose da especificação principal que cria; pule-a e você terá um placeholder TBD para preencher manualmente. Uma especificação existente já tem um Purpose, então o do delta é ignorado ali — edite openspec/specs/<capability-path>/spec.md diretamente para alterá-lo. Aqui, <capability-path> é o diretório relativo a specs/, como user-auth em um projeto plano ou identity/user-auth em um projeto organizado por domínio.

Dimensione corretamente a mudança ​

O erro de autoria mais comum não é um requisito mal redigido — é uma mudança que tenta ser três mudanças.

Uma boa mudança tem uma única intenção que você pode expressar em uma frase. "Adicionar um alternador de modo escuro." "Limitar a taxa do endpoint de login." "Migrar sessões de cookies." Se descrever a mudança exige muitos "e também", esse é o sinal de que deve ser dividida.

Sinais de que uma mudança é grande demais:

  • O escopo da proposta parece uma lista de recursos não relacionados.
  • Revisá-la levaria uma tarde inteira, então ninguém fará.
  • Duas pessoas não conseguiriam trabalhar nela sem colidir.
  • Metade das tarefas poderia ser lançada sozinha.

Mudanças menores são mais fáceis de revisar, mais fáceis de construir em uma sessão focada e mais fáceis de raciocinar seis meses depois, quando o arquivamento é tudo o que resta. Você sempre pode executar várias mudanças em paralelo — veja Editando e iterando e Workflows.

O oposto também acontece: uma correção de erro de digitação de uma linha não precisa de três requisitos e um documento de design. Ajuste a cerimônia à importância.

Como orientar a IA rumo a um bom rascunho ​

Como o /opsx:propose faz o primeiro rascunho, a qualidade do que você recebe de volta acompanha a qualidade do que você lhe dá. Você não precisa escrever requisitos manualmente — precisa orientar bem a IA:

  • Declare a intenção e o limite. "Adicionar um alternador de modo escuro que segue a configuração do SO no primeiro carregamento — não toque na API de tema existente." A metade fora do escopo importa tanto quanto a metade dentro do escopo.
  • Nomeie os casos que importam para você. "Certifique-se de que há um cenário para um usuário que já escolheu um tema manualmente." A IA cobre o que você aponta.
  • Depois edite. É Markdown simples. Aperte um SHALL vago, exclua um cenário que não testa nada, adicione o caso que faltou — ou peça à IA: "o requisito de timeout é vago, fixe-o em 30 minutos."

Rascunhe, afie, repita. Algumas rodadas disso produzem uma especificação em que você confiaria, que é o objetivo principal.

Uma lista de verificação rápida ​

Para onde ir a seguir ​