O WebAssembly, ou Wasm para abreviar, provou ser uma tecnologia revolucionária inúmeras vezes, graças à sua velocidade de execução rápida e quase nativa, à variedade de opções de linguagem de programação e ao robusto modelo de sandbox de negação por padrão. Ele já foi muito utilizado em toda a web e também tem sido um player formidável no lado do servidor.
Todo ecossistema emergente precisa de uma visão de como todas as peças se encaixam, e é exatamente aí que o Modelo de Componente WebAssembly entra. O Modelo de Componentes é um sistema que facilita as interações entre unidades individuais de código do WebAssembly e as interações entre o código do WebAssembly e um ambiente host. Tudo gira em torno do conceito de componentes WebAssembly, que são essencialmente módulos Wasm regulares com tipos de dados codificados. Esses tipos permitem a geração de código de ligação nos bastidores que faz com que os componentes se comuniquem perfeitamente entre si.
O Component Model inaugura uma nova era de desenvolvimento de software moderno — os desenvolvedores podem escolher componentes de qualquer ecossistema de linguagem de programação e compô-los em um único aplicativo. Tem um aplicativo de processamento de dados em Python, mas precisa de um analisador eficiente de Rust? Sem problemas. Uma equipe na sua organização é proficiente em Go, mas outra só escreve JavaScript? Não há problema algum: cada equipe pode produzir componentes WebAssembly que podem ser compostos sem problemas.
O WebAssembly enfrenta um problema que vimos com quase todas as novas plataformas de execução de código: como compartilhamos dados de forma segura, protegida e eficiente entre unidades de código separadas, potencialmente produzidas por cadeias de ferramentas de linguagem de programação completamente diferentes? Geralmente, dois módulos WebAssembly separados podem fazer o que muitos sistemas fazem e passar dados entre eles como JSON, Protobuf ou qualquer outro formato prolífico de troca de dados. Serializar e desserializar esses formatos é bastante caro e, afinal, dado que os dois módulos que querem se comunicar provavelmente estão sendo executados pelo mesmo tempo de execução, lado a lado, e não por uma rede, é possível que a implementação disso seja melhor.
A dificuldade está na maneira como cada linguagem de programação representa os dados. As implementações de linguagem podem optar por usar codificações diferentes para strings, e uma linguagem pode preferir armazenar dados sequenciais como uma matriz, enquanto outra pode preferir listas vinculadas. Para permitir que códigos de diferentes linguagens se comuniquem entre si, eles precisam concordar com um formato comum para todos os tipos de dados. Isso é conhecido como Application Binary Interface, ou ABI. Na prática, nenhuma delas concorda. Normalmente, se for desejado que algum código escrito em uma linguagem se comunique com algum código escrito em outra linguagem, algum pobre desenvolvedor deve sentar e cuidadosamente (e dolorosamente) escrever código para traduzir entre as duas linguagens. Ela exige conhecimento profundo de como ambas as linguagens funcionam e é excepcionalmente propensa a erros. Alguns ecossistemas de idiomas conseguiram produzir ferramentas que podem fazer isso automaticamente, mas mesmo assim, isso é apenas para idiomas selecionados.
Felizmente, o Component Model define um formato de dados comum para todas as linguagens, conhecido como ABI canônico . Para facilitar as coisas para os humanos, também existe uma linguagem de definição de interface chamada WebAssembly Interface Types, ou WIT, para descrever interfaces de componentes.
Então, temos todos esses componentes, mas como podemos saber onde podemos usá-los? Afinal, o WebAssembly é executado em muitos lugares — em navegadores da web, em servidores, na borda, em pequenos dispositivos e muito mais — todos com recursos diferentes. O WIT nos traz o conceito de mundos . Um mundo é a interface à qual um componente se adapta: é um conjunto de funções que um componente pode importar e um conjunto de funções que o componente exporta. Ela nos permite raciocinar sobre componentes e como eles se compõem com bastante facilidade. Aqui está a definição de um componente que vive no mundo `wasi:cli/command`, que descreve componentes que são executados em uma linha de comando de terminal:
Fonte: https://github.com/WebAssembly/wasi-cli , modificado para brevidade
Este componente se preocupa com coisas como o sistema de arquivos e aleatoriedade, além de ter fluxos de entrada e saída, mas, mais importante, ele fornece uma função para ser executada quando o comando é invocado.
Os mundos podem ser definidos por qualquer pessoa, mas há uma série de mundos de padrões para componentes que podem lidar com solicitações HTTP, acessar dispositivos USB, usar modelos de IA e muito mais por vir. Os ambientes host podem anunciar quais mundos eles implementam para facilitar aos desenvolvedores saber quais componentes funcionam. Como os componentes são componíveis, também é possível implementar alguns mundos em termos de outros mundos e compor os dois componentes. Por exemplo, se você tem um ambiente de host que implementa um mundo de soquetes, mas tem um componente que deseja fazer solicitações HTTP em um mundo HTTP, você pode escrever um componente adaptador que implementa o mundo HTTP usando soquetes:
Com uma composição simples, seu componente agora pode ser executado no mundo dos sockets sem nenhuma modificação! As possibilidades são infinitas.
O Modelo de Componentes é monumental, não apenas para o WebAssembly, mas para todos os desenvolvedores em todos os lugares. Isso mudará fundamentalmente a maneira como os desenvolvedores raciocinam e desenvolvem software — já há toneladas de utilidade, e ainda estamos no começo. Fique ligado nos desenvolvimentos que acontecem no ecossistema WebAssembly, pois certamente veremos mais e mais casos de uso atraentes surgindo à medida que a adoção continua a aumentar.