- A tendência recente de reescrever ferramentas de Node.js em linguagens mais rápidas como Rust, Zig e Go é preocupante, e aqui estão algumas preocupações objetivas organizadas
[Desempenho]
- Ainda não parece que todas as possibilidades de acelerar ferramentas JavaScript foram exploradas
- Há muitos pontos em ESLint, Tailwind e outras ferramentas que podem ser melhorados com facilidade
- No navegador, JavaScript é “rápido o suficiente” para a maioria das cargas de trabalho
- Então por que, nas ferramentas de CLI, estamos tentando abandonar JavaScript?
Reescritas em grande escala
- Por muito tempo, o ecossistema de ferramentas JavaScript se concentrou em “fazer funcionar”
- Agora, como as APIs em grande parte já se estabilizaram, todos querem “a mesma coisa, só que mais rápida”
- Ferramentas novas podem ser mais rápidas porque já são escritas pensando em desempenho, e como a API já está definida, é possível economizar tempo de desenvolvimento
- Se ao reescrever de A para B há ganho de velocidade, é fácil afirmar que B é mais rápido que A
- Mas a própria reescrita pode ser o motivo de ficar mais rápido (porque na segunda vez você sabe mais e presta mais atenção em desempenho)
Bytecode e JIT
- No navegador isso é visto como algo natural, mas há o benefício do cache de bytecode e do JIT (compilador Just-In-Time)
- Se o JavaScript for armazenado corretamente em cache, o navegador não precisa fazer parsing e compilar o código-fonte em bytecode
- Funções executadas com frequência são ainda mais otimizadas para código de máquina (JIT)
- Em scripts Node.js, não se aproveitava em nada o benefício do cache de bytecode
- Mas agora também é possível usar cache de compilação no Node (definindo a variável de ambiente
NODE_COMPILE_CACHE)
- Como o JIT precisa executar a função várias vezes para que ela “aqueça”, é difícil obter benefício em scripts executados uma única vez
- No Pinafore, tentou-se substituir uma biblioteca blurhash em JavaScript por uma versão Rust (Wasm), mas na 5ª iteração a diferença de desempenho desaparece
- Também vale considerar compilar scripts Node de forma AOT com ferramentas como Porffor
- Ao usar Wasm, há perda de desempenho em comparação com ferramentas totalmente nativas
[Facilidade de contribuição e depuração]
- Este é o principal ceticismo em relação ao movimento de “reescrever tudo em nativo”
- JavaScript é uma linguagem popular por causa de sua tipagem permissiva, facilidade de aprendizado e suporte nos navegadores
- Por muito tempo, no ecossistema JavaScript, tanto os autores de bibliotecas quanto os usuários usaram JavaScript
- Isso ajuda a reduzir a barreira de contribuição
- Mas, quando autores de bibliotecas JavaScript passam a usar outra linguagem, esse ponto se perde
- Além disso, é simples corrigir dependências JavaScript localmente (editando diretamente em
node_modules)
- Já no caso de linguagens nativas, é preciso fazer checkout do código-fonte e compilá-lo
- Ao depurar uma biblioteca JavaScript, é possível usar as familiares ferramentas de desenvolvedor do navegador ou o depurador do Node.js
- No Wasm, depurar não é impossível, mas exige um conjunto de habilidades diferente
[Conclusão]
- É uma boa coisa que esteja surgindo uma nova geração de ferramentas para o ecossistema JavaScript
- As ferramentas existentes são muito lentas e parecem poder se beneficiar da concorrência
- Mas isso não significa que o próprio JavaScript seja inerentemente lento ou que não haja mais espaço para melhorias
- Olhando para as melhorias recentes nas ferramentas de desenvolvedor do Chromium, parece que ainda há um longo caminho pela frente
- Há preocupação com como seria um mundo dominado apenas por desenvolvedores Rust e Zig
- Quando um desenvolvedor JavaScript mediano se deparar com um bug em uma ferramenta de build, poderá se sentir impotente
- Isso pode acabar ensinando impotência aprendida a jovens desenvolvedores web
- Estamos entrando em um caminho desconhecido, o que pode trazer consequências não intencionais
- Por outro lado, existe outro caminho menos arriscado e capaz de alcançar quase o mesmo resultado
- Mas a tendência atual não mostra sinais de desaceleração
Opinião do GN⁺
- Reescrever em Rust, Zig e afins pode não ser sempre a melhor opção. Parece haver mais espaço para melhorias dentro do próprio JavaScript, como compile cache
- Fica a dúvida se expor desenvolvedores iniciantes a problemas complexos como segfaults é realmente algo positivo. Isso pode, ao contrário, apenas ensinar impotência
- É preciso pensar se vale mesmo a pena ganhar velocidade sacrificando as vantagens do ecossistema construído em JavaScript ao longo do tempo, como edição livre entre bibliotecas e um ambiente de depuração familiar
- Os esforços para melhorar as bibliotecas JavaScript existentes também devem continuar. As possibilidades do JavaScript ainda não foram totalmente exploradas
- Embora pareça difícil ir contra a maré, essa direção ainda exige um debate sério e reflexão em nível de comunidade
15 comentários
A forma de operar de uma lojinha de bairro e de uma grande rede pode ser um pouco diferente. Em vez de adotar uma postura crítica à mudança em si, acho mais saudável pensar no significado desse fenômeno.
Pode até parecer que a mudança acontece por gosto pessoal ou por seguir modas, mas normalmente as empresas não tomam decisões assim, né?
Python ou o próprio JavaScript são lentos? Talvez não dê para dizer que sim.
Mas as ferramentas frequentemente usadas feitas com Python ou JavaScript são lentas? Acho que a resposta é sim.
Uso vários dispositivos de baixo consumo, e há muitas ferramentas que são irritantemente lentas...
Histórias de repertório quase idêntico também se repetem do lado da comunidade Python.
JavaScript não foi escrito em JavaScript, mas a maioria dos desenvolvedores JavaScript não se importa com essa parte. Para "desenvolvedores iniciantes" e "jovens desenvolvedores web", o fato de JavaScript não ter sido escrito em JavaScript não é um problema, mas dizer que é um problema que as ferramentas de desenvolvimento JavaScript não sejam escritas em JavaScript não faz muito sentido. Na verdade, os desenvolvedores que se importam com esse tipo de coisa são apenas uma minoria muito pequena entre os dois grupos.
Mesmo sem negar que, com otimização suficiente, seja possível atingir velocidades quase semelhantes, será que isso realmente vale a pena?
O que aconteceu foi apenas a chegada de uma transição: de uma era em que era mais econômico escrever ferramentas de desenvolvimento em JavaScript em vez de C++, para uma era em que escrever em Rust se tornou mais econômico do que escrever em JavaScript.
A forma de reverter essa tendência não é lançar um movimento de otimização em JavaScript gastando mais dinheiro, e sim criar condições para que seja possível desenvolver ferramentas JavaScript eficientes com custos de desenvolvimento menores. (Pode até parecer a mesma coisa, mas a diferença está em onde se investe o esforço.)
Concordo. Acho que precisamos redefinir a viabilidade econômica com foco nos usuários das ferramentas.
Até agora, parece que a viabilidade econômica tem sido uma métrica mais voltada para os desenvolvedores das ferramentas do que para quem as usa. Dá a sensação de que as ineficiências e os problemas de desempenho que os usuários precisam enfrentar ficaram relativamente em segundo plano nas prioridades. Pessoalmente, uso bastante
uvevite, e, se possível, prefiro evitar ferramentas comopipoucreate-react-app.Acho difícil concordar, porque considero que ferramentas de CLI deveriam poder funcionar sem runtime.
Se alguém disser que dá para criar um executável standalone de WASM, como o próprio texto diz, haveria perda de desempenho.
Assim como não é comum escrever CLI em Java, acho que com JavaScript é a mesma coisa.
Parece que o autor está confundindo o fato de que tanto SPAs quanto ferramentas de JavaScript usam JavaScript com a ideia de que, por isso, as competências necessárias ao redor também seriam as mesmas. Eu diria que ferramentas de JavaScript exigem competências nas áreas de programação de sistemas e compiladores.
Mesmo que a linguagem seja a mesma, o ambiente de execução é diferente entre navegador e NodeJS, e só quem consegue atravessar essa lacuna poderá contribuir para ferramentas de JavaScript. Como o ambiente de execução é diferente, talvez faça mais sentido considerá-los ecossistemas distintos.
Acho que isso também superestima o número de pessoas capazes de atravessar a fronteira entre desenvolvimento de SPA e desenvolvimento de ferramentas JavaScript. Exigir de um desenvolvedor front-end conhecimentos comparáveis aos de programação de sistemas é forçar demais. Usuários de ferramentas não conseguem, no máximo, entender apenas mensagens de erro superficiais ou os sintomas observáveis? Não acho que seja um problema que se resolva apenas por conhecer a linguagem.
Parece que estão misturando ferramentas e bibliotecas. Em relação às bibliotecas, até consigo concordar em certa medida, mas quanto às ferramentas, sei lá..
Desenvolvedores de outras linguagens também já estão acostumados com ferramentas escritas em código nativo, não é?
Pessoalmente, seja uma ferramenta ou uma biblioteca, se ela for escrita em JavaScript, desenvolvedores familiarizados com JavaScript podem depurá-la e, se necessário, contribuir com ela. Mas, se ela for reescrita em Rust, as contribuições em código aberto acabam ficando restritas aos desenvolvedores Rust. Como a base de desenvolvedores JavaScript é esmagadoramente maior do que a de Rust, pode ser mais vantajoso para o ecossistema de código aberto que ferramentas e bibliotecas sejam escritas em JavaScript.
Acho que o JavaScript tem um ambiente de execução fragmentado entre o navegador e o NodeJS e, por isso, uma simples comparação entre o número de usuários da linguagem tem limites como argumento. Desenvolvedores backend em Spring e desenvolvedores do JDK, desenvolvedores de React/Angular/Vue e desenvolvedores de ferramentas JavaScript têm interesses e posições diferentes, numa relação de consumidores e produtores
Pessoalmente, penso que, para atingir o objetivo de melhorar o desempenho e a usabilidade das ferramentas JavaScript, mudar a linguagem de implementação, que é apenas um meio, também é uma opção possível
Acho difícil separar com clareza os consumidores e os produtores de ferramentas de desenvolvimento. À medida que a empresa cresce, é comum que as equipes personalizem a toolchain ou implementem plugins adicionais de acordo com as regras que desejam seguir, e, nesses casos, acredito que só o fato de usar a mesma linguagem já traz uma grande vantagem.
Também há muitos casos em que os usuários da ferramenta passam a se interessar por melhorias ou pela própria implementação da ferramenta e acabam contribuindo de forma natural.
Acho que quem passa a se interessar por customizar toolchains, ou trabalha com isso, está atuando não só como consumidor, mas como um prosumer, ou até como produtor. No caso de plugins, entendo que eles operam dentro de um contrato de plugin entre produtor e consumidor. Nessa situação, também concordo que usar a mesma linguagem ajuda, tanto tecnicamente quanto em custo de comunicação, em comparação com oferecer um formato separado de arquivo de configuração ou pontos de extensão.
Dito isso, não acho que os problemas de desempenho de ferramentas em JavaScript, ou a latência de JIT do NodeJS, estejam dentro do escopo de decisão do consumidor. Isso porque quem definiu essa arquitetura e essas especificações de funcionamento foram os produtores das ferramentas e os desenvolvedores do runtime.
É duvidoso que, só porque o ecossistema de JavaScript é grande, haja mais desenvolvedores capazes de contribuir com codebases de compiladores/transpiladores. Acho que bibliotecas, frameworks e ferramentas fundamentais são áreas completamente diferentes.
Mas reescrever em si pode ser o motivo de ficar mais rápido -> olhando em retrospecto, isso faz muito sentido mesmo...
Concordo com o que essa pessoa diz, justamente porque é algo muito seletivo.
Ainda assim, em outra dimensão, o fato de existirem várias soluções além de JS também é um elemento muito importante em termos de avanço tecnológico, então acho que a situação oposta também deve ser respeitada!
Opiniões no Hacker News
Há quem considere que JavaScript é inerentemente lento. Muitos engenheiros tentaram torná-lo mais rápido, mas ele ainda continua mais lento do que linguagens com tipagem estática. Em programas de grande porte, linguagens com tipos claros são mais adequadas
JavaScript não é tão fácil de aprender e tem um sistema complexo de protótipos e tipos. O TypeScript compensa isso, mas ainda assim continua complexo
Apenas mudar de linguagem já pode melhorar bastante o desempenho. Houve casos em que, ao trocar sistemas existentes de JS e PHP para Go, foi observado um ganho de desempenho de 8 a 10 vezes
A importância do processamento paralelo está sendo subestimada. Rust é adequado para escrever código paralelo, enquanto JS não é apropriado para isso
JavaScript agora tem velocidade semelhante à do Java e é de 2 a 4 vezes mais lento que C++. Para elevar o desempenho, é preciso sair da zona de conforto
Programas em Rust, Zig e Go são fáceis de inspecionar no código-fonte e compilar. Aprender uma nova linguagem influencia a forma de resolver problemas
Há quem ache que ainda não se esgotaram todas as possibilidades de melhorar o desempenho das ferramentas em JavaScript. Mesmo assim, construir sobre uma base melhor é mais eficiente
Rspack é uma reimplementação compatível do Webpack escrita em Rust, com desempenho 5 a 10 vezes melhor. Pode substituir o Webpack com facilidade
É fácil modificar dependências JavaScript localmente, mas Rust tem menos bugs, então há menos necessidade de mexer nelas. Rust é difícil de aprender, mas isso pode torná-lo um programador melhor também em outras linguagens