Design de sistema primeiro
A maioria dos tickets descreve o que construir e esconde as perguntas que decidem se ele sobrevive ao contato com produção: quantos usuários, com que frequência, quantos dados, o que acontece quando uma dependência está lenta, quem é o dono da verdade quando dois escritores competem. Esta skill torna essas perguntas explícitas antes de o código ser escrito, de uma forma que o autor da tarefa possa ler e contestar.
A passagem é: escopo → estimativa → design de alto nível → mergulho profundo → conclusão, aplicada a trabalho real: existe uma base de código, um autor com intenção e um orçamento. O objetivo é uma imagem nítida da funcionalidade do ponto de vista do sistema.
Responda no idioma em que o usuário escreve. O briefing é para ele, não para você.
1. Avalie a profundidade primeiro
Exagerar no design de uma correção de digitação é tão errado quanto subdimensionar um fluxo de pagamento. Escolha o nível, diga em uma linha e gaste o tempo de acordo.
| Nível | Tarefa típica | O que você produz |
|---|---|---|
| L0 – trivial | Alteração de cópia, renomeação, ajuste de estilo, bug óbvio com correção local | Nada extra. No máximo uma frase se existir um risco oculto ("este rótulo também está em cache no CDN por 24h"). Depois, apenas execute a tarefa. |
| L1 – alteração local | Novo campo, novo filtro, pequena alteração de endpoint, um hook, um ajuste de consulta | Uma verificação de design inline de 3 a 7 linhas: o que ela toca, a carga que suporta, a única coisa que pode causar problemas (N+1, invalidação de cache, paginação, idempotência). Depois, implemente. |
| L2 – funcionalidade | Nova tela com fluxo de dados, novo endpoint + armazenamento, notificações, busca, exportação, integração com terceiros | O briefing de design (seção 4), com cerca de uma página. Depois, implemente de acordo com o briefing. |
| L3 – subsistema | Novo serviço, canal em tempo real, pipeline de eventos, modelo de dados multi-inquilino, migração de um caminho crítico, qualquer coisa com "escala" no ticket | Briefing completo mais um mergulho profundo por componente arriscado, alternativas consideradas, caminho de migração, o que medir após o lançamento. |
Sinais que empurram uma tarefa para cima de nível: latência voltada ao usuário, escritores concorrentes, fan-out (um evento → muitos destinatários), crescimento ilimitado de uma tabela ou lista, limites de taxa de terceiros, dinheiro, PII, qualquer coisa que execute em um agendamento, ou soluções "temporárias" que obviamente permanecerão. Sinais que a empurram para baixo: ferramentas internas com poucos usuários, dados que cabem na memória para sempre, experimentos com feature flags e kill switch.
Se o usuário pedir explicitamente uma revisão de design ou uma análise mais profunda, trate como L3 independentemente do tamanho.
2. A passagem, passo a passo
Trabalhe nestes em ordem. Para L1, comprima-os em algumas linhas; para L2/L3, cada passo torna-se uma seção do briefing. references/framework.md tem as listas de verificação de perguntas para cada etapa; leia-o na primeira vez que executar uma passagem L2+ em uma sessão.
Passo 1 — Entender e escopo
- Reafirme a funcionalidade em um parágrafo como o sistema a vê: atores, gatilhos, entradas, saídas, efeitos colaterais.
- Separe os requisitos funcionais (o que faz) dos não funcionais (quão bem: escala, latência, disponibilidade, consistência, durabilidade, segurança, custo, operabilidade). Os tickets quase nunca declaram o segundo tipo; infira-os do contexto do produto e diga que foram inferidos.
- Escreva o que está fora do escopo, para que o briefing não cresça silenciosamente.
- Reúna a intenção do autor: texto do ticket, descrição do PR, comentários, designs vinculados, ADRs existentes, como funcionalidades semelhantes foram construídas neste repositório. O autor geralmente tem um design em mente; torne-o explícito em vez de substituí-lo.
- Pergunte ao usuário apenas questões que alterem materialmente o design (por exemplo, "isso deve estar visível em um segundo, ou um minuto é suficiente?"). Para todo o resto, declare uma suposição e siga em frente; as suposições vão para o briefing.
Passo 2 — Estimar
Números transformam opiniões em decisões. Faça uma estimativa aproximada mesmo quando o ticket não tiver nenhuma; references/estimation.md contém os números de referência (escada de latência, potências de dois, noves de disponibilidade, capacidades por nó) e exemplos resolvidos.
- Usuários / inquilinos → usuários ativos diários → ações por dia → QPS médio e de pico (pico é geralmente 2-5× a média, mais para fluxos explosivos como "todos abrem o aplicativo às 9:00").
- Proporção leitura/escrita, tamanho do payload → armazenamento por dia / ano, largura de banda.
- Crescimento: qual é o número em 12 meses se o produto for bem-sucedido?
- Onde existem números reais (análises, contagens de linhas do banco de dados, dashboards existentes, limites de configuração), use-os e cite a fonte; caso contrário, forneça uma faixa e marque-a como suposição.
Em seguida, use os números para eliminar padrões, não apenas para justificá-los: "a 30 gravações/s, uma tabela Postgres com um índice está bem; uma fila não é necessária para taxa de transferência, apenas se quisermos retentativas e desacoplamento do provedor de e-mail."
Passo 3 — Mapear o design atual (as-is)
Leia o código antes de descrevê-lo. Nomeie arquivos reais, módulos, tabelas, endpoints, jobs, caches, filas. Não invente componentes.
- Quais componentes a funcionalidade toca? Desenhe o fluxo de dados em um diagrama de texto curto (
cliente → BFF → serviço → Postgres,evento → fila → worker). - Onde está o estado e quem é o dono (BD, cache, armazenamento do cliente, URL)?
- Quais primitivas existentes podem ser reutilizadas (uma tabela de outbox, um executor de jobs, um cache de consultas, um hub WebSocket, um componente
Paginaçãocompartilhado)? - Caminhos críticos, gargalos conhecidos, SPOFs existentes, limites atuais (limites de taxa, tamanhos de página, timeouts) que a funcionalidade herda.
- Para uma tarefa de frontend, o as-is ainda é um sistema: camada de busca de dados, política de cache, limites de bundle, transporte em tempo real — veja
references/frontend.md.
Passo 4 — Propor o design alvo (to-be)
Comece pela intenção do autor. Se for sólida, diga e aperte-a; se entrar em conflito com os números ou com um modo de falha conhecido, mostre o conflito com sua consequência e ofereça a menor alteração que o corrija. O autor decide; seu trabalho é tornar a troca visível.
- Design de alto nível como diagrama de texto, além do contrato de API (endpoints / eventos / mensagens com formatos) e o modelo de dados (tabelas, chaves, índices, retenção).
- Para cada escolha não trivial, nomeie o padrão e a alternativa que rejeitou, com o motivo vinculado aos números do Passo 2.
references/patterns.mdé o catálogo: escalabilidade, cache, async/filas, armazenamento de dados e consistência, estilos de API e transporte em tempo real, limitação de taxa, geração de IDs, confiabilidade, observabilidade — cada um com "usar quando / evitar quando / trade-offs". - Mapeie a funcionalidade para um sistema canônico quando um se encaixar ("isto é um sistema de notificações: fila + workers por canal + dedup", "isto é fan-out de feed de notícias", "isto é um limitador de taxa"). A última seção do catálogo lista as formas canônicas e seus blocos de construção padrão. A analogia dá ao leitor um ponto de referência conhecido e uma lista de verificação do que tais sistemas geralmente precisam.
- Prefira as primitivas existentes do repositório e o design mais simples que atenda aos números com margem. Diga explicitamente quais atualizações são adiadas e qual sinal as acionaria ("adicione uma réplica de leitura quando o p95 desta consulta passar de 200 ms ou a tabela passar de 50M linhas").
Passo 5 — Mergulho profundo no que pode quebrar
Para L2, escolha uma ou duas partes mais arriscadas; para L3, percorra todas elas. Perguntas padrão, em ordem aproximada de frequência com que causam problemas:
- Concorrência e idempotência — envios duplicados, retentativas, dois escritores, entrega pelo menos uma vez. Onde está a chave de idempotência? Qual é a restrição única?
- Consistência — quem lê dados obsoletos e por quanto tempo; isso é aceitável; caminho de invalidação de cache; leia-o-próprio-escrito.
- Falha de uma dependência — provedor fora do ar, fila atrasada, módulo remoto falhando ao carregar. Timeouts, retentativas com jitter, disjuntor, degradação graciosa, o que o usuário vê.
- Pontos quentes — chaves quentes, inquilinos famosos, listas ilimitadas, N+1, varreduras de tabela completa, índice faltante, manada trovejante na expiração de cache.
- Crescimento — a tabela/lista/fila que cresce sem limites; retenção, arquivamento, paginação (cursor sobre offset), particionamento.
- Migração e implantação — backfill, período de dupla escrita, feature flag, caminho de reversão, alterações de contrato compatíveis com versões anteriores.
- Segurança e privacidade — autorização no nível de dados (isolamento de inquilino), PII em logs/filas, limitação de taxa em endpoints públicos, validação de entrada.
- Observabilidade — qual métrica prova que funciona (SLI), qual alerta dispara quando não funciona, o que registrar para depuração de uma única requisição.
Passo 6 — Concluir, oferecer a visualização
Diagramas custam tokens, então são opt-in. O briefing em si usa apenas fluxos de texto de uma linha (cliente → API → Postgres).
Para L2 e L3, termine o briefing com uma pergunta, junto com as questões em aberto, no idioma do usuário:
Desenhar a arquitetura? 1 — diagrama as-is/to-be no terminal · 2 — mais uma pasta de design (Mermaid +
architecture.html) · 3 — não
- Desenhe apenas após o usuário escolher 1 ou 2, seguindo
references/visualization.md. Não espere pela resposta para começar a implementar; se o usuário seguir em frente sem responder, é um "não". - Pule a pergunta e desenhe imediatamente apenas quando o usuário já pediu um diagrama, uma imagem, uma visualização ou a pasta de design.
- Se ninguém puder responder (uma execução não interativa, CI, uma avaliação), não desenhe e não pergunte; mencione em uma linha que diagramas estão disponíveis mediante solicitação.
- Nunca ofereça para L0 ou L1.
Produza o briefing (próxima seção), depois continue com a tarefa: implemente de acordo com o briefing, mantenha o briefing na descrição do PR / MR também e liste questões em aberto para o autor, em vez de decidi-las silenciosamente.
3. Regras de julgamento
- Números antes de padrões. Nunca recomende Kafka, sharding, CQRS, um cluster de cache dedicado ou microsserviços sem uma estimativa que os exija. Simplicidade é uma funcionalidade; complexidade deve merecer seu lugar.
- Explique, não dê aula. Cada recomendação carrega um "porque" de uma frase que o autor pode verificar. Analogias a sistemas canônicos são bem-vindas; listas de palavras-chave não.
- Respeite o design do autor. Apresente discordâncias como "X causará Y na carga Z; a correção mais barata é W". Se eles ainda preferirem seu caminho, implemente o caminho deles e anote o risco no briefing.
- Código existente é evidência. Leia-o. Um briefing que descreve componentes que não existem é pior do que nenhum briefing.
- Separe o obrigatório do bom de ter. Marque cada recomendação como "necessário agora", "necessário antes do lançamento" ou "necessário em ~N usuários".
- Frontend conta. Cache do cliente, paginação, atualizações otimistas, transporte em tempo real, limites de bundle e isolamento de falhas são design de sistema;
references/frontend.mdcobre a versão do lado do cliente de cada etapa. - Mantenha-se no idioma e vocabulário do usuário. Traduza nomes de padrões se a equipe o fizer; mantenha o termo em inglês entre parênteses na primeira vez.
4. O briefing de design
Use esta estrutura para L2 e L3. Mantenha os cabeçalhos; remova uma seção apenas quando estiver genuinamente vazia e diga em uma linha. Alvo: uma página para L2. references/brief-template.md tem um exemplo preenchido e o formulário compacto L1.
# Briefing de design: <funcionalidade>
**Profundidade:** L2 · **Status:** proposta · **Intenção do autor:** <uma linha>
## 1. Escopo
Funcional: ...
Não funcional (inferido, a menos que declarado): escala · latência · disponibilidade · consistência · segurança · custo
Fora do escopo: ...
Suposições: ...
## 2. Estimativas
| Métrica | Agora | +12 meses | Fonte |
| --- | --- | --- | --- |
| DAU / inquilinos | | | |
| QPS de pico (leitura / gravação) | | | |
| Crescimento de armazenamento | | | |
Conclusão: <o que os números permitem / proíbem>
## 3. Design atual (as-is)
<fluxo de texto de uma linha> · propriedade do estado · primitivas reutilizáveis · limites herdados
Arquivos: ...
## 4. Design alvo (to-be)
<fluxo de texto de uma linha> · contrato de API · modelo de dados · analogia de sistema canônico
Escolhas de padrões: <padrão> — porque <motivo>; rejeitado <alternativa> porque <motivo>.
## 5. Riscos e mergulhos profundos
1. <risco> → mitigação (necessário agora / antes do lançamento / em N)
...
## 6. Implantação, migração, observabilidade
Flags, backfill, reversão · SLI + alerta · o que registrar
## 7. Perguntas em aberto para o autor
- ...
- Desenhar a arquitetura? 1 — diagrama no terminal · 2 — mais pasta de design · 3 — não
## 8. Plano de implementação
Etapas ordenadas, cada uma pequena o suficiente para revisar.
5. Referências — o que ler quando
| Arquivo | Leia quando |
|---|---|
references/framework.md | Primeira passagem L2+ em uma sessão: listas de verificação de perguntas por etapa, lista de NFRs, como extrair a intenção do autor, antipadrões de análise. |
references/estimation.md | Qualquer momento em que você precisar de um número: escada de latência, noves, capacidades por nó, matemática de QPS/armazenamento, exemplos resolvidos. |
references/patterns.md | Escolher ou justificar um padrão; mapear uma funcionalidade para um sistema canônico (chat, feed, notificações, autocomplete de busca, sincronização de arquivos, limitador de taxa, armazenamento KV, gerador de IDs, pagamentos, ...). Tem um índice. |
references/frontend.md | A tarefa é uma alteração de UI / SPA / micro-frontend: cache de busca de dados, paginação, tempo real, limites de bundle, isolamento de falhas, números do lado do cliente. |
references/brief-template.md | Escrever o briefing: exemplo completo L2 e o formulário inline compacto L1. |
references/visualization.md | Apenas após o usuário pedir diagramas (Passo 6). Desenhá-los: regras de diagrama de caixa no terminal, convenções Mermaid, layout da pasta de design, como preencher assets/architecture.html. |