- Em resposta à afirmação de que, com codificação agêntica, “documentos de especificação podem substituir código”, aponta-se uma limitação fundamental: quando a especificação se torna suficientemente precisa, ela inevitavelmente converge para a mesma forma do código
- Ao observar o projeto Symphony da OpenAI, vê-se que o respectivo SPEC.md não é uma especificação, mas na prática pseudocódigo em Markdown
- Na prática, ao tentar uma implementação em Haskell com base na especificação do Symphony, surgiram vários bugs e problemas de confiabilidade, como espera infinita do agente
- O trabalho de especificação originalmente exige um nível de reflexão mais profundo do que programar, mas, no atual ambiente da indústria otimizado para velocidade, forma-se uma estrutura que produz em massa especificações de baixa qualidade geradas por IA
- O princípio de “garbage in, garbage out” também se aplica integralmente a agentes de codificação, e, com documentos sem clareza e detalhamento, é impossível gerar código confiável
Dois equívocos sobre codificação agêntica
- Existem dois equívocos centrais nos quais os defensores da codificação agêntica se apoiam
- Equívoco 1: documentos de especificação são mais simples do que o código correspondente — uma visão de terceirização segundo a qual engenheiros podem ser transformados em gestores que escrevem especificações e delegam o trabalho a uma equipe de agentes
- Equívoco 2: trabalho de especificação é necessariamente mais criterioso do que trabalho de programação — a alegação de que passar por um documento de especificação melhora a qualidade e promove práticas de engenharia melhores
Código disfarçado de especificação: análise do caso Symphony
- O projeto Symphony da OpenAI é apresentado como um orquestrador de agentes gerado a partir de um documento de especificação (SPEC.md), mas, na prática, o conteúdo do SPEC.md está mais próximo de pseudocódigo em Markdown do que de uma especificação
- Tipos de conteúdo incluídos no SPEC.md:
- Dump em prosa do esquema de banco de dados — enumeração de campos como
session_id, thread_id, codex_input_tokens etc.
- Conversão em prosa de código — fórmulas como
available_slots = max(max_concurrent_agents - running_count, 0) para controle de concorrência e a fórmula de backoff de retry (delay = min(10000 * 2^(attempt-1), agent.max_retry_backoff_ms))
- Seções redundantes como "Config Fields Summary (Cheat Sheet)", adicionadas explicitamente para ajudar o modelo a gerar código
- A seção “Reference Algorithms”, que é praticamente o próprio código, como a função
start_service()
- Alegar que o documento de especificação é um substituto para o código, quando ele próprio é lido como código, é enganoso
- Para tornar um documento de especificação suficientemente preciso, é inevitável transformá-lo em uma forma de código ou escrevê-lo em um inglês formal altamente estruturado
O argumento da “interface estreita” de Dijkstra
- Citando Dijkstra, argumenta-se que a escolha da interface não é uma simples divisão de trabalho, e que há um custo adicional de colaboração e comunicação através da interface
- São apresentados exemplos históricos: a matemática grega estagnou por permanecer em atividades linguísticas e visuais; a álgebra islâmica decaiu ao regressar a um estilo retórico; e a Europa Ocidental saiu das “vãs tentativas de precisão linguística” do escolasticismo medieval e avançou graças aos sistemas simbólicos formais de Vieta, Descartes, Leibniz, Boole e outros
- Os codificadores agênticos não podem evitar a “interface estreita” (= código) exigida pelo trabalho de engenharia; no máximo, podem transformar esse trabalho em outra forma que pareça diferente na superfície, mas exija a mesma precisão
Instabilidade: problemas de confiabilidade na geração de código a partir de especificações
- Seguindo a recomendação do README do Symphony, foi solicitado ao Claude Code que implementasse o sistema em Haskell, mas o resultado não funcionou
- Surgiram vários bugs, exigindo correções via prompt (o que pode ser verificado no histórico de commits)
- Mesmo quando aparentemente “funcionava” sem mensagens de erro, o agente
codex ficava esperando indefinidamente sem qualquer progresso diante de um ticket simples do Linear (“criar um repositório git vazio”)
- Tomando de empréstimo a expressão de Dijkstra, confirma-se que as “vãs tentativas de precisão linguística” do Symphony ainda falham em gerar implementações confiáveis
- O problema não se limita ao Symphony — até especificações como a YAML spec, extremamente detalhadas, amplamente usadas e acompanhadas de suítes de testes de conformidade, ainda assim têm a maioria das implementações de YAML incapazes de cumprir totalmente a especificação
- A especificação do Symphony já chega a 1/6 do tamanho da implementação em Elixir incluída; se for expandida ainda mais, chega-se a uma situação como a alegoria de Borges em “Sobre o rigor na ciência” — um mapa do tamanho do império que acaba se tornando inútil
- Em resposta ao argumento de que “o resultado seria melhor se fosse gerado em uma linguagem mais mainstream”, afirma-se que, se o agente tem dificuldade para gerar código em Haskell, isso sugere falta de capacidade de generalização para além dos dados de treinamento
Slop: o problema da qualidade em especificações geradas por IA
- O trabalho de especificação deveria originalmente ser mais difícil do que programar, pois seu objetivo é levar a examinar o projeto de forma reflexiva e crítica antes de começar a codificar
- Porém, dentro da tendência da indústria de tecnologia de reduzir e desvalorizar o trabalho, partir da premissa de que “trabalho de especificação é mais fácil do que programar” significa que o fracasso já está garantido
- É impossível realizar o trabalho difícil e desconfortável exigido pela escrita de especificações enquanto se busca otimizar a velocidade de entrega
- A Seção 10.5 do SPEC.md do Symphony (
linear_graphql extension contract) é um exemplo representativo de slop — um produto típico de agente em que frases “parecem especificação”, mas carecem de consistência, propósito e compreensão do quadro geral
- Regras isoladas são listadas, como
query deve ser uma string não vazia e deve conter exatamente uma operação GraphQL, mas falta contexto global
- Mesmo que esses documentos de especificação tivessem sido escritos por humanos, eles inevitavelmente seriam slop, porque foram otimizados para o tempo de entrega, e não para consistência ou clareza
- O fato de trechos de código estarem anotados como
text sem syntax highlighting também é um sinal de documento gerado por IA — presume-se que o modelo seguiu o pedido ao pé da letra, e não sua intenção
Conclusão
- Especificações não foram originalmente projetadas para economizar tempo
- Se o objetivo é otimizar o tempo de entrega, é melhor escrever o código diretamente do que passar por um documento intermediário de especificação
- O princípio de “garbage in, garbage out” se aplica integralmente — se a entrada for um documento sem clareza e sem detalhes, não existe um mundo em que um agente de codificação consiga preencher essas lacunas com confiabilidade
- Agentes de codificação não leem mentes e, mesmo que lessem, se o próprio pensamento estiver confuso, não há o que possam fazer
6 comentários
Parece exatamente a mesma coisa que na época do desenvolvimento orientado por modelos.
O desenvolvimento orientado por especificações, SDD, não existe desde sempre?
Parece que, com soluções baseadas em Python ou JavaScript, é possível obter implementações satisfatórias apenas com documentos de especificação detalhados. Trabalho na área de jogos/medicina baseada em C/C++, e ultimamente tenho pensado muito que automatizar só com documentos de especificação detalhados, quanto mais delegar a um FULL AI AGENT, ainda parece arriscado demais.
Comentários no Hacker News
Não concordo com a ideia de que, mesmo fornecendo documentação pouco clara, um agente de programação não consegue preencher os detalhes
LLMs são essencialmente máquinas de interpolação/extrapolação de linguagem e são muito bons em completar detalhes ausentes
Há muitos casos em que eles produzem código funcional só com descrições curtas e concisas
Ainda assim, esse preenchimento de detalhes nem sempre é correto, e para garantir confiabilidade é preciso restringir explicitamente as partes importantes
Hoje existe uma cultura de escrever código, mas quase não existe uma cultura de escrever especificações ultraprecisas, exceto em lugares como a NASA
Quanto mais curto e comum for o código, melhor funciona, mas em descrições complexas isso desmorona facilmente
No fim, admitir que “o preenchimento de detalhes pode estar errado” significa reconhecer que a geração confiável é difícil
Por exemplo, existem linguagens de síntese de programas como Synquid
Elas mostram quais são os limites de gerar programas a partir de especificações matematicamente exatas
O problema chamado specification gap, isto é, provar que um programa implementa fielmente a especificação, é a questão central
Linguagem natural é ambígua demais para definir um programa de forma adequada
O fato de um LLM preencher detalhes plausíveis não resolve essa lacuna
Linguagens de especificação matemática são precisas, mas têm curva de aprendizado alta e são muito mais difíceis e intensivas em trabalho do que simplesmente escrever prompts em Markdown
O modelo lembra meus interesses ou preenche lacunas com seu próprio conhecimento para criar apps, jogos ou whitepapers completos
Às vezes é “exatamente o que eu queria”, e às vezes é “exatamente a sensação que eu estava descrevendo”
Em lidar com significado, contexto e nuance, em alguns pontos ele até supera humanos
A IA está ficando cada vez mais inteligente e capaz
Ou seja, está mais próximo de puxar coisas dos dados de treinamento do que de criar detalhes realmente novos
Concordo com a frase “uma especificação suficientemente detalhada já é código”
Isso é o mesmo argumento de No Silver Bullet, de Brooks
Mas a maioria das pessoas não quer esse nível de detalhe
Quando dizem “faça um app de tarefas para mim” para a IA, na prática querem dizer “faça um app melhor do que o que eu imaginei”
Mas essa abordagem não escala bem para outros tipos de software
No fim, é preciso expressar esse diferencial como especificação
Mas em áreas como bancos de dados, sistemas de arquivos e computação paralela, em que exatidão e desempenho importam, a implementação é muito mais difícil do que a especificação
Nesses casos, fazer a IA gerar código que passe em verificação formal é um grande desafio
Para ganhar dinheiro ou competir, são necessários requisitos concretos
Vendo vibe coding pela ótica da teoria da informação, a premissa é que existe um decodificador capaz de reconstruir um espaço de programas úteis a partir de um espaço pequeno de prompts
A taxa de compressão é justamente o ganho do vibe coding
Um prompt como “app de comunicação em equipe baseado em canais IRC” é indecifrável se você não conhece Slack
Portanto, é importante perceber o que está faltando
Para programar com IA de forma eficaz, é melhor dividir os prompts em unidades curtas e fornecer junto documentação existente, código já tentado etc.
Segundo Algorithmic Information Theory, a quantidade de informação de uma string é igual ao comprimento de sua representação autocontida mais comprimida
Porém, a condição de “autocontida” só vale quando os pesos do modelo funcionam como codebook
Como humanos presumem muito mais contexto compartilhado do que LLMs, tendemos a superestimar os limites do decodificador
Mas, num sistema com restrições fortes e ênfases claras, parece que a taxa de compressão do vibe coding poderia aumentar de forma explosiva
A linguagem natural oferece uma nova interface para pessoas que têm menos acesso a linguagens de programação
O LLM não pensa por elas, mas abre um novo caminho para transformar ideias em sistemas funcionais
Em breve, as pessoas provavelmente vão criar um dialeto de inglês técnico tipo LLMSpeak para melhorar desempenho do modelo e eficiência de tokens
A ideia seria reduzir ambiguidades, economizar tokens e comprimir conceitos complexos em uma única palavra
Até regras gramaticais como a Oxford comma provavelmente surgiriam para aumentar a clareza
Se a especificação for tão minuciosa assim, não há muito motivo para usar prompts
No fim, seria necessário redefinir tudo em linguagem humana novamente, então o ganho de tokens seria limitado
Veja a wiki do Lojban e um vídeo de um falante de Lojban
Tentativas de dialetos artificiais têm grande chance de fracassar, como aconteceu com o Esperanto
Esse tipo de linguagem pode até ser útil quando usado entre LLMs
As linguagens de programação já exercem esse papel
Uma spec é como um envelope que contém todos os programas que satisfazem certas condições
Criar esse envelope é mais difícil do que escrever um único programa
Assim como um LLM gera um código diferente a cada vez, uma especificação permite tanto implementações boas quanto ruins
Na prática, quando uma implementação é adotada, ela vira a especificação de fato da versão seguinte
Em ambientes com código legado (brownfield), as especificações não são limpas, então os LLMs têm dificuldade para lidar bem com isso
Existe uma explosão combinatória ao considerar como uma linha da especificação interage com as demais
Mas, do ponto de vista do compilador, código também é só especificação
No fim, dizer que “código é mais fácil do que especificação” é algo relativo
A especificação “armazenar credenciais de usuário” abrange desde bcrypt até cookies em texto puro
Humanos têm um instinto de “isso não pode”, mas agentes não sabem disso se não for explicitado
Portanto, para garantir segurança, é preciso especificar até o que não deve ser feito
Se desempenho ou segurança forem importantes, essas propriedades precisam ser explicitadas
Por exemplo, uma frase como “este programa deve ser O(n)” é muito mais simples do que a implementação
Parece que cada pessoa usa spec com um significado diferente
Para mim, spec define “o que” fazer, plan define “como”, e build packet significa os “passos detalhados”
Na maioria dos casos, o importante é o “o quê”
Escrever como os dados vão de A para B, passam por C, são preservados em D e representados em formato F em E é muito mais fácil como especificação do que implementar isso em Rust
Quando você faz engenharia orientada por agentes, muitas vezes os documentos de especificação ficam mais longos do que o código
Linguagem natural é imperfeita, mas código é exato
O objetivo da especificação é preservar funcionalidades mesmo após várias rodadas de desenvolvimento iterativo
Documentos de design em estilo waterfall foram mais eficazes do que testes ou comentários
Desse jeito, também consegui refatorar projetos completos de vibe coding ou trocar de linguagem de forma tranquila
Agora parece que voltamos ao fluxo de desenvolvimento dos anos 70 e 80
Uma frase como “implemente a interface TCP” é muito mais curta do que o código real
No fim, se houver mapeamento para um schema claro, a linguagem natural também pode ser suficientemente compacta
O caminho Spec → LLM é ineficiente e desperdiçador
Na prática, LLM → Spec é mais realista
Se a especificação existir em forma compilável, o LLM pode usar esse feedback para gerar código melhor
Tentativas de criar “inglês validado (validated English)” só aumentam a complexidade
No fim, o que importa é código que realmente funcione
O código contém muito mais coisa do que a especificação
Na maioria dos projetos, 90% é código de framework ou infraestrutura, e só 10% é lógica de negócio
A especificação é muito mais concisa porque não trata dos detalhes de linguagem ou framework
Quando isso acontece, o código fica quase no mesmo nível da especificação
Especialistas de domínio também conseguem ler, e testar fica mais fácil
Mas o código real muda bastante
O conflito entre ver a especificação como ferramenta de gestão e vê-la como ferramenta de engenharia gera dissonância cognitiva
Gestores enxergam especificações como tickets para delegação, enquanto desenvolvedores as usam como ferramentas de pensamento para refinar raciocínio
Alguns desenvolvedores começam adotando a visão gerencial por conveniência, mas logo percebem a diferença
Hype ou reuniões com investidores podem sustentar isso por algum tempo, mas no final os usuários querem o produto real
Daqui a pouco vão reinventar também o waterfall e o ágil.
Como desenvolvedor embarcado em C, primeiro elaboro a especificação de modo que seja possível verificar quase todo o fluxo de cada Feature/Subfeature por meio de charts.
Depois de revisar longamente a especificação e fechar a versão final, gero e utilizo um código que corresponde 1:1 de forma completa à especificação.
A legibilidade ao revisar pela especificação é muito superior à da revisão de código.