8 pontos por GN⁺ 2025-04-14 | 2 comentários | Compartilhar no WhatsApp
  • Caso de reestruturação completa da UI para dispositivos de sala de estar com base em Rust e WebAssembly
  • Arquitetura projetada para entregar alto desempenho e baixa latência de entrada mesmo em dispositivos com diferentes níveis de performance
  • Abandono da base em React para desenvolver internamente um SDK de UI exclusivo em Rust, garantindo alta produtividade
  • Controle da complexidade do código e do desempenho por meio de uma arquitetura baseada em Entity-Component-System (ECS)
  • Análise franca sobre as vantagens, desvantagens e problemas decorrentes do uso de WebAssembly e Rust

Por que reconstruir a UI do Prime Video com Rust e WebAssembly

  • A Amazon precisava enfrentar o desafio de executar o mesmo app do Prime Video em vários dispositivos de sala de estar (consoles, set-top boxes, streaming sticks, TVs etc.)
  • Para oferecer uma experiência de usuário consistente em dispositivos com níveis de desempenho distintos, era essencial ter um motor de UI de alta performance
  • Antes, usava uma stack mista de React (TypeScript), JavaScript, C++, WebAssembly e Rust
  • Devido à lentidão de execução do JavaScript e à dificuldade de atualização, decidiu migrar tudo para Rust
  • Com WebAssembly, fica mais fácil atualizar o app, e Rust é vantajoso para otimização de desempenho

Principais desafios de desenvolvimento em dispositivos de sala de estar

  • Era necessário atender a uma ampla faixa de especificações de desempenho, de dispositivos potentes como o PS5 até sticks USB de baixo consumo
  • O desenvolvimento precisava ser feito com uma única base de código, sem manter equipes separadas para cada dispositivo
  • Na maioria dos dispositivos, só é possível atualizar via firmware, sem app store, o que dificulta atualizar código nativo
  • Para atualizar a UI com frequência, era vantajoso usar código baseado em JavaScript e WebAssembly
  • A combinação Rust + WebAssembly foi escolhida como ponto de equilíbrio entre alta performance e ciclo rápido de atualizações

Comparação entre a arquitetura anterior e a nova arquitetura de UI baseada em Rust

  • A arquitetura anterior tinha a seguinte estrutura:
    • Lógica de UI escrita em React, enquanto Rust (WebAssembly) cuidava do motor de UI de baixo nível
    • React → message bus → motor de UI em WebAssembly → backend de renderização em C++
  • Para resolver o problema de latência de entrada, toda a lógica de negócio foi migrada para o SDK de UI em Rust
  • Nova arquitetura:
    • Do SDK de UI até a renderização, tudo é composto em Rust
    • Eliminação do message bus, com todo o processamento rodando dentro do WebAssembly
    • O código é compilado em WebAssembly e enviado para a TV, trazendo melhor velocidade de atualização e responsividade do que antes

Principais componentes do novo SDK de UI em Rust

  • Introdução do conceito de Composable, semelhante ao React → unidade reutilizável de composição de UI
  • Sistema de UI reativo baseado em Signal e Effect
    • Signal: quando um valor muda, aciona os Effects relacionados
    • Memo: reage apenas quando o valor é diferente do anterior
  • A hierarquia da UI é definida com a macro compose!
  • Os elementos de UI são formados por Widgets (componentes fornecidos) e Composables (estruturas definidas pelo usuário)
  • Uso da arquitetura Entity-Component-System (ECS):
    • Entity: ID
    • Component: dados de atributos (ex. Layout, RenderInfo, Text)
    • System: função que executa lógica sobre combinações específicas de Components

Estrutura e funcionamento do sistema ECS

  • Cada sistema exige combinações específicas de componentes e, com base nisso, processa as atualizações da UI
  • Exemplo:
    • Resource Management System: componente de imagem → upload para a GPU → atualização de RenderInfo
    • Layout System: cálculo de vários componentes relacionados a layout
    • Rendering System: saída real na tela com base em RenderInfo
  • Essa estrutura permite uma migração gradual de várias páginas do React para Rust
  • A coexistência e a transição entre páginas baseadas em JavaScript e páginas baseadas em Rust acontecem sem atritos

Bons resultados e benefícios

  • Desenvolvedores de JavaScript/React também conseguiram migrar para o SDK de UI em Rust sem perda de produtividade
  • Graças à estrutura familiar do SDK de UI, até iniciantes em Rust conseguiram se adaptar rapidamente
  • Passou a ser possível implementar animações de layout, transições rápidas de tela e outros recursos antes inviáveis
  • Ferramentas internas de desenvolvimento (gerenciador de recursos, inspetor de layout etc.) também puderam ser criadas rapidamente com base em Rust
  • A latência de entrada caiu drasticamente de 250 ms para 33 ms (em dispositivos de baixo desempenho)

Dificuldades e limitações técnicas

  • O ecossistema do WebAssembly System Interface (WASI) ainda está em evolução, e atualizações do Rust podem quebrar código existente
  • No WebAssembly, quando ocorre um panic, o app inteiro é encerrado, o que dificulta garantir estabilidade
    • Diferentemente do JavaScript, o tratamento de exceções é limitado → é necessário usar ativamente o tipo Result
    • Ao depender de bibliotecas externas, é preciso incentivar implementações livres de panic
  • Em ambiente de navegador, WebAssembly e certas APIs específicas de renderização não são suportados, então isso não foi aplicado ao cliente web

Bytecode Alliance e contribuição para o ecossistema

  • A Amazon participa ativamente da padronização do WASI e da melhoria de recursos relacionados como integrante da Bytecode Alliance
  • O WebAssembly Micro Runtime em uso é baseado em C, e o Wasmtime, baseado em Rust, também está sendo avaliado em paralelo
  • Para o avanço do ecossistema WebAssembly, a empresa está fornecendo feedback técnico e participando diretamente do desenvolvimento

Outras perguntas e respostas

  • Isso também funciona em navegadores web? → alguns navegadores baseados em WebKit não oferecem suporte a WASM; além disso, há perda de desempenho e complexidade de implementação, então isso ainda está em análise
  • É possível implementar com WebGL, mas por enquanto foi adiado porque o retorno sobre o investimento parece baixo

Resumo

  • A UI do Prime Video baseada em Rust+WebAssembly atende ao trio de alto desempenho, baixa latência de entrada e atualizações rápidas
  • O SDK de UI próprio e a arquitetura ECS gerenciam com eficiência comportamentos complexos de UI
  • A adoção de Rust não é simples, mas com design estruturado e cultura de desenvolvimento adequada foi possível alcançar produtividade e estabilidade ao mesmo tempo
  • O ecossistema WebAssembly ainda está em evolução, mas já é plenamente viável em serviços reais
  • A adoção bem-sucedida se baseou em prototipagem rigorosa e em uma estratégia de transição gradual

2 comentários

 
seunggi 2025-04-14

Em comparação com frontends que já vêm com bibliotecas de gerenciamento de estado como base, eu sempre pensei que jogos fossem justamente o tipo de coisa em que todo estado mexe em todo estado, então simplesmente se faz no estilo mais direto possível. Mas, por outro lado, usar ECS em aplicativos em geral seria parecido com usar gerenciamento de estado padronizado por cada desenvolvedor ou por bibliotecas próprias; então fiquei curioso sobre como isso foi feito nesse aspecto.

 
y15un 2025-04-14

Aplicar à UI o ECS que a gente costumava ver só em engines de jogo... isso sim é uma ideia bem inusitada. Hoje aprendi mais uma.