Destino Dev

Blog

Pair programming em entrevistas técnicas: setup, roteiro e exercícios práticos

Por John Pires · 10 de março de 2026

Cenário prático do dia a dia

Pair programming em entrevistas técnicas é um método que se tornou padrão em várias empresas para avaliar habilidades reais de desenvolvimento: comunicação, pensamento em voz alta, design incremental e domínio de ferramentas. Devs com 1-3 anos de experiência geralmente têm fundamentos, mas tropeçam na transição entre raciocínio algorítmico e engenharia aplicada em um fluxo colaborativo. Este cenário descreve as fricções que aparecem em entrevistas remotas e presenciais e o que esperar ao conduzir ou participar de uma sessão pareada.

Na prática, você enfrenta três variáveis: (1) a tarefa técnica — algoritmo, API ou bugfix; (2) a plataforma — IDE compartilhada, editor local com tests, ou quadro branco; (3) o papel — entrevistador ou candidato. Cada combinação muda o conjunto de boas práticas necessárias. Uma sessão remota com Live Share e testes automatizados exige regras explícitas de controle de teclado, while-board ou mobbing demandam outras.

Um problema recorrente: a ansiedade do candidato que impede comunicação efetiva. Outra fricção: entrevistadores que esperam uma solução completa sem guiar por iteração. Há também aspectos técnicos práticos, como configurar dependências, executar testes e compartilhar contexto rapidamente. Resolver esses pontos reduz falsos negativos e aumenta a qualidade do match entre time e candidato.

Quando usar pair programming em entrevistas

Empresas usam pair programming para avaliar mais do que a solução final — avaliam processo, capacidade de decomposição, trade-offs e cultura. Use pair quando a vaga exige colaboração intensa, revisão em tempo real ou tomada de decisão arquitetural rápida. Para cargos muito algorítmicos puros, um coding problem em ambiente controlado pode ser suficiente; para cargos full-stack ou de time colaborativo, pair é superior.

Objetivos mensuráveis

Defina métricas simples: tempo até um PR inicial executando testes verdes, qualidade da comunicação (explicação de trade-offs), e capacidade de diagnosticar e corrigir um bug injetado. Ter objetivos mensuráveis reduz subjetividade e dá feedback objetivo ao candidato.

Regra prática: 5 minutos de setup, 30-40 minutos de desenvolvimento iterativo, 10-15 minutos de revisão e perguntas. Se o setup demora mais que 5 minutos, o processo técnico está falho.

Arquitetura da solução

Arquitetura no contexto de entrevistas pair deve ser minimalista, reprodutível e determinística. A ideia é ter um scaffold que permita ao candidato começar a entregar valor rápido: testes automatizados, um README claro com requisitos, exemplos de entrada/saída e scripts de inicialização. Isso reduz overhead e permite avaliar habilidades de fato.

Uma boa arquitetura para entrevistas remotas envolve três camadas:

  • Infra de execução: container ou Node.js local com scripts npm prontos;
  • Harness de testes: testes unitários e de integração rápidos (Jest/Mocha) que falham com mensagens claras;
  • Contrato mínimo: especificação reduzida (ex.: API REST com 2 endpoints ou função com contratos de entrada/saída), exemplos e dados de teste.

Por que essa arquitetura funciona? Porque ela separa o que contamina a avaliação — ambiente e setup — do que importa — capacidade de escrever código correto e comunicar raciocínio. Em vez de pedir que o candidato configure um banco de dados, pre-provide dados em memória ou fixtures. Prefira execução local com mocks ao invés de infra pesada.

Blueprint de repositório para entrevistas

Um repositório mínimo deve conter: package.json com scripts start/test, pasta src com código inicial, tests com casos de borda e README com o roteiro. Forneça scripts que rodem em um único comando: npm ci && npm test — isso é determinístico e rápido.

Controle de tempo e checkpoints

Implemente checkpoints no README: milestone 1 (parsing e casos básicos), milestone 2 (edge cases), milestone 3 (otimização). Isso dá estrutura ao roteiro e permite ao entrevistador intervir com hints quando o candidato empacar sem perder muito tempo.

