Eu tive uma ideia que não me deixou dormir: e se eu construísse um app inteiro usando IA, do zero até produção, sem escrever uma linha de código manualmente?

Não estou falando de pedir pro ChatGPT gerar um CRUD e copiar no VSCode, ou para o Copilot completar funções aqui e ali.

Estou falando de usar o Claude Code como as minhas mãos. Ele lê os arquivos, escreve o código, roda os testes, faz commit, executa comandos no servidor. Eu defino o que fazer, reviso o que foi feito, e tomo as decisões de arquitetura.

O resultado foi o MapWise: um editor de mapas com tracking em tempo real, import de CSV, camadas geométricas, agrupamento de markers, e um chat com IA para gerenciar o mapa em linguagem natural. Rails 8, SQLite, Hotwire, Google Maps, Action Cable, deploy no GCP com Kamal.

61 commits. 507 testes. ~12 mil linhas de código. 5 dias.

Esse post é o relato honesto dessa experiência - o que funcionou, o que quebrou, e o que eu aprendi sobre o que significa ser desenvolvedor quando a IA escreve o código.

O experimento

A regra era simples: eu não digitaria código. Toda linha de Ruby, JavaScript, HTML e CSS seria escrita pelo Claude Code. Eu podia (e devia) revisar tudo, pedir mudanças, rejeitar abordagens, e definir a arquitetura. Mas as mãos no teclado eram da IA.

Isso inclui coisas que você não esperaria: ele rodava bin/rails test, analisava os erros, corrigia e rodava de novo. Ele fazia git commit e git push. No deploy, ele literalmente executou gcloud compute instances create pra criar a VM, instalou Docker via SSH, configurou o Kamal e rodou bin/kamal setup.

Não era pair programming. Era mais como ser um arquiteto de software que dirige um desenvolvedor muito rápido, muito obediente, e ocasionalmente teimoso.

O plano

Antes de abrir o terminal, eu sentei e escrevi um plano. Não um plano vago - um documento com fases, features por fase, decisões de arquitetura, stack, e a ordem de execução. Eu sabia o que queria antes de pedir qualquer coisa pra IA.

Isso é crucial, e é o ponto que mais quero enfatizar: a IA é um amplificador do desenvolvedor que você já é.

Se você é um dev experiente que sabe tomar decisões de arquitetura, sequenciar trabalho, e identificar problemas - a IA amplifica isso. Você produz em 5 dias o que levaria semanas. Mas se você não tem essa base, a IA vai amplificar a falta dela. Vai gerar código que parece funcionar mas que é mal estruturado, sem testes, com abstrações erradas, e que vira um pesadelo na primeira mudança.

A IA não compensa falta de experiência. Ela acelera a experiência que você tem.

A jornada em fases

O projeto passou por 6 fases, cada uma planejada de antemão. Cada fase era uma sessão (ou duas) de conversa onde eu apresentava o plano e ia guiando a IA pra executar.

Fase 1: O básico

Auth, CRUD de mapas, editor com sidebar, markers no mapa, estilos, API keys, embed via iframe, dashboard. A base do app.

Aqui a IA voou. CRUD é o pão com manteiga de todo framework, e o Claude fez isso rápido e limpo. Eu defini a regra: controllers nunca falam com o banco direto - tudo passa por service classes. Ele seguiu à risca. Maps::Create.call, Markers::Update.call, cada ação isolada numa classe.

O primeiro momento “hmm” foi com o Google Maps. Existem dois modos de renderização que são mutuamente exclusivos: se você passa um mapId, ele usa AdvancedMarkerElement com estilos na nuvem; sem mapId, usa Marker legado com JSON styles. A IA tentou usar os dois ao mesmo tempo. Não funciona. Tive que explicar a restrição e ele refez.

Lição: a IA é boa em padrões comuns. Quando a API tem regras implícitas ou armadilhas não documentadas, você precisa saber o suficiente pra corrigir.

