Construindo sistemas escaláveis. Aqui eu divido o que aprendo sobre arquitetura, visão de produto e por que só saber codar quase nunca é suficiente.

Joined January 2019
isso aqui é bem importante rapaziada. idempotência vc usa quando uma mesma operação pode ser executada N vezes, mas o efeito final precisa acontecer só uma vez por exemplo: Uma cobrança. o client pode dar retry, a request pode chegar duplicada, o webhook pode ser reenviado etc. Mesmo que vc processe a mesma operação mais de uma vez, vc não pode cobrar o cliente duas vezes dedup é um pouco diferente. Ai o objetivo é identificar que aquela request/evento ja passou por ali e impedir que ela seja processada novamente normalmente vc guarda alguma chave/id por um periodo e se ela aparecer de novo dentro daquela janela, descarta então meio que: idempotência = executar novamente não muda o resultado/efeito final dedup = nem deixa a mesma coisa ser processada novamente as duas coisas podem ser usadas juntas, mas resolvem problemas ligeiramente diferentes
As a dev do you know the difference between - idempotency - deduplication Most devs get confused.
2
22
2
567
30,402
discordo bastante de quem está subindo código sem revisar, e acho que essa ideia só funciona APENAS em alguns cenários bem específicos. se vc trabalha em uma empresa real, com cliente real e dinheiro real passando pelo software, qualquer merda que a LLM colocar em produção continua sendo responsabilidade sua. adivinha só: no git blame vai estar seu nome. não importa se vc escreveu linha por linha, pediu pro Codex fazer ou deixou 15 agents trabalhando enquanto dormia. No fim, foi vc quem decidiu que aquele código estava pronto pra entrar. e vejo muita gente se apoiando no argumento de "ah, mas os testes passaram..." só que, sem um bom input do desenvolvedor dizendo oq precisa ser testado, muitas vezes os testes gerados pela própria LLM são só encheção de linguiça. é quase o msm problema de quando a IA alucina alguma coisa com uma confiança absurda e vc acredita. só que aqui é mais perigoso. é saBOR cobertura 🫴 outro argumento que vi é que agora ficou "barato corrigir" IMHO isso é uma meia verdade vc não eliminou o custo, só distribuiu ele pra outros lugares se cada nova feature entra em produção no estilo roleta russa, rapidamente o QA vira gargalo, suporte começa a receber mais problema, engenharia para pra apagar incêndio, cliente encontra bug antes de vc e produto deixa de estar trabalhando em coisa nova mas pra mim o ponto mais importante nem é esse é oq acontece com a codebase depois de alguns meses trabalhando assim se ninguém entende direito oq esta entrando, se as abstrações começam a nascer sem necessidade, se cada agent resolve o mesmo problema de um jeito diferente, chega uma hora que ler e entender aquela codebase fica caro demais ai eventualmente aparece um problema que a LLM não consegue resolver sozinha pq depende de contexto de negócio, histórico de decisão ou por qualquer outro motivo e vc entra no modo tigrinho: manda prompt. roda. não funcionou. manda outro. roda. reza... e continua até sair alguma coisa pra mim esse é o cenário realmente perigoso não acho que devemos deixar code review de lado. é provavelmente uma das partes mais chatas do trabalho hoje? sim. mas enquanto somos nós que respondemos pelo software que vai pra produção, revisar e entender oq esta entrando ainda é uma das principais coisas garantindo que a codebase continue minimamente saudável. e vc que ta só terceirizando a qualidade pros seus pares no code review... Deus ta vendo. e seu Tech Lead tb.
1
104
vamos ver se esse jev é bom mesmo
97
respirando por canudinho
1
65
tava lembrando aqui de quando sem querer fiz o @zanfranceschi perder o final de semana rodando os resultados da @rinhadebackend de 2024 😅
E o @eufilipemacedo que encontrou inconsistências em algumas API que não são testadas pelo teste atual. Muio obrigado Filipe, agora vou ter que rodar todas as API novamente e isso vai levar mais de 4 horas, além de ter que mexer na computação dos pontos! HAHAHA 🫶
4
171
sabe quando vc avisa que vai da merda, ninguém da bola e depois acontece exatamente oq vc tinha previsto? é muito fácil nessa hora lançar o famoso: "eu avisei" só que IMHO isso não agrega em nada. primeiro resolve o problema. depois vale voltar e entender oq aconteceu. O risco estava realmente claro? vc conseguiu explicar o impacto? ficou registrado? ou pra quem estava decidindo aquilo era só mais uma preocupação técnica entre várias outras? e pode ser tb que todo mundo tenha entendido perfeitamente e decidido assumir o risco msm assim. acontece.
1
1
148
Filipe Macedo retweeted
voltem a contratar design gráfico gente, pelo amor de Deus, esses flyers criados por IA são horríveis
90
3,151
196
15,891
200,017
eu provavelmente iria por esse caminho: deixaria a API responsável por gerar a presigned URL e faria o upload direto pro S3. A partir dai, evento do S3 -> SQS -> workers processando resize/compress/crop -> S3 de derivados. o que eu gosto desse desenho é que o upload fica completamente desacoplado do processamento. Se em algum momento entrar um pico muito maior, a fila absorve e os workers vão processando no throughput que vc definir. 500k fotos/dia da algo perto de 6 uploads/s na média, então IMHO o maior desafio nem é o numero em si, mas como isso se comporta nos picos.
Você precisa processar o upload de 500 mil fotos de perfil por dia sem travar a navegação do usuário. O que você usaria? - Node / Go / Python / PHP - Processar direto na API / SQS + Lambda / RabbitMQ + Workers / BullMQ + Redis
2
8
240
Filipe Macedo retweeted
Tem uma galera que fica viciada em ser a vítima. Em ser o perdedor. Vira parte da narrativa da pessoa. Tem discurso que é discurso de perdedor quase por definição. A pessoa tá sempre arrumando problema, desculpa pras coisas darem errado. Só fujam de gente assim.
5
9
1
103
2,122
Você não precisa de Harness Engineering xitter.cf/i/spaces/1RKZzBAqkoNKB

