mozak.tech Engenharia de IA Corporativa 41%

Parte I — Alicerces da Inteligência Artificial Moderna

1.7 — Ferramentas de IA no Fluxo de Trabalho do Desenvolvedor (AI Dev Tools)

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ódigo

O 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 testes

3. 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 unknown

Fluxo 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ódigo

Isso 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 React

Exemplo 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.

⚗ Laboratório prático — mozak.tech
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.