Fase 2: O editor de verdade

Import de CSV/Excel com mapeamento de colunas, clustering de markers, grupos com seleção por círculo no mapa, info windows, camadas geométricas com Terra Draw (polígonos, linhas, círculos, freehand), multi-marker placement.

Essa fase teve os maiores tombos.

Terra Draw crasha em modo readonly. A IA inicializou o Terra Draw no viewer (read-only) e o app explodiu. A solução? Pular initTerraDraw() completamente no viewer e renderizar camadas via Google Maps Data layer. Ele levou uns 3 tentativas pra acertar isso porque ficava tentando “consertar” o Terra Draw ao invés de contornar.

Comunicação entre Stimulus controllers. O sidebar e o mapa são elementos irmãos no DOM - um Stimulus controller não alcança o outro diretamente. A IA tentou várias gambiarras antes de eu pedir pra criar um módulo utilitário (utils/controllers.js) com helpers como findMapController(). Daí em diante, tudo fluiu.

CSV.open vs CSV.read. CSV.open(path, headers: true).headers retorna true. Sim, o booleano true. A IA ficou presa num loop tentando debugar por que os headers não apareciam. Esse é o tipo de bug que uma pessoa resolveria em 5 minutos no Stack Overflow, mas que a IA não tem contexto pra perceber.

Fase 4: Tracking em tempo real

Webhooks pra receber posições de GPS, Action Cable pra broadcast em tempo real, trails com polylines, detecção de desvio de rota (Haversine + cross-track distance), alertas, playback histórico com controles de animação.

Essa foi a fase mais ambiciosa e onde a IA mais impressionou. Action Cable com Stimulus, diff-based rendering de markers (sem rebuild completo a cada update), paginação de tracking points - tudo funcionou de primeira ou com ajustes mínimos.

O cálculo de desvio de rota foi implementado com a fórmula de cross-track distance. Eu não pedi uma lib pra isso - o Claude implementou a matemática direto em Ruby. E acertou.

Fase 5: Chat com IA dentro do app

Um tab no editor onde você digita “cria 5 markers em São Paulo” e o chat cria. Usa RubyLLM com tool use - o modelo de IA chama ferramentas que manipulam o mapa.

O editor do MapWise com o chat de IA aberto - o usuário pede pra criar markers e a IA executa diretamente no mapa.

Meta: uma IA construindo a feature de IA do app.

Os problemas aqui foram todos de integração com RubyLLM. Os nomes de tools são auto-derivados do nome da classe com prefixo de módulo (ai_tools--create_marker), o que quebrava o tool use. Precisei de override manual. A DSL de params usa desc: ao invés de description: - a IA errou isso 3 vezes antes de eu mandar ela ler a documentação do gem.

E o RubyLLM não tem limite de iterações de tool use. Sem um guard no callback on_tool_call, o modelo fica em loop infinito criando markers. Isso eu tive que antecipar e pedir explicitamente.

Fase 6: Verificação de email

A fase mais “normal” - email verification com deadline de 7 dias, banner de aviso, bloqueio após expiração, letter_opener_web pra dev.

Aqui a IA fez tudo sozinha sem drama. Feature padrão, padrão limpo.

Os números

No final do dia 5:

Métrica Valor
Commits 61
Testes 507 (1297 assertions)
Cobertura 96% linhas, 85% branches
Ruby (app/) ~2.250 linhas
JavaScript ~3.170 linhas
Templates ERB ~2.165 linhas
Testes ~4.690 linhas
Deploy GCP VM, Kamal 2, zero-downtime

A IA escreveu cada linha. Eu não abri um editor de texto uma vez sequer.

O que a IA faz bem

Código estrutural. Controllers, services, models, migrations, rotas, testes - o pão com manteiga do Rails. Rápido, consistente, seguindo os padrões que eu defini.

