Aula 01 · 75–100 minutos

Pensar em sistemas antes de desenhar caixas

Aula introdutória de System Design: requisitos, fluxo, escala, qualidade e verificação.

Resultado e mapa da aula

Ao final, você conseguirá receber um pedido vago — "publique eventos de um produto" — e devolvê-lo como um desenho inicial com: objetivo mensurável, fluxo de execução, números que sustentam a escala, falhas assumidas, controles de segurança e sinais operacionais. Isto é a base que separa um diagrama decorativo de uma proposta de engenharia.

  1. Começamos pelo problema e pelos limites.
  2. Seguimos uma requisição em tempo de execução.
  3. Transformamos volume e expectativa em orçamento técnico.
  4. Escolhemos o mínimo de componentes que atende ao orçamento.
  5. Verificamos a decisão com métricas, testes e perguntas de revisão.

O problema real: tecnologia antes da pergunta

"Vamos usar Kafka, Redis e uma base NoSQL" não é um design. São opções sem uma função demonstrada. Elas podem aumentar custo, superfície de falha e carga operacional sem resolver o que a pessoa usuária percebe.

Antes do desenho, transforme frases em perguntas verificáveis: qual ação é crítica? Quem pode executá-la? Qual dado é a fonte de verdade? Quanto atraso é tolerável? Que taxa e pico precisamos suportar? O que deve ocorrer quando uma dependência não responde? Quanto custa ficar indisponível?

O método: da necessidade à decisão

  1. Defina o contrato do produto: atores, comandos, consultas e resultado observável. "Criar anúncio" não é igual a "encontrar anúncio".
  2. Classifique os dados: fonte de verdade, derivados e temporários. A fonte precisa de durabilidade; uma projeção de busca pode ser reconstruída.
  3. Escreva atributos de qualidade com números: p95 de confirmação menor que 300 ms, perda de publicação igual a zero dentro do contrato, busca até 10 s atrasada.
  4. Desenhe o caminho crítico: somente os componentes necessários para devolver o resultado ao usuário.
  5. Desenhe o trabalho adiado: eventos e consumidores que podem falhar e recuperar sem bloquear o comando.
  6. Declare evidência: métrica, log, trace, teste ou alarme que prova cada promessa.

Esse ordenamento importa porque código executa em uma ordem concreta: o cliente envia uma requisição; a borda autentica, autoriza e valida; o caso de uso grava a verdade; a resposta volta; depois, um consumidor atualiza derivados. Se você mistura essas etapas, não consegue dizer qual falha afeta a confirmação e qual apenas atrasa a busca.

Fluxo de execução: publicar não é o mesmo que aparecer na busca

Uma pessoa autenticada envia um comando. A API valida e autoriza. O serviço grava o anúncio e um evento de forma atômica. A resposta é imediata. Depois, um consumidor constrói o índice de busca e emite telemetria.

Fluxo de publicação de anúncioUma pessoa autenticada envia um comando. A API valida e autoriza. O serviço grava o anúncio e um evento de forma atômica. A resposta é imediata. Depois, um consumidor constrói o índice de busca e emite telemetria.Pessoa usuáriaPOST /anúnciosBorda da APIauth · authz · validaçãoCaso de usopublicar anúncioFonte de verdadeanúncio + outboxcaminho síncronoEvento durávelAnúncioPublicadoConsumidor de índiceretry + idempotênciaÍndice de buscaprojeção reconstruívelTelemetrialatência · erros · atrasocaminho assíncrono

Diagrama 1 — A decisão relevante é a fronteira: confirmar depois de uma gravação durável, mas não esperar o índice de busca. Em uma implementação real, o detalhe de publicar o evento precisa evitar a lacuna entre "dado gravado" e "evento emitido"; o padrão outbox é uma alternativa comum a analisar nas aulas de consistência.

O desenho não começa na caixa: começa na promessa

O diagrama abaixo é complementar ao fluxo de publicação: ele mostra a sequência de raciocínio. Leia-o da esquerda para a direita. A confirmação só vem depois do fato durável; a derivação pode atrasar, mas precisa produzir evidência operacional. Essa separação será a base para decidir sobre filas, caches e réplicas sem usá-los como slogans.

Use os controles do diagrama para comparar as composições e seguir as relações.

Diagrama 2 — Para cada promessa há uma medida ou teste correspondente. Use-o na questão 1 e no exercício: identifique o contrato, o ponto de durabilidade, o efeito derivado e a evidência.

