Disclaimer
Este texto foi inicialmente concebido pela IA Generativa em função da transcrição de um vídeo do canal Dev Eficiente, apresentado por Alberto Souza. Se preferir acompanhar por vídeo, é só dar o play.
Introdução
Nos últimos meses codei um sistema de ponta a ponta, em parceria com uma empresa que queria colocar um produto no ar. Fiz tudo com Claude Code, em sessões longas de trabalho, que variaram de duas horas e meia a quatro horas. Na última sessão, de pouco mais de quatro horas em auto mode, o agente fez 42 commits na main e codou um módulo inteiro, com oito casos de uso, que saiu quase totalmente funcional. Fiz um único ajuste, em um dos casos de uso.
Este é o primeiro texto de uma série sobre esse produto. Aqui eu conto como estruturei o ambiente, como conduzi cada iteração e quais decisões tomei ao longo do caminho. Nos próximos, entro na qualidade do código que saiu desse fluxo, no que eu inspecionei e no que eu não inspecionei.
Uma dessas decisões atravessa o texto inteiro e merece ser dita logo de início: eu não revisei o código gerado. O esforço foi todo para a entrada.
O sistema
O produto é composto por três serviços. Um core em Java, que concentra as regras do negócio. Um agente em JavaScript, construído com o SDK do Claude Code, que sustenta as conversas com o usuário e o uso de tools padrões e customizadas. E um front-end em React, sem nada fora do padrão.
Ao final da última sessão, o back-end estava com pouco mais de 1300 testes e o agente com pouco mais de 800. Volto a esses testes mais adiante, porque eles têm um papel curioso nessa história.
Vale dizer também o que esse projeto não é. Não é um experimento controlado. É um sistema que vai para o ar, que pessoas vão usar, e que já recebeu feedback de quem estava testando dentro da empresa parceira. A gente iterou em cima desse feedback para ir deixando o produto mais certo.
Como conduzi cada iteração
A primeira parte do sistema tinha dez casos de uso, e eu fiz um por um. A segunda parte tinha oito casos de uso principais, que na ponta do lápis viram uns quinze ou dezesseis quando se contam os menores. E foi essa segunda parte que o agente codou inteira em quatro horas.
Para chegar lá, mantive uma pasta com o contexto de cada iteração. Foram quinze iterações no total, e a última, que gerou o módulo inteiro, concentrou bastante contexto. O padrão que segui em todas foi o mesmo.
Primeiro, eu entrego o contexto. Em geral é composto por arquivos explicando o que é necessário com a linguagem da empresa.
Segundo, peço que ele leia tudo e me diga o que entendeu, sem fazer nada ainda. Ele descreve o que leu, aponta como aquilo se encaixa no que já existe e lista os pontos em aberto.
Terceiro, peço que, antes de partirmos para o planejamento, ele me diga quais perguntas quer ver respondidas. Ele gera um arquivo com uma rodada de perguntas e eu respondo uma a uma. Teve pergunta que eu não entendi e pedi que ele explicasse melhor. Teve pergunta que me fez perceber que eu mesmo não estava entendendo o módulo direito. Isso vira uma segunda rodada, uma terceira, uma quarta. Um sinal simples de que a conversa está convergindo é a barra de rolagem do arquivo ficando cada vez menor a cada rodada.
Quarto, quando as dúvidas acabam, mando um prompt curto: pode seguir até o final da implementação, confio em você. E deixo rodando.
Esse bate-bola de perguntas e respostas não é invenção minha. A própria Anthropic recomenda esse tipo de rodada com o agente. Faço bastante isso porque, do meu ponto de vista, o agente é o time que vai executar o trabalho. Entrego o contexto e pergunto: quais dúvidas você tem para fazer isso direito?
Não vou dizer que existe um prompt certo nem um playbook para trabalhar com Claude Code, Codex ou qualquer outra ferramenta do gênero. Acho que não existe. O que eu faço é ler a documentação da ferramenta que mais uso, ler os materiais publicados pela Anthropic e pela OpenAI, que são as referências, e formar a minha opinião. E a minha opinião cabe em uma frase: dá contexto, tira as dúvidas, solta para o jogo.
O agente como o time que eu liderava
A maneira como eu entendo o uso de um agente de código hoje me lembra muito a maneira como eu lidava com as equipes que liderei. Eu sempre liderei com um viés técnico. O que as pessoas estavam fazendo, em alguma escala, eu era capaz de fazer. Não tudo, tinha coisa que eu não tinha ideia de como resolver. Mas em tudo que eu sabia fazer, eu tentava entender se elas estavam fazendo melhor ou pior do que eu queria.
O meu papel era trazer o time, inicialmente, para o nível que eu considerava adequado. Depois disso, as pessoas iam estudar, praticar, refletir e, eventualmente, estavam trabalhando com bastante autonomia. Para mim, era assim que fazia sentido ter um time: um grupo de pessoas que em algum momento seria mais eficiente do que eu sozinho.
Com o agente é a mesma coisa. Ele é o time, só que uma máquina. Ele foi treinado em muitas práticas de como fazer as coisas, e o modelo por baixo vai fazer as análises e gerar os próximos passos. O que eu preciso fazer é direcionar: dizer o que eu acho importante, o que eu quero e o que eu não quero. Uma vez direcionado, o meu papel é não atrapalhar. Claro, se tiver alguma restrição forte, preciso fazer de tudo para ser respeitada.
Por isso não fiquei escrevendo especificações à mão. Usei o plugin Superpowers, que gera especificação, plano de execução e registra a saída de cada execução. Não parei para inspecionar os detalhes do que ele gerou. Se eu tivesse feito sem o plugin, teria chegado no mesmo resultado? Acredito que sim. Mas esse é um experimento que não vou fazer, porque não vou gerar tudo de novo para comparar.
A decisão de não revisar
Chegamos ao ponto central. Nesse produto eu não revisei o código. Mal olhei o que estava sendo gerado. Eu testava a funcionalidade como usuário, liberava para a empresa parceira testar e seguia para a próxima iteração.
A resposta comum para essa decisão é que o gargalo está na revisão e que a saída do agente não é confiável. Só que essa é a mesma frase que ouvíamos quando o código era gerado pela interface web de um chat e colado no projeto, e depois quando surgiram os primeiros assistentes de código. Passaram-se quatro ou cinco anos, os modelos e os harnesses evoluíram muito, e a recomendação continua a mesma: revisar o código, revisar a especificação, revisar o plano.
Eu tenho a crença de que, para dar um próximo passo que mude o jogo da efetividade, você precisa estar disposto ou disposta a cair em armadilhas. A fazer uma grande besteira em busca desse passo. Falando por mim, não quero ser, nem liderar, uma equipe cujo dia a dia é reclamar do gargalo da revisão sem se perguntar se ela ainda é necessária.
Vale dizer que eu nunca gostei de revisar código. Nas equipes que cuidei, a revisão existia mais como oportunidade de eu trabalhar em cima da entrega de quem buscava senioridade do que como verificação de correção. E, para evitar debate infinito, a revisão era sistemática: havia um sistema de design de código que regia o trabalho, as pessoas revisavam contra esse sistema, e pronto. Se já era chato revisar código escrito por humanos, revisar código escrito por uma máquina que acabou de adiantar o meu lado é ainda menos atraente.
Não revisar não quer dizer que não cuidei. Quer dizer que estou colocando em prática, cada vez mais, uma ideia que defendo há tempo: tudo o que eu faço longe da origem do trabalho fica mais complexo, no sentido de número de elementos que preciso cuidar, e mais difícil, no sentido de esforço. Por isso sempre gostei de engenharia de requisitos. O esforço máximo deveria estar na origem.
A pergunta que estou testando nesse produto é essa: se eu for excelente na entrada desse harness mais modelo, posso esquecer a revisão na saída?
Sobre os testes, um detalhe que ilustra o ponto. O back-end tem mais de mil testes, e eu não li nenhum. Para mim, como pessoa, não faria diferença se não houvesse nenhum. Eles existem para o time, que é o agente: quando ele termina de codar, ele roda a bateria e itera em cima do resultado. Não lembro de ter visto um teste quebrar durante as sessões. Será que a bateria é boa? Será que está enviesada pelo código que o próprio agente escreveu? Não sei. É isso que vamos ver junto em um próximo episódio.
O que entrou no CLAUDE.md
Se o esforço vai para a entrada, o que exatamente eu coloquei nela? Menos do que se poderia imaginar. Não há dezenas de skills. O arquivo tem o básico: arquitetura, stack, estrutura do projeto. E, do mesmo jeito que eu tentava não perturbar o time o tempo inteiro, quero fazer o mínimo para que a máquina faça um trabalho decente.
Sobre convenções, pedi código em português mantendo as convenções da linguagem para nome de classe, atributo e método, e nomes de método no imperativo. Marquei isso como parte importante, mas com uma ressalva: era importante quando um humano ia ler o código. Se quem vai ler é a máquina, não sei quanto vou me preocupar com isso mais para frente.
Sobre design, coloquei as práticas que uso há anos e que estão públicas no meu GitHub:
- Não retornar nulo.
- Separar a borda externa da interna. Os detalhes de saída recebem o objeto de domínio, e o DTO de entrada tem um método que devolve o objeto de domínio.
- Priorizar construtor. Setters só com instrução explícita.
- Só alterar o estado de referências que você criou ou que carregam um marcador nítido de que podem ser alteradas.
- Favorecer coesão, considerando que o controller é o caso de uso, em vez de criar camadas de controller, serviço e afins por padrão.
- Módulos não acessam o repositório de outros módulos. Toda comunicação entre módulos passa por uma interface bem definida, que nesse caso foi HTTP. Poderia ser uma chamada em memória, mas eu gosto de limites severos de comunicação entre módulos.
- Ser restritivo com reúso. Muitas vezes eu repito antes de extrair, para entender se é coincidência ou reúso de verdade. O agente apontou trechos repetidos como dívida técnica, e eu deixei por enquanto.
Também entraram direcionamentos específicos do domínio. O produto tem uma parte de créditos, consumidos em função do uso do agente. Eu sei que a fórmula de cálculo vai evoluir e sei que fórmulas desse tipo precisam ser imutáveis, para que seja possível auditar o passado. Então deixei explícito que uma fórmula existente nunca pode ser alterada, só substituída.
Entre o primeiro grande módulo e o segundo, introduzi o CDD, que é a teoria de design de código que criei para limitar a complexidade pelo viés cognitivo. Adicionei uma skill de revisão de CDD e de coesão, para ser aplicada na hora em que o código é gerado, não como um hook posterior. Também expliquei a linha de design que eu queria: entidades muito finas, só com a informação realmente estável, e o resto construído em outras abstrações que decoram essa entidade. Já usei essa abordagem na plataforma Dev + Eficiente e gostei do resultado. Talvez o segundo módulo tenha saído mais fácil de caber na mente de uma pessoa do que o primeiro. Mas, se ninguém for ler, e se o modelo lida cada vez melhor com volumes maiores de tokens, nem sei se isso faz diferença.
Por fim, o padrão de teste. Priorizar a versão real das dependências e minimizar mocks. Usar MC/DC como critério de cobertura. Escrever testes apenas para os controllers, que são os casos de uso. E rodar tudo em memória, sem subir o contexto do Spring. A bateria precisa rodar em velocidade de teste de unidade, porque o feedback loop do próprio agente depende disso. Se ele quiser testar e cada rodada demorar minutos, o trabalho atrasa. Essa combinação, teste rápido usando o máximo de coisas reais e mirando sempre o caso de uso, funcionava bem quando eu escrevia código com as minhas mãos, e mantive.
Resumindo: um CLAUDE.md com as práticas e recomendações de design que eu quero, um padrão de teste nítido e um sistema de preparo para que o agente possa fazer o trabalho dele. Nada disso é definitivo. Tudo está em cheque.
Onde entra o diferencial humano
Se tudo está em cheque, onde entra o diferencial humano? Para mim, entra cada vez mais na entrada. Como você guia, como você limita, o que você quer e o que você não quer. E como fazer isso inventando o menos possível.
O que saiu desse fluxo é um sistema de estratégia de marketing. A primeira parte tem dez passos, cada um com um agente dedicado, e ao final uma entrega: um plano de estratégia. Quem usa o sistema é a pessoa que a empresa chama de estrategista, que conversa com quem quer colocar um produto no ar e monta a estratégia. Quem se beneficia é a empresa cliente. Cada agente tem uma tool que, quando percebe que algo relevante aconteceu na conversa, gera uma saída estruturada que eu gravo do jeito que preciso. Há um passo em que a pessoa sobe conteúdos já publicados para análise. É um produto de verdade, com muitas partes.
Foi também o primeiro sistema em que aceitei que talvez esteja tudo bem conviver com o não determinismo para esse tipo de tarefa. Era um domínio com muito texto, muita conversa, e estruturas que ainda não estavam nítidas para mim. Não estou dizendo que aceitaria isso onde o determinismo é brutalmente importante, como uma ordem de stop em uma operação financeira. Ali, vai um if. Mas para esse produto, aceitei, e vou detalhar essa estratégia em outro vídeo.
Conclusão
Uma sessão de quatro horas é, para mim, uma sessão longa de trabalho para um agente. Vai ter gente com relatos de 24 ou 48 horas, mas o que importa é a comparação com o que eu faria nessas mesmas quatro horas. Meu chute é que, na minha melhor forma, eu levaria uma semana para codar o que ele codou em uma manhã.
A minha busca desenvolvendo software é encontrar maneiras cada vez mais eficientes de gerar valor para quem precisa do software. E eficiência, para mim, é fazer algo com uma barra de qualidade suficiente, cada vez mais rápido, minimizando o gasto de energia. Menos energia, mais rápido, igual ou melhor.
Não acredito que manter o mesmo modelo de trabalho que eu tinha antes dessas ferramentas vá me levar para onde eu quero. Esse produto foi um passo a mais nessa direção. Se a decisão de não revisar foi uma armadilha, vamos descobrir juntos nos próximos episódios, olhando o código que saiu.
Referências
- Documentação do Claude Code: https://code.claude.com/docs
- Práticas de design de código da Dev + Eficiente (repositório público no GitHub): https://github.com/asouza/pilares-design-codigo
- Plugin Superpowers para Claude Code: https://github.com/obra/superpowers
- CDD (Cognitive Driven Development): https://arxiv.org/pdf/2210.07342
- Vídeo sobre entidades finas, no canal: https://youtu.be/vx1anvp7ls0
Dev + Eficiente
Desenvolva software de alta qualidade e domine Engenharia de IA com o Dev + Eficiente. Cursos práticos, acesso vitalício, comunidade ativa e acesso a vagas remotas exclusivas em diversas empresas de tecnologia. Sua jornada para se tornar um dev mais eficiente pode começar agora.
Top comments (0)