Manter convenções. Uma vez que eu estabeleci a regra das service classes, o Claude nunca quebrou. Ele manteve namespaces, padrões de .call, :: prefix pra constantes top-level dentro de namespaces - tudo consistente ao longo de 61 commits.

Testes. A IA escreveu 507 testes. E não eram testes faz-de-conta - eram testes que pegavam bugs reais. Quando eu pedia uma feature nova, ele escrevia os testes junto e rodava pra garantir que passavam.

Tarefas repetitivas mas chatas. CRUD, fixtures, helpers de teste, boilerplate de Stimulus controllers. Coisas que você sabe fazer, mas que tomam tempo.

Exploração de APIs. Mesmo em cenários em que a documentação é obscura, a IA consegue explorar a API, chegando até mesmoa examinar o código-fonte de gems e bibliotecas pra entender como usar. É algo que eu costumava fazer, mas a IA faz isso melhor e mais rápido.

O que a IA faz mal

Saber quando parar. Às vezes o agente tenta fazer algo além do escopo definido ou tenta soluções muito complexas. Um exmplo que lembro é quando o Claude sugeriu uso de Thread.current pra compartilhar estado entre controllers. Ele não percebeu que isso era uma má ideia, e que existiam soluções mais simples.

Contornar ao invés de consertar. O instinto da IA é tentar consertar a causa raiz, mesmo quando a solução pragmática é contornar. O Terra Draw readonly é um exemplo: a solução não era “consertar o Terra Draw”, era “não usar Terra Draw nesse contexto”. Eu tive que dar essa direção.

O que eu aprendi: boas práticas de dev são boas práticas de IA

Essa é a conclusão mais inesperada do experimento. Tudo que um desenvolvedor competente já faz - e que a gente às vezes trata como “burocracia” - é exatamente o que faz a IA funcionar bem. Não é coincidência. São práticas que existem porque facilitam o trabalho de quem não tem o contexto completo na cabeça. E a IA é exatamente isso: alguém sem contexto que precisa de orientação clara.

Tenha um plano

Eu não comecei abrindo o terminal. Comecei escrevendo um documento com fases, features, stack, decisões de arquitetura. Antes de pedir qualquer coisa pra IA, eu sabia o que queria.

Sem plano, cada sessão vira um brainstorm. A IA não tem opinião sobre o que fazer primeiro - ela faz o que você pede. Se você não sabe o que pedir, o resultado é um código que vai pra todo lado.

O plano não precisa ser perfeito. O meu mudou várias vezes. Mas ter uma direção é a diferença entre construir um produto e gerar código aleatório.

Faça mudanças pequenas

61 commits em 5 dias dá uma média de 12 commits por dia. Cada commit era uma unidade coerente: uma feature, um fix, uma refatoração. Não era um commit gigante com “changes”.

Isso é importante por dois motivos. Primeiro, a IA erra menos quando o escopo é pequeno. Pedir “implementa o sistema de tracking completo” vai dar problema. Pedir “cria o model TrackedVehicle com webhook_token e active flag” funciona de primeira.

Segundo, commits pequenos são pontos de salvamento. Quando a IA faz besteira (e vai fazer), você tem pra onde voltar. Várias vezes eu pedi pra reverter uma abordagem e recomeçar de um commit anterior. Se tudo estivesse num commit só, não teria como.

Isso é o mesmo conselho que todo livro de engenharia de software dá. Não é novidade. Mas com IA, a consequência de ignorar esse conselho é amplificada.

Atualize a documentação a cada iteração

O Claude Code tem um arquivo de memória onde ele guarda contexto entre sessões. Depois de cada fase, eu pedia pra ele atualizar: quais decisões foram tomadas, quais armadilhas encontramos, quais padrões estabelecemos.

Na prática, era como manter um CLAUDE.md (ou AGENTS.md, ou qualquer nome) atualizado. Quando uma sessão nova começava, a IA lia esse arquivo e já sabia: “ah, controllers usam service classes, Terra Draw não pode rodar em readonly, nomes de tools do RubyLLM precisam de override manual.”

