tema
Backend
Backend é sobre contratos e comportamento sob estresse: como sua API responde a erros, concorrência e picos de tráfego. Espere perguntas sobre design de API, idempotência, transações e os limites entre camadas.
Simuladores de Backend
Principais perguntas de Backend
ver todas →O que torna um endpoint idempotente
Repetir a mesma requisição não muda o resultado — essencial para retries seguros em falhas de rede.
MédioPlenoREST vs. GraphQL: quando cada um vence
GraphQL resolve over/under-fetching para múltiplos clientes, ao custo de mais complexidade (N+1, cache, limitação de query).
MédioPlenoJWT vs. sessão em banco: trade-offs reais
JWT escala sem estado mas é difícil de revogar cedo; sessão dá controle total mas exige consulta e store compartilhado.
MédioPlenoCenário: uma rota Node.js travando o servidor inteiro
Provavelmente código síncrono pesado bloqueando o event loop — confirme com profiling de event loop lag.
DifícilSêniorQuando envolver uma operação em transação
Quando múltiplas escritas precisam ser tudo-ou-nada — uma falha no meio não pode deixar estado parcial.
MédioPlenoImplementando rate limiting em uma API
Contador precisa viver num store compartilhado (ex: Redis) entre instâncias, nunca em memória local de cada processo.
DifícilSêniorPara que serve um build multi-stage no Docker
Separa o estágio de build do estágio final, copiando só o artefato necessário — imagem final menor, sem ferramentas de build.
MédioPlenoO que é um graceful shutdown
Parar de aceitar requisições novas, terminar as em andamento, fechar conexões, e só então encerrar o processo.
DifícilSêniorQuais métodos HTTP são idempotentes
GET, PUT e DELETE são idempotentes; POST não é.
FácilJúniorDiferença entre 401 e 403
401 = não autenticado; 403 = autenticado, mas sem permissão para aquele recurso.
FácilJúniorO GIL do Python: o que ele impede e o que não impede
Uma thread executa bytecode Python por vez. Threads não paralelizam CPU-bound, mas ajudam I/O-bound (o GIL é solto no I/O). CPU real → multiprocessing.
MédioPlenoLista x generator: memória e avaliação
Lista materializa tudo na memória; generator produz sob demanda (memória ~constante, lazy, iterável uma vez).
FácilJúniorCenário: argumento default mutável
O default é criado uma vez na definição da função e reutilizado — a lista acumula entre chamadas. Use `=None` e crie dentro.
MédioPlenoPor que sobrescrever `equals` sem `hashCode` quebra o HashMap
HashMap acha o bucket por hashCode e só aí usa equals. equals sem hashCode → objetos iguais em buckets diferentes → não recupera, containsKey false.
MédioPlenoChecked vs unchecked exceptions
Checked: compilador força tratar/declarar (condição recuperável). Unchecked: erro de programação. Crítica: checked polui assinaturas e gera catch vazio.
MédioPlenoCenário: pausas de latência atribuídas ao garbage collector
Confirme com logs de GC qual geração/coletor. Causas: heap pequeno, churn de objetos, leak. Ajustes: heap maior, coletor de baixa pausa (G1/ZGC), menos alocação no hot path.
DifícilSêniorGoroutine x thread do sistema operacional
Goroutine: leve, pilha que cresce, agendada pelo runtime (M:N sobre threads do SO). Thread do SO: pesada, pilha fixa de MB, agendada pelo kernel.
MédioPlenoChannels ou mutex: qual usar
Channel: transferir propriedade de dado / orquestrar (worker pool, cancelamento). Mutex: proteger estado compartilhado que fica no lugar (contador, cache).
DifícilSêniorErro como valor de retorno em Go
Erro é `(valor, error)` tratado pelo chamador: fluxo explícito e local, difícil ignorar sem aparecer. Crítica: verboso e sem força do compilador; `%w` preserva contexto.
MédioPlenoDeadlock por `.Result` / `.Wait()` em código async
`.Result`/`.Wait()` bloqueia a thread do SynchronizationContext que a continuação do `await` precisa → os dois se esperam. Correto: `await` de ponta a ponta; `ConfigureAwait(false)` em libs.
DifícilSêniorStruct x class: valor x referência
class = referência (copia o ponteiro); struct = valor (copia os bytes). Struct grande = cópia cara; mutar struct numa coleção muta uma cópia. Faça structs pequenas e imutáveis.
MédioPlenoLINQ é preguiçoso: avaliação diferida
A query só roda quando você itera (foreach/ToList/Count). Iterar duas vezes reexecuta; mudanças na fonte antes da iteração contam; exceção estoura longe da definição.
MédioPlenoNull safety no sistema de tipos do Kotlin
Tipo nulável é explícito (`String?`) e o compilador força tratar antes de usar (`?.`, `?:`, smart cast). `!!` descarta essa garantia e relança NPE — é o antipadrão.
FácilJúniorCoroutines e concorrência estruturada
Coroutines: funções suspensíveis que dão código sequencial pra async, mais baratas que threads. Concorrência estruturada: filhas vivem dentro de um scope e são canceladas com ele — sem trabalho órfão.
DifícilSêniorO que uma `data class` gera de graça
Gera equals/hashCode/toString/componentN/copy a partir das props do construtor primário. Props no corpo ficam de fora; `copy` é raso; use `val` imutável se for chave de mapa.
MédioPlenoOwnership e as regras de borrow
Um dono por valor; liberado ao sair de escopo (sem GC). Borrow: N referências imutáveis XOR uma mutável, e nenhuma vive mais que o valor. Elimina data race e use-after-free em compile time.
DifícilSênior`Result` e `Option` no lugar de null e exceção
`Option<T>` (Some/None) substitui null; `Result<T,E>` (Ok/Err) devolve erro como valor. `?` extrai o Ok ou retorna cedo com o Err. `panic!` só pra irrecuperável.
MédioPlenoSegurança de memória sem garbage collector
Liberação determinística no fim do escopo, inserida em compile time pelas regras de ownership. Sem thread de GC → sem pausas → latência previsível. Ciclos: Rc/Arc + Weak.
DifícilSêniorA cadeia de middleware do Express
Funções `(req,res,next)` executadas na ordem de registro; cada uma encerra a resposta ou chama `next()`. Ordem = pipeline: body parser e auth antes das rotas, erro/404 por último.
FácilJúniorErro em handler async que não chega no error handler
Express 4 só pega erro síncrono ou `next(err)`; um `throw` em handler async rejeita a promise que ele ignora. Use `.catch(next)`, um asyncHandler wrapper, ou Express 5.
MédioPlenoO que o Express não te dá
Validação, helmet/CORS, auth, rate limit, logging + request id, formato e handler de erro, limite de body, compressão, graceful shutdown — tudo é você que pluga.
MédioPlenoEmbutir x referenciar num modelo de documento
Embuta o que é lido junto, pertence ao pai e não cresce sem limite. Referencie muitos-para-muitos, dado compartilhado/mutável, ou array que cresceria sem teto (limite de 16 MB).
MédioPlenoQuando um relacional seria a escolha melhor que MongoDB
Relacional: muitos joins ad-hoc imprevisíveis, transações multi-tabela com invariantes fortes, BI/agregações arbitrárias, constraints declarativas, schema estável. Mongo: documento = objeto, acesso previsível, sharding.
DifícilSêniorÍndices no MongoDB e o índice composto
B-tree acelera match/range/sort, custa escrita. Índice composto serve só consultas pelo PREFIXO dos campos, na ordem (regra ESR). `explain()` mostra IXSCAN vs COLLSCAN.
MédioPlenoRedis não é só chave-valor: as estruturas
String (cache, INCR), Hash (objeto por campos), List (fila), Set (dedupe/conjuntos), Sorted Set (ranking, rate limit por janela), Streams (log com consumer groups), HLL (contagem aproximada).
MédioPlenoCache-aside, TTL e o thundering herd
Cache-aside: app lê o cache, no miss busca no banco e grava com TTL; escrita invalida. Thundering herd: chave quente expira → todos dão miss juntos → pico no banco. Mitigue com lock, jitter no TTL, ou stale-while-revalidate.
DifícilSêniorRDB x AOF: durabilidade no Redis
RDB: snapshot periódico, compacto e rápido de restaurar, mas perde as escritas desde o último. AOF: log de comandos, bem mais durável (~1s com fsync everysec), arquivo cresce e restart mais lento. Prod costuma usar os dois.
MédioPlenoStreams e backpressure
readFile carrega tudo na RAM (OOM sob concorrência). Stream processa em chunks (memória constante). Backpressure pausa a origem quando o destino não vaza; use `pipeline()` pra erro + cleanup.
DifícilSêniorWorker threads x cluster x child_process
worker_threads: CPU-bound no seu código (memória compartilhável). cluster: escalar servidor HTTP por cores (processos, porta compartilhada). child_process: rodar programa externo ou isolar.
MédioPlenoErro não tratado: rejection, exception e o processo que morre
uncaughtException: erro síncrono no topo. unhandledRejection: Promise rejeitada sem catch. Não 'continue' após eles — o estado pode estar inconsistente. Logue, alerte, graceful shutdown, deixe morrer, supervisor reinicia.
DifícilSêniorCommonJS x ES Modules no Node
CJS: require síncrono, runtime, `__dirname`. ESM: import estático (tree-shakeable), bindings ao vivo, `import.meta.url`, top-level await. Migração morde em: extensão obrigatória, `"type": "module"`, interop CJS↔ESM, mocking.
MédioPlenoConfiguração por ambiente sem vazar segredo
Do ambiente via `process.env` (`.env` só em dev, gitignorado; secret manager em prod). Valide/tipe no boot e falhe rápido. Centralize num `config.ts`. Nunca commite segredo. Um build, env define o comportamento.
FácilJúnior`is` x `==` e o cache de inteiros pequenos
`==` compara valor; `is` compara identidade (mesmo objeto). CPython cacheia ints -5..256, então `100 is 100` é True e `1000 is 1000` é False. Use `is` só pra None/singleton; nunca dependa do cache.
FácilJúniorDecorators: o que são e uma pegadinha comum
Função que recebe e devolve uma função (`@d` = `f = d(f)`), pra logging/cache/retry/etc. Sem `functools.wraps` no wrapper, a função decorada perde nome, docstring e assinatura.
MédioPleno`asyncio`: quando ajuda e quando não
Event loop single-thread; `await` no I/O cede pra outra corrotina. Ótimo pra I/O-bound concorrente, inútil pra CPU-bound (bloqueia o loop). Chamada síncrona bloqueante dentro de corrotina trava tudo — precisa ser async de ponta a ponta.
DifícilSêniorContext managers e o `with`
`with` garante setup/teardown ao redor de um bloco mesmo com exceção. Implemente `__enter__`/`__exit__`, ou use `@contextlib.contextmanager` sobre um gerador (antes do yield = enter, depois = exit).
MédioPlenoImagem x container x camadas
Imagem = template imutável em camadas cacheadas por conteúdo. Container = instância rodando + camada gravável no topo. Ordene o Dockerfile do que muda menos pro que muda mais pra aproveitar cache.
FácilJúniorMulti-stage build: o que fica de fora da imagem final
Stage builder tem o toolchain e gera o artefato; stage final parte de base mínima e `COPY --from=builder` só o artefato. Sem compilador/dev deps/fonte na imagem de prod → menor e menos superfície de ataque.
MédioPlenoVolume x bind mount x tmpfs
Bind mount: path do host (dev, hot reload). Volume nomeado: gerenciado pelo Docker, portável, backup — estado de produção. tmpfs: só RAM, some ao parar — temporário/sensível.
MédioPlenodocker compose: rede entre serviços e ordem de subida
Serviços se acham pelo NOME do serviço como hostname (rede do compose). `depends_on` ordena o start, não a prontidão — use `condition: service_healthy` + healthcheck, ou retry de conexão na app.
MédioPlenoString imutável, o pool e `StringBuilder`
Imutável → chave de mapa segura, thread-safe, string pool. `s = s + x` num loop cria uma String nova copiando tudo a cada volta = O(N²). Use `StringBuilder` (append amortizado) ou `String.join`.
FácilJúnior`Optional`: para que serve e como NÃO usar
Sinaliza ausência esperada no RETORNO de um método, forçando tratar o vazio. Errado: como campo, como parâmetro, `Optional<List>`, e `.get()` sem checar (é o `!!` do Java).
MédioPlenoStreams do Java: preguiça e operações terminais
Intermediárias (filter/map/sorted) são preguiçosas e montam o pipeline; a terminal (collect/count/findFirst) dispara o processamento, elemento a elemento, com curto-circuito. Stream é de uso único; não mute estado externo no lambda.
MédioPlenoSlice x array e o compartilhamento de backing array
Array: tamanho no tipo, copiado. Slice: header (ptr,len,cap) sobre um backing array; fatiar não copia. Dois slices sobrepostos → mutação/append de um afeta o outro. Use `copy()` ou `s[a:b:b]`.
MédioPleno`defer`: ordem, avaliação de argumentos e o loop
Roda quando a FUNÇÃO retorna, em LIFO; argumentos avaliados na hora do `defer`. Loop: os defers acumulam até a função acabar — abrir N arquivos com `defer Close()` no loop esgota FDs. Extraia o corpo numa função.
MédioPlenoInterfaces implícitas e o `nil` interface trap
Satisfação por método, sem `implements` (interface definida por quem consome). Interface = (tipo, valor); só é nil se os dois são nil. Retornar um `*T` nil como `error` faz `err != nil` dar true.
DifícilSênior`IDisposable`, `using` e recursos não gerenciados
GC cuida de memória, não de recursos do SO (arquivo, conexão, lock). `using`/`Dispose()` libera de forma determinística ao sair do escopo (try/finally embutido). Esquecer num DB connection esgota o pool.
MédioPlenoNullable reference types (`string?`) no C# moderno
`string` = não-nulo, `string?` = pode ser nulo, com warning do compilador ao desreferenciar sem checar. Opt-in por warning porque ligar num codebase antigo gera centenas de avisos (o modelo velho assumia tudo nulável).
MédioPlenoRetornar `IEnumerable<T>` x `List<T>` x `IReadOnlyList<T>`
`List<T>` público vaza implementação e deixa mutar. `IEnumerable<T>` é abstrato mas pode ser lazy (reexecuta). `IReadOnlyList<T>` (com `.ToList()` por baixo) comunica 'pronto e imutável' — geralmente o melhor.
MédioSênior`sealed class`/`sealed interface` e `when` exaustivo
Subclasses num conjunto fechado conhecido em compile time → `when` exaustivo sem `else`, e variante nova não tratada vira erro. Equivalente da união discriminada do TS pra modelar estado com N formas.
MédioPlenoExtension functions: o que são e o que NÃO são
`fun Tipo.metodo()` deixa chamar como método sem herdar/editar a classe. Mas é função estática açucarada: resolução pelo tipo DECLARADO (não polimórfica), sem acesso a privados, e um método real de mesma assinatura a cobre.
DifícilSênior`let`, `run`, `with`, `apply`, `also` — qual usar
`let` (it, retorna o bloco): transformar / rodar se não-nulo. `apply` (this, retorna o objeto): configurar. `also` (it, retorna o objeto): efeito colateral numa cadeia (log, validar). Não aninhe até virar sopa.
MédioPleno`String` x `&str` (e `Vec<T>` x `&[T]`)
`String`: dona, heap, crescível. `&str`: fatia emprestada de texto que vive em outro lugar. Parâmetro de leitura → `&str` (aceita String, literal, sub-fatia sem alocar). Só receba `String` se precisa da posse.
MédioPlenoTraits: dispatch estático (`impl Trait`) x dinâmico (`dyn Trait`)
Trait = comportamento compartilhado (o polimorfismo do Rust). Genérico/`impl Trait`: monomorfização, custo zero, tipo fixo em compile time. `dyn Trait`: vtable, custo pequeno em runtime, permite coleção heterogênea.
DifícilSêniorCenário: lutando com o borrow checker — `.clone()` é sempre a saída?
`.clone()` cego custa alocação e evita aprender o modelo. Prefira: emprestar (`&T` em parâmetros de leitura), reordenar pra empréstimos não se sobreporem, `Rc`/`Arc`/`Cow` pra compartilhamento real. Clone consciente às vezes é ok.
MédioPleno`express.Router` e organização de rotas
Router = mini-app montado num prefixo. Cada recurso num arquivo com suas rotas/middleware locais; o app monta os routers e tem o middleware global + error handler + 404. Rota só valida, chama serviço, responde.
FácilJúniorValidar entrada numa rota Express
Schema (Zod/Joi) como middleware antes do handler: rejeita com 400 estruturado ou anexa `req.validated` tipado. Formato no middleware; regra de negócio no serviço (409/422). Com Zod+TS o tipo do handler sai do schema.
MédioPlenoExpress x frameworks mais novos (Fastify, Elysia, Hono)
Fastify: performance + schema de entrada/saída embutido. Elysia/Hono: tipagem end-to-end e cliente tipado sem codegen, validação embutida. Troque em projeto novo ou gargalo real; fique no Express se o codebase é grande e estável.
MédioSêniorAggregation pipeline e por que a ordem dos estágios importa
Sequência de estágios, saída de um vira entrada do outro. `$match`/`$sort` no início podem usar índice (depois de `$group`/`$unwind` não); `$project` cedo reduz o que trafega; `$lookup` é caro, filtre antes.
DifícilSêniorWrite concern e read preference
Write concern: quando o write é confirmado (`w:1` rápido/arriscado, `w:majority` durável/lento). Read preference: de onde ler (primary consistente, secondary distribui mas com lag). Escolha por operação.
DifícilSêniorAntipadrões de modelagem no MongoDB
Arrays sem limite (rumo aos 16 MB), coleções pequenas demais, documentos inchados com campos raramente usados, índice pra tudo, e modelar relacional com `$lookup` em toda query.
MédioPlenoRedis é single-thread — por que isso é uma vantagem (e o cuidado)
Um comando por vez → cada comando é atômico, sem lock. Rápido porque é RAM + O(1). Mas um O(N) grande (`KEYS *`, `SMEMBERS` de set gigante, Lua pesado) trava a thread e todos esperam — use `SCAN`.
MédioPleno`MULTI/EXEC` x script Lua pra atomicidade
`MULTI/EXEC`: enfileira comandos fixos (sem usar resultado de um no próximo); read-modify-write precisa de `WATCH` + retry. Lua (`EVAL`): roda atômico no servidor COM lógica (if, usa resultados) — idiomático pra rate limit e locks.
DifícilSêniorQuando a memória enche: políticas de eviction
Ao bater maxmemory: `noeviction` faz writes falharem; `allkeys-lru`/`lfu` removem as menos usadas (escolha pra cache); `volatile-*` só mexem em chaves com TTL. Monitore `evicted_keys` — alto = instância pequena.
MédioPleno
Perguntas frequentes
O que os entrevistadores mais avaliam em backend?
Backend é sobre contratos e comportamento sob estresse: como sua API responde a erros, concorrência e picos de tráfego. Espere perguntas sobre design de API, idempotência, transações e os limites entre camadas.
Quanto tempo leva pra treinar backend até me sentir pronto?
Depende do seu ponto de partida, mas a maioria sente diferença depois de 2-3 simulações completas com revisão das perguntas erradas — é aí que os padrões que se repetem em entrevista real ficam visíveis.