8 puntos por GN⁺ 2025-04-14 | 2 comentarios | Compartir por WhatsApp
  • Un caso de reconstrucción total de la UI para dispositivos de sala sobre Rust y WebAssembly
  • Se diseñó una arquitectura para lograr alto rendimiento y baja latencia de entrada incluso en dispositivos con distintos niveles de desempeño
  • Dejaron atrás React y desarrollaron internamente un SDK de UI exclusivo para Rust, asegurando alta productividad
  • Gestionan la complejidad del código y el rendimiento mediante una arquitectura basada en Entity-Component-System (ECS)
  • Un análisis honesto sobre las ventajas, desventajas y problemas de usar WebAssembly y Rust

Por qué reconstruyeron la UI de Prime Video con Rust y WebAssembly

  • Amazon tenía el reto de ejecutar la misma app de Prime Video en distintos dispositivos de sala (consolas, decodificadores, sticks de streaming, TVs, etc.)
  • Para ofrecer una experiencia de usuario consistente en dispositivos con distintos niveles de rendimiento, necesitaban un motor de UI de alto desempeño
  • Antes usaban una pila tecnológica mixta compuesta por React (TypeScript), JavaScript, C++, WebAssembly y Rust
  • Debido a la lentitud de ejecución de JavaScript y a la dificultad para actualizarlo, decidieron migrar por completo a Rust
  • WebAssembly facilita las actualizaciones de la app, y Rust resulta favorable para la optimización de rendimiento

Principales retos de desarrollo en dispositivos de sala

  • Necesitaban cubrir una amplia gama de especificaciones de rendimiento, desde equipos potentes como la PS5 hasta sticks USB de bajo consumo
  • Tenían que desarrollar con una sola base de código, sin mantener equipos separados para cada dispositivo
  • En la mayoría de los dispositivos, solo se pueden hacer actualizaciones de firmware y no hay tienda de apps, por lo que actualizar código nativo es difícil
  • Para actualizar la UI con frecuencia, era más conveniente usar código basado en JavaScript y WebAssembly
  • Eligieron la combinación Rust + WebAssembly como punto de equilibrio entre altos requisitos de rendimiento y ciclos rápidos de actualización

Comparación entre la arquitectura anterior y la nueva arquitectura de UI basada en Rust

  • La arquitectura anterior tenía la siguiente estructura:
    • La lógica de UI se escribía en React, mientras Rust (WebAssembly) procesaba el motor de UI de bajo nivel
    • React → bus de mensajes → motor de UI en WebAssembly → backend de renderizado en C++
  • Para resolver el problema de latencia de entrada, migraron toda la lógica de negocio al SDK de UI en Rust
  • Nueva arquitectura:
    • Desde el SDK de UI hasta el renderizado, todo está construido en Rust
    • Se eliminó el bus de mensajes y todo el procesamiento se ejecuta dentro de WebAssembly
    • El código se compila a WebAssembly y se envía a la TV, logrando mejor velocidad de actualización y capacidad de respuesta que antes

Componentes principales del nuevo SDK de UI en Rust

  • Introdujeron un concepto composable similar al de React → unidades reutilizables para construir UI
  • Sistema de UI reactiva basado en Signal y Effect
    • Signal: cuando cambia un valor, dispara los Effect relacionados
    • Memo: solo reacciona cuando el valor cambia respecto al anterior
  • La jerarquía de UI se define mediante la macro compose!
  • Los elementos de UI se componen de Widget (componentes provistos por defecto) y Composables (estructuras definidas por el usuario)
  • Uso de arquitectura Entity-Component-System (ECS):
    • Entity: ID
    • Component: datos de atributos (ej. Layout, RenderInfo, Text)
    • System: función que ejecuta lógica sobre una combinación específica de Component

