- Ao lançar o Dagger Cloud v3, a nova UI foi escrita em WebAssembly (WASM) e Go
- Go normalmente não é usado no desenvolvimento de UI web, mas essa abordagem foi escolhida para "unificar a base de código e otimizar o desempenho"
- Este texto compartilha "o contexto da escolha, os desafios durante a implementação e o resultado final"
Problema anterior: ineficiência causada por duas bases de código
- A Dagger opera com base em DAGs (Directed Acyclic Graphs) e oferece visualização disso na TUI (interface de terminal) e no dashboard web (Dagger Cloud)
- Antes, a TUI era implementada em Go e a UI web em React/TypeScript
- Porém, era difícil manter sincronização entre as duas UIs, e a UI web em especial apresentava problemas de desempenho ao processar grandes volumes de dados em tempo real
- Ao lidar com fluxos complexos de eventos do OpenTelemetry (centenas de milhares de spans), ficaram evidentes a degradação de desempenho e os problemas de velocidade da UI em React
- Também era necessário implementar a mesma funcionalidade duas vezes, o que representava uma grande carga de desenvolvimento para uma equipe pequena
- Por isso, passou-se a considerar uma nova abordagem com o objetivo de unificar a base de código e otimizar o desempenho
Solução escolhida: Go + WebAssembly
- Unificação da base de código com Go
- Como a TUI já era implementada em Go, também implementar a UI web em Go permitia reutilização de código
- Havia muitos desenvolvedores Go na equipe, o que trazia ganhos de produtividade e facilidade de manutenção
- Uso de WebAssembly (WASM)
- O WebAssembly foi adotado para permitir executar código Go diretamente no navegador
- No entanto, Go + WASM ainda não tem um ecossistema maduro, então havia alguns desafios:
- Falta de bibliotecas de componentes → foi preciso implementar a UI manualmente
- Limite de memória do WASM no navegador (2GB) → era necessário otimizar ao lidar com grandes volumes de dados
- Por outro lado, a otimização de memória poderia beneficiar tanto a TUI quanto a UI web
Estratégia para minimizar os riscos do projeto
- Uso do framework Go-app
- Foi escolhido um framework baseado em Go para desenvolvimento de PWA (Progressive Web App)
- Ele oferece um modelo baseado em componentes semelhante ao React, o que facilitou a transição
- Criação e validação de protótipos
- A UI existente foi reimplementada em Go-app na maior medida possível para identificar os principais problemas
- O WASM já é um padrão aberto bem documentado, e as principais dúvidas puderam ser resolvidas na documentação do Go-app
- O maior problema era o limite de uso de memória, o que exigiu design e otimizações para resolvê-lo
Do protótipo à produção
Estratégias de otimização de desempenho
- Otimização da renderização de logs em grande escala
- Era necessário melhorar o desempenho de renderização ao processar mais de 200 mil linhas de log
- Para isso, foi otimizada a biblioteca de renderização de terminal virtual (midterm),
→ melhorando o desempenho tanto da TUI quanto da UI web
- Melhoria na velocidade de parsing de JSON
- O Go WASM tem parsing de JSON lento → foi projetado um backend inteligente baseado em WebSocket
- O uso de
encoding/gob do Go otimizou a transferência de dados
- Otimização do tamanho do arquivo WASM
- Tamanho inicial do arquivo WASM: 32MB
- Aplicação de compressão Brotli → redução para 4,6MB
- Como era difícil tratar essa compressão via CDN, ela foi aplicada diretamente no processo de build
Outras melhorias
- Tirando os problemas de memória já previstos, a maior parte das preocupações não se concretizou
- Escrever componentes de UI não foi difícil, e a integração com outros serviços (Tailwind, Auth0 etc.) também não apresentou problemas
- Foi possível usar pacotes NPM no WebAssembly, garantindo interoperabilidade com JavaScript
- O Go-app oferece mais flexibilidade que o React na forma de atualizar componentes, dando maior liberdade para otimização
- Ferramentas de profiling do Go (
pprof) e o profiler embutido do navegador permitiram analisar o desempenho
- Graças ao suporte a PWA, foi possível executar como app para desktop/mobile, sem precisar abrir o navegador
Benefícios obtidos após a migração
- Melhoria na consistência da UI
- Como a TUI e a UI web passaram a usar a mesma base de código, foi possível oferecer uma UX mais consistente
- Melhoria de desempenho e uso de memória
- Ao lidar com grandes volumes de dados, houve melhora na velocidade de renderização e redução no uso de memória
- Aumento da produtividade da equipe
- Antes, era necessário otimizar separadamente a UI web e a TUI,
mas agora uma única otimização pode ser aplicada às duas interfaces ao mesmo tempo
- Com isso, foi possível focar mais no desenvolvimento de novos recursos
Vale a pena migrar para Go + WASM?
- Em geral, não é recomendado, mas pode ser útil em condições específicas:
- Equipes com muitos desenvolvedores Go
- UIs complexas em que TypeScript/React mostram limites de desempenho
- Necessidade de compartilhar código entre TUI e UI web
- Ambientes em que é preciso maximizar a velocidade de desenvolvimento
- Se essas condições forem atendidas, Go + WASM pode ser uma boa alternativa
Porém, na maioria dos casos, as tecnologias web existentes (React, TypeScript etc.) continuam sendo mais adequadas
6 comentários
É tipo o antigo GWT?
Hmm... fico curioso para saber se isso vai resultar em um desenvolvimento mais seguro em termos de tipos do que com TS.
Por mais que eu olhe, parece que estão resolvendo um problema simples de um jeito complicado...
É mais eficaz do que parece criar frontends baseados em Go. Dá para entender por que os casos de uso estão aumentando.
Mesmo assim, dá vontade de tentar.
Opiniões no Hacker News
Há a opinião de que, sendo uma equipe pequena, precisam fazer deploy rapidamente
Havia uma equipe forte de engenheiros Go e uma UI complexa que seria difícil de escalar com TypeScript/React
Houve preocupação se seria um framework que “renderiza em canvas”, mas não é o caso
Eles decidiram criar o frontend usando <a href="https://go-app.dev/" rel="nofollow">https://go-app.dev/</a>
Há a opinião de que Go não é adequado para esse tipo de trabalho
Seria interessante um relatório de acompanhamento daqui a alguns meses sobre se a migração de uma stack mais pesada para uma stack mais performática, mas um tanto incomum, trouxe resultados positivos
O criador do go-app encontrou esta postagem e ficou surpreso, desejando sucesso ao produto
Como o Go WASM era lento para fazer parsing de JSON, isso levou a mudanças na arquitetura e à criação de um “backend inteligente” para carregamento progressivo de dados via WebSockets
Há a opinião de que WASM é adequado para nichos específicos, mas inadequado para criar aplicações web gerais
Considera-se que há grande valor em usar a mesma linguagem para todos os componentes (frontend/backend/app)