2

O Boss final do Vibe Coding: IA atuando como Backend

OBS: Originalmente postei esse conteúdo no meu HashNode, porém estava lembrando que faz um tempo que não posto nada aqui, por isso resolvi postar aqui também.

Nos dias de hoje, a rotina de quem trabalha com Desenvolvimento de Software conta com diversas tomadas de decisão, sejam elas para escolher qual arquitetura, ferramenta, pattern usar em suas implementações.

Mas tem algo que tem fugido de nossas escolhas: utilização de IA.

Repare que não falo em usar padrões de Prompt como Chain-Of-Though ou Role-Based, usar os modelos da DeepSeek ou da Anthropic, contar com vários agentes ou fazer um pair-programming com a IA, falo que a maioria das empresas tem imposto o uso de IA no dia-a-dia como um acelerador de entregas. Usar não é uma opção.

Fazer um juízo de valores a respeito dessas decisões não cabe a mim, pelo menos não a este texto, e observando esse cenário, tenho buscado achar maneira de usar a IA para me ajudar na aceleração das minhas entregas.

Nisso, um pensamento correu em minha mente:

"e se eu usasse a IA para programar e... SER O CÓDIGO???**"

E se fosse a IA ser quem aplica a regra de negócio de um serviço, não usando código, mas sim a resposta que ela me devolve?

A resposta para essa pergunta é o que você vai encontrar com mais detalhes abaixo. Boa leitura!

O começo: procurando ideias

Para conseguir ter um resultado interessante, eu precisaria aplicar esse conceito em um projeto que tivesse uma regra de negócio que envolvesse uma complexidade um pouco maior, mas que também não fosse um bicho de 7 em sua implementação.

Após algumas sugestões da IA (sim, ela está presente em cada passo), achei que seria interessante desenvolver uma API REST para controle de estoque, onde eu conseguiria cadastrar produtos, locais de estoque e guardar uma quantidade X do produto Y no local Z.

Um projeto assim está dentro do nível de complexidade que estava buscando.

Colocando o Vibe Coding em prática

Para me auxiliar, utilizei o Antigravity da Google, utilizando o plano PRO que eles oferecem para IA. Ao invés de usar a IDE dele, usei o CLI mesmo, pois não abro mão de usar o meu IntelliJ, pois me sinto mais em casa com ele. Falando em IDE, vou passar um resumo do que solicitei ao Claude Sonnet para gerar de código:

  • Aplicação em Java 26 e Spring Boot 4;

  • Banco de Dados H2 e Postgres em PRD;

  • JUnit e Mockito para testes unitários (compatível com as versões que passei acima);

  • Como sou um pobre programador, pedi para ele configurar o Mistral como nossa "IA Backend";

  • Implementar essa relação de endpoints:

    • Um endpoint GET que retorna uma lista de todos os Produtos guardados;

    • Um endpoint GET que retorna um Produto pesquisado e os Locais onde ele está guardado;

    • Um endpoint GET que retorna todos os Locais cadastrados;

    • Um endpoint POST para criar um Estoque;

    • Um endpoint POST para guardar um Produto;

    • Um endpoint PUT para editar um Estoque;

    • Um endpoint PUT para mudar um Produto de um Estoque para outro;

    • Um endpoint DELETE para remover um Produto do Estoque;

    • Um endpoint DELETE para remover um Estoque, caso vazio;

  • Uma ênfase em que a regra de negócio por trás do guardar o produto no estoque não deveria ser escrita em código, mas questionado a uma IA se o sistema poderia guardar ou não;

  • Utilizei o modo de /plannig do Antigravity, que fez com que eu respondesse algumas perguntas referente a alguns pontos que não tinham ficado claros;

Escrita do projeto

Com tudo isso entendido e esclarecido, ela me apresentou um plano com 12 passos de implementação, para que eu revisasse e desse meu aval para dar início a marretagem de código.

Fui aprovando e revisando o que era implementado até o passo 10, que foi onde minha cota com o Claude Sonnet acabou 🥲.

Mudando para o Gemini 3.1 Pro, seguimos com o passo 10, que acabou se revelando o último (sim, eram 12 passos, mas do 1 ao 3 ela considerou como um passo só 🤷‍♂️) , que era a implementação de testes unitários.

HORA DE RODAR!

A IA foi lá e escreveu código, mapeou as entidades, preparou os endpoints, pensou na autenticação, e quando chegou na hora de executar... não funcionou mas foi lindo de ver.

Havia um erro de compilação no código gerado, na classe responsável por chamar o Mistral para tomar a decisão em cima do prompt descrito, que se tratava de um bean que o Spring Boot não estava conseguindo injetar na classe (o ObjectMapper da lib Jackson). Decidi testar as capacidades dela para resolver esse problema e ela apanhou um pouco para conseguir corrigir, e a solução que ela achou melhor foi simplesmente instanciar um novo ObjectMapper para o serviço usar:

OBS: acho que aqui ela desistiu de ajustar a injeção do bean e foi pelo caminho mais fácil 🤣.

Ajustando esse problema, consegui colocar de pé a aplicação e testar os endpoints que não dependiam da IA, como criar Locais e listá-los, e tudo estava bem funcional.

Autenticação

Foi implementada uma autenticação bem simples (a Basic Auth, como você deveria imaginar) onde eu configurava usuário e senha via application.yaml mesmo, e a cada requisição eu preciso do Header com a devida autenticação.

Briga com o H2

Como eu estava usando o H2, queria verificar se a estrutura de tabelas foi criada corretamente, tentei acessar o /h2-console e bati com a cabeça na parede: o navegador ficava infinitamente me pedindo usuário e senha por conta do Basic Auth.