Código completo com explicações

A seguir um exemplo prático: um exercício comum em entrevistas pair é implementar uma função que encontra a longest unique-character substring dentro de uma string — útil para avaliar sliding-window, complexidade e clareza. Este repositório simulado é Node.js com testes Jest e um pequeno Express para demonstrar uso em endpoint interno (útil quando a entrevista precisa cobrir API + algoritmo).

Contexto antes do primeiro bloco de código: abaixo está o arquivo src/longestUnique.js — implementa o algoritmo usando sliding window O(n) e retorna a substring mais longa sem caracteres repetidos.

// src/longestUnique.js
function longestUniqueSubstring(s) {
  if (typeof s !== 'string') throw new TypeError('input must be string');
  let start = 0;
  let maxLen = 0;
  let maxStart = 0;
  const lastIndex = new Map();

  for (let i = 0; i < s.length; i++) {
    const ch = s[i];
    if (lastIndex.has(ch) && lastIndex.get(ch) >= start) {
      start = lastIndex.get(ch) + 1;
    }
    lastIndex.set(ch, i);
    const len = i - start + 1;
    if (len > maxLen) {
      maxLen = len;
      maxStart = start;
    }
  }
  return s.slice(maxStart, maxStart + maxLen);
}

module.exports = { longestUniqueSubstring };

O que esse código faz: implementa a janela deslizante com mapa de ultimo índice visto. Complexidade O(n) tempo e O(k) espaço (k = charset). Após rodar, retorna a substring desejada.

Contexto antes do segundo bloco: agora mostramos um pequeno servidor Express que expõe um endpoint /api/longest que recebe { s: string } e retorna { result: string } — útil para exercícios que combinam API e lógica.

// src/server.js
const express = require('express');
const bodyParser = require('body-parser');
const { longestUniqueSubstring } = require('./longestUnique');

const app = express();
app.use(bodyParser.json());

app.post('/api/longest', (req, res) => {
  try {
    const { s } = req.body;
    const result = longestUniqueSubstring(s);
    res.json({ result });
  } catch (err) {
    res.status(400).json({ error: err.message });
  }
});

if (require.main === module) {
  const port = process.env.PORT || 3000;
  app.listen(port, () => console.log(`Server running on ${port}`));
}

module.exports = app;

O que acontece quando você executa: iniciar o servidor (node src/server.js) e fazer POST /api/longest com JSON retorna a substring esperada. Use curl ou Postman no pairing para validar comportamento end-to-end.

Contexto antes do terceiro bloco: inclua testes Jest que cobrem casos padrões, bordas e tipos inválidos — isso permite ao entrevistador rodar a suíte e usar falhas como pontos de diagnóstico durante a sessão.

// tests/longest.test.js
const request = require('supertest');
const app = require('../src/server');
const { longestUniqueSubstring } = require('../src/longestUnique');

describe('longestUniqueSubstring', () => {
  test('basic cases', () => {
    expect(longestUniqueSubstring('abcabcbb')).toBe('abc');
    expect(longestUniqueSubstring('bbbbb')).toBe('b');
    expect(longestUniqueSubstring('pwwkew')).toBe('wke');
  });

  test('edge cases', () => {
    expect(longestUniqueSubstring('')).toBe('');
    expect(longestUniqueSubstring('au')).toBe('au');
  });

  test('type validation', () => {
    expect(() => longestUniqueSubstring(null)).toThrow(TypeError);
  });
});

describe('API /api/longest', () => {
  test('returns result', async () => {
    const res = await request(app)
      .post('/api/longest')
      .send({ s: 'abcabcbb' })
      .expect(200);
    expect(res.body.result).toBe('abc');
  });

  test('handles invalid input', async () => {
    await request(app)
      .post('/api/longest')
      .send({ s: null })
      .expect(400);
  });
});

O que acontece quando roda: npm test executa Jest, os testes devem passar. Em uma sessão pair, peça ao candidato para primeiro rodar os testes, ver as falhas e concentrar-se em fazer um teste passar por vez — TDD rápido ajuda a guiar a sessão.

