Quem é que escreve, afinal?
Existe um momento que há três anos soaria como ficção científica e hoje é rotina: você digita uma descrição — "um endpoint que recebe um pedido, confere o carrinho contra o estoque, recusa com uma mensagem de erro clara se não houver saldo e, caso contrário, cria uma reserva" — e minutos depois roda um código que faz exatamente isso. Compilado, testado, pronto para deploy.
Se você parar um segundo e se perguntar o que produziu nesses minutos, a resposta é incômoda. Não foi o código — quem o digitou foi o modelo, e você poderia gerá-lo de novo amanhã a partir da mesma descrição. O que você produziu foi a descrição. A precisão com que fixou intenção, restrições e comportamento foi o verdadeiro trabalho. O código foi uma consequência dele.
Isso não é uma curiosidade de canto; é uma mudança no alicerce. Por décadas, o código-fonte foi a coisa que importava — aquilo que se escrevia, versionava, mantinha e defendia. A especificação, quando existia, era enfeite. Essa hierarquia está sendo virada de cabeça para baixo. O artefato duradouro está subindo o rio, rumo à spec. O código vira algo que você deriva dela — mais perto de uma saída compilada do que de um manuscrito.
A inversão
A ordem antiga tinha uma lei de ferro, e todo desenvolvedor experiente a conhece: o código é a única documentação precisa. Todo o resto mente. O design doc descreve um sistema que nunca foi construído daquele jeito. O wiki tem dois anos. O comentário em cima da função descreve o que ela deveria fazer um dia, não o que faz hoje. Só o código nunca mente, porque o código é o que de fato roda. Quem quisesse saber como o sistema se comportava lia o código — não a spec.
Essa verdade era desagradável, mas correta, e tinha uma consequência clara: specs apodrecem, código vive. Então você investia no código e deixava as specs no abandono. Por que manter um documento que já está desatualizado enquanto você ainda o digita?
A IA inverte essa lógica. Quando o modelo produz de forma confiável o código certo a partir de uma descrição precisa, de repente é a spec que tem efeito e o código o que decorre. Uma boa spec produz bom código. E — aqui está o fio da navalha — uma spec vaga produz código plausivelmente errado. O modelo preenche com uma suposição toda lacuna que você deixa aberta. Ele não pergunta; ele chuta, e chuta com toda a confiança. Você queria que submissões duplicadas fossem tratadas de forma idempotente — mas não escreveu isso? Então ganha uma implementação que alegremente cria um segundo pedido na segunda requisição idêntica. O código parece impecável. Só não faz o que você quis dizer.
Com isso, o gargalo se desloca. Digitar o código deixou de ser o passo caro; o passo caro é enunciar com precisão o que o código deve fazer. É exatamente o que hoje chamam de desenvolvimento orientado por spec ou por intenção: você não escreve a solução, você escreve a intenção de forma tão afiada que a solução decorre inevitavelmente dela. A vagueza que você antes carregava na cabeça e resolvia inconscientemente enquanto digitava agora precisa sair — para o papel, para o repositório, para palavras. Porque o modelo não divide a sua cabeça.
O que contém uma boa spec
Se a spec vira o artefato primário, vale perguntar do que ela é feita. E a resposta é reveladora, porque é quase exatamente aquilo que um modelo não consegue adivinhar. Uma boa especificação não é um romance nem uma cerimônia de quarenta páginas. É um conjunto enxuto e denso de compromissos:
- Intenção. Que problema isto resolve, para quem, e como você sabe que está resolvido? Não "um sistema de descontos", mas "clientes recorrentes devem ver no carrinho um abatimento percentual derivado do que gastaram no ano anterior". Sem intenção, o modelo constrói algo de aparência plausível que passa longe do alvo.
- Invariantes. O que precisa valer sempre, aconteça o que acontecer? Uma conta nunca fica negativa. O total de um pedido nunca é negativo. Dois usuários nunca recebem a mesma reserva. São as frases que um modelo não consegue derivar, porque vêm do negócio, não do código.
- Casos de borda. A lista vazia, o acesso concorrente, o fuso horário na virada do dia, o valor zero, o token expirado. Justamente os casos que nunca aparecem no caminho feliz — e que o modelo pula se você não os nomear.
- Não-objetivos. A parte mais subestimada. O que isto explicitamente não deve fazer? "Nada de reembolsos parciais na versão um." "Não tratamos moeda estrangeira." Um não-objetivo economiza mais código do que qualquer descrição de funcionalidade gera, porque impede o modelo de inventar escopo que ninguém pediu.
- Critérios de aceitação. As afirmações verificáveis das quais o "pronto" depende. "Com estoque zero, recusa com HTTP 409." "Duas requisições idênticas dentro de dez segundos criam exatamente um pedido." O bonito disso: eles já são quase testes. Um critério de aceitação bem formulado é um caso de teste em espera — e critérios-de-aceitação-como-testes fecham o ciclo, porque ao mesmo tempo guiam o modelo e depois provam que ele acertou o que se quis dizer.
Dá para ver o padrão: cada um desses pontos é contexto que o modelo não consegue derivar da tarefa sozinho. A sintaxe ele domina. A estrutura ele domina. O que ele não tem é a imagem do que precisa ser verdade neste negócio, com estes dados, sob estas regras. É exatamente isso que a spec registra — e é só isso que ela precisa registrar.
A spec como artefato vivo
Isso torna inevitável uma consequência que muitos times ainda não tiraram: se a spec é o que produz o código, então a spec pertence ao repositório. Não a um Confluence que ninguém abre. Não a um Google Docs que pertence a um ex-colega. Ao lado do código, sob controle de versão, com histórico, revisada em pull requests como código.
Essa é a verdadeira resolução do velho problema do "o código é a única verdade" — não por refutação, mas por inversão. Antes as specs apodreciam porque corriam atrás do código; você mudava o código e esquecia o documento. Agora o código corre atrás da spec: você muda a spec e re-deriva o código dela. A spec não pode mais ficar obsoleta se é a fonte da qual a versão atual é gerada. O problema do apodrecimento inverte de direção.
Na prática, você já vê isso por toda parte em forma embrionária. O arquivo README ou AGENTS que um agente de código lê primeiro, antes de tocar numa linha, é uma spec — uma que diz ao modelo como este projeto funciona. O design doc a partir do qual se geram esqueletos, fronteiras de módulos e interfaces é uma spec. A coleção de critérios de aceitação que também alimenta a suíte de testes é uma spec. Esses arquivos não são mais documentação sobre o sistema. São a porta de entrada dele — aquilo que você muda quando quer mudar o comportamento.
E, por serem isso, merecem o tratamento antes reservado ao código: revisões em que alguém questiona a intenção antes de uma linha ser gerada. Diffs em que se vê como uma invariante mudou. Blame que mostra quem decidiu, e quando, que moeda estrangeira está fora de escopo. É o ponto em que "a gente escreveu algo uma vez" vira um artefato mantido e assumido.
Regerar em vez de remendar
Aqui a mudança fica de fato radical, porque altera como você lida com falhas. No mundo antigo, o código era precioso porque um humano o havia escrito linha por linha. Jogá-lo fora e reescrever parecia queimar dinheiro — então você remendava. Remendava o bug, adicionava um caso especial, colava um contorno por cima da suposição torta. Ao longo de anos, crescia uma geologia de remendos em que ninguém mais achava a intenção original.
Quando o código sai de uma spec em minutos, a conta muda. Diante de uma falha de verdade, a primeira pergunta deixa de ser "onde eu remendo?" e passa a ser "a falha está no código ou na spec?". E muitas vezes está na spec: você nunca nomeou o caso de borda, nunca capturou a invariante, nunca traçou o não-objetivo. Então o caminho mais barato não é operar o código gerado, mas afiar a spec e re-derivar a parte afetada. Você conserta a intenção, não a saída.
Isso é mais do que comodidade; é outro modelo de custo. Um contorno que custa meio dia de um desenvolvedor — digamos, grosso modo, algumas centenas de US$, se formos honestos — produz código que da próxima vez alguém vai ter de entender de novo. Uma spec afiada custa a mesma meia hora de pensamento, produz código limpo e melhora o artefato do qual todo o futuro é gerado. O remendo paga uma vez; a spec melhor paga toda vez.
Isso não vale em termos absolutos — já chego lá. Um conserto isolado de uma linha é um conserto isolado de uma linha, e passá-lo por uma rodada de spec seria cerimônia. Mas como postura padrão está certo: quando o código é quase descartável porque se regenera barato, você para de reparar a cópia e passa a reparar o original.
A disciplina que o humano precisa trazer
Agora o porém, e ele é grande. Toda essa inversão exige do humano exatamente o que humano menos gosta de fazer: pensar com clareza antes.
Digitar código foi, por muito tempo, também um jeito de fugir do pensar. Você começava, sentia enquanto escrevia onde emperrava, descobria o caso de borda porque o compilador reclamava, entendia o problema construindo. Digitar era uma ferramenta de pensamento — lenta, mas indulgente. Você podia começar sem clareza e ficar claro no caminho.
O desenvolvimento orientado por spec tira essa indulgência. Escrever uma spec significa resolver a vagueza lá na frente, antes de existir uma linha. Você tem de conhecer a intenção antes de digitá-la. Tem de nomear as invariantes antes que qualquer coisa possa violá-las. Tem de traçar os não-objetivos antes de ser tentado a inventar escopo. Isso é mais difícil do que programar, não mais fácil, porque cobra o único trabalho que nenhuma ferramenta tira de você: saber o que você de fato quer, e dizê-lo com precisão.
É justamente aí que specs ruins falham, e falham do jeito mais caro. Porque — e este é o adendo honesto — uma spec pode estar tão errada quanto código. Uma especificação precisamente formulada, bem revisada, versionada no repositório, mas apoiada numa suposição falsa sobre o negócio, produz o errado de forma confiável e em escala. Precisão não é correção. Dá para se comprometer, com todo o cuidado, na direção errada. A spec move o esforço de pensar para a frente; ela não o abole.
Nem tudo merece uma spec
O que nos leva ao contraponto honesto, porque quem leva esta lição longe demais troca um tipo de desperdício por outro. Nem tudo merece uma especificação formal, e spec-first como dogma vira exatamente a burocracia à qual bons engenheiros são, com razão, alérgicos.
O script descartável que joga um CSV de um formato para outro uma única vez não precisa de declaração de intenção com invariantes e não-objetivos. Você quer isso em cinco minutos e nunca mais ver na frente. Antepor-lhe uma spec seria tão absurdo quanto escrever um documento de requisitos para uma lista de compras.
O segundo caso é mais sério: trabalho exploratório. Às vezes você simplesmente ainda não sabe o que quer — e o jeito mais honesto de descobrir não é remoer diante de uma spec em branco, mas deixar o agente construir uma versão tosca, meio crua, e reagir a ela. Você vê a coisa rodando, sente o que está errado e aí a intenção toma forma. Nesse modo, a spec emerge do protótipo, não o contrário. Insistir lá na frente numa clareza que você ainda não pode ter não é disciplina; é autoengano.
A resolução é a mesma de todo bom princípio de engenharia: ajustar a cerimônia ao raio de impacto. O que acontece, na pior das hipóteses, se isto estiver errado? Se toca dinheiro, dados de cliente, autenticação, algo irreversível, algo que vive e cresce por muito tempo — então a intenção merece uma spec de verdade, versionada, revisada, e o esforço se paga muitas vezes. Se é um experimento de uma tarde ou um script que morre após uma única execução — então spec-first é lastro. Desenvolvimento orientado por spec é uma ferramenta, não uma religião. O erro não é construir sem spec; o erro é construir a coisa cara, longeva e perigosa sem spec e o script barato e morto com uma.
Conclusão
Por décadas, o código-fonte foi a coisa que importava — o artefato duradouro do qual se lia a verdade de um sistema, porque todo o resto mentia. Essa era não termina de forma dramática; termina em silêncio: no instante em que um modelo produz código de forma confiável a partir de uma descrição precisa, aquilo que você de fato escreve e mantém sobe um nível — para a especificação. O código vira a saída. A intenção vira a fonte.
Isso não é alívio; é um deslocamento do esforço. O trabalho pesado não desaparece, ele se antecipa: pensar com clareza antes de construir; nomear intenção, invariantes, bordas e não-objetivos de forma tão afiada que um modelo não tenha nada de errado a adivinhar; e então manter o artefato do qual o código é gerado, vez após vez. Fuja desse trabalho e você recebe código plausivelmente errado em escala — mais rápido do que nunca.
É exatamente por isso que, na NH Labs, tratamos a spec como o artefato primário para tudo o que importa. Não para o script descartável, e isso é proposital. Mas para o sistema que movimenta dinheiro, guarda dados de cliente e cresce ao longo de anos, nós escrevemos e versionamos a própria intenção — no repositório, revisada, assumida — não apenas o código que decorre dela. Assim, no fim, não fica apenas rastreável o que o sistema faz, mas comprovado e assumido o que ele deveria fazer. O código pode ser regerado. A intenção precisa permanecer.