Consigo perceber quando você está em 'vibe coding'
(alexkondov.com)- Recentemente, no time, é fácil perceber quando um código foi gerado por LLM
- Esse tipo de código pode ser claro e bem testado, mas não segue as convenções do projeto
- Ignora vários padrões existentes e bibliotecas, fazendo implementações novas do zero
- Há uma crescente preocupação com a tendência de buscar apenas a velocidade no desenvolvimento de software
- No fim, o que importa é a qualidade, a consistência e a capacidade de manutenção
Traços do 'vibe coding'
- Entre os códigos escritos pelos membros da equipe recentemente, alguns parecem claros e funcionais, mas já revelam ser gerados por LLM por não seguirem as convenções próprias do projeto
- Por exemplo, mesmo com uma biblioteca de data fetching já existente no projeto, escreve-se manualmente uma implementação de requisição HTTP que cubra todos os casos de exceção
- Recria repetidamente as funções utilitárias de módulos existentes, e, mesmo havendo um mecanismo de alteração de configuração por módulo, altera configurações globais
- Mesmo com a cultura de escrever código de forma funcional consolidada, cria novo código baseado em classes
- Esse é um estilo de código que as pessoas há alguns anos atrás não escreveriam de forma alguma
Importância da manutenção e dos princípios de software
- No desenvolvimento de software, investimos por muito tempo para estabelecer padrões e práticas que possam ser mantidas por longo prazo
- Na prática, qualquer pessoa pode escrever código que funcione, mas o verdadeiro desafio é ter código com manutenção e alterações fáceis ao longo do tempo
- Não se trata apenas da implementação da funcionalidade; o que importa é ter uma base de código que possa ser mantida com o passar do tempo
- O 'vibe coding' pode derrubar essa filosofia e esses critérios
Será que a velocidade é o nosso maior padrão?
- Ao comparar com a cena de um novo barista em uma cafeteria que, ao apressar-se, derruba o café, reforça que a obsessão por velocidade não gera um resultado correto
- As equipes de desenvolvimento de hoje também correm demais para criar novos softwares e sofrem com queda de qualidade
- O que as pessoas realmente querem é um resultado correto, mesmo que demore um pouco mais
- Eu costumava achar que focar só em velocidade era um problema de áreas não técnicas, mas estou desapontado ao ver que colegas desenvolvedores também seguem a velocidade e abandonam os princípios
O que realmente queremos
- Não importa como o código foi colocado no IDE
- O que importa é a atitude do desenvolvedor de se importar com a qualidade
- Embora o LLM seja reconhecido como uma grande inovação técnica, ainda assim reforça-se que a responsabilidade de construir software real permanece com o desenvolvedor
- Recomenda-se conhecer e aplicar princípios existentes como: “escrita de melhor prompt”, “escolha da biblioteca correta”, “fornecimento de exemplos”, “trabalho em arquivos pequenos”
- Ele adverte para não deixar qualidade do código e manutenibilidade apenas no 'peso' do modelo
2 comentários
Discussão no Hacker News
Eu queria trabalhar numa equipe em que ninguém reimplementa busca HTTP do zero se a biblioteca de fetching de dados já cobre todos os casos de exceção do projeto, ninguém recria um módulo de funções utilitárias que já existe, ninguém mexe em configuração global a partir de módulos individuais quando isso nem deveria acontecer, e ninguém cria uma classe nova num código que usa majoritariamente abordagem funcional; mas, na prática, muitos desenvolvedores repetem esse tipo de coisa o tempo todo
Sinceramente, isso acontece com muita facilidade em projetos grandes quando a documentação é fraca. No projeto de pesquisa acadêmica em que trabalho, a documentação do código basicamente diz que o próprio código já se autoexplica, e só menciona brevemente configuração de CMake, build e como rodar benchmarks. Regras internas e convenções você só descobre apanhando. Quando chega alguém novo, é comum reimplementarem funcionalidades que já existiam ou mudarem configuração global. No fim, o melhor acaba sendo indexar a codebase e perguntar direto para um LLM (porque as pessoas-chave do projeto saíram ou só respondem muito tempo depois).
Acho que estão deixando passar o ponto do autor. Se velocidade for a maior de todas as virtudes, esse tipo de coisa vai continuar acontecendo. Se velocidade for um valor absoluto, a produção teria que crescer exponencialmente para compensar a dívida técnica. Se existem outros fatores importantes além da velocidade, então é preciso administrar e pagar essa dívida com inteligência. Mas hoje parece mais que estão assumindo uma dívida enorme e torcendo para dar certo, e muita gente de fato é ruim em gerenciar dívida.
Muita gente reinventa a roda sempre que tem chance, ignora convenções esperadas ou usa padrões misturados. O autor chamaria isso de "vibe coding", mas na verdade isso não é um problema exclusivo de LLM; acontece com qualquer pessoa quando está correndo atrás de resultado ou quando falta experiência. A frase "código que ninguém da equipe escreveria desse jeito" sugere até que pode haver uma frustração direcionada a alguém específico. É preciso cautela antes de generalizar essa visão para outros casos.
Já vi desenvolvedor adicionar uma ORM extra. A primeira já era suficiente, mas colocaram uma segunda só porque "está na moda". Tanto desenvolvedores quanto LLMs têm seus próprios vieses. É extremamente importante entender as regras e os padrões do projeto e trabalhar dentro desse quadro. Construir do seu próprio jeito, sem considerar o contexto, é muito arriscado. No caso de pessoas, isso pode ser mitigado com cultura de code review e incentivo à leitura de código. No caso de LLMs, é preciso orientar explicitamente todos os padrões e regras, senão o risco de gerar código desalinhado com o projeto é grande. O ponto central é definir de forma explícita os valores e critérios.
Eu já trabalhei numa equipe boa assim. Havia muitos projetos pequenos (2 a 4 pessoas), mas de alta importância. Nesse tipo de ambiente, é mais fácil construir cultura e consenso para equilibrar qualidade e velocidade. Em times assim, ninguém — nem humano, nem LLM — teria um PR desses aprovado.
Pessoalmente, eu vejo LLM como um desenvolvedor bem júnior. Ele quer fazer o trabalho direito e seguir instruções, mas entende pouco da codebase e dos padrões. Você precisa guiá-lo em cada etapa, explicar até os erros potenciais, passar tarefas específicas e pequenas e revisar o código com cuidado. Eu, por exemplo, primeiro monto o modelo de dados na cabeça e só depois parto para o código. Explicações concretas são importantes. Uma regra não escrita que eu sigo é sempre colocar um comentário em bloco no topo do arquivo explicando o conteúdo do arquivo. Isso funciona como um segundo prompt quando a sessão recomeça. Esse método funciona bem sem parecer "mágico", mas no meio do caminho uns 30% do trabalho acaba sendo limpeza, renomeação e refatoração para deixar o código apresentável. Ainda assim, com LLM eu trabalho muito mais rápido do que escrevendo tudo completamente à mão.
Às vezes, chamar LLM de "desenvolvedor júnior" ou "copiloto" não representa direito nem os pontos fortes nem os fracos. Diferente de uma pessoa, ele esquece facilmente e comete erros muito básicos, mas também há coisas em que é melhor do que eu, como problemas de off-by-one com arrays. E ele conhece quase tudo da internet em nível enciclopédico. Depois de usar bastante, passei a pensar nele como um cão de caça: o dono precisa conduzir a caçada e finalizar o trabalho.
A diferença entre LLM e um desenvolvedor júnior está na capacidade de aprender. Um júnior aprende e evolui com o tempo; o LLM, não. Quanto mais instruções você coloca no prompt, maior a chance de ele esquecer mais coisas e voltar para respostas genéricas. Toda vez que o prompt recomeça, você precisa orientar tudo do zero.
Para mim, LLM não é tão diferente assim de procurar código na internet e dar copy-paste. No fim, o desenvolvedor ainda precisa inspecionar o código e verificar se ele realmente funciona. Ultimamente, por causa da saúde dos olhos, tenho que trabalhar em blocos de 20 minutos e descansar, então eficiência ficou ainda mais importante. Como o LLM gera código muito mais rápido do que um humano, já ajuda muito mesmo se ficar só com o trabalho mais básico. No momento, estou gerando structs para SIMD com Unity C# e LINQ, e basta dizer ao LLM as condições desejadas para obter o código ou a string que eu quero muito mais rápido do que copiando e colando manualmente. Faz sentido pensar em IA como um HUD. Em vez de uma IA que constrói o programa inteiro, eu preciso de uma ferramenta de apoio poderosa para unidades pequenas de trabalho.
Para mim, LLM é um substituto muito melhor do que StackOverflow. Eu posso perguntar qualquer coisa na hora e ele responde com precisão. A partir da resposta, eu reescrevo para o meu código ou faço com que ele gere só uma função. Antes de copiar qualquer coisa, eu sempre tento entender completamente o código. Às vezes eu até já pensei se não seria melhor para a carreira abrir PRs de 400 mil linhas em projetos open source numa linguagem que eu mal conheço do que trabalhar de forma honesta e orientada à qualidade. Isso porque, na prática, anos de experiência muitas vezes são mais valorizados do que habilidade real.
Para fazer um LLM trabalhar com sucesso, tive mais resultado limitando seu uso à etapa de codificação propriamente dita, não à parte de pensar. Funciona melhor quebrar a tarefa em partes pequenas e passar especificações concretas, arquivos a serem modificados, localização de exemplos de referência e assim por diante, com o máximo de detalhe possível. Não precisa ser minúcia absoluta, mas quanto mais pistas houver, maior a chance de sucesso. E o código gerado eu ainda reviso pedaço por pedaço com
git add -p. Dá trabalho preparar e revisar, mas ainda economiza muito mais tempo e energia do que escrever tudo sozinho ou deixar código capenga do jeito que está.O maior risco do vibe coding é que, enquanto um desenvolvedor muito bom só fica um pouco mais rápido, um desenvolvedor fraco passa a gerar muito mais código ruim em velocidade muito maior. A questão é se esses desenvolvedores conseguem evoluir com vibe coding ou se apenas ficam estagnados ali mesmo.
Pela minha experiência, até um desenvolvedor mediano pode virar um desenvolvedor ruim muito rapidamente. O motivo é a falsa autoconfiança combinada com um aumento explosivo na produção de código. O código gerado por IA quase não considera arquitetura geral, fluxo de informação ou princípio da responsabilidade única. Para parecer seguro, ele é montado devolvendo placeholders em vez de exceções. Aí o código chamador precisa verificar toda hora se o resultado é placeholder ou não. Se os parâmetros de entrada já são ruins, a IA tenta consertá-los por conta própria e ignora a estrutura
gather_parameters → call → process_results. E quando chega a parte de testes, o problema fica muito pior.Agora muita gente vai redescobrir o conceito de programador net-negative, aquele cuja mera presença reduz a qualidade do projeto.
Pelo que vejo, o recurso mais escasso aqui é zelo. O vibe coding em si não é a causa da falta de zelo; a IA é só uma ferramenta. Todos os problemas citados pelo autor também se aplicam a desenvolvedores humanos juniores e podem melhorar com orientação e comunicação melhores. Eu não acho que a IA reduza por si só o interesse por qualidade (quem não ligava para isso já era assim antes). Uma objeção comum é que ela elimina oportunidades de formar juniores, mas em muitos casos ela está sendo usada como solução temporária porque não há alternativa melhor no momento (é o caso da minha startup, que também tem dificuldade para contratar). Ferramentas de IA podem acabar mudando o padrão de qualidade esperado em software, e acho que isso ainda vai evoluir bastante.
O LLM precisa usar como contexto não só o estado atual, mas também o histórico de commits. Muitas codebases estão migrando gradualmente do padrão A para o B, e vários padrões coexistem. Como essas migrações não acontecem de uma vez, o antigo e o novo costumam ficar misturados por muito tempo. Mesmo que o LLM reconheça os padrões, como no exemplo de HTTP, seguir o certo ou não acaba dependendo da sorte.
Já trabalhei numa codebase grande que passou por mais de 20 anos de fusões, trocas de nome e aquisições. Ainda restam exemplos de chamadas de API muito antigas, embora exista código mais novo separado; muita coisa foi mantida por causa de clientes específicos. Também há muitas APIs parecidas sem documentação nenhuma, então eu preciso sair investigando uma por uma para descobrir qual me devolve os dados de que preciso.
Um jeito de lidar com isso é usar um arquivo como
CLAUDE.mdpara deixar instruções claras do tipo "siga este padrão, evite aquele".Mais eficaz do que isso é explicar de forma bem concreta como trabalhar em cada parte e dar exemplos específicos.
O problema é que essa própria capacidade de perceber contexto costuma faltar bastante em quem faz vibe coding. Muita gente já tinha pouca experiência de programação antes mesmo dos LLMs.
Isso só funciona se as mensagens de commit forem bem escritas. Na prática, a maioria é algo como "ajuste neste arquivo" ou "corrige bug".
Ao usar LLM, ferramentas automatizadas como linter, formatter e checagem estrita de tipos ajudam muito. Isso vale especialmente quando contribuições chegam de alguém — ou de um agente LLM — que não conhece o estilo do código nem as convenções implícitas. Dá para inspecionar automaticamente e corrigir na hora o que for possível. O mesmo vale para testes. Um sistema automatizado de validação é muito útil para manter qualidade, seja o autor humano ou agente.
Acho que, na prática, essas ferramentas não impedem a maior parte dos casos de vibe coding mencionados no artigo.
Às vezes essas ferramentas só deixam a superfície arrumada enquanto escondem o problema real.
Todos os principais assistentes de IA já embutem formas de mitigar esse tipo de problema por padrão, como o
/initdo Claude Code e o/Generate Cursor Rulesdo Cursor. Isso permite aplicar orientações em escala na organização de um jeito mais automatizado do que simples context engineering. No fim, também é interessante observar como essas ferramentas acabam dividindo a comunidade de desenvolvimento.Na prática, mesmo quando tudo está muito claramente definido em
CLAUDE.md, o CC (Claude Code) muitas vezes ignora. Conforme a conversa vai avançando, parece repetir os mesmos problemas, e eu ainda não encontrei uma solução totalmente satisfatória. Por isso, não acho correto descartar este artigo como se fosse apenas mais um texto anti-IA.Estou reavaliando o Cursor. A razão de ele não entregar a velocidade esperada não são só erros pequenos (como o modelo trocar
:por,), mas também o fato de a codebase ser grande demais, antiga demais e ter qualidade muito inconsistente. O LLM tende a copiar mais os padrões mais comuns — que muitas vezes são os piores. Mesmo quando você diz claramente "use esta parte como referência", ele continua sendo influenciado pela codebase inteira. E, mesmo colocando isso em rules, não parece muito diferente de colocar direto no prompt. Fico me perguntando se existe alguma solução para isso.O cerne do problema não é a ferramenta, e sim o "coder" obcecado pela vibe: alguém que escreve código sem zelo.
Pela minha experiência, quase todos esses problemas são resultado de janela de contexto limitada e de um "context engineering" subótimo. Quando o LLM recebe bem o contexto importante, como funções globais, ele até tende a usar isso relativamente bem. O problema é como manter e fornecer esse contexto sem interrupção. Espero muitos avanços nisso com abordagens como sub-agents.
Concordo com tudo isso. A melhor forma de usar LLM é como o compilador oferece um nível acima da linguagem de montagem: você descreve claramente requisitos, entrada e saída, e ele faz uma tradução lógica para código. Por isso é preciso minimizar a confusão (entropia) na entrada. O LLM é, por natureza, uma translation engine; ele funciona melhor quando usado para traduzir, não para "gerar". Ainda assim, periodicamente surgem modelos mais inteligentes e intuitivos, e isso faz com que seja necessário se preocupar menos para obter bons resultados. No fim, vai chegar um momento em que o LLM entregará resultados melhores do que desenvolvedores humanos em qualquer tarefa, assim como acontecerá com outros papéis humanos.
É uma analogia errada. LLM não é um motor que "compila" linguagem natural em código de alto nível. Linguagens de programação e linguagem de máquina exigem um sistema de significados claro e consistente, enquanto linguagem natural pertence a outra camada de abstração. O mesmo LLM pode produzir respostas diferentes com outra seed ou outra versão. Já um compilador, com a mesma entrada, precisa obrigatoriamente produzir a mesma saída.
Também não concordo com a ideia de LLM como uma camada de abstração tipo compilador. Na prática, LLM é só um gerador arbitrário de tokens. Nunca vi um produto feito com LLM que fosse realmente bom o suficiente para uso sério. Esse tecnootimismo de singularidade ou dados infinitos não tem base realista. Conseguir dados de alta qualidade custa caro demais. No momento, previsões esperançosas são inúteis.
Demorei mais do que o autor para entender que "muita gente prefere café rápido e barato a café bom". No mundo real, a maioria valoriza mais velocidade e preço do que qualidade.
O post no HN está mais gostosinho do que o próprio texto