Tratamento de erros e edge cases

Erros comuns em entrevistas pair vêm em duas frentes: técnicos (bugs, edge cases não tratados) e interpessoais (silêncio, takeover do teclado). Aqui listamos armadilhas técnicas específicas e como detectá-las no código e no processo.

Erros técnicos frequentes

Na implementação do algoritmo acima, erros frequentes são: não validar tipos, não lidar com strings vazias, e esquecer de atualizar índices ao encontrar um caractere repetido. Esses problemas causam falhas silenciosas ou resultados incorretos para inputs específicos. Os testes devem cobrir esses casos.

Outra armadilha é esquecer casos com caracteres unicode que ocupam mais de um codeunit. Dependendo da linguagem e vaga, explique se o desafio precisa ser byte-aware ou codepoint-aware e como adaptar o algoritmo — por exemplo, usando [...s] para arrays de codepoints em JS.

Erros de processo durante o pair

Entrevistadores que tomam controle do teclado o tempo todo retiram a chance do candidato mostrar autonomia. Candidatos que não verbalizam raciocínio tornam difícil avaliar processo. Estabeleça regras no início: quem controla o teclado, quando pedir ajuda, e quando anotar pontos para discussão.

Dica prática: combine um driver e um navigator. Mude de função a cada 10-15 minutos. Driver codifica, navigator observa, planeja e faz perguntas. Isso aumenta sinal observável e diminui ansiedade.

Performance e otimização

Performance em entrevistas não é sobre micro-optimizações prematuras. É sobre reconhecer complexidade, justificar trade-offs e aplicar otimizações que fazem sentido. Use a implementação O(n) como baseline. Se o candidato propõe uma versão O(n^2), peça para estimar tempo em strings grandes e justificar escolha.

Em contextos full-stack, uma otimização sensata pode ser mover trabalho off the critical path (debounce, cache), ou escolher índices adequados em consultas. Durante pair, incentive candidatos a discutir custo espaço-tempo e impacto na experiência do usuário.

Medição rápida

Mostre números: escreva um script simples para gerar strings grandes e medir tempo de execução. Isso ajuda a demonstrar que a otimização proposta tem impacto mensurável. Exemplo de microbench (pseudocódigo): gerar 10M chars e medir performance; se a solução O(n) finalizar em poucas centenas de ms e O(n^2) em segundos, a escolha fica clara.

Quando parar de otimizar

Pare quando a complexidade adicional não agrega valor ao produto ou à vaga. Em entrevistas, explique o ponto de equilíbrio: se o algorithmic complexity já atende limites do problema, prefira clareza e testabilidade.

Conclusão prática

Pair programming em entrevistas é um instrumento que, quando bem arquitetado, reduz erros de avaliação e permite observar competências dynamics que testes isolados não capturam. A chave é minimizar overhead (setup rápido), estruturar checkpoints, oferecer testes fáceis de rodar e guiar a sessão com papéis claros.

Para o candidato: fale em voz alta, valide hipóteses, rode testes cedo e peça feedback. Para o entrevistador: prepare um scaffold reproduzível, tenha hints preparados e evite takeover desnecessário. Ambos ganham com uma sessão clara e iterativa.

Implementar o repositório de exemplo mostrado aqui (scaffold Node + endpoint + testes) reduz setup para menos de 5 minutos e cria espaço para avaliar comunicação, design incremental e capacidade de resolver problemas práticos em tempo limitado.

Próximos passos práticos: monte um template no seu org com package.json, scripts e testes; documente checkpoints no README; treine entrevistadores em técnicas de feedback e intervenção. A consistência do processo melhora a taxa de contratação e reduz vieses.

Resumo técnico final: prefira scaffolds determinísticos, cubra edge cases em testes, use sliding-window para problemas de substring única e estabeleça papéis e tempo para maximizar sinal durante a entrevista.

Assuntos: pair-programming, entrevistas-tecnicas, Node.js, Testes, algoritmos

Leia também