Pular para conteúdo

O framework da entrevista

Uma entrevista de system design é um problema aberto com um relógio. Sem estrutura, é fácil gastar vinte minutos no esquema do banco e nunca chegar à parte que interessava ao entrevistador. O framework abaixo é uma sequência de sete passos, cada um com um objetivo, um tempo, frases para dizer e um modelo que você pode esboçar no quadro. É o mesmo framework ensinado na Aula 1 · Framework de entrevista e seguido por todos os estudos de caso; aqui ele está escrito como um checklist para ensaiar.

Ao longo da página, o exemplo é a pergunta da página inicial: "Projete um site de ingressos para um show num estádio. A venda abre sábado às 10:00." — a venda relâmpago do BoxOffice, com 2 milhões de fãs para 60.000 assentos.

Os modelos ficam em inglês

Os modelos dos blocos de texto estão em inglês de propósito: é a língua em que a maioria das entrevistas de system design acontece, e o vocabulário (QPS, p99, idempotency key) é o mesmo em português. Copie-os assim e preencha em qualquer língua.

flowchart LR
    A[1. Esclarecer<br/>~5 min] --> B[2. Estimar<br/>~5 min]
    B --> C[3. API e modelo de dados<br/>~5 min]
    C --> D[4. Design de alto nível<br/>~10 min]
    D --> E[5. Aprofundamentos<br/>~12 min]
    E --> F[6. Gargalos e trade-offs<br/>~5 min]
    F --> G[7. Fechamento<br/>~3 min]
    E -.novo requisito ou preocupação.-> A

Tempos

Passo Entrevista de 45 minutos Entrevista de 60 minutos Resultado no quadro
1. Esclarecer os requisitos 5 min 6–8 min Lista curta de requisitos funcionais e não funcionais; o que fica fora
2. Estimar 5 min 5–7 min QPS de pico, proporção leitura/escrita, armazenamento, o número decisivo
3. API e modelo de dados 5 min 6–8 min 3–6 endpoints ou eventos; entidades centrais com suas chaves
4. Design de alto nível 10 min 12–15 min Um diagrama, uma leitura e uma escrita percorridas
5. Aprofundamentos 12 min 15–18 min Um ou dois componentes em profundidade
6. Gargalos e trade-offs 5 min 5–7 min O que quebra primeiro, pontos únicos de falha, o que você trocou
7. Fechamento 3 min 3–5 min Resumo em quatro frases e próximos passos

Quem administra o relógio é você

Olhe o relógio a cada transição. Se você está no minuto 20 e ainda no passo 3, diga isso e comprima: "Vou manter o modelo de dados curto para sobrar tempo para a parte difícil." Entrevistadores raramente penalizam um atalho deliberado; penalizam nunca chegar ao aprofundamento. Cinco minutos antes do fim, feche, mesmo que o entrevistador ainda esteja perguntando.


1. Esclarecer os requisitos

Objetivo. Transformar um enunciado de uma linha num problema com fronteiras: quem usa, para quê, em que escala, e o que nunca pode dar errado. Tudo o que vem depois deste passo se justifica por algo escrito aqui.

O que dizer.

  • "Antes de desenhar qualquer coisa, gostaria de definir o escopo. Posso fazer algumas perguntas?"
  • "Vou me concentrar nestas três funcionalidades; deixo X e Y de fora, a menos que você queira."
  • "Então o requisito mais difícil é… — isso bate com o que você tinha em mente?"

Perguntas a fazer.

  • Usuários e funcionalidades: quem são os usuários? Quais são as 3–5 ações centrais? O que está explicitamente fora do escopo?
  • Escala: quantos usuários (ativos por dia, simultâneos no pico)? Quanto dado? Crescimento nos próximos anos?
  • Forma de leitura/escrita: dominado por leituras ou por escritas? Há picos (uma venda, um jogo, um lançamento)?
  • Consistência: o que nunca pode estar errado (dinheiro, estoque, permissões)? O que pode ficar alguns segundos desatualizado?
  • Latência e disponibilidade: quão rápida precisa ser a ação principal (p99)? Que disponibilidade se espera?
  • Restrições: regiões, regulação (dados pessoais), orçamento, sistemas existentes, tamanho do time.