Estructura y funcionamiento del sistema ECS

  • Cada sistema requiere una combinación específica de componentes y, con base en ella, procesa las actualizaciones de la UI
  • Ejemplos:
    • Resource Management System: componente de imagen → carga al GPU → actualización de RenderInfo
    • Layout System: cálculo de distintos componentes relacionados con layout
    • Rendering System: salida visual real en pantalla con base en RenderInfo
  • Esta estructura permitió una migración gradual de distintas páginas desde React hacia Rust
  • La coexistencia y transición entre páginas basadas en JavaScript y páginas basadas en Rust fue fluida

Buenos resultados y beneficios

  • Incluso los desarrolladores de JavaScript/React lograron cambiar al SDK de UI en Rust sin pérdida de productividad
  • Gracias a la estructura familiar del SDK de UI, incluso quienes empezaban con Rust pudieron adaptarse rápidamente
  • Fue posible implementar funciones antes imposibles, como animaciones de layout y transiciones rápidas de pantalla
  • También pudieron crear con rapidez herramientas internas de desarrollo (administrador de recursos, inspector de layout, etc.) sobre Rust
  • La latencia de entrada, que era de 250 ms, se redujo drásticamente hasta 33 ms (en dispositivos de gama baja)

Dificultades y límites técnicos

  • WebAssembly System Interface (WASI) sigue siendo un ecosistema en evolución, por lo que existe la posibilidad de que actualizaciones de Rust rompan código existente
  • En WebAssembly, si ocurre un panic, toda la app se cierra → esto dificulta garantizar la estabilidad
    • A diferencia de JavaScript, el manejo de excepciones es insuficiente → es necesario usar activamente el tipo Result
    • Al depender de librerías externas, es necesario impulsar implementaciones libres de panic
  • En entornos de navegador, WebAssembly y ciertas API de renderizado específicas no están soportadas, por lo que no se aplica al cliente web

Bytecode Alliance y contribuciones al ecosistema

  • Amazon participa activamente en la estandarización de WASI y en la mejora de funciones relacionadas como miembro de Bytecode Alliance
  • El WebAssembly Micro Runtime que usan está basado en C, y también evalúan en paralelo Wasmtime, basado en Rust
  • Están participando directamente con feedback técnico y desarrollo para impulsar el ecosistema WebAssembly

Otras preguntas y respuestas

  • ¿También es posible en navegadores web? → algunos navegadores WebKit no soportan WASM y, por degradación de rendimiento y complejidad de implementación, todavía lo siguen evaluando
  • Sí es posible implementarlo con WebGL, pero por ahora quedó en pausa porque el retorno no justifica la inversión

Resumen

  • La UI de Prime Video basada en Rust + WebAssembly cumple con la combinación de alto rendimiento, baja latencia de entrada y actualizaciones rápidas
  • Su SDK de UI propio y la arquitectura ECS gestionan eficientemente comportamientos complejos de la UI
  • Aunque adoptar Rust no es sencillo, con un diseño sistemático y una cultura de desarrollo adecuada lograron productividad y estabilidad al mismo tiempo
  • El ecosistema WebAssembly aún está madurando, pero en servicios reales ya es perfectamente viable
  • Su adopción exitosa se basó en un prototipado riguroso y una estrategia de migración gradual

2 comentarios

 
seunggi 2025-04-14

En comparación con el frontend que suele venir con una librería de manejo de estado como base, siempre he pensado que en los juegos literalmente todos los estados interactúan con todos, así que simplemente se hace de una forma más directa, digamos, “a lo macho”. Pero, por otro lado, usar ECS en una aplicación implicaría algo parecido a usar un manejo de estado estandarizado por patrones, similar a que cada desarrollador use su propia librería o una librería interna, así que me da curiosidad saber cómo resolvieron esa parte.

 
y15un 2025-04-14

Aplicar a la UI un ECS que uno normalmente veía en motores de juegos; vaya, sí que es una idea bastante novedosa. Hoy también me llevo algo nuevo aprendido.