Estimativas: uma hipótese pequena é melhor que um número mágico

Suponha 1 milhão de publicações por dia. A média é aproximadamente 1.000.000 / 86.400 ≈ 12 publicações por segundo. Média não dimensiona pico: se o tráfego de campanha chega a 20×, o sistema precisa começar a discussão perto de 240 operações/s, não de 12. Registre também tamanho: a 4 KiB por evento, 1 milhão de eventos/dia equivale a cerca de 4 GiB/dia antes de índices, réplicas e overhead.

Estimativa não é previsão. Ela torna a incerteza visível e permite revisar a decisão quando a premissa muda. Documente a fórmula, a janela e o multiplicador de pico; nunca esconda uma suposição dentro de "deve escalar".

Atributos de qualidade são contratos com trade-offs

  • Latência: distribuições importam mais que média. P95/P99 mostram a experiência da cauda.
  • Disponibilidade: uma meta como 99,9% precisa de janela, escopo e cálculo; não significa que cada dependência tenha a mesma meta.
  • Durabilidade: especifique quando a confirmação é legítima: após persistência local, após réplica ou após confirmação remota? Cada escolha muda latência e risco.
  • Consistência: defina o que pode ficar temporariamente defasado e o que não pode. "Eventual" sem limite e sem recuperação é só ambiguidade.
  • Segurança: autenticação responde quem é o ator; autorização responde se ele pode publicar naquele escopo; validação limita forma e tamanho da entrada. São controles distintos.
  • Custo e operabilidade: um componente é aceitável apenas se a equipe consegue medir, atualizar, recuperar e pagar por ele.

Uma disponibilidade de 99,9% deixa cerca de 43,2 minutos indisponíveis em 30 dias; 99,99% deixa cerca de 4,32 minutos. Esses valores são aproximações de orçamento, não substituem a definição de incidente nem o SLO de um serviço.

Alternativas que falham — e o que fazer no lugar

Esperar cada efeito antes de responder

Gravar, indexar, notificar e analisar tudo no caminho síncrono soma latência e torna a confirmação indisponível quando a busca falha. Separe efeitos que podem atrasar, mantendo evento durável, reprocessamento e uma leitura que deixe claro o estado.

Usar retry sem limite

Um retry pode multiplicar carga durante uma falha e produzir duplicatas. Use timeout explícito, número limitado de tentativas, backoff com jitter e idempotência baseada numa chave de negócio. Retry não corrige erro de validação ou autorização.

Prometer "exatamente uma vez" sem definir a fronteira

Em sistemas distribuídos, entrega e efeito são questões diferentes. Um consumidor pode receber a mesma mensagem mais de uma vez; projete a gravação como idempotente e defina em qual armazenamento o efeito é deduplicado.

Ocultar segurança no diagrama

Não basta colocar um cadeado numa caixa. A borda deve obter identidade de fonte confiável, verificar autorização para o recurso solicitado, validar payloads com limites e não registrar segredos ou dados sensíveis em telemetria.

Prática guiada: desenhe o primeiro corte

Raciocínio antes do desenho

O conflito de horário é a invariável: ele exige uma fonte de verdade que faça a decisão de disponibilidade e a criação da reserva como uma única operação observável. O lembrete não deve estar no caminho crítico, porque seu atraso permitido é maior que o objetivo da confirmação.

Uma abordagem plausível, mas incorreta

Uma leitura de disponibilidade seguida de uma escrita separada deixa uma janela entre as duas operações. Duas requisições concorrentes podem ler "livre" e ambas criar uma reserva. A autenticação não resolve essa corrida; ela só identifica o ator.

-- Incorreto: a decisão e o efeito estão separados.
SELECT id FROM reservas
WHERE agenda_id = $1 AND inicio = $2;

-- Se a consulta não retornou linha, a aplicação faz depois:
INSERT INTO reservas (agenda_id, inicio, paciente_id)
VALUES ($1, $2, $3);

O problema não é o parâmetro $1; ele é correto para separar dados de instrução SQL. A limitação é semântica: a segunda operação ainda se baseia numa observação que pode ter ficado obsoleta.

Uma solução correta, com limite explícito

Faça o banco rejeitar o segundo ocupante por uma restrição única que representa a regra de negócio. A aplicação então converte a violação conhecida em um conflito de domínio; não deve expor erro interno nem tentar novamente cegamente um conflito que é válido.