REQUIREMENTS
Functional (in scope):
  1. ...
  2. ...
  3. ...
Out of scope: ...
Non-functional:
  Scale:        DAU = ..., peak concurrent = ..., data = ...
  Latency:      p99 of <main action> < ... ms
  Availability: ... % (which paths?)
  Consistency:  strong for ..., eventual for ...
  Durability:   never lose ...
  Other:        security / privacy / cost / regions
The hard part (one sentence): ...

Erros comuns

  • Desenhar no primeiro minuto e depois descobrir que o sistema é dominado por escritas.
  • Fazer vinte perguntas e nunca se comprometer: depois de 5 minutos, declare suposições e siga em frente.
  • Esquecer os requisitos não funcionais — são eles que tornam o design interessante.
  • Não escrever os requisitos: você vai precisar deles no passo 6 para justificar os trade-offs.

Venda relâmpago do BoxOffice — passo 1

  • Funcionais: ver a página do evento e o mapa de assentos; segurar um ou mais assentos por alguns minutos; pagar; receber o ingresso por e-mail e no app.
  • Fora do escopo: revenda, gestão do estádio, recomendações.
  • Não funcionais: 2 M de fãs chegam por volta das 10:00 para 60 mil assentos; o site precisa ficar de pé e ser justo (ordem de chegada, bots bloqueados); um assento nunca é vendido duas vezes; segurar um assento deve parecer instantâneo (p99 abaixo de ~500 ms depois da admissão); a página do evento pode ficar alguns segundos desatualizada.
  • A parte difícil: um pico enorme de disputa sobre um estoque pequeno e fortemente consistente — não o volume de dados.

2. Estimar

Objetivo. Pôr ordens de grandeza nos requisitos para que cada escolha posterior tenha um número por trás. Você não está fazendo um orçamento; está encontrando o número, ou os dois números, que decidem o design.

O que dizer.

  • "Vou fazer uma estimativa rápida de guardanapo; vou arredondar sem medo."
  • "Um dia tem cerca de 10⁵ segundos, então 10 milhões de requisições por dia dão umas 100 por segundo em média."
  • "O número que importa aqui é…, porque significa que precisamos de…"

Perguntas a se fazer.

  • Requisições por segundo, média e pico (fator de pico de 2–10× para tráfego normal; muito mais numa venda relâmpago).
  • Proporção leitura/escrita; quanto pesa cada escrita (bytes).
  • Armazenamento por dia/ano (e com replicação ×3); banda de entrada e de saída.
  • Concorrência pela Lei de Little: requisições em andamento = taxa × tempo.
  • O limite de qual componente está mais perto desses números? (Veja a folha de números.)
ESTIMATION (round to powers of 10)
Users:      DAU = ...            peak concurrent = ...
Requests:   per user per day = ...
            avg QPS = DAU x req/user / 1e5 = ...
            peak QPS = avg x peak factor (...) = ...
Read:write  = ... : ...          write QPS = ...
Storage:    item size = ... B    items/day = ...
            per year = ... (x3 replicas = ...)
Bandwidth:  peak QPS x response size = ... MB/s
Concurrency (Little): peak QPS x latency = ... in flight
Deciding number(s): ...  =>  implication: ...

Erros comuns

  • Gastar dez minutos com aritmética precisa. Um algarismo significativo basta.
  • Estimar a média e projetar para ela: dimensione sempre para o pico.
  • Números que nunca influenciam uma decisão. Se uma estimativa não muda o design, pule-a.
  • Esquecer de dizer as suposições em voz alta, e assim o entrevistador não pode corrigi-las.