16
2
2
23
4,597
sinceramente eu não sei como a galera consegue simplesmente confiar no output da IA. mesmo quando a funcionalidade ta funcionando e os testes estão passando, me incomoda MUITO não parar pra olhar oq realmente esta rodando por baixo do capô. eu ainda gosto de revisar, entender as decisões que a LLM tomou, ver se a abstração faz sentido, se não criou complexidade desnecessária, se não escondeu algum problema etc. pra mim teste passando valida comportamento. não necessariamente valida se a decisão de engenharia foi boa. talvez isso mude com o tempo, mas hoje eu ainda não consigo abrir mão dessa etapa.
1
1
87
são poucos os cenários em que isso faz sentido. se vc ta usando orquestração/subagents pra atividade cotidiana, muito provavelmente ta queimando token atoa 😅
2
148
é retratado como complexo pq ele adiciona complexidade de fato rs em cenário controlado/lab realmente é mais simples em produção o buraco fica um pouco mais embaixo, pq vc adiciona novos pontos de falha e passa a lidar com coisas que antes nem existiam no fluxo síncrono ai entram retry, idempotência, mensagem duplicada, ordering, poison message, DLQ, backpressure, eventual consistency, schema evolution, dual write etc e talvez o ponto mais subestimado seja observabilidade/debug se o monitoramento não estiver bom, é bem fácil vc ter uma request que gerou um job, que gerou outros 30 jobs, 29 terminaram e 1 morreu em algum ponto, e ninguém sabe pq aquele estado final nunca aconteceu e isso não significa que mensageria deva ser evitada. A ideia é simples. Operar isso de forma confiável em produção é que adiciona complexidade
Por que as pessoas tratam mensageria assíncrona como algo 'super complexo' que só vai ser adicionado em fases avançadas de um projeto? É literalmente guardar uma informação pra evitar picos de tráfego e processar essa informação depois. Super simples. Você NÃO precisa de microsserviços pra usar fila, você pode ter UMA aplicação monolítica onde UM módulo consome a fila de OUTRO módulo! Alguns exemplos bacanas: - Receber webhooks de pagamentos: você não precisa processar tudo na hora, várias vezes o processamento tem vários passos e guardar no assíncrono só tem vantagens, até mesmo em debug e visualização de dados; - Fazer envios de comunicação: a parte mais comum de tudo isso, você não quer spammar emails em massa para seu provedor de e-mails ou API do whatsapp, guardar numa fila e processar gradualmente é uma ótima escolha - Processamento de dados: limpar aqueles dados antigos, tabelas com soft delete, atualizar informações de um usuário sob demanda, isso não precisa ser um cronjob maluco, pode ser uma mensagem na fila pronta pra ser consumida na hora certa
3
6
87
4,928
é isso família, vamos ver se é bom msm
1
77
vai depender principalmente do cenário e do objetivo desse endpoint. isso é consumido por uma UI? isso é server to server? se for UI, muito provavelmente vamos acabar precisando dos dois. Normalmente o usuário precisa visualizar/navegar pelos dados antes de decidir exportar, então ainda faz sentido existir um endpoint paginado além do mecanismo de export. agora, se for server to server, ai começa a depender bastante do volume. se estamos falando de poucos dados, provavelmente o design A faz mais sentido. É uma solução bem mais simples, rápida e pragmática. Só precisamos garantir coisas básicas como paginação cursor-based, indexes apropriados, limites coerentes etc. o problema é que se esse volume crescer bastante, esse endpoint pode virar uma bomba relógio dependendo de como ele estiver sendo consumido e de como as queries estão otimizadas. agora, se ja sabemos que estamos falando de um conjunto grande de dados, ai pra mim o design B começa a fazer mais sentido.
Backend Interview Question: A client wants every order event from the last 30 days. Which API would you design?
1
1
6
985
Como eu desenharia este Design B: xitter.cf/fazendev/status/209545…
o desenho desse design B é bem legal de fazer. eu imagino mais ou menos assim (em alto nível): primeiro temos um componente responsável por varrer o banco usando cursor-based pagination. A gente mantém um checkpoint pra conseguir continuar de onde parou caso o processo morra no meio. com um ORDER BY determinístico + cursor baseado em uma chave estável, conseguimos ir avançando pelo dataset. Conforme esse componente vai encontrando os dados, ele faz um fan-out criando jobs pra uma fila. ai entram os workers responsáveis por pegar esses jobs, buscar/processar aquele pedaço dos dados e gerar os chunks do CSV. algo tipo: part-00001.csv part-00002.csv quando todos os chunks terminarem, iniciamos uma etapa de finalização responsável por juntar essas partes na ordem correta e gerar o arquivo final no S3 (via streaming/multipart). terminou? gera uma signed URL com expiração e dispara o webhook pro cliente avisando que a exportação esta pronta. e ai começa a parte legal desse desenho, pq da pra ir adicionando as garantias conforme a necessidade: idempotência, controle de concorrência, expiração dos arquivos, observabilidade do progresso, etc. a grande sacada é que transformamos uma exportação potencialmente gigantesca em vários pedaços pequenos e independentes, sem precisar que nenhum componente processe o dataset inteiro de uma vez
105
pega a visão
Pô, que raiva. Acabei de perder algumas horas de trabalho por causa de uma aba antiga. Eu estava escrevendo um artigo aqui no X, já tinha formatado, colocado imagens e revisado tudo. Fechei a aba atual (com a versão nova) e sem querer, voltei numa aba que já estava aberta com a versão antiga. O autosave rodou… e substituiu tudo pelo texto velho 🤬 E o pior: este é um problema bem comum. Isso se chama lost update. Isso não ocorre somente em editor de texto. Acontece em formulário, drag-and-drop, qualquer tela com duas cópias do mesmo dado abertas. Segue o fio pra saber como evitar que esse problema também aconteça com os seus usuários 📷🧶
118
o desenho desse design B é bem legal de fazer. eu imagino mais ou menos assim (em alto nível): primeiro temos um componente responsável por varrer o banco usando cursor-based pagination. A gente mantém um checkpoint pra conseguir continuar de onde parou caso o processo morra no meio. com um ORDER BY determinístico + cursor baseado em uma chave estável, conseguimos ir avançando pelo dataset. Conforme esse componente vai encontrando os dados, ele faz um fan-out criando jobs pra uma fila. ai entram os workers responsáveis por pegar esses jobs, buscar/processar aquele pedaço dos dados e gerar os chunks do CSV. algo tipo: part-00001.csv part-00002.csv quando todos os chunks terminarem, iniciamos uma etapa de finalização responsável por juntar essas partes na ordem correta e gerar o arquivo final no S3 (via streaming/multipart). terminou? gera uma signed URL com expiração e dispara o webhook pro cliente avisando que a exportação esta pronta. e ai começa a parte legal desse desenho, pq da pra ir adicionando as garantias conforme a necessidade: idempotência, controle de concorrência, expiração dos arquivos, observabilidade do progresso, etc. a grande sacada é que transformamos uma exportação potencialmente gigantesca em vários pedaços pequenos e independentes, sem precisar que nenhum componente processe o dataset inteiro de uma vez
Um cliente quer todos os eventos de pedidos dos últimos 30 dias. Qual API você projetaria?
2
3
1
26
2,168