Nesta página
  1. O problema não é a IA
  2. Atalho
  3. Bug
  4. Segurança
  5. Como usar direito
  6. Júnior vai sumir?

Vibe coding é armadilha

4 miniacodigo

O prompt é o pedido que você escreve pra IA. "Faz um app de agendamento". Em dez minutos tem tela, botão e uma lista. Aí dois clientes marcam o mesmo horário, ou o botão diz que salvou e o banco está vazio. Banco é onde a agenda fica gravada. Alguém pergunta por que quebrou. Se a resposta não sai, o problema não foi a velocidade. Foi aceitar código que você não consegue explicar.

Prompt curto, app de agendamento em dez minutos. Dois horários iguais entram, ou o catch devolve ok e a linha não existe. Se você não explica o código, a velocidade não era o problema.

O problema não é a IA

A IA acelera quem já sabe o que tem que existir. Para quem não sabe, ela esconde a parte que precisava ser aprendida. A trava é uma regra que o banco aplica sozinho. Ela falha em três lugares.

A IA acelera quem já sabe a invariante. Sem ela, o modelo esconde o que você precisava aprender. Três furos: constraint, erro engolido, RLS.

Atalho

Pular a parte de entender parece ganho. No agendamento, entender é uma frase: o mesmo profissional não pode ter dois horários iguais. Insert é o pedido de gravar uma linha. Sem a trava no banco, os dois inserts passam. A tela mostra os dois. O código "funcionou".

A invariante é uma: o mesmo profissional não pode ter dois inícios iguais. Sem unique (profissional_id, inicio), os dois inserts passam. Não há erro. Há duplicata, e você procura bug na tela.

Sem a trava, as duas linhas ficam.
profissionalinício
o mesmo15:00
o mesmo15:00
agenda.sql · sql
alter table public.agendamentos
  add constraint um_horario_por_profissional
  unique (profissional_id, inicio);

Com a trava, o segundo pedido de gravar é recusado. Aí existe um erro pra ler. Sem a trava, os dois entram. Você procura o problema na tela, e a tela está certa.

Com a constraint, o segundo insert falha. Sem ela não há exception. Há duas linhas.

Bug

Este é o tipo de função que a pressa aceita. Catch é o trecho que pega a falha. Neste, ele pega e responde que deu certo. O botão fica verde. A linha não foi salva.

O catch devolve sucesso. A UI fica verde. A linha não foi salva.

O botão ficou verde. O banco está vazio.
telabanco
Salvonada
criar.js · javascript
async function criarAgendamento(dados) {
  try {
    await salvar(dados);
    return { ok: true };
  } catch (erro) {
    return { ok: true };
  }
}

Você não sabe onde procurar porque o aviso sumiu. O lugar é o catch. Ele tem que devolver o erro, ou mostrar a mensagem, não fingir que deu certo.

O catch apagou o stack. Devolva o erro, ou a mensagem. Não retorne ok.

Segurança

RLS é a regra de quem pode ler cada linha. Sem ela, a chave pública do site, a que vai no navegador, lê a agenda de todo mundo. A chave secreta é a de administrador. Se ela estiver no JavaScript da página, quem abre o site copia a chave.

Tabela sem RLS, lida pela anon key no navegador, devolve a agenda inteira. Service role no JavaScript ignora qualquer policy.

rls.sql · sql
alter table public.agendamentos enable row level security;

create policy "cada um vê o seu"
on public.agendamentos
for select
to authenticated
using ((select auth.uid()) = user_id);

Como usar direito

IA é dupla, não muleta. Quem responde pelo código continua sendo você. Estas cinco regras cabem num arquivo. Cada uma existe para você não aceitar o próximo arquivo no escuro.

Prompt é o pedido. Commit é um ponto salvo do projeto: se a próxima mudança quebrar, você volta nele.

  1. Uma tarefa por prompt. "Cria a trava de horário único" é uma tarefa. "Faz o app inteiro" mistura tela, banco e regra, e você não revisa nada.
  2. Peça para explicar o código antes de aceitar. Se a explicação não diz o que muda no banco e qual erro ela engole, não entra.
  3. Leia a doc oficial da ferramenta que o código usa. Texto de blog e resposta de chat atrasam. A página da RLS, do framework ou da API é a fonte.
  4. Commit antes de pedir a próxima mudança. Se a alteração quebrar, você volta num comando, em vez de caçar o que mudou no meio de dez arquivos.
  5. Teste o caso que dói. Dois horários iguais. Usuário sem id. Salvamento que falha. Se só o caminho feliz foi clicado, o app não foi testado.

Um prompt de revisão que dá para colar em cima de qualquer função gerada:

revisar.txt · text
Explica essa função como revisão de código.
O que ela grava no banco?
Qual erro ela esconde?
O que acontece se o id do usuário vier vazio?
Não mude o arquivo. Só responda.

Júnior vai sumir?

Não. Some a tarefa de digitar o óbvio sem saber o que ele faz. Continua o trabalho de ler o erro, achar a linha e decidir se a regra do negócio está no banco.

Quem está começando e usa a IA para perguntar "por que esse catch devolve ok?" aprende mais rápido do que quem datilografava a mesma função em 2019. Quem cola o app inteiro e não sabe responder quando quebra fica travado. Isso não é só júnior. Sênior nesse modo trava do mesmo jeito, só que o estrago é maior.

Se você discorda, o argumento tem que dizer qual trabalho some e quem passa a fazer essa parte. "A IA faz tudo" não responde quem olha o banco quando dois horários iguais entram.