Venda relâmpago do BoxOffice — passo 2

  • Fãs por assento: 2.000.000 ÷ 60.000 ≈ 33. A maioria dos fãs não vai conseguir ingresso: justiça e um "esgotado" claro importam.
  • Pico de leitura (≈ ilustrativo): 2 M de fãs atualizando a cada ~10–20 s nos primeiros minutos ⇒ da ordem de 10⁵ requisições por segundo, quase todas para a mesma página de evento e o mesmo mapa de assentos.
  • Pico de escrita (≈ ilustrativo): 60 mil assentos reservados em poucos minutos ⇒ da ordem de 10³ reservas por segundo — pouco, mas todas disputam as mesmas linhas.
  • Armazenamento: 60 mil pedidos × ~1 KB ≈ 60 MB por show — irrelevante.
  • Números decisivos: um pico de leitura de 100.000 req/s (⇒ CDN e cache) e ~1.000 escritas disputadas por segundo num único evento (⇒ uma sala de espera e reservas atômicas de assentos).

3. API e modelo de dados

Objetivo. Tornar o design concreto: as principais operações que os clientes chamam (ou os eventos que os serviços trocam) e as entidades com suas chaves e padrões de acesso. Os padrões de acesso escolhem o banco; as operações que mexem com dinheiro ou estoque ganham chaves de idempotência.

O que dizer.

  • "Estas são as quatro chamadas de que o cliente precisa; a que importa é…"
  • "Esta chamada altera o estoque, então recebe uma chave de idempotência — um retry não pode segurar um segundo assento."
  • "O padrão de acesso principal é 'todos os assentos de um evento por setor', então a chave da tabela começa pelo evento."

Perguntas a se fazer.

  • Quais chamadas são leituras e quais são escritas? Quais precisam ser síncronas?
  • Quais são as chaves e a consulta principal de cada entidade? Qual precisa de transações?
  • Paginação (por cursor), versionamento, autenticação em cada chamada.
API (REST; auth = bearer token)
GET  /events/{id}                       -> event page (cacheable)
GET  /events/{id}/seats?section=...     -> seat map (short TTL cache)
POST /holds         {eventId, seatIds}  Idempotency-Key: ...  -> holdId, expiresAt
POST /orders        {holdId, payment}   Idempotency-Key: ...  -> orderId, status
GET  /orders/{id}                       -> status (PENDING/CONFIRMED/FAILED)
Webhook: POST /payments/webhook (signed by the provider)

DATA MODEL
Entity      Key                 Main access pattern          Store / consistency
event       event_id            read by id                   SQL + cache, eventual OK
seat        (event_id, seat_id) by event + section; hold     SQL, strong (transactions)
order       order_id            by id; by user_id            SQL, strong
...

Erros comuns

  • Projetar vinte endpoints. Mostre os 3–6 que carregam os fluxos centrais.
  • Escolher o banco antes de escrever os padrões de acesso.
  • Esquecer a idempotência nas escritas que podem ser repetidas (reservas, pedidos, pagamentos).
  • Paginação por offset em listas grandes que mudam (use cursores).

Venda relâmpago do BoxOffice — passo 3

As quatro chamadas acima são todo o fluxo de compra. As linhas de seat ficam no PostgreSQL com chave primária (event_id, seat_id), um status (free, held, sold), hold_until e order_id. POST /holds recebe uma chave de idempotência para que um clique duplo ou um retry do cliente devolva a mesma reserva. order guarda a chave de idempotência do pagamento enviada ao provedor. Os dados de eventos e locais são quase só lidos e vão para o cache.


4. Design de alto nível

Objetivo. Um diagrama que atenda a todos os requisitos funcionais de ponta a ponta, com o fluxo de dados rotulado. Mantenha-o simples; você vai melhorá-lo nos aprofundamentos. Percorra uma leitura e uma escrita em voz alta.