-- Migração: a invariável reside onde os dados são arbitrados.
CREATE UNIQUE INDEX reservas_horario_unico
ON reservas (agenda_id, inicio);

-- Comando: uma única tentativa parametrizada de criar.
INSERT INTO reservas (agenda_id, inicio, paciente_id)
VALUES ($1, $2, $3);

-- Se a restrição falhar: responder "horário indisponível".

Para intervalos que se sobrepõem, uma chave simples talvez não baste; PostgreSQL oferece restrições de exclusão, e outros bancos oferecem mecanismos diferentes. A lição não é "índice único resolve tudo", e sim: expresse a invariável no mecanismo que decide concorrência e teste a disputa real.

Uma solução possível

  1. Na borda, autentique o usuário, autorize-o para a clínica/agenda e valide identificadores e intervalo de tempo.
  2. No serviço de reservas, execute uma transação ou operação condicional que só crie a reserva se o horário ainda estiver livre. Uma leitura seguida de escrita separadas permitem corrida.
  3. Na mesma fronteira de durabilidade, registre um evento de reserva criada (por exemplo, outbox) para que o agendador de lembretes possa recuperar após falha.
  4. Retorne a reserva confirmada depois da operação que preserva a invariável; o agendador consome o evento, deduplica por identificador da reserva e cria o lembrete.
  5. Meça p95 do comando, conflitos de agenda, falhas da operação condicional, idade do evento pendente e atraso do lembrete.

Verificação: um teste concorrente deve tentar reservar o mesmo horário duas vezes e provar que apenas uma operação confirma. Um teste de falha deve simular o consumidor indisponível, restaurá-lo e verificar que o lembrete é recuperado uma vez. Em produção, um alerta sobre idade da outbox detecta "confirmamos, mas ainda não propagamos".

Recupere da memória: 10 questões

Recupere da memória: 10 questões

Qual é a primeira saída útil de um design?

Por que separar indexação da confirmação de publicação?

1 milhão de eventos/dia equivale aproximadamente a quantos eventos/s em média?

Qual controle responde “este ator pode editar este recurso”?

Qual risco existe em retry ilimitado?

Qual é uma boa fonte de evidência para “a busca está atrasada demais”?

Quando uma confirmação pode ser enviada?

Qual abordagem evita corrida ao reservar um horário?

O que significa projetar um consumidor idempotente?

Qual decisão é mais característica de Principal Engineer?

Perguntas de entrevista e de revisão

"Por onde você começa um system design?" Resposta forte: comece pelo usuário e pelo resultado, transforme os requisitos em números e riscos, descreva o caminho crítico e só então selecione componentes. Mostre uma premissa e como a validaria.

"Por que usar uma fila?" Não responda com "para escalar". Explique o desacoplamento temporal: a ação aceitável agora pode gerar um efeito posterior; em seguida discuta durabilidade, ordem, duplicatas, backpressure e monitoramento do atraso.

"Como você projeta alta disponibilidade?" Delimite escopo e SLO primeiro. Depois cite remoção de ponto único de falha, isolamento, timeouts, recuperação testada, observabilidade e o custo/consistência que a meta exige.

"O que muda para Principal?" Diga que a unidade de decisão passa de um serviço para um ecossistema: contratos entre domínios, caminhos de migração, plataformas, custo total, riscos e mecanismos para outras equipes tomarem boas decisões sem centralização.

Feche o modelo mental

System Design começa por comportamento e termina por evidência. Um bom primeiro desenho deixa claras as premissas, separa o que precisa concluir agora do que pode recuperar depois, explicita falhas e oferece sinais para corrigir a hipótese em produção.

Próxima aula planejada: orçamento de escala e latência ponta a ponta.

Referências primárias para aprofundar

HTTP define a semântica de métodos, respostas e comunicação na RFC 9110. Para o vocabulário e o modelo de confiabilidade operacional, use o SRE Workbook — Implementing SLOs. Para telemetria distribuída e contexto de rastreamento, consulte a W3C Trace Context Recommendation. A discussão da prática usa a documentação do PostgreSQL sobre restrições de integridade. A semântica de entrega e consumidores será aprofundada nas próximas aulas com documentação oficial das tecnologias escolhidas para cada caso.

Consulte também o registro de pesquisa da aula e as fontes fundamentais da trilha, disponíveis no repositório do curso.