O Problema do Node (e do Bun) & Como Deveria Ser o JavaScript no Back-End
Uma breve contexto do JavaScript
O JavaScript, a língua franca da Web, passou por uma grande transformação em relação à sua função inicial - adicionar interatividade à páginas web, para ser usado para consturir virtualmente qualquer aplicação.
De fato, a evolução do JavaScript tem sido profunda, graças aos esforços colossais de gigantes da tecnologia como Mozilla, Google, Microsoft e Apple que otimizaram e refinaram incansavelmente suas implementações, bem como aos meticulosos processos de padronização e que envolveram centanas de organizações e milhares de especialistas. Hoje, o JavaScript, pode ser considerado por diversas medidas objetivas, como uma das melhores linguagens de script disponíveis, tanto em termos de implementação como de especificação.
Ainda assim é importante destacar que o JavaScript é uma linguagem de script, sendo desenvolvida única e exclusivamente com o objetivo de automatizar, gerir e manipular 'coisas' dentro no navegador. Sendo projetada para a execução e integração rápida em um hospedeiro (o navegador) e ser uma sandbox. O JavaScript foi criado para não interegir com o sistema operacional, por exemplo, o que é essencial para criar aplicações.
Esta decisão fundamental significa que a criação de aplicações apenas com JavaScript necessita de uma "gambiarra". A mais famosa é de longe o Node, um programa em C++ que faz a conexão entre o V8 (a caixa-de-areia que executa sua aplicação em JavaScript) com o mundo exterior. Agora surgiu o Bun, mas não se enganem, é apenas uma 'engenhoca' mais elaborada, que tem como propósito, corrigir um 'problema' que é deliberamente uma decisão de projeto da linguagem, o JavaScript não foi feito para criar aplicações!!! E muitos vão teimar em não concordar com isto, mas é uma questão muito simples, basta ler a especificação.
Um fato muito interessante é que apesar disso, o Node é uma ferramenta execelente para criar (certos tipos) de aplicações e o Bun provavlemente vai ser ainda melhor. E isso levanta muitas perguntas interessantes.
Todavia, antes se torna fundamental distuinguir entre aplicações e scripts:
Script na sua essência têm uma unica função, diz respeito à escrita de pequenas rotinas para automatizar tarefas, transformar dados ou extender e controlar outros softwares. Normalmente são rotinas curtas, escritas em um único arquivo e têm toda a entrada necessária no ínicio do processo. Executam até produzir uma única saida e são finalizados. É um fluxo quasi-sequencial. Envolve frequentemente a interação direta com uma 'aplicação hospedeira'. Quase sempre é interpretado pois são usados justamente para ganhos de flexibilidade e produtividade.
Aplicações são software autónomos que interagem diretamente com o mundo real, executando em loop, aguardando por novas entradas de forma constante e produzindo diversas saídas. São verdadeiros emaranhados de chamadas (não importa quão bem projetados) espalhados por diversos arquivos. Frequentemente envolvem processos complexos e abrangentes de design, codificação, build e debug. São destinados a executar um grande conjunto de tarefas de maneira coesa, estruturada e organizada de maneira ininterrupta.
Todo o poder de JavaScript no Backend
(menos) Java
O Java é frequentemente considerado como uma das linguagens de desenvolvimento de aplicativos mais bem-sucedidas, é tão bem sucedido que o nome JavaScript foi propositalmente escolhido para surfar em sua popularidade.
Sua poderosa máquina-virtual, extensa biblioteca padrão, natureza estaticamente tipada com checagens em tempo de compilação e a adoção intrisíca da melhores práticas da orientação a objetos, dão ao Java uma abordagem estruturada para o desenvolvimento de aplicativos, permitindo a construção de sistemas complexos e de grande escala com requisitos rigorosos de confiabilidade e desempenho. Por outro lado, o JavaScript foi concebido como uma linguagem de script.
Muitas aplicações que utilizam Node/Typescript/Prisma parecem adotar padrões de design, abordagens de arquitetura e rationales que são típicos do Java, ou qualquer outra linguagem focada no desenvolvimento de aplicações como C#.
(mais) Script
A utilização ideal do JavaScript no desenvolvimento de back-end da Web não está em replicar a funcionalidade de linguagens feitas para desenvolver aplicativos complexos, mas em criar scripts e automatizar as ferramentas que alimentam a Web, como por exemplo Nginx e Postgres.
Em vez de trazer nosso servidor Web e dados para dentro do JavaScript, como paradigma do desenvolvimento de aplicações e frequentemente feito no Node, levar o JavaScript diretamente para nosso servidor (Nginx) e dados (Postgres) é uma abordagem muito mais sensata e fiel ao seu próposito como linguagem de script. Essa abordagem perrmite a extensão dessas ferramentas com maestria através da flexibilidade e perfomance que apenas o JavaScript é capaz de oferecer, enquanto aproveita toda a velocidade, robustez e eficiência das ferramentas que estão sendo controladas.
Extendendo o banco de dados com plv8:
O plv8 fornece um ambiente de execução para JavaScript dentro do PostgreSQL, permitindo a execução de código JavaScript diretamente dentro do banco de dados. Isso oferece a possibilidade de definir e impor regras de negócios no nível do banco de dados, garantindo consistência e integridade dos dados. Tradicionalmente isso sempre foi feito usando Procedural SQL (e provavelmente por isso também, bastante evitado por muitos desenvolvedores) mas por que não aproveitar todas as vantagens do js?
CREATE OR REPLACE FUNCTION valida_usuario()
RETURNS TRIGGER AS $$
const novoUsuario = NEW.nome_usuario;
const email = NEW.email;
if (novoUsuario.length < 5 || !email.includes('@')) {
plv8.elog(ERROR, 'Usuário inválido!');
return null;
}
return NEW;
$$ LANGUAGE plv8;
Este não é um artigo sobre a programação de banco de dados (quem sabe em outro artigo), mas segundo a documentação do próprio Prisma:
"There are two schools of thought about performing computations in your database: people who think it's great, and people who are wrong."
Aqui ilustro apenas que usar o JavaScript para 'fazer computações' no banco de dados oferece muitas vantagens em relação ao utilizar o PL/pgSQL.
Extendendo o servidor Web com ngx_http_js_module:
Assim como o plv8 permite consolidar a lógica de negócios no banco de dados, o módulo JS do Nginx permite criar roteamentos complexos, proxies, e lógicas de sub requisições diretamente no servidor web usando JavaScript.
//nginx.conf
http {
js_import main from '/etc/nginx/js/main.js';
server {
listen 80;
location / {
js_content main.handler;
}
}
}
// main.js
export function handler(r) {
if(r.uri.startsWith('/api')) {
r.proxy_pass('http://api_backend');
} else {
r.proxy_pass('http://web_backend');
}
}
Novamente um exemplo extremamente tosco, apenas como ilustração. Note que com esta abordagem, pode-se, por exemplo, criar api gateways altamente sofisticados e extremamente robustos. Algo que seria muito mais díficil e menos eficiente usando Lua por exemplo.
Conclusão:
O JavaScript evoluiu muito desde sua concepção, transformando-se de um mero instrumento para adicionar interatividade à páginas web em uma linguagem capaz de construir sistemas robustos e complexos. Entretanto, há uma necessidade imperativa de não perdermos de vista sua essência e propósito como uma linguagem de script, especialmente em ambientes de backend aonde existem diversas alternativas que são objetivamente melhores para desenvolver aplicações - quase sempre.
A integração de JavaScript com ferramentas como Nginx e Postgres, através de módulos como plv8 e ngx_http_js_module, abre portas para um novo mundo de possibilidades aonde o JavaScript é de fato a melhor ferrementa para realizar muitas tarefas no backend.
Um breve relato
Após todas essas considerações, gostaria de compartilhar um pouco da minha experiência pessoal como desenvolvedor web full stack aposentado. Conduzi uma empresa de desenvolvimento de software durante sete anos, tive a oportunidade de entregar uma variedade de produtos utilizando diferentes tecnologias e stacks, mas há um projeto que ocupa um lugar especial no meu coração e no qual me orgulho profundamente, o último deles, antes de seguir outro rumo na minha jornada profissional.
Como um grande fã de programação de bando de dados, eu já namorava com o plv8 há um tempo, tendo usado pontualmente em alguns produtos. Neste projeto fez total sentido implementar todas as regras de negócios única e exlusivamente dentro do banco de dados e foi all-in. Não existe um backend no sentido tradicional, toda logica referente a todos os CRUDs são tratadas apenas pelo plv8 dentro do postgres. A aplicação web adjacente é literamente converter uma requisão http em uma chamada de banco de dados, transformando diretamente os parametros da url ou body da requisição em uma query de sql sem qualque lógica.
Além disso, após considerar soluções como Kong e Krakend, optamos por construr um API Gateway seguindo os moldes apresentado, integrando com este e outros serviços não relacionados ao banco de dados, que, por curiosidade, foram desenvolvidos em Go e Java. Neste cénario especifico - não existe bala de prata - estas decições se provaram muito acertadas.
É com grande satisfação que relato que esta aplicação, além de ter sido entregue antes do prazo e abaixo custo - após ajustes pontuais durante a implantação do sistema na empresa contratante - está em operação por mais de três anos sem registrar uma única falha. Ao usar a ferramenta certa para cada tarefa, alcançamos um nível de maturidade técnica que me faz reiterar: sempre use a ferramenta certa.
Perguntas
-
O JavaScript está sendo usado muito além de seu propósito. Isso é algo positivo ou negativo?
-
Você que têm experiência com linguagens fortemente tipadas por natureza e voltadas para o desenvolvimento de aplicações (como Java/C#/Swift) qual é a sua opinião sobre o uso de JavaScript para constuir aplicações no servidor ou nativas?
-
O que você pensa sobre o uso de JavaScript para estender e controlar ferramentas como Nginx e Postgres? Isso representa uma quebra de paradigma para você ou é algo natural? Você já conhece ou utilizou o plv8 ou nginx js_module?
-
No desenvolvimento frontend, vemos também o JavaScript sendo levado para muito além de seus limites como linguagem de script, sendo utilizado para criar aplicações muito complexas. Na evolução contínua e natural da linguagem, deveríamos reconsiderar a especificação como uma linguagem de script e começar a moldá-lo mais explicitamente para a construção de aplicações web ou devemos 'deixar' novas soluções emergirem? Segundo o criador do JSON, deveriamos aposentar o JavaScript.
E ai programador, quero saber sua opinião, o que você pensa sobre tudo isso?