O que dizer.

  • "Vou começar simples e depois evoluir: clientes, borda, serviços, armazenamento, trabalho assíncrono."
  • "Este é o caminho de uma requisição de reserva…" (siga-a pelas caixas).
  • "Esta caixa é um ponto único de falha por enquanto; volto a ela no passo 6."

Perguntas a se fazer.

  • Quais requisições param na borda (CDN, cache) e quais chegam aos serviços?
  • O que é síncrono (o usuário espera) e o que vai para trás de uma fila?
  • Onde está a fonte da verdade de cada entidade?
HIGH-LEVEL CHECKLIST
[ ] Clients -> DNS -> CDN (static, cacheable pages)
[ ] Edge: WAF / API gateway (auth, rate limit) -> load balancer
[ ] Stateless services (which ones? what does each own?)
[ ] Source of truth per entity (SQL / NoSQL / object store)
[ ] Caches (what, where, TTL)
[ ] Async: queue / event stream, consumers, what is eventual
[ ] External dependencies (payment, email, 3rd party)
[ ] One read and one write traced through the diagram

Erros comuns

  • Vinte caixas com setas sem rótulo. Cada seta diz o que passa por ela.
  • Citar produtos em vez de papéis ("Kafka" antes de dizer por que você precisa de um log de eventos).
  • Esconder estado em servidores "sem estado" (sessões em memória).
  • Polir uma caixa antes de o fluxo inteiro funcionar.

Venda relâmpago do BoxOffice — passo 4

Fãs → DNS → CDN para a página do evento e os assets → WAF (bots) → API gateway (autenticação JWT, rate limit por usuário) → load balancer → serviços sem estado: catalog (eventos, atrás de um cache), inventory (assentos, no PostgreSQL), order, payment (adaptador para o provedor externo), notification (e-mail, atrás de uma fila). O serviço order publica OrderConfirmed no Kafka por meio de um outbox; notification, search e analytics o consomem. Caminho de leitura: o mapa de assentos vem de um cache atualizado a cada segundo. Caminho de escrita: POST /holds vai para inventory, que atualiza as linhas dos assentos de forma atômica.


5. Aprofundamentos

Objetivo. Mostrar profundidade onde o problema é difícil. Escolha um ou dois componentes (ou deixe o entrevistador escolher) e entre em algoritmos, organização dos dados, consistência, tratamento de falhas e números. É aqui que acontece a maior parte da avaliação.

O que dizer.

  • "A parte difícil deste problema é…, então eu gostaria de aprofundar ali. Pode ser?"
  • "Há três jeitos de fazer isso: … Eu escolheria o segundo porque…"
  • "Deixa eu conferir isso com números: …"

Perguntas a se fazer.

  • Onde está a disputa, o fan-out, a chave quente ou a fronteira de consistência?
  • O que acontece com a carga de pico, com uma dependência lenta, com um retry, com uma queda no meio da operação?
  • Como você saberia que funciona (métricas, um teste de carga)?
DEEP-DIVE CHECKLIST (for the chosen component)
[ ] Why this is the hard part (number from step 2)
[ ] 2-3 options, with the trade-off of each
[ ] Chosen option: algorithm / data layout / keys
[ ] Consistency: what is atomic, what is eventual, how conflicts are prevented
[ ] Capacity: load vs capacity, utilization below the knee
[ ] Failure: slow dependency, crash midway, duplicate request, hot key
[ ] Observability: the metric / trace that proves it works

Erros comuns

  • Aprofundar a parte fácil (o frontend, a página de login).
  • Listar opções sem escolher nenhuma.
  • Um aprofundamento sem análise de falhas: "e se este nó morrer?" sempre vem.
  • Ignorar a dica do entrevistador apontando para um componente específico.

Venda relâmpago do BoxOffice — passo 5

