Artigos sobre System Design, arquitetura, engenharia de software e IA
Notas sobre System Design, arquitetura, engenharia full stack, IA, ciência e a disciplina de achar o que está errado antes de falhar.
- SLO para um time de cinco pessoasVocê não precisa de time de SRE para ter SLO. Precisa de um número, uma janela e uma regra para quando errar.
- Entregar é um hábitoNinguém decide não entregar. Decide fazer mais uma coisa antes. Como construir o hábito que acaba com isso.
- Desenhando um design system que sobrevive aos seus designersUm design system morre quando quem o fez vai embora. Os que vivem gravam decisões em tokens e restrições, não na memória.
- Eu encontro a falha que ninguém encontra. Este é o método.Não é intuição. É um procedimento repetível que assume que o sistema está mentindo e vai procurar onde.
- Projete a falha antes da funcionalidadeO caminho feliz qualquer um escreve. O sistema de verdade é o que acontece quando ele quebra, e é isso que se projeta primeiro.
- Testando sistemas não determinísticosVocê não pode fazer assert em uma string exata de um modelo. Pode fazer assert em propriedades, distribuições e invariantes, e deve.
- As doze perguntas que faço em toda revisão de arquiteturaAs mesmas doze perguntas, na mesma ordem, em todo sistema. Elas encontram a maior parte do que importa em um dia.
- A IA escreve o código. O sistema continua sendo seu.O modelo digita mais rápido que você. Mas não responde pelo que acontece às 3 da manhã. Essa parte ainda é sua.
- O custo real de um retryRetries adicionam carga bem na hora em que o sistema está mais fraco. Backoff, jitter, orçamento e breakers evitam a amplificação.
- O ciclo mais lento da ciência não é pensarTodo mundo quer que a IA faça o cientista pensar mais rápido. O tempo não se perde pensando. Se perde esperando, e espera é engenharia.
- O quadro branco é onde o sistema é construído de verdadeAs decisões que doem depois são tomadas na primeira hora, antes de qualquer código. O que eu desenho e por quê.
- A feature de IA que ninguém pediuO botão com a estrelinha foi feito para o conselho, não para o usuário. Como identificar, e o que construir no lugar.
- Onde as regras de negócio deveriam morar, e onde elas acabamA regra é escrita uma vez na especificação e cinco vezes no código. Como ela se espalha, e como trazê-la de volta para casa.
- A CDN é a decisão de escala mais barata que você vai tomarAntes de adicionar servidor, pergunte quais respostas nunca precisavam chegar num servidor.
- Escrevendo o relatório de auditoria que ninguém quer ler, para que leiamUma auditoria vale o que as correções que ela causa valem. Estrutura, linguagem e ordem decidem se o relatório vira ação ou arquivo.
- Por que continuo escolhendo Next.js para produtos que precisam durarNão é por ser popular. É porque um time consegue dominar o caminho inteiro da requisição sem inventar cola.
- Um orçamento de latência para features com LLMO modelo é a dependência mais lenta que você já adicionou. Orce como orça um banco de dados, por feature, por etapa.
- As fronteiras são o produtoFuncionalidades vêm e vão. As fronteiras que você traça entre elas são o que você ainda vai estar pagando daqui a cinco anos.
- A infraestrutura é sua, goste você disso ou nãoCada linha de código roda sobre decisões que você tomou ou aceitou por padrão. As duas são suas.
- O que um histograma de latência está tentando te dizerA média esconde. Leia a forma, depois p50, p95 e p99, e entenda por que fan-out transforma o p99 dos outros no seu p50.
- O ORM está bem. Suas queries não.Todo banco lento que audito tem a mesma forma: um ORM culpado por queries que ninguém leu. Leia o SQL. Conserte o padrão.
- Strangler fig, feito com honestidadeO padrão funciona. O que mata é fingir que o sistema antigo vai morrer sozinho. Ele não vai.
- Guardrails que não estragam o produtoA maioria dos guardrails é uma recusa pregada no final. Os bons são projetados dentro da tarefa, e o usuário quase nunca esbarra neles.
- Auditar um sistema que você não construiu, sem ofender quem construiuUma auditoria que produz ressentimento não produz correções. Como entrego achados duros e mantenho o time do meu lado.
- CI que te diz a verdadeBuild verde que mente é pior do que build nenhum. O que é preciso para o CI virar um sinal em que dá para agir.
- Idempotência é uma decisão de negócioChamar duas vezes e ter o mesmo resultado parece técnico. Definir o que é "o mesmo" é onde o negócio assina.
- O ciclo da hipótese, e onde o software pode encurtá-loCiência é um ciclo, não uma linha. Software deve encurtar as voltas baratas e deixar as caras tão lentas quanto a verdade exige.
- Estado do React que pertence ao servidorA maioria dos useState que audito guarda uma cópia do banco. Coloque esse estado onde ele mora e os bugs vão junto.
- Alucinação é propriedade do sistema, não bug do modeloO modelo gera texto plausível. Se o plausível vira falso na frente do usuário depende do sistema que você construiu em volta dele.
- Por que a maioria dos microsserviços deveria ter sido móduloA fronteira de rede é um imposto permanente. Quatro razões para um serviço merecê-la, e os sinais de que o seu deveria ser módulo.
- Diga não à reescritaA reescrita promete começo limpo e entrega um segundo sistema correndo atrás do primeiro. Cinco perguntas antes de aprovar.
- Container não é isolamentoContainer é um processo fantasiado. Trate como fronteira de segurança e uma hora você vai se arrepender.
- Formulários são sistemas distribuídosUm formulário são duas máquinas, uma rede não confiável e um usuário que clica duas vezes. Desenhe como o sistema distribuído que ele é.
- Core Web Vitals são um problema de arquiteturaVocê não conserta LCP com plugin. As métricas estão medindo seu fluxo de dados, suas fronteiras e seu deploy.
- Por que um engenheiro de software se importa com ciênciaA ciência é o sistema mais antigo para produzir conhecimento confiável. Ignorá-la é deixar o melhor design na mesa.
- Programar em par com IA mudou o que eu coloco no quadro brancoQuando o código fica barato, o quadro branco deixa de ser sobre código. Passa a ser sobre falha, posse e invariantes.
- Eventos de domínio e notificações não são a mesma coisaUm é um fato que o negócio se importa. O outro é um cutucão. Confundir os dois é como sistemas orientados a eventos apodrecem.
- Fé, família e uptimeO que coloco acima do trabalho, e como essas restrições tornaram meus sistemas mais confiáveis, não menos.
- Avaliando features com LLM como engenheiro, não como fãSe o seu sinal de qualidade é uma demo e uma sensação, você não tem uma feature. Tem uma esperança. Assim eu construo evals.
- Rate limiting sem prejudicar os usuários que você querToken bucket, identidade em vez de IP, limites por plano, modo sombra: como barrar abuso sem devolver 429 para quem paga.
- De artigos a perguntas: o que um instrumento de pesquisa deveria fazerUm resumidor te dá menos para ler. Um instrumento de pesquisa te dá perguntas melhores. A diferença é o produto inteiro.
- Postgres basta, até o dia em que não basta, e como saber que dia é esseA maioria dos times sai do Postgres cedo demais ou tarde demais. Os sinais que dizem qual dos dois são mensuráveis.
- Projetando para a exclusãoTodo sistema sabe criar um registro. Poucos sabem excluir direito. Projete a exclusão primeiro e o resto fica mais simples.
- Code review é revisão de riscoA maioria das revisões confere se o código está bonito. A pergunta que importa é o que quebra, para quem, e como você desfaz.
- Generics em TypeScript que ajudam, e os que atrapalhamUm generic que relaciona entrada e saída é um presente. Um que aparece uma vez na assinatura é uma mentira que o compilador não pega.
- Projetando APIs que podem ser usadas errado sem estragoClientes fazem retry, duplicam, mandam dado velho e chamam fora de ordem. Projete para que o uso errado comum seja inofensivo.
- O que a IA não consegue auditarModelos são ótimos em achar o que parece errado. As falhas que importam são as que parecem certas, e essas ainda precisam de uma pessoa.
- Multi-tenancy: a decisão que você não consegue desfazerSchema compartilhado, schema por tenant ou banco por tenant: cada um tem suas dores, e trocar depois significa migrar tudo.
- Software que começa pela evidênciaToda afirmação que um sistema faz deveria saber dizer por quê. Como construo software em que a evidência vem antes da conclusão.
- Migrations sem downtime na práticaA mudança de schema nunca é a parte difícil. O lock, o backfill e o código velho ainda rodando são.
- O engenheiro full-stack é um engenheiro de sistemasFull stack nunca foi saber duas linguagens. É assumir a falha onde quer que ela aconteça.
- O que um médico me ensinou sobre sistemasConheci meu pai uma vez, no consultório dele. O jeito dele de diagnosticar é como audito sistemas hoje.
- O humano no loop é uma decisão de designHumano no loop não é checkbox para o slide de compliance. É uma interface, um fluxo e um orçamento que você precisa projetar.
- A armadilha da biblioteca compartilhadaO pacote criado para evitar duplicação costuma ser o acoplamento mais forte do sistema. Como reconhecer, e o que fazer no lugar.
- Detalhes não são pequenosUm detalhe é uma decisão em escala pequena. Os sistemas que falham, e as pessoas de quem lembramos, são feitos deles.
- Os três primeiros alertas que todo sistema precisaAntes de dashboard, antes de SLO, antes de tudo: três alertas que pegam a maioria das quedas e quase nunca mentem.
- Como eu leio um sistema que nunca vi em uma horaO método de auditoria que uso para entender um sistema desconhecido rápido: entradas, dados, dinheiro e o que acontece quando cai.
- Error boundaries de ponta a pontaError boundary não é um componente React. É uma decisão sobre onde a falha para, tomada em cada camada, do clique até o banco.
- O que um build verde escondeUm pipeline que passa prova que os testes que você escreveu passam na máquina em que rodaram. O resto é fé. Eis o que conferir.
- Upload de arquivos, feito certo da primeira vezNunca deixe um arquivo passar pelo seu servidor. Assine, envie direto, verifique depois e trate todo nome de arquivo como hostil.
- Observabilidade para aplicações com LLMLogs e latência não bastam. Você precisa do prompt, da saída, do custo e da qualidade por request, e de poder reproduzir tudo.
- Registros de decisão de arquitetura que alguém realmente lêA maioria dos ADRs é escrita uma vez e nunca mais aberta. Aqui está o formato e a disciplina que os fazem sobreviver.
- Autodidata não quer dizer sozinhoNunca terminei uma graduação, mas nunca aprendi sozinho. Como achar professores quando ninguém te designa um.
- Proveniência de dados para cientistas, explicada por um engenheiroUm número que não se rastreia é opinião com casas decimais. O que é proveniência e como construí-la sem complicação.
- UI com streaming e o que ela custa para o backendStreaming faz a página parecer rápida. Também mantém conexões abertas, multiplica queries e esconde caminhos lentos. Orce isso.
- Quando não usar um modelo de linguagemUm modelo de linguagem é um componente com custo, latência e taxa de erro. Em metade dos lugares onde vejo um, uma regex teria ganhado.
- Projetando para a dependência lenta, não para a mortaDependência morta falha rápido. A lenta lota seus pools e te derruba. Bulkheads, deadlines, fallbacks e p99.
- Log estruturado ou nadaLinha de log que você não consegue consultar é linha que você vai ler uma vez, no incidente, tarde demais.
- O monólito modular na práticaUma unidade de deploy, fronteiras internas rígidas. Como fica numa base TypeScript real, e onde os times trapaceiam.
- O custo escondido de cada dependência que você adicionaA instalação é grátis. A árvore transitiva, o ritmo de upgrades, o peso no bundle e o risco de supply chain não são.
- A ética de construir ferramentas para a medicina sem ser médicoNão sou médico. Construo ferramentas que médicos e cientistas vão usar. Esta é a linha que eu traço, e por quê.
- Quando adicionar um message broker, e quando você está fugindo de uma decisãoO que um broker compra, o que custa, e o sinal de que a fila está ali para evitar decidir quem é dono do dado.
- Prompt injection é a validação de input que você esqueceuResolvemos SQL injection separando código de dados. Prompt injection é a mesma lição num sistema que não consegue separá-los por completo.
- Tipos nas bordas: valide uma vez, confie em todo lugarTipos do TypeScript somem em runtime. Coloque uma checagem real em cada borda e deixe o compilador levar a prova para dentro.
- A primeira coisa que confiro em qualquer códigoAntes da arquitetura, antes dos testes, antes do README: encontro cada lugar em que os dados são escritos e conto.
- O custo de nuvem que ninguém coloca no orçamentoComputação é a linha que todo mundo olha. A fatura cresce nas linhas que ninguém lê.
- Reversibilidade como objetivo de arquiteturaA melhor decisão de arquitetura é a que dá para desfazer em um sprint. Otimize para isso antes de otimizar para qualquer outra coisa.
- Construindo sistemas de nível mundial de uma cidade pequena do ParanáLugar importa. O que você precisa fazer diferente quando nunca está na sala.
- O prompt não é a especificaçãoO prompt diz ao modelo o que fazer hoje. A spec diz a todo mundo o que significa estar certo. Os times vivem confundindo os dois.
- Back-pressure é feature, não bugUm sistema que diz "agora não" é mais saudável do que um que aceita tudo e cai. Construa o caminho da recusa.
- A IA e o fim do boilerplate, e o que ocupa o espaçoGerar código ficou barato. As habilidades escassas migraram para especificação, verificação e critério, e a carreira foi junto.
- TTL de DNS e outras coisas pequenas que mordem às 3 da manhãAs quedas que mais doem raramente são arquiteturais. São um número que alguém definiu uma vez e esqueceu.
- Máquinas de estado para tudo que importaSopa de flags esconde contradições. Estados explícitos, tabela de transições e log de transições deixam bugs e relatórios óbvios.
- O que eu procuro em um engenheiroNem a stack, nem os anos. Cinco hábitos que aparecem na primeira hora e preveem todo o resto.
- O deploy faz parte do designSe você não consegue descrever como uma mudança chega em produção com segurança, o design não terminou.
- O bug está sempre na fronteiraDentro de um módulo, o código é consistente consigo mesmo. Os bugs moram onde duas coisas com premissas diferentes se encontram.
- TypeScript como ferramenta de design, não como linterSe seus tipos só pegam erro de digitação, você usa um décimo da ferramenta. Tipos são onde eu desenho o sistema primeiro.
- Como eu reviso código que um modelo escreveuO mesmo padrão de qualquer pull request, mas os bugs moram em lugares diferentes. Aqui é onde eu olho.
- Consistência eventual, explicada para o time de produtoPor que o pedido aparece três segundos depois, quais fluxos nunca podem atrasar e como fazer uma UI que diz a verdade.
- Dados cardiovasculares são um problema de sistemasO coração produz mais tipos de dado do que quase qualquer órgão. Fazê-los concordar não é problema médico. É problema de integração.
- O edge runtime: quando ajuda e quando só move o problemaComputar perto do usuário só é rápido se o dado está perto da computação. Senão você adicionou uma viagem de ida e volta a cada query.
- Lendo código legado como um arqueólogoCódigo legado não é código ruim. É um registro de decisões sob pressão. Aprenda a ler as camadas antes de cavar.
- Agentes também precisam de fronteirasUm agente é um loop com permissões. Toda regra que aplico a serviços vale para ele, com um raio de dano maior.
- A rota de API que virou um monólitoComeçou como um handler. Dois anos depois é um arquivo de 900 linhas que ninguém ousa tocar. Veja como evitar isso.
- Cache é uma decisão de consistência disfarçadaCache é uma cópia, e toda cópia te obriga a decidir o quão desatualizado o usuário pode ver o mundo.
- Validação não é uma faseTimes de software aprenderam que testar no final não funciona. Ferramentas de ciência precisam da mesma lição: valide cada etapa.
- Load test da coisa certaA maioria dos load tests mede a velocidade de servir uma home cacheada. Produção falha em outro lugar.
- Contratos antes do códigoEscreva a interface, o schema e os casos de falha antes da primeira linha de implementação. É a revisão de design mais barata que existe.
- Uma revisão de segurança que dá para fazer em uma tardeNão é pentest. As sete verificações que encontram a maior parte do que é explorado de verdade, em quatro horas, com o que você já tem.
- WebSockets, SSE ou polling: uma tabela de decisãoTrês jeitos de levar dado ao vivo ao navegador. O certo depende de direção, escala e hospedagem, não do que soa moderno.
- O padrão outbox em palavras simplesCommite o evento junto com os dados, deixe um relay publicar, faça consumidores idempotentes. A escrita dupla, resolvida sem jargão.
- A pesquisa é um sistema com problema de throughputCientistas não são lentos. O pipeline em volta deles é. Como um engenheiro de sistemas enxerga um laboratório.
- Blue-green, canary e o rollback honestoEstratégia de deploy só vale o rollback que ela realmente permite. A maioria dos times superestima o seu.
- Arquitetura hexagonal sem a cerimôniaPorts and adapters é uma boa ideia enterrada debaixo de uma pilha de pastas. Fique com a ideia, jogue fora a pilha.
- A vantagem do generalistaAs falhas moram nas fronteiras entre camadas, e o generalista é quem consegue ver a costura.
- Embeddings não são mágica. São uma compressão dos seus dados.Um embedding é um resumo com perdas escolhido pelos dados de treino de outra pessoa. Trate como formato de compressão, não como oráculo.
- Server Components mudam onde fica a fronteiraA fronteira antiga era a API. A nova é uma diretiva no topo do arquivo. A maioria dos times ainda não percebeu.
- A mentira do ambiente de stagingStaging prova que o código roda. Quase nunca prova que roda em produção, e fingir o contrário sai caro.
- Quanto custa de verdade um serviço novoO código é a parte barata. Esta é a fatura que vem junto com cada caixinha que você adiciona ao diagrama.
- O modelo vai mudar. A interface não deveria.Projete a fronteira em volta do modelo para que trocar provedor, versão ou prompt seja mudança de config, não reescrita.
- Por que ainda escrevo SQL à mãoO banco é o motor mais capaz da sua stack. Um query builder esconde essa capacidade. As queries que importam, eu mesmo escrevo.
- Um checklist de degradação graciosa para times de produtoDecida de propósito o que o usuário vê quando recomendações, busca, pagamento ou banco falham. Um checklist para times de produto.
- O que os médicos me ensinaram sobre requisitosAchei que sabia levantar requisitos depois de centenas de projetos. Então sentei com gente cujos erros têm pulso.
- Gestão de secrets para times pequenos que vão crescerO .env é ótimo no dia um e um risco no dia noventa. Este é o caminho que não exige reescrita.
- O banco de dados não é sua camada de integraçãoDois sistemas que compartilham um banco são um sistema com dois pipelines de deploy e nenhum contrato. Veja como sair dessa.
- Leia o tratamento de erros primeiroBlocos catch são onde um time escreveu o que teme e o que escolheu ignorar. Leia-os antes de qualquer outra coisa.
- O custo de um token em produçãoO preço por token é a menor parte da conta. Contexto, retries e loops são para onde o dinheiro vai de verdade.
- Auth não é uma decisão de bibliotecaEscolha a biblioteca por último. Antes, decida de quem é a identidade, onde a sessão vive e o que acontece quando ela é revogada.
- O problema da partição quente e por que sharding não te salvaSharding espalha chaves, não carga. Quando uma chave é quente por conta própria, você precisa de outra caixa de ferramentas.
- O ano em que perdi todos os contratosEm 2020 todos os contratos sumiram em semanas. O que reconstruí tinha outro formato, e o formato é a parte útil.
- Fine-tuning, retrieval ou prompt: uma decisão que tomo toda semanaTrês ferramentas, três tipos de problema. A maioria dos times escolhe por empolgação. Eu escolho pelo que muda e com que frequência.
- Um template de post-mortem que produz mudançaA maioria dos post-mortems é bem escrita e não muda nada. O template decide qual tipo você vai escrever.
- O problema não é o monolito, é o acoplamentoQuebrar um monolito emaranhado em serviços te dá um sistema distribuído emaranhado. Resolva o acoplamento primeiro.
- Seiscentos projetos depois: o que se repeteDepois de mais de 600 projetos construídos, revisados ou auditados, as falhas pararam de me surpreender. A lista curta que sempre volta.
- Feature flags como arquiteturaUma flag é um branch do seu sistema que vive em produção. Trate como tal, ou ela vira o bug que ninguém consegue reproduzir.
- A fila que você não sabia que tinhaSeu diagrama mostra uma fila. Seu sistema tem vinte. A lei de Little explica por que todas enchem ao mesmo tempo.
- Reprodutibilidade é um problema de engenharia'Rodou no meu laptop' não é resultado científico. As ferramentas para resolver isso já existem, e são chatas.
- Observabilidade é feature de produtoConseguir responder "o que aconteceu com esse usuário" vale mais do que a maioria dos itens do seu roadmap.
- Versionar uma API é uma relação, não um númeroA versão na URL é a parte menos importante. O que importa é quem depende de você e o que você deve a essas pessoas.
- RAG é um pipeline de dados com um modelo de linguagem no finalA maioria das falhas de RAG que audito são bugs de ingestão e retrieval fantasiados de IA. Conserte o pipeline, depois pense no prompt.
- Cache no Next.js sem surpresasQuatro camadas de cache, uma regra: nunca cacheie o que não consegue nomear, e nunca nomeie o que não consegue invalidar.
- Exactly-once é uma promessa que ninguém cumpreEntregar e processar são promessas diferentes. At-least-once mais consumidor idempotente é a garantia que você realmente tem.
- Strict mode é o code review mais barato que você vai terUm revisor que lê cada linha, a cada tecla, nunca cansa e não tem ego. Custa uma linha no tsconfig.
- Planejamento de capacidade em um guardanapoA conta de padaria que diz se você está construindo para 10 rps ou 10.000, e em qual número você está errado.
- Modelos pequenos, alavanca grandeO frontier model é o default errado. Quase todo trabalho num pipeline real é estreito, repetitivo e barato de acertar com modelo pequeno.
- Um monorepo TypeScript que continua rápido depois do segundo anoMonorepos não ficam lentos por serem grandes. Ficam lentos porque ninguém desenhou o grafo de dependências de propósito.
- A lei de Conway é uma ferramenta, não uma maldiçãoSeu sistema vai espelhar o organograma, goste você ou não. Então desenhe o organograma de propósito.
- O pull request que parece bemDiff pequeno, testes verdes, descrição clara, aprovação rápida. A anatomia da mudança que derrubou a produção mesmo assim.
- Backup que você nunca restaurou é hipóteseBackup é uma afirmação sobre o futuro. Só o restore transforma ele em fato.
- Evolução de schema sem downtimeExpand and contract, backfill em lotes, migrations conscientes de lock e cutover por flag: como mudar o schema com tudo rodando.
- Structured outputs são contratosUm schema transforma o modelo de gerador de texto em componente integrável. Trate com a seriedade de uma API.
- Timeout é a resiliência mais barata que você vai comprarSem timeout significa infinito. Como eu defino connect, read e orçamento total para uma dependência lenta não derrubar tudo.
- Ciência aberta precisa de infraestrutura chataCiência aberta não falha nos ideais. Falha em armazenamento, identificadores, uptime e na pessoa não paga que mantém o servidor vivo.
- Dívida técnica é um empréstimo, e todo empréstimo tem um nomeA dívida não é o atalho. É o atalho sem dono, sem prazo e sem data de pagamento. Conserte a metáfora e o backlog anda.
- Da gráfica ao quadro brancoRecorte de vinil, conserto de eletrônicos e obra me ensinaram os três hábitos que ainda uso para desenhar sistemas.
Nada corresponde a isso.