Objetivo da Aula
Comparar ferramentas de copilot de código (Cursor, Copilot, Windsurf) com critérios técnicos objetivos para escolher a adequada para cada contexto
Escrever um .cursorrules (ou equivalente) que instrua o copiloto sobre o stack, padrões e restrições do projeto
Identificar quando copilots de IA aceleram genuinamente vs quando introduzem dívida técnica invisível
Configurar um fluxo de trabalho que usa IA para geração e o dev para revisão crítica, sem criar dependência cega
Mensurar a produtividade real de copilots com métricas concretas
Por que isso importa
Um engenheiro de IA que não sabe usar ferramentas de IA para programar está na situação de um carpinteiro que não usa parafusadeira. As ferramentas existem, você vai competir com quem as usa bem.
Mas o risco oposto é real: “vibe coding” — usar copilot para gerar código sem entender o que foi gerado — cria sistemas frágeis que o autor não consegue manter, debugar ou escalar. Cases de falha:
Case 1: Dev usou Cursor para gerar uma implementação de autenticação JWT. Funcionou nos testes. Em produção, 3 meses depois: a chave JWT estava hardcoded no código gerado. O copilot seguiu o padrão do exemplo que o dev deu — e o exemplo tinha a chave hardcoded. Ninguém revisou.
Case 2: Time de startup usou vibe coding para construir MVP em 2 semanas. Funcionou. Na rodada A, contrataram devs seniores para escalar. Levaram 3 meses para refatorar o código — mais tempo que teria levado construir do zero.
O equilíbrio: copilot é um amplificador. Se você sabe o que está fazendo, multiplica sua velocidade por 2-5×. Se não sabe, multiplica sua velocidade de criação de problemas pela mesma proporção.
Conceitos Fundamentais
Como copilots funcionam internamente
Copilots de código são LLMs treinados em código. Quando você escreve código no editor, o copilot recebe:
Contexto enviado ao modelo:
1. System prompt (regras do editor/provedor)
2. Arquivo atual (o que você está editando)
3. Arquivos relacionados (imports, tipos referenciados)
4. .cursorrules ou equivalente (suas regras customizadas)
5. Cursor/posição atual no códigoO modelo gera sugestões baseadas em tudo isso. A qualidade da sugestão depende diretamente da qualidade do contexto.
Implicação prática: Arquivos grandes (> 500 linhas) podem não caber inteiramente na context window. O copilot pode não “ver” funções que estão 300 linhas acima. Isso explica sugestões que duplicam código existente ou ignoram abstrações já definidas.
Comparativo de ferramentas (2025)
Ferramenta | Modelo padrão | Janela de contexto | Indexação de codebase | Melhor para |
Cursor | Claude 3.5/Sonnet | 200k tokens | ✓ Sim (Ctrl+K) | Refatoração de base existente, Chat com codebase |
Windsurf | Claude | 200k tokens | ✓ Sim (Cascade) | Multi-arquivo, agentes inline |
VSCode Copilot | GPT-4o | 128k tokens | Parcial | Autocompletar, integração nativa no VS Code |
JetBrains AI | Claude/Llama | Varia | ✗ Não | Ecossistemas Java/Kotlin, análise estática |
Zed | Claude | 200k tokens | ✗ Não | Performance extrema, pair programming |
Quando Cursor bate VSCode Copilot: projetos com múltiplos arquivos relacionados onde você precisa que o copilot entenda a arquitetura completa. “Refatore essa função para usar o padrão Repository que já usamos em UserRepository” — Cursor vai encontrar e usar como referência. Copilot básico vai sugerir algo genérico.
Quando VSCode Copilot é suficiente: autocompletar em arquivos bem isolados, snippets repetitivos, documentação de funções simples.
O .cursorrules: seu system prompt para o copilot
.cursorrules é um arquivo de texto que o Cursor injeta no contexto de cada request. Pense como um system prompt do copilot especificamente para seu projeto.O arquivo tem 3 tipos de instruções:
1. Contexto técnico — o que o copilot precisa saber sobre o stack:
Stack: Next.js 14 App Router + TypeScript 5 + Prisma + PostgreSQL
Gerenciador de pacotes: pnpm (não npm ou yarn)
Node.js: 20+
Usar apenas APIs estáveis — nenhuma API "experimental"2. Convenções de código — padrões que você quer que o copilot siga:
Nomenclatura: camelCase para variáveis, PascalCase para classes/tipos
Imports: sorted — std lib, externos, internos; separados por linha vazia
Exports: named exports, nunca default exports em TypeScript
Async: sempre async/await, nunca .then()/.catch() exceto em testes3. Restrições de segurança — o que o copilot NUNCA deve fazer:
NUNCA: interpolação de string em queries SQL — use query params
NUNCA: chaves de API no código — use process.env
NUNCA: console.log em código de produção — use o logger configurado
NUNCA: any no TypeScript — use tipos explícitos ou unknownFluxo de trabalho: IA acelera, dev decide
O fluxo de trabalho que funciona em produção:
1. Dev especifica o OBJETIVO (em linguagem natural ou comentário)
"// implementar validação de CPF seguindo o algoritmo dos dois dígitos verificadores"
2. Copilot gera PROPOSTA
(código gerado automaticamente)
3. Dev REVISA criticamente:
- A lógica está correta?
- Há casos de borda não tratados?
- Segue os padrões do projeto?
- Introduz dependência desnecessária?
4. Dev AJUSTA (se necessário) e aprova
(merge ou aceitar sugestão)
5. Dev ESCREVE O TESTE
(nunca deixar o copilot escrever o teste do próprio código gerado — conflito de interesses)O passo mais importante: o dev escreve o teste. Copilot que escreve código + copilot que escreve o teste do próprio código = o teste vai passar, mas pode estar testando a coisa errada. Testes devem ser escritos com ceticismo sobre a implementação.
Aprofundamento Técnico
Indexação de codebase: como o Cursor entende seu projeto
O Cursor indexa seu repositório inteiro usando embeddings — converte cada arquivo em vetores e os armazena localmente. Quando você faz uma pergunta ou pede uma geração, o Cursor usa RAG:
Sua pergunta: "Como funciona o sistema de autenticação?"
↓
Cursor busca por similaridade nos embeddings do projeto
↓
Encontra: auth/middleware.ts, auth/jwt.ts, auth/types.ts
↓
Injeta esses arquivos no contexto junto com sua pergunta
↓
Claude responde com contexto real do seu códigoIsso explica por que Ctrl+K com “use o padrão de Repository do UserRepository” funciona — o Cursor encontra UserRepository por similaridade e injeta como exemplo.
Fundamento: Novo Perímetro de Dados com IA
Ao usar copilots de código (Cursor, GitHub Copilot), o contexto enviado ao provedor inclui arquivos abertos, histórico de edições, e às vezes o repositório inteiro. Segredos em .env, tokens em comentários, e credenciais em código saem para servidores de terceiros. Modelos de retenção variam por provedor — alguns usam seus inputs para treinar. O novo perímetro de dados vai além do perímetro de rede: qualquer dado no contexto de uma ferramenta de IA pode sair da sua rede. Regras mínimas: .env e arquivos de credenciais em .cursorignore e .gitignore; PII de usuários nunca deve aparecer no contexto antes de ser mascarado; revise a política de retenção do provedor antes de adotar em ambientes regulados.
Limitação: indexação leva tempo. Em projetos grandes (> 10k arquivos), a primeira indexação pode demorar minutos. Arquivos com segredos (.env) devem estar no .gitignore AND no .cursorignore para não serem indexados.
Quando copilot gera código ruim (e como detectar)
Sinais de código gerado que você deve rejeitar:
// ❌ Copilot gerou comentário que descreve o óbvio — não agrega
// Esta função retorna o usuário pelo ID
async function getUserById(id: string) { ... }
// ❌ Copilot duplicou lógica que já existe
function validateEmail(email: string) {
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)
}
// (se você já tem isValidEmail() em utils/validation.ts)
// ❌ Copilot adicionou import que não usa
import { useState, useEffect, useCallback, useMemo } from 'react'
// mas o componente usa apenas useState
// ❌ Copilot inventou uma API que não existe
const resultado = await openai.createCompletion({ // API antiga removida
model: 'text-davinci-003',
...
})A regra: se você não consegue explicar linha por linha o que o código faz, não faça merge. Isso é verdade para código humano também — mas a velocidade de geração de copilot torna o risco mais alto.
Métricas de produtividade com copilot
Como medir se você está sendo mais produtivo:
Métrica | Como medir | Meta razoável |
Aceitação de sugestões | % de sugestões aceitas sem modificação | > 30% = copilot entende seu contexto |
Tempo em code review do próprio código | Minutos de revisão por PR | Não deve aumentar com copilot |
Bugs introduzidos | Bugs/commit antes e depois de adotar copilot | Não deve aumentar |
Linhas de código/hora | LOC/hora bruta | Espere 2-3× de aumento |
Se bugs/commit aumentou após adotar copilot: você está aceitando sugestões sem revisar suficientemente.
Exemplos Anotados
Exemplo 1: .cursorrules completo para projeto Next.js + IA
# .cursorrules — Projeto AssAI Platform
# Atualizado: 2025-06
## Stack
- Next.js 14.2 com App Router (não Pages Router)
- TypeScript 5.4 strict mode (tsconfig.json tem strict: true)
- Anthropic SDK 0.55+ para chamadas de LLM
- Prisma 5+ com PostgreSQL 16
- pnpm como gerenciador de pacotes
## Padrões de código obrigatórios
### TypeScript
- Nunca use `any` — use `unknown` e faça type narrowing
- Prefira `interface` a `type` para contratos de objeto
- Todas funções async devem ter tipo de retorno explícito: `Promise<Result>`
- Use discriminated unions para estados: `type State = { status: 'loading' } | { status: 'done', data: T }`
### Imports
- Ordem: node built-ins, externos, @/internos, relativos
- Separar grupos com linha em branco
- Named exports sempre — nunca `export default` em TypeScript
### LLM e API Anthropic
- Modelo padrão: claude-haiku-4-5-20251001 para tarefas simples
- claude-sonnet-4-6 para raciocínio complexo
- Sempre incluir tratamento de RateLimitError com exponential backoff
- Logar input_tokens e output_tokens a cada chamada via logger.info()
- NUNCA armazenar respostas de LLM sem sanitizar PII primeiro
## Proibições absolutas
- NUNCA: SQL por interpolação de string. Use Prisma ou query params
- NUNCA: console.log — use o logger em src/lib/logger.ts
- NUNCA: chaves de API no código. Use process.env com validação no startup
- NUNCA: `process.exit()` em handlers — lance exceção e deixe o processo morrer limpo
- NUNCA: mutação de props em componentes ReactExemplo 2: Usando Cursor para refatorar com contexto de codebase
// Antes: código procedural para criar usuário
async function criarUsuario(email: string, nome: string) {
const hash = await bcrypt.hash('senha123', 10)
await db.query('INSERT INTO users (email, nome, senha_hash) VALUES (?, ?, ?)', [email, nome, hash])
}
// Depois: peça ao Cursor "refatore para seguir o padrão Repository de UserRepository"
// Cursor vai:
// 1. Encontrar UserRepository.ts no projeto
// 2. Usar como template para gerar o padrão consistente
// 3. Resultado:
// src/repositories/UsuarioRepository.ts
export class UsuarioRepository {
constructor(private readonly db: PrismaClient) {}
async criar(input: CriarUsuarioInput): Promise<Usuario> {
const senhaHash = await bcrypt.hash(input.senha, 10)
return this.db.usuario.create({
data: { email: input.email, nome: input.nome, senhaHash }
})
}
}Padrões e Armadilhas
Padrões recomendados
Padrão 1: Specifique o padrão existente, não o padrão genérico Em vez de pedir “implemente um serviço de email”, peça “implemente um serviço de email seguindo o mesmo padrão de NotificacaoService”. O copilot vai usar seu código como template em vez de inventar um padrão próprio.
Padrão 2: Escreva o esqueleto, deixe o copilot preencher Escreva a assinatura da função, o tipo de retorno, e os comentários explicando a lógica. Deixe o copilot gerar o corpo. Você garante a interface correta; copilot acelera a implementação.
Padrão 3: .cursorignore para arquivos sensíveis Assim como .gitignore evita que segredos vão para o git, .cursorignore evita que o Cursor indexe arquivos com credenciais, PII ou segredos de negócio. Inclua: .env, *.pem, secrets/, data/private/.
Armadilhas comuns
⚠️ Armadilha 1: Aceitar sugestão de autenticação sem revisar O que acontece: copilot gera implementação de JWT funcionalmente correta mas com expiresIn: '100y' ou sem verificação de iss/aud. Funciona nos testes. Em produção, tokens nunca expiram. Versão correta: código de segurança (auth, criptografia, validação de inputs) é revisado com dupla atenção. Tenha uma checklist específica para esses contextos.
⚠️ Armadilha 2: .cursorrules desatualizado O que acontece: você atualiza o Next.js de 13 para 14 mas não atualiza o .cursorrules. Copilot continua gerando código com APIs do Next.js 13 (Pages Router, getServerSideProps) que não existe no 14. Versão correta: trate .cursorrules como documentação técnica do projeto — atualize quando o stack muda.
⚠️ Armadilha 3: Usar copilot para entender código que você deveria entender O que acontece: você pede ao Cursor “o que esse código faz?” em vez de ler e entender. Você desenvolve dependência — sem copilot, você não consegue trabalhar. Em situações de urgência (incidente às 3h), você está travado. Versão correta: use copilot para acelerar coisas que você SABE fazer. Para entender código novo, leia você mesmo primeiro. Pergunte ao copilot para confirmar seu entendimento, não para construir o entendimento inicial.
Se não for realizar o laboratório, pule para o próximo capítulo.
Ponte para o Lab
Esta unidade não tem starter com TODOs de código — é uma atividade de configuração:
Atividade principal: adaptar o .cursorrules
O arquivo starter-cursorrules tem 10 regras comentadas com placeholders. Você vai:
Adaptar para seu stack: substitua “Next.js 14” pelo framework que você usa. Se usa FastAPI, mude as regras de TypeScript para Python + type hints.
Adicionar 2 regras específicas do seu projeto: pense em padrões que você já usa (ou deveria usar) que não estão no template. Exemplos: “use sempre o logger em src/utils/logger.py, nunca print()”, “commits em português”.
Adicionar 1 proibição absoluta relevante: algo que o copilot gerou errado no passado, ou que você quer prevenir. Exemplos: “NUNCA use Thread sem daemon=True em scripts Python”, “NUNCA importe módulos de teste em código de produção”.
Testar a configuração: peça ao copilot “escreva uma função que lê dados do banco de dados”. Veja se ele segue as regras que você definiu.
Dica para a parte mais difícil (identificar regras específicas): pense nos últimos 3 bugs que você ou seu time encontraram no code review. Cada um pode virar uma regra no .cursorrules.
Agora você está pronto para o lab.