Perguntas de entrevista para programador / engenheiro de software e como respondê-las
Uma entrevista para programador raramente é um exame de definições. Quem te entrevista quer ver como pensas quando algo se parte, como decides entre dois designs imperfeitos e como trabalhas com código que não foste tu a escrever. Costuma haver uma parte técnica ou de coding (ao vivo ou um teste prévio), mas a maior parte do tempo passa-se a explicares as tuas decisões: porque escolheste aquela estrutura de dados, porque meteste uma fila em vez de chamar diretamente, porque é que aquele bug demorou três dias.
O que separa quem passa de quem não passa raramente é o conhecimento, mas sim a capacidade de raciocinar em voz alta sem bloquear. Muita gente sabe resolver o problema, mas cala-se enquanto pensa, ou despeja a solução sem explicar o caminho. Aqui tens perguntas específicas do cargo com um guia para orientar cada uma. Lê-as, mas não fiques por aí: a resposta só conta se a souberes dizer sob pressão.
O que avaliam nesta entrevista
- Resolução de problemas e raciocínio técnico em voz alta
- Debugging sistemático sob incerteza
- Design e arquitetura: gerir trade-offs sem resposta única
- Qualidade de código e colaboração em code reviews
- Comunicação: explicar decisões técnicas com clareza
- Gestão de código herdado e dívida técnica
Perguntas frequentes para programador / engenheiro de software
- 01
Conta-me o bug mais difícil que já depuraste. Como o encontraste e porque é que te deu tanto trabalho?
Não descrevas o bug, descreve o teu método: como o reproduziste, que hipóteses descartaste e como isolaste a causa. O que avaliam é o teu processo de debugging, não a anedota.
Exemplo de resposta «Tínhamos um erro de pagamentos que só aparecia em produção, uma em cada mil transações. Primeiro consegui reproduzi-lo: capturei os payloads reais dos casos falhados e montei um teste que os reproduzia em local. Descartei o gateway de pagamento comparando os seus logs com os nossos, e descartei dados corrompidos validando o esquema. No fim era uma condição de corrida: dois webhooks do mesmo pagamento chegavam com milissegundos de diferença e o segundo sobrepunha-se ao primeiro. Deu-me uma semana de trabalho porque o log agregado escondia a ordem real de chegada. Resolvi-o com um lock por id de pagamento e acrescentei um teste de concorrência para que não voltasse a acontecer.»
- 02
Estás numa code review e um colega assinala que a tua solução não escala. O que fazes?
Mostra que separas o ego do código. Conta como pedes o caso concreto que quebra a tua abordagem, que perguntas fazes para perceber o limite real e quando aceitas por oposição a quando defendes com dados.
Exemplo de resposta «A primeira coisa é pedir-lhe o caso concreto: a partir de que volume é que a minha abordagem deixa de funcionar? Se me disser que com 10 000 elementos por pedido o meu ciclo dispara, verifico-o com dados reais de produção. Aconteceu-nos com uma listagem que eu tinha resolvido em memória: ele tinha razão para os 5% de contas grandes, por isso paginei a consulta. Mas se o caso que me apresenta não existe nem nos nossos dados nem no roadmap, digo-o com números: preferimos o simples hoje e deixamos o limite anotado. Aceito quando há evidência, defendo quando a evidência está do meu lado, e nunca faço disto algo pessoal.»
- 03
Desenha-me em traços gerais um sistema que encurte URLs (ou um feed, um carrinho...). Por onde começas?
Começa pelas perguntas, não pela solução: volume, leituras vs escritas, latência aceitável. Raciocina os trade-offs em voz alta (consistência vs disponibilidade, onde colocar cache) em vez de despejar uma arquitetura fechada de cor.
Exemplo de resposta «Antes de desenhar seja o que for, faria três perguntas: quantas URLs novas por dia e quantos redirecionamentos?, podem expirar?, interessa a analítica de cliques? Suponhamos mil escritas e um milhão de leituras diárias: é um sistema de leituras, por isso otimizo aí. Geraria códigos de 7 caracteres em base 62 a partir de um contador com blocos pré-reservados por instância, para evitar colisões sem ter de coordenar cada pedido. Guardaria o mapeamento numa base chave-valor e poria uma cache à frente para os 20% de URLs que levam 80% do tráfego. O redirecionamento pode ser eventualmente consistente: se uma ligação demorar um segundo a propagar-se, não faz mal; isso permite-me replicar sem bloquear escritas.»
- 04
Porque escolheste [a tua linguagem/framework principal] no teu último projeto e quando é que teria sido má ideia?
Fala de critérios reais: ecossistema, desempenho, a equipa que o vai manter. Reconheceres quando NÃO era a opção certa vale mais do que defendê-lo como se fosse perfeito para tudo.
Exemplo de resposta «No meu último projeto escolhi TypeScript com Node porque a equipa já dominava JavaScript, o produto era uma API com muita integração de terceiros e a tipagem poupava-nos os erros parvos de contratos entre serviços. Não foi uma decisão da moda: pesei que contratar perfis fosse fácil e que o ecossistema tivesse bibliotecas maduras para o que precisávamos. Quando é que teria sido má ideia? Se o núcleo fosse cálculo intensivo de CPU, processamento de imagem ou algo com requisitos rígidos de memória: aí o Node afoga-se e eu teria ido para Go ou para Python com extensões nativas. Aliás, um job de geração de PDFs acabámos por passá-lo para um worker separado porque bloqueava o event loop.»
- 05
Tens de adicionar uma feature a uma parte do código que não percebes e que ninguém documentou. Como procedes?
Mostra estratégia perante o código herdado: ler os testes, traçar as entradas e saídas, fazer alterações pequenas e verificáveis. Menciona o que te recusarias a tocar sem rede de segurança.
Exemplo de resposta «Primeiro leio os testes, se existirem: são a única documentação que não mente. Se não existirem, traço o fluxo com um caso real: ponho logs ou um debugger na entrada e sigo os dados até à saída, e com isso desenho um mapa de o que mexe com o quê. Antes de adicionar a minha feature, escrevo dois ou três testes de caracterização que fixem o comportamento atual, mesmo que me pareça estranho: esse comportamento pode ser um contrato que alguém espera. Depois faço a alteração mais pequena possível e verifico que os testes continuam verdes. O que não faria era refatorizar ao mesmo tempo que adiciono a feature, nem mexer sem rede em algo que envolva dinheiro ou dados de utilizadores: aí primeiro testes, depois alterações.»
- 06
Fala-me de uma vez em que tomaste um atalho técnico (dívida técnica) de propósito. Como o justificaste?
Deixa claro que foi uma decisão consciente com custo conhecido, não um descuido. Explica o que ganhaste (prazo, validar uma hipótese), como o deixaste documentado e que plano havia para o pagar.
Exemplo de resposta «Para validar uma integração com um cliente grande, fiz hardcode da configuração dele em vez de construir o sistema de configuração por cliente que era o correto. Decidi-o com o meu responsável presente: montar o genérico eram três semanas e o cliente decidia numa. Deixei o atalho sinalizado: um comentário com o porquê, um ticket no backlog com a solução real estimada, e um alerta caso outro cliente chegasse àquele código. O cliente assinou e, no trimestre seguinte, pagámos a dívida com o sistema genérico. Para mim a diferença entre dívida boa e má é essa: a boa tem data, dono e um custo que alguém aceitou em voz alta; a má é a que se descobre seis meses depois por surpresa.»
- 07
Diferença entre duas coisas que parecem semelhantes no teu stack (p. ex. lista vs dicionário, SQL vs NoSQL, síncrono vs assíncrono): quando usas cada uma?
Responde com o quando, não com a definição de manual. Ancora cada opção a um caso de uso e ao custo que assumes (memória, latência, complexidade). Se puderes, refere uma vez em que escolheste mal e o mudaste.
Exemplo de resposta «SQL contra NoSQL, por exemplo: não é uma guerra de religiões, é uma pergunta sobre os teus dados. Se têm relações que importam (encomendas, clientes, faturas) e precisas de transações, SQL, porque as garantias dá-tas a base de dados e não as tens de reinventar no código. NoSQL uso-o quando o esquema é volátil ou o volume de leituras simples é enorme: sessões, catálogos desnormalizados, eventos. O custo que assumes com NoSQL é que as perguntas que não previste tornam-se caras. Aconteceu-me: montámos analítica sobre uma base de documentos e ao fim de seis meses cada relatório novo era um sofrimento; migrámos essa parte para Postgres e as consultas passaram de horas de trabalho a um JOIN.»
- 08
O teu código passa em local mas falha em produção. O que verificas primeiro?
Enumera os suspeitos por probabilidade: variáveis de ambiente, versões de dependências, dados reais vs de teste, concorrência, fuso horário. O importante é a ordem do teu raciocínio, não acertar na causa exata.
Exemplo de resposta «Vou por ordem de probabilidade. Primeiro, configuração: variáveis de ambiente que faltam ou que apontam para outro sítio, é a causa mais comum e a mais barata de verificar. Segundo, dados: em local testo com dados limpos e produção tem os casos raros (nulos, acentos, registos de 2015). Terceiro, versões: o lockfile foi respeitado no deploy?, a versão do Node ou da base de dados é a mesma? Quarto, tudo o que em local não existe: concorrência real, latência de rede, permissões, fuso horário do servidor. E enquanto verifico, olho para os logs do erro real em produção em vez de supor: metade das vezes o stack trace já te diz em qual dessas quatro famílias estás.»
Muitas destas perguntas são do tipo «conta-me uma vez em que…». Para estruturar essas respostas com uma história clara, usa o método STAR.
Dicas para te destacares
- Pensa em voz alta durante o coding. O silêncio penaliza-te mais do que um erro: quem te entrevista precisa de ver o teu raciocínio, não só o resultado.
- Antes de programar, repete o problema e pergunta pelos casos-limite. Atirares-te a escrever sem esclarecer requisitos é o sinal de alarme número um.
- Quando defenderes uma decisão técnica, nomeia o trade-off que aceitaste. «Escolhi X mesmo sabendo que Y» soa a sénior; «X é melhor» soa a júnior.
- Leva dois ou três projetos preparados para contar em detalhe: que problema resolviam, a tua decisão mais difícil e o que farias de diferente. É o material de onde saem metade das perguntas de seguimento.
Pratica uma entrevista para programador / engenheiro de software
Cola o teu CV e a oferta e fala com um recrutador de IA que adapta as perguntas ao teu cargo. Feedback honesto por competências, sem cartão.