Aprofundamento 1 — nunca vender um assento duas vezes. Opções: (a) ler o status na aplicação e depois escrever — uma condição de corrida; (b) SELECT … FOR UPDATE numa transação — correto, mas segura locks de linha enquanto a transação está aberta; (c) um único update condicional atômico: UPDATE seat SET status='held', hold_until=now()+interval '10 min', order_id=? WHERE event_id=? AND seat_id=? AND status='free' — 1 linha atualizada significa que o fã conseguiu, 0 significa que outro conseguiu. Escolha (c): curto, o lock dura só o comando, e o banco garante o invariante. Um job de expiração libera as reservas cujo hold_until passou. Nunca mantenha uma transação aberta enquanto chama o provedor de pagamento.

Aprofundamento 2 — sobreviver às 10:00. Uma sala de espera virtual: os fãs que chegam recebem uma posição (sorteada entre os presentes às 10:00, depois por ordem de chegada), e o gateway os admite no ritmo que inventory aguenta — digamos 2.000 por minuto —, emitindo um token de admissão assinado e de vida curta exigido por POST /holds. A Lei de Little dimensiona: 2.000 admitidos/min com ~5 min no fluxo de compra ⇒ ~10.000 fãs lá dentro ao mesmo tempo. A fila transforma um pico de 10⁵ req/s num fluxo constante que o banco aguenta; o custo é o tempo de espera, mostrado com honestidade pela posição na fila.


6. Gargalos e trade-offs

Objetivo. Dar um passo atrás e estressar o design: o que quebra primeiro com 10× a carga, onde estão os pontos únicos de falha, o que você trocou e como observaria e testaria. É aqui que você mostra julgamento.

O que dizer.

  • "Com dez vezes a carga, a primeira coisa a quebrar é…, porque…"
  • "Escolhi X em vez de Y porque…; o custo é…; eu revisaria se…"
  • "Para ter confiança, eu faria um teste de carga com perfil de spike e observaria…"

Perguntas a se fazer.

  • Qual componente está mais perto do limite (utilização perto do joelho)? Qual é ponto único de falha?
  • O que acontece quando cada dependência externa fica lenta ou cai?
  • Que consistência você relaxou, e o que o usuário vê por causa disso?
  • Quanto custa, aproximadamente? O que você monitoraria (SLIs) e o que geraria alerta?
TRADE-OFF STATEMENT
We chose <X> over <Y>
because <requirement / number from steps 1-2>.
The cost is <latency / consistency / money / complexity>,
which is acceptable because <...>.
We would revisit it if <condition>.

BOTTLENECK SWEEP
First to break at 10x: ...      fix: ...
Single points of failure: ...   fix: ...
Slow/down dependency: ...       containment: timeout / breaker / queue / fallback
Observability: SLIs = ...       alert on: burn rate of ...
How we'd test it: load profile ... / chaos experiment ...

Erros comuns

  • "Escala" sem dizer o quê, até quanto e a que custo.
  • Apresentar um design sem fraquezas — todo design tem algumas; nomeá-las é o sinal.
  • Esquecer a operação: deploys, monitoramento, plantão, custo.
  • Ficar na defensiva quando o entrevistador encontra uma falha. Diga "bom ponto" e adapte.

Venda relâmpago do BoxOffice — passo 6

  • O primeiro a quebrar: o provedor de pagamento às 10:00 (cota externa, picos de latência) → timeout, circuit breaker, um estado PENDING no pedido com a reserva do assento estendida; a sala de espera admite menos fãs se o provedor ficar lento.
  • Pontos únicos de falha: o primário do PostgreSQL → standby síncrono em outra AZ com failover automático; o Redis → replicado, e o mapa de assentos pode recorrer a uma cópia um pouco mais antiga.
  • Trade-offs: consistência forte só para assentos e pedidos, eventual para todo o resto; a sala de espera troca a paciência do usuário por um sistema que fica de pé; o mapa pode mostrar como livre um assento que já está reservado (a chamada de reserva é a autoridade).
  • Prova: um teste de spike com k6 até o pico esperado e um game day em que o provedor de pagamento fica lento; SLIs: taxa de sucesso e p99 das reservas, disponibilidade do checkout; alertas de burn rate no checkout.