Logo pensei que tivesse algum problema no Filter que confere as autenticações, mas tudo que parecia em ordem. Revisei as configurações no application.yaml, fiz alguns ajustes e também não consegui acessar. Logo, pedi para quem fez descobrir o problema e me explicar.

Meus amigos, aqui a LLM ficou muito perdida! Tentamos umas 5 correções diferentes e ela errou com sucesso! Até que ela conseguiu identificar corretamente o ponto de erro: A versão 4 do Spring Boot colocou em um módulo separado a autoconfiguração do /h2-console, sendo necessário importar a lib que contém esse módulo para funcionar.

Como se trata de uma versão mais nova do Spring Boot, ela errou muito até chegar num diagnóstico coerente e assertivo, me lembrando que IA's sempre terão muita dificuldade com o que é novo. Fiquei tão decepcionado que dei uma bronca nela.

OBS: acho importante ressaltar que usei o Gemini para essa correção, o que pode trazer mais motivos para a dificuldade na resolução.

Configurando nossa IA Backend

Agora era chegada a hora de aplicar nossa regra de negócio de milhões: deixar que a IA tome a decisão de guardar ou não o produto.

Configurei o Mistral para ser acionado, e aproveitei e dei uma revisada no código implementado (principalmente na parte do Spring AI, que não conhecia até então), e a implementação contava até com proteção contra Prompt Injection!

Essa limpeza é feita em todos os lugares que o usuário consegue mandar uma informação de texto livre (nome do Produto, nome do Local...), colocando uma camada extra de segurança no projeto. Claro que não está completo, mas já é um bom começo.

Hora da verdade: acionando os endpoints com decisão da IA

Comecei testando o endpoint responsável por guardar um Produto em um Local, e funcionou de primeira! Achei tão impressionante que revi o código, para ver se estava sendo a IA responsável por liberar ou não, e era ela mesma!

Do ponto de vista de funcionalidade...

O que mais achei interessante aqui, é que toda resposta de erro retornada por querer guardar uma quantidade maior de produtos que o local comporta era diferente, porque além de aprovar ou não, ela também devolve uma justificativa.

Já o restante não era tão bom... O tempo de resposta fica consideravelmente maior por termos de interagir com a IA, e isso fica muito nítido quando tentamos guardar um produto que não existe, que é barrado antes de ser enviado para ela, e nos da uma resposta quase que instantânea. De qualquer forma, essa demora acaba não atrapalhando tanto.

Do ponto de vista de implementação...

A LLM foi literal demais neste endpoint de guardar produtos, pois o produto é salvo no banco a parti deste endpoint. E olha só que zona ficou essa implementação:

  • São consultados todos os produtos cadastrados no banco;

  • É verificado se existe algum produto com o mesmo nome enviado para o endpoint;

  • Não havendo, ele salva esse Produto;

  • Somente ai que ele vai pegar a soma da quantidade de Produtos guardados no Local (caso ele exista) e repassar esses dados para ela decidir se pode guardar ou não, de acordo com a capacidade máxima do estoque;

Eu fiquei boquiaberto com o quanto isso ficou esquisito. Isso significa que a cada vez que eu quisesse guardar um produto, eu consultoria TODOS os Produtos, e passaria UM POR UM para poder achar um que tivesse o mesmo nome, tendo uma grande chance de fazer tudo isso atoa por não ter o produto cadastrado ainda.

Não podia deixar isso assim, e parti para a refatoração desse fluxo, buscando separar o cadastro do produto em um enpoint separado, só para isso.

Nessa missão, envolvi o Gemini, onde passei o seguinte prompt para ele:

Quero que você implemente um POST para tornar possível cadastrar um produto na base de dados. Remova a lógica de cadastro que tem no endpoint POST /api/products que faz o cadastro do produto ao colocar o produto no local.

O que ele me entregou foi o POST que pedi, conforme o esperado, mas ele ainda não havia removido aquele trecho que percorria todos os Produtos, mesmo tendo feito algumas alterações pouco relevantes na implementação desse serviço. Foi aqui que tive uma ideia: trocar de modelo para ver se o Claude se saia melhor que o Gemini.

Troquei de modelo e colei o mesmo prompt, e olha só que interessante:

O modelo conseguiu identificar sozinho que ele poderia usar o ID do produto, e não seu nome, para verificar se ele existe.

O Gemini não conseguiu ter essa sagacidade, sendo que passei o mesmo prompt para ambos.

Isso me traz a impressão direta de que o Claude oferece uma visão mais crítica de programação do que o Gemini. Claro que só isso é pouco para levar isso como certeza absoluta, mas já é algo que faz a gente pensar a respeito.

Considerações finais

Com os poucos testes que fiz, já da para tirar alguns insights interessantes sobre como é desenvolver com IA e usá-la em nossas regras de negócio, porém ainda não fiz tudo que planejei para esse projeto.

Pretendo colocar mais decisões e partes do serviço a cargo da LLM, e na medida que eu for melhorando esse projeto, vou atualizando você por aqui.

Até aqui, fica a reflexão de como essa ""arquitetura"" mexe com a experiência do usuário final, assim como os meios de programar essa solução podem trazer reflexões interessantes sobre como comportamento dos modelos e funções podem agregar na nossa rotina de desenvolvimento.

Muito obrigado por me acompanhar nessa jornada, e prometo que trarei novas funcionalidades para o projeto, com a IA sendo usada de maneiras inimagináveis, onde vamos testar seus limites.

Carregando publicação patrocinada...