Sem essa documentação, cada sessão começaria do zero. A IA não lembra o que fez ontem. Ela lê o código e os docs. Se os docs estão desatualizados, ela vai repetir os mesmos erros.

Isso é idêntico ao que acontece com devs humanos num time. Se não tem doc, o dev novo vai cometer os mesmos erros que o time já resolveu. A IA é o dev novo eterno - ela sempre precisa de contexto.

Escreva código fácil de mudar

Service classes com uma responsabilidade. Controllers magros. Módulos utilitários compartilhados. Nomes claros. Testes.

Não é porque a IA escreveu o código que ele pode ser bagunçado. Na verdade, é o oposto: código bem estruturado é mais fácil pra IA entender e modificar. Quando eu pedia uma mudança num service class isolado, a IA acertava de primeira. Quando a mudança envolvia código acoplado, ela tropeçava.

Código manutenível não é vaidade. É pragmatismo. Facilita mudanças - tanto pra humanos quanto pra IA.

Testes não são opcionais

507 testes. Toda feature nova vinha com testes. A IA rodava bin/rails test depois de cada mudança e corrigia o que falhava.

Isso me salvou mais vezes do que eu consigo contar. A IA às vezes faz uma mudança que quebra algo em outro lugar - algo que ela não percebe porque não tem o contexto completo. Os testes pegam. Sem eles, esses bugs iriam pra produção silenciosamente.

A IA como amplificador

Volto ao ponto central: a IA é um amplificador do desenvolvedor que você já é.

Se eu não soubesse que service classes são uma boa ideia pra esse tipo de app, a IA não teria sugerido. Se eu não soubesse que Terra Draw crasha em readonly, a gente teria ficado preso por horas. Se eu não tivesse um plano com fases claras, cada sessão teria sido um caos sem direção.

O plano veio de mim. As decisões de arquitetura vieram de mim. A identificação dos problemas veio de mim. A IA executou.

Fred Brooks, no ensaio No Silver Bullet, faz a distinção entre complexidade essencial e acidental de software. A essencial é a parte conceitual - as estruturas, a lógica, as relações entre as coisas. A acidental é a parte mecânica - sintaxe, ferramentas, linguagens. A IA resolve boa parte da complexidade acidental. A essencial continua sendo sua.

Se você é um dev que sabe tomar decisões, sequenciar trabalho, e manter código limpo - a IA te transforma numa máquina. Se você não tem essa base, ela vai amplificar a falta dela. Vai gerar código que parece funcionar mas que é mal estruturado, sem testes, com abstrações erradas, e que vira um pesadelo na primeira mudança.

O desenvolvedor do futuro não é o que digita mais rápido. É o que pensa melhor.

O MapWise ainda não está pronto pra clientes - falta domínio e envio de email em produção. Mas o app está deployado, funcional, com 507 testes passando e zero-downtime deploy. O ponto não é que está perfeito - é que um agente de IA entregou software de produção. Não um protótipo, não uma demo, não um “vibe coding” descartável. Software real, com arquitetura real, testado, deployado.

E eu não sou o único. O Fábio Akita entregou um produto do zero à produção em 6 dias - e já tem assinantes. O Bun não foi construído com IA, mas hoje usa pesado: o criador do Bun, Jarred Sumner, contou no X que já mergearam pelo menos 84 PRs do Claude em um mês.

Tweet do Jarred Sumner - "In Bun's repo, we've merged at least 84 PRs from Claude since last month."

Isso não é mais experimento isolado. É um padrão emergente: devs experientes usando IA como alavanca pra entregar produtos inteiros em dias, não meses.

A parte mecânica está sendo automatizada. A parte que exige julgamento, experiência e visão vai ser o diferencial.

E olha - eu construí um app de produção inteiro em 5 dias. Sozinho. Com IA. Isso não é o futuro. Isso já é o presente.

Por hoje é só.