Desafio de System Design: sistema de geração de cortes
Sobre o Evento
Neste evento da comunidade, Tiago Aguiar propôs a Jessica Nathany e a Luis Marcano o mesmo problema: desenhar o sistema que gera cortes de vídeo para redes sociais a partir de episódios de podcast. Cada um fez o seu desenho em casa e apresentou ao vivo, com a proposta de que cada um explique por que foi por um caminho e não por outro. O resultado é uma comparação de três arquiteturas para o mesmo requisito, cheia de trade-offs.
O que foi discutido
- O que é system design e a diferença para design system: o primeiro trata de como os componentes não visíveis ao usuário se organizam e se comunicam, o segundo de paletas, componentes visuais e UI
- A experiência de projetar com requisitos incompletos, sem número de usuários, rate limit ou regras de negócio, e como isso muda o desenho
- O desenho da Jessica: API Gateway, endpoints, serviço assíncrono com mensageria, workers de transcrição, destaques e cortes, bucket para arquivos e a dúvida entre LLM externa e local
- O papel do template de câmeras, que marca onde cada pessoa aparece no vídeo para o recorte vertical
- O desenho do Luis: monolito modular, upload direto ao storage por URL temporária em partes (chunks), Outbox e workers em ordem (transcrição, destaques, cortes)
- Filas separadas por worker versus fila única, dead letter, retentativas e como retomar o processamento de onde parou
- O desenho do Tiago: CDN, proteção contra ataques, cobrança por créditos, orquestrador com comandos e eventos, render por corte e rotina de expurgo de vídeos antigos
- Custo e variabilidade das LLMs, o uso de modelos especializados e a possibilidade de o usuário trazer a própria chave de API
Sobre Jessica Nathany e Luis Marcano
Jessica já está familiarizada com decisões de arquitetura e comunicação entre sistemas, inclusive com a passagem de aplicações legadas para arquiteturas distribuídas, e tem um podcast. Já participou de um programa com Tiago sobre entrevistas técnicas e como se preparar para elas. Luis é membro da comunidade, não tem experiência profissional em arquitetura de sistemas e encarou o desafio como exercício de estudo, para colocar em prática conceitos que só conhecia como termos soltos. A ideia do tema nasceu de uma conversa na comunidade sobre system design em entrevistas.
Principais pontos
Sem requisitos de escala, o desenho vira escolha
Jessica sentiu falta de números que guiam a arquitetura: quantos usuários, quantas requisições por segundo, quais regras de negócio. Tiago contou que de propósito só passou o tema e que assumiu um cenário mediano, nem para cem usuários nem para um milhão. A conversa mostrou que quase toda decisão tem um cenário em que faz sentido e outro em que é exagero: o próprio Tiago admitiu que, para poucos usuários, itens do seu desenho, como CDN, poderiam ser dispensados. Jessica ainda lembrou que o modelo de dados de uma arquitetura distribuída não precisa copiar o modelo do negócio.
"por exemplo, a quantidade de usuários que vai usar a plataforma, o que eu posso usar aqui, será que eu posso manter dessa forma, será que eu preciso escalar até quanto?" por Jessica Nathany
Assíncrono com mensageria: ganha desacoplamento, paga em complexidade
No desenho da Jessica, o usuário faz o upload e o restante roda em background, com workers consumindo filas (por exemplo, Kafka) para transcrever, achar os destaques e gerar os cortes. O ganho é que nenhuma etapa bloqueia a tela do usuário. O custo é mais componentes: é preciso consumir a fila, tratar dead letters e pensar em um fallback. Jessica também levantou a dúvida de usar LLM externa, que gera custo por token, ou um modelo local, que dá mais trabalho para operar, e Tiago acrescentou que rodou o Whisper localmente com placa NVIDIA, mas que, na nuvem, a máquina ficaria cara.
"O ponto negativo é que aumenta um pouco de complexidade, porque eu vou jogar isso com uma fila, vou ter que consumir os dados da fila, tenho que tratar também a questão de dead letters" por Jessica Nathany
Upload direto ao storage e só o áudio na transcrição
Luis defendeu que o arquivo de vídeo não passe pela API: o front-end pede uma URL temporária, e o upload é enviado em partes ao Blob Storage, que retoma do último pedaço se a conexão cair. Isso evita estourar o limite de uma requisição HTTP para arquivos de vários gigabytes. Para a transcrição, ele envia apenas o áudio, que pesa uma fração do vídeo, a um serviço de IA que devolve um JSON com início e fim de cada fala (timespans), usado depois para montar os cortes. O front-end só fica travado durante o upload, como no YouTube.
"eu prefiro no caso encarregar essa parte do upload diretamente para o Blob Storage que é o meu serviço de armacenamento na nuvem, porque dali ele vai conseguir gerenciar muito mais fácil fazendo o envio do upload do vídeo através de chunks" por Luis Marcano
Filas separadas, Outbox e retomada de onde parou
No desenho do Luis, cada worker grava o resultado e uma linha em uma tabela Outbox, que avisa que a próxima etapa pode começar e, como Tiago observou, serve também de cópia das mensagens caso o broker perca alguma. Ele pensou em uma fila única, e Jessica argumentou a favor de uma fila e um consumer por worker: um problema em um consumer não atrapalha os outros, e é possível escalar só o que gargala. Luis concordou. Na falha de uma etapa, a proposta foi tentar de novo com espera crescente, mandar para dead letter depois de algumas tentativas e permitir retomar a partir da última etapa concluída, aproveitando vídeo e transcrição já salvos.
"mas deveria ter uma opção, por exemplo de continuar de onde eu parei, ou continuar o reprocessamento" por Luis Marcano
Orquestrador e créditos: verificar o plano antes de começar
Tiago desenhou um orquestrador que posta comandos nas filas dos workers e escuta os eventos de conclusão, consultando antes de cada etapa paga o saldo de créditos do usuário em um livro-razão de consumo. Isso permite cobrar por plano e barrar etapas caras. Luis comentou que bloquear só no meio do fluxo frustra quem já subiu o vídeo e já gerou a transcrição, e sugeriu validar o plano antes de iniciar o processo. Tiago concordou que o ponto faz sentido e apontou o desafio de estimar o custo de LLMs, que varia com o modelo e com o tamanho do vídeo.
"assim olha você tá me deixando eu começar o trabalho mas não me deixe acabar sabe" por Luis Marcano
Frase de destaque
"a gente fica escutando termos, fica escutando uma frase, sabe? E vai ficar no meio que solto." por Luis Marcano
Lições do evento
- Sem requisitos de escala, qualquer arquitetura é um chute: perguntar quantos usuários, quantas requisições e quais limites vem antes de desenhar.
- Quase toda decisão tem trade-off: o assíncrono com filas dá desacoplamento e custa complexidade; um serviço único é mais simples e escala pior.
- Arquivos grandes não devem passar pela API: upload direto ao storage com URL temporária e em partes evita limites de requisição e retrabalho.
- Enviar só o áudio para a transcrição reduz drasticamente o volume trafegado em relação ao vídeo inteiro.
- Filas e consumers separados por etapa isolam falhas e permitem escalar só o gargalo; retentativas, dead letter e retomada da última etapa concluída evitam refazer o trabalho.
- Quando há cobrança por consumo, verificar o plano antes de iniciar o fluxo evita frustrar o usuário no meio do caminho.