Code Reviews em Equipas Pequenas: Processo que Escala de 3 a 5 Developers
TL;DR
- Code reviews em equipas de 3-5 pessoas precisam de automação pesada (linters, type checkers) para não virarem gargalos: aponta erros óbvios antes de humanos lerem código.
- Dois tipos de PR: "bloqueantes" (lógica crítica, dados, segurança) e "não-bloqueantes" (UI, docs, refactor): critérios claros = ciclos mais rápidos.
- Máximo 1 aprovador por PR em não-bloqueantes, 2 em bloqueantes: menos confusão, responsabilidade clara, e mantém velocidade acima de tudo.
- Template de PR obrigatório com contexto + screenshot/vídeo: reduz perguntas durante revisão e economia de ~30% do tempo de feedback.
- Rotação semanal de "reviewer da semana": evita bottleneck numa única pessoa e força toda a gente a conhecer o código.
O Problema Real com Code Reviews em Equipas Pequenas
Quando tens 3-5 developers, code review é um dilema classicamente português: ou fazes superficialmente e quebras coisas, ou fazes a sério e ninguém consegue ser produtivo porque fica tudo à espera de aprovação.
Vi isto inúmeras vezes. Uma startup fintech com 4 engineers onde cada PR passava por 3 pessoas, 2 rondas de comentários, e demorava 48 horas a ser merged. Resultado: developers em ping-pong permanente, features a atrasar, moral em baixo. Ninguém estava satisfeito: nem quem fazia review (pressão constante), nem quem abria PR (sentia-se microscopado).
O verdadeiro problema é que code review em equipas pequenas é essencialmente um acto de confiança combinada com verificação automatizada. Não podes permitir-te ter humanos a fazer linting ou a procurar bugs óbvios. Precisas de máquinas a fazer o trabalho sujo, e humanos focados em lógica, arquitectura, e segurança.
1. Automação: Metade da Batalha já Ganha
Antes de qualquer humano ler a tua PR, ela tem de passar por um gauntlet de verificação automatizada. Isto não é luxo. É obrigatório.
O mínimo absoluto:
- Linting e formatting (ESLint, Prettier para JavaScript/TypeScript; rustfmt para Rust; black para Python).
- Type checking (TypeScript stricto, mypy, ou equivalente).
- Testes unitários e integração (Jest, Vitest, pytest: pelo menos 70% coverage nas funcionalidades novas).
- Security scanning (Snyk, GitHub Advanced Security, ou semelhante).
- Build success (a PR tem de compilar/passar em staging antes de sequer chegar ao olho humano).
Configurar isto corretamente poupava tempo bruto num projecto interno. Um CRM em Next.js com Convex que tínhamos, antes de introduzir CI/CD decente, recebia PRs com erros de TypeScript que só eram apanhados em review. Depois de setup correcto com GitHub Actions (10 minutos de configuração), 40% das PRs falhavam automaticamente antes de chegarem a um humano.
Aqui está um exemplo real de CI/CD pipeline para uma stack Next.js + TypeScript + Convex:
name: PR Validation
on:
pull_request:
branches: [main, develop]
jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: "22.0.0"
cache: "npm"
- run: npm ci
- name: TypeScript Check
run: npx tsc --noEmit
- name: Lint
run: npm run lint
- name: Format Check
run: npx prettier --check .
- name: Unit Tests
run: npm run test:unit
- name: Build Check
run: npm run build
- name: Security Scan
run: npx snyk test --severity-threshold=high
database:
runs-on: ubuntu-latest
if: contains(github.head_ref, 'schema') || contains(github.head_ref, 'migration')
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: "22.0.0"
- run: npm ci
- name: Validate Migrations
run: npm run migrations:validate
Resultado esperado: De 5 PRs abertas, 2-3 falham automaticamente. Developer arranja, refaz PR em 5 minutos. Humano só vê PRs que passaram nas máquinas.
2. Classificar PRs: Bloqueantes vs Não-Bloqueantes
Nem todas as PRs têm o mesmo risco. Tratar uma mudança de CSS igual a uma mudança de lógica de pagamento é estúpido.
Define dois tipos claros:
Bloqueantes (requerem 2 aprovações):
- Qualquer mudança a código crítico: lógica de pagamento, autenticação, acesso a dados sensíveis.
- Mudanças a schema de base de dados ou migrations.
- Alterações a infraestrutura ou CI/CD.
- Qualquer coisa que afecte SLA ou uptime.
Não-bloqueantes (1 aprovação, mais rápido):
- UI/UX (exceto se mudar fluxo crítico).
- Refactorings internos que mantêm comportamento.
- Documentação.
- Testes novos.
- Dependências não críticas.
Exemplo: Um formulário de contacto pode passar com 1 review. Um webhook de confirmação de pagamento não.
Configure isto no GitHub com branch protection rules:
Branch: main
Require a pull request before merging
Require approvals: 1 (ou 2 consoante label)
Require conversation resolution before merging: true
Require status checks to pass: true (CI/CD pipeline)
E usa labels automáticos no template de PR (vê próxima secção).
3. Template de PR: Contexto é Ouro
A maioria das equipas abre PRs com descrição a 2 linhas. Depois a revisão fica um ping-pong de perguntas: "Porque mudaste isto?", "Isto afecta X?", "Testaste com Y?".
Um template obrigatório reduz isto drasticamente. Aqui está um que realmente funciona:
## Descrição
Breve resumo do que muda e porquê.
## Contexto
- Issue/ticket associado (link)
- Porquê esta abordagem vs alternativas
- Impacto em partes do sistema
## Screenshots / Vídeo
[Se é mudança visual, anexa screenshot. Se é fluxo complexo, vídeo de 15s]
## Checklist
- [ ] Testes novos ou actualizados
- [ ] Documentação actualizada
- [ ] Sem breaking changes (ou documented)
- [ ] Testado em staging
- [ ] Performance verificada (se aplicável)
## Tipo de PR
<!-- Remove os que não aplicam -->
- Bug fix
- Feature
- Refactor
- Docs
- Infrastructure
<!-- Requer 1 ou 2 aprovações? -->
- [ ] Bloqueante (2 aprovações necessárias)
Isto não é boilerplate vazio. Obriga o developer a pensar antes de abrir PR, e economiza 30-40% do tempo de revisão porque o contexto já está lá.
4. Rotação de Reviewer: Evita Bottleneck
Uma equipa de 4 pessoas, 1 reviewer "natural" (senior, ou "o que percebe de tudo"), e de repente essa pessoa está num inferno: 8-10 PRs pendentes, Slack cheio, produtividade própria destroçada.
Solução: Rotação semanal de reviewer designado.
Segunda: Developer A é reviewer. Terça: Developer B. Quarta: Developer C. Quinta/Sexta: Developer D. Próxima semana recomeça.
Regra de ouro: Se é o teu dia de review, dedicar 2 horas de manhã e 1 de tarde especificamente a reviews. Código pessoal pausa.
Benefício adicional: Toda a gente aprende o código da equipa ao ter de o revisar. Não há "a pessoa que sabe disto".
Ferramentas como GitHub assignee automation ou Slack bots podem avisar quem é o reviewer do dia:
# Script simples que roda num workflow
REVIEWERS=("alice" "bob" "charlie" "diana")
DAY=$(date +%A)
WEEK_NUMBER=$(date +%V)
REVIEWER_INDEX=$((WEEK_NUMBER % ${#REVIEWERS[@]}))
REVIEWER=${REVIEWERS[$REVIEWER_INDEX]}
echo "🔍 Reviewer desta semana: $REVIEWER"
5. Timing: SLA para Reviews
"SLA para reviews? Não parece um bocado corporativo?"
Talvez. Mas sem deadline, PRs ficam esquecidas. Aqui está o que funciona:
- Bloqueantes: Aprovação ou feedback em 4 horas de trabalho.
- Não-bloqueantes: Em 24 horas.
- Se depois de 48h ninguém respondeu: Author tem permissão para ping directamente Slack ou self-merge (com cautela).
Isto elimina o "ei, esqueceste da minha PR" que consome energia mental.
6. Feedback Construtivo, Não Gatekeeping
Um gotcha real que vejo: reviewers transformam-se em gatekeepers. "Isto não é como eu faria", "Prefiro este padrão".
Diferenciar:
- Must-fix (segurança, performance, bugs): Bloqueador real.
- Should-consider (style, optimizações menores): Sugestão.
- Nice-to-have (nitpicks): Comentário educacional, não bloqueia.
Marcar claramente no comentário:
❌ MUST-FIX: SQL injection risk aqui. Preparestatement obrigatório.
💡 SHOULD-CONSIDER: Cached result aqui? User.getById é N+1 a database.
📚 NICE-TO-HAVE: Conhecias que lodash tem memoize? Mais elegante que isto.
Isto mantém a qualidade sem criar fricção.
7. Merge Strategy: Squash vs Rebase vs Merge
Para equipas pequenas, a recomendação é squash + rebase:
- Squash: Uma PR = Um commit (história limpa, fácil revert).
- Rebase: Mantém linha temporal linear, evita merge commits.
Configure no GitHub:
Settings > Pull Requests > Allow squash merging ✓
Allow merge commits ✗
Allow rebase merging ✓
E no momento de merge, o GitHub oferece a opção. Padrão: squash com mensagem clara.
Squash commit: "feat: add two-factor auth to login flow (#234)"
8. Armadilha Comum: Perfeccionismo Paralisa
Vira-se isso com frequência: Revisor quer que a PR seja perfeita. Developer adiciona 15 comentários. Author fica desmotivado. Feature arrasta-se por uma semana.
Regra: Se a PR passa testes, mantém standard de qualidade existente, e não quebra nada, aprova-a. Refactorings "mais perfeitos" vão para a próxima iteração, ou é task separada.
Código 80% agora é melhor que código 100% em 3 semanas.
Conclusão
Code review em equipas pequenas é menos sobre ser perfecionista e mais sobre ser prático. Automação pesada, critérios claros, rotação para evitar bottlenecks, e feedback focado em segurança + arquitetura. Isto escala de 3 developers a 5 sem implosão.
Se estás a enfrentar um problema parecido, marca uma conversa em https://impact-origin.com/agendamento.
