A documentação satisfaz em dobro: como especificações transformaram minha relação com IA.
Quando comecei a usar IA pra codar, eu fazia o que todo mundo faz. Abria o chat, descrevia a task em duas frases e esperava mágica. "Cria um endpoint de CRUD pra entidade X." "Faz um componente de tabela com paginação."
E a IA entregava. Código que compilava, que parecia profissional. Mas quando eu ia integrar no projeto, começava o pesadelo. As camadas estavam misturadas. A nomenclatura era diferente. A lógica de negócio vazava pro controller. Eu gastava mais tempo corrigindo o output do que teria gasto escrevendo do zero.
A frustração não era com a IA, era comigo. Eu estava pedindo pra uma máquina adivinhar o que eu queria, sem dar o mínimo de contexto sobre como eu queria.
Aí eu parei. E fiz algo que parecia ir contra tudo que anos de Agile tinham me ensinado.
Eu voltei a documentar.
Não documentar como burocracia. Documentar como instrução. Porque uma ferramenta de geração de texto só produz output previsível quando o input é preciso, e especificação é a forma mais eficiente de precisão que a engenharia de software já inventou.
O pêndulo da documentação: de RUP ao Agile, do Agile à IA
Se você entrou na área nos últimos dez anos, talvez nunca tenha ouvido falar de RUP. Rational Unified Process. O framework que dominava os anos 2000 com uma premissa clara: antes de escrever uma linha de código, você documentava tudo. Casos de uso, diagramas de sequência, documentos de visão, modelos de domínio. Projetos inteiros tinham mais páginas de documentação do que linhas de código.
O problema? O mundo mudava mais rápido do que a documentação acompanhava. Requisitos levavam semanas pra serem aprovados, e quando o código ficava pronto, o negócio já era outro.
Então veio o Manifesto Ágil. 2001. "Software funcionando vale mais que documentação abrangente." E o pêndulo foi pro outro extremo. User stories de uma linha. Critérios de aceite vagos. Conhecimento vivendo na cabeça das pessoas e nos comentários do PR. Documentação virou sinônimo de burocracia.
E por quase duas décadas, isso funcionou. O dev que ia implementar a task era o mesmo que tinha participado do refinamento. Ele tinha o contexto na cabeça. O conhecimento tácito compensava a falta de especificação explícita.
Até que a IA entrou na equação.
Uma ferramenta de geração de texto não participou do seu refinamento. Não estava na daily. Tem zero contexto além do que você fornece naquele momento. Aquela user story de uma linha que funcionava quando o destino era um dev humano se tornou completamente insuficiente quando o destino é um modelo de linguagem.
A IA forçou o pêndulo de volta. Não pra RUP. Pra um lugar novo: documentação como input de máquina. Enxuta, estruturada, versionável. Não pra convencer um comitê, mas pra instruir uma ferramenta.
A documentação voltou. Mas dessa vez, ela tem um consumidor que realmente lê cada palavra.
A especificação é o novo código
A qualidade do output é diretamente proporcional à qualidade do input.
Se o output da IA depende do input, então o trabalho mais importante do engenheiro de software não é mais escrever código, é escrever a especificação que gera o código.
Quando você usa IA sem especificação, está jogando dado. Quando escreve uma especificação clara antes de acionar a IA, com arquitetura, constraints, regras de negócio e critérios de aceite, o output passa a ser previsível. Reproduzível. Auditável.
Isso não é prompt engineering. Prompt engineering é otimizar a pergunta. O que estou falando é de algo anterior: engenharia de requisitos aplicada a ferramentas de geração de texto. A mesma disciplina que a gente quase matou na era Agile, ressurgindo com um propósito mais poderoso.
Assim como nenhum compilador gera binário bom a partir de código ruim, nenhuma IA gera implementação boa a partir de instrução vaga.
Minha evolução em 4 fases
Não sentei um dia e desenhei uma metodologia. Cada fase nasceu de uma frustração com a anterior.
Fase 1: Descrever a task
Tinha uma task no board, abria o chat, descrevia o que precisava. A IA entregava código funcional, mas com lógica no lugar errado, nomenclatura diferente e camadas misturadas. Cada output exigia uma sessão de refatoração. "Validações padrão" não significa nada pra uma ferramenta que não conhece o seu padrão.
Fase 2: Estruturar a arquitetura e ser obsessivo com review
Comecei a descrever como o projeto estava organizado. Domain, Application, Presentation, Infrastructure, Main. Onde fica cada coisa, qual camada depende de qual.
E me tornei obsessivo com review. Cada output passava pelo mesmo crivo de um PR de dev junior. Lógica no controller? Rejeita. Import de infraestrutura no domain? Rejeita. Porque se você aceita um desvio, os próximos outputs vão seguir o mesmo caminho. Review rigoroso é manutenção do padrão.
O output melhorou drasticamente. Mas eu repetia as mesmas instruções toda vez, e isso não escalava.
Fase 3: Guidelines completos com constraints
Criei um único arquivo YML que descrevia tudo: estrutura, camadas, responsabilidades e constraints. Guidelines e constraints juntos, porque são duas faces da mesma moeda: o guideline diz o que fazer, a constraint diz o que jamais fazer. A IA olha pra um lugar só e tem o contrato completo.
As rejeições em review caíram. A consistência subiu. Mas eu ainda descrevia o o quê de forma narrativa demais.
Fase 4: Requisitos com matriz de rastreabilidade
Essa fase nasceu de um lugar inesperado: uma aula que eu tive em 2017. Lá na faculdade, numa disciplina de requisitos, apareceu o conceito de matriz de rastreabilidade. Na época fez sentido acadêmico, anotei, passei na prova e segui a vida. Como quase tudo que a gente aprende na graduação e acha que nunca vai usar.
Anos depois, decidi testar. Cada feature virava requisitos funcionais e não-funcionais com ID único, critérios de aceite em Gherkin, e rastreabilidade até a implementação: qual classe, qual método, qual camada.
Não era mais "implementa o cálculo de distribuição", era "implementa o requisito RF-012, critérios A, B e C, na camada de Application, use case CalcularDistribuicaoUseCase."
Tasks que consumiam duas sprints, quatro semanas, passaram a ser entregues em uma. Não por mágica. Por clareza. A IA não ficou mais inteligente. Eu fiquei mais preciso.
O toolkit: as ferramentas que sustentam essa abordagem
Tudo que descrevi até aqui pode parecer abstrato. "Escreva especificações melhores" é um conselho vago se você não sabe o que escrever e onde colocar. Nesta seção, vou abrir as ferramentas concretas que uso no dia a dia, anonimizadas, mas fiéis à estrutura real.
São quatro peças que se complementam: guidelines do projeto, specs de features, prompts estruturados e arquivos de contexto.
Guidelines com constraints: o contrato do projeto
O guideline é o documento mais importante do fluxo. É onde a IA encontra, num lugar só, o que o projeto é e o que ele nunca pode ser. Arquitetura, camadas, responsabilidades e violações. Tudo junto, porque são duas faces da mesma moeda.
Eu escrevo guidelines em YML por uma razão simples: é estruturado o suficiente pra ser preciso, mas legível o suficiente pra um humano revisar. A IA processa YML sem ambiguidade, e eu leio sem precisar de parser.
Aqui está um exemplo mínimo de como estruturo um guideline de arquitetura em camadas:
project:
name: "my-service"
language: "java"
version: "21"
framework: "spring-boot-3"
architecture: "clean-architecture"
layers:
domain:
path: "src/main/java/{group}/domain"
description: "Regras de negócio puras."
contains:
- entities
- value-objects
- domain-services
- repository-interfaces
constraints:
- "NUNCA importar classes de infrastructure"
- "NUNCA importar classes de presentation"
- "NUNCA usar anotações de framework (@Service, @Component, @Entity do JPA)"
- "Dependência ZERO de bibliotecas externas"
application:
path: "src/main/java/{group}/application"
description: "Orquestração de casos de uso."
contains:
- use-cases
- input-ports
- output-ports
constraints:
- "NUNCA importar classes de presentation ou infrastructure"
- "NUNCA conter lógica de negócio, delegar para domain"
- "Cada use case é uma classe com método único execute()"
- "Use cases recebem e retornam DTOs, nunca entities"
presentation:
path: "src/main/java/{group}/presentation"
description: "Adaptadores de entrada. Controllers REST, consumers de fila."
contains:
- controllers
- request-DTOs
- response-DTOs
constraints:
- "NUNCA importar classes de domain diretamente"
- "NUNCA conter lógica de negócio"
- "Validação de formato aqui. Validação de negócio no domain"
infrastructure:
path: "src/main/java/{group}/infrastructure"
description: "Implementações concretas. Banco, cache, APIs externas."
contains:
- repository-implementations
- ORM-entities (JPA @Entity)
- external-api-clients
constraints:
- "NUNCA importar classes de presentation"
- "Implementa interfaces definidas em domain ou application"
- "JPA @Entity vive AQUI, não no domain"
main:
path: "src/main/java/{group}/main"
description: "Composição. Spring config, injeção de dependência."
constraints:
- "Única camada que conhece TODAS as outras"
- "Responsabilidade exclusiva: montar o grafo de dependências"
general-constraints:
- "Constructor injection ONLY, nunca @Autowired em field"
- "Um use case por arquivo"
- "Proibido: var para tipos não óbvios, wildcards em import, System.out"
Repara que cada camada tem um bloco constraints dedicado. Isso é intencional. A IA não precisa inferir o que é proibido, está explícito, na mesma estrutura que define o que é permitido. Quando ela gera um código que viola uma constraint, eu não preciso explicar por que rejeitei. Aponto pro guideline. A regra já existia antes do output.
E o mais importante: esse arquivo é versionado. Ele evolui junto com o projeto. Quando uma decisão arquitetural muda, o guideline muda junto, e todos os outputs futuros já refletem a mudança.
Specs e PRDs: o requisito antes do código
Guidelines resolvem o como. Specs resolvem o o quê.
Antes de pedir qualquer implementação, eu escrevo uma spec da feature. Não precisa ser um documento de 40 páginas, precisa ser preciso. O que a feature faz, o que ela não faz, quais os critérios de aceite, quais as regras de negócio, e como ela se conecta com o que já existe.
A estrutura mínima que uso: contexto (por que essa feature existe), escopo (o que está dentro e o que está fora), requisitos funcionais com ID e critérios de aceite em Gherkin, requisitos não-funcionais, e a matriz de rastreabilidade indicando onde cada requisito deve ser implementado.
Quando a IA recebe uma spec nesse formato junto com os guidelines do projeto, a margem de interpretação cai pra quase zero. Ela sabe o quê implementar, onde colocar, e o que não pode fazer. O output vira previsível.
Prompts estruturados: exemplos e restrições
Mesmo com guidelines e specs, a forma como você aciona a IA importa. Um prompt desestruturado desperdiça todo o trabalho anterior.
Eu sigo uma estrutura simples: contexto (referência aos guidelines e à spec), instrução específica (o que gerar), restrições inline (o que evitar naquela geração) e formato de saída (como entregar). Isso não é prompt engineering sofisticado. É clareza. É a mesma coisa que você faria ao delegar uma task pra um dev: contexto, instrução, limites, formato esperado.
Arquivos de contexto do projeto
A última peça é o que conecta tudo: um arquivo na raiz do projeto que funciona como ponto de entrada pra IA. Um documento que diz "esse projeto é X, usa Y, segue Z, e aqui estão os links pros guidelines e specs."
Toda nova conversa com a IA começa do zero. Sem esse ponto de entrada, você precisaria re-explicar o projeto a cada sessão. Com ele, você aponta pro arquivo e a IA tem o mapa completo. É o onboarding automatizado. O dev humano novo lê o README. A IA lê o arquivo de contexto. A diferença é que a IA realmente lê cada palavra.
Os resultados: de 4 semanas pra 1
Features de complexidade alta consumiam duas sprints. Quatro semanas. Não porque eu fosse lento. Era o ciclo: implementar, revisar, encontrar desvios, refatorar, testar, corrigir. Metade do tempo era gasto corrigindo o que saiu errado por falta de clareza.
Com guidelines, specs e rastreabilidade, essa mesma feature passou a ser entregue em uma semana. O review deixou de ser refatoração e virou conferência contra a spec. Em termos de velocity, multiplicação por 4x.
E tem um efeito que nenhuma métrica captura: a confiança. Quando cada requisito tem um ID e você sabe onde foi implementado, você não torce pra estar tudo certo. Você sabe, porque consegue rastrear.
A próxima era da engenharia de software já começou
Lá no início deste artigo, eu contei que voltei a documentar. Mas a verdade é que eu não voltei pra lugar nenhum. Eu fui pra um lugar novo.
A documentação do RUP era pra convencer humanos. A que escrevo hoje não tem plateia. Precisa ser precisa. Porque o consumidor é uma ferramenta que não tem ego, não interpreta nas entrelinhas e não preenche lacunas com experiência. Processa exatamente o que recebe e devolve proporcionalmente.
A gente passou vinte anos otimizando o como: frameworks, linguagens, CI/CD. Tudo pra acelerar a transformação de ideia em código. E fazia sentido, porque durante décadas o gargalo era a transformação. Mas a IA resolveu esse gargalo. E quando ele caiu, expôs o próximo: a clareza do que se quer construir.
A IA escancarou isso. E a habilidade que vai separar o dev mediano do dev excepcional não é mais a fluência em linguagem X ou framework Y, é a capacidade de transformar problemas vagos em especificações precisas. É engenharia de requisitos. A matéria que você provavelmente dormiu na faculdade.
Eu sei porque eu dormi. Literalmente. Mais de uma vez. Até que, anos depois, aquela matéria que eu mal conseguia manter os olhos abertos se tornou a peça que faltava.
A próxima era da engenharia de software já começou. E ela não é sobre escrever código. É sobre escrever o que vem antes dele.
Comments ()