7. Fechamento

Objetivo. Deixar uma imagem clara: um resumo curto, os trade-offs principais e o que você faria com mais tempo. Terminar no horário.

O que dizer.

  • "Resumindo: …"
  • "As duas decisões que eu mais defenderia são… e o principal risco é…"
  • "Com mais tempo, eu olharia…"
WRAP-UP (4 sentences + next steps)
1. The problem in one line and the hard part: ...
2. The design in one line (edge -> services -> storage -> async): ...
3. The key decisions and their trade-offs: ...
4. The main risk and how we contain it: ...
Next with more time: multi-region / cost / abuse & security / analytics / evolution

Erros comuns

  • Ficar sem tempo e sem resumo.
  • Introduzir componentes novos nos dois últimos minutos.
  • Repetir o percurso inteiro em vez das decisões.

Venda relâmpago do BoxOffice — passo 7

"Construímos um fluxo de venda de ingressos para um show num estádio em que 2 milhões de fãs disputam 60.000 assentos às 10:00. A CDN e os caches absorvem o pico de leitura, uma sala de espera transforma a multidão num fluxo constante, e as reservas de assento são updates condicionais atômicos no PostgreSQL, então um assento nunca é vendido duas vezes. O pagamento passa por um adaptador idempotente com timeouts e circuit breaker, e a confirmação segue de forma assíncrona por um outbox e o Kafka até o e-mail e o analytics. O principal risco é o provedor de pagamento no pico; com mais tempo, eu acrescentaria um segundo provedor, uma segunda região para o caminho de leitura e um modelo de pontuação de bots no WAF."

A arquitetura final

flowchart LR
    F[Fãs: web e mobile] --> DNS --> CDN[CDN: página do evento, assets]
    CDN --> WAF[WAF + proteção contra bots]
    WAF --> GW[API Gateway: JWT, rate limit, admissão da sala de espera]
    GW --> WR[(Fila da sala de espera)]
    GW --> LB[Load Balancer]
    LB --> CAT[catalog]
    LB --> INV[inventory]
    LB --> ORD[order]
    CAT --> C[(Cache: eventos, mapa de assentos)]
    C --> DB[(PostgreSQL: assentos, pedidos)]
    INV --> DB
    ORD --> DB
    ORD --> PAY[adaptador de payment] --> PSP[Provedor de pagamento]
    PSP -.webhook.-> PAY
    ORD -->|outbox| K[Kafka]
    K --> NOT[notification] --> EM[Provedor de e-mail]
    K --> AN[analytics]
    K --> SR[search]

Ensaie no playground

Ler o framework não é o mesmo que executá-lo sob pressão. O playground tem uma venda relâmpago pré-carregada — um lançamento com estoque limitado, a abertura das 10:00 do BoxOffice em forma genérica: quando a venda abre, o tráfego salta 20× e o design inicial (users → balanceador → app → inventory-db, mais o payment provider) falha de um jeito instrutivo.

Experimente

Rode o cenário como ele vem (a venda abre em t = 60 s) e veja qual nó fica vermelho primeiro. Depois aplique os movimentos do passo 5, um de cada vez — sirva as leituras de uma CDN e de um cache na frente de inventory-db, mande as escritas por um API gateway para uma fila de sala de espera drenada por workers abaixo da cota do provedor de pagamento (500 req/s), proteja a aresta do pagamento com timeout e circuit breaker — e rode de novo após cada mudança. Diga em voz alta, como numa entrevista, qual número cada mudança melhorou (p99, taxa de erros, atraso do consumidor, custo).

Para onde ir agora