Node.js para desenvolvedores Java

E/S leve e voltada para eventos de seus aplicativos da web

Node.js desvenda a simultaneidade ao substituir a abordagem padrão multiencadeada de Java por uma E/S de encadeamento único, conduzida por evento. Neste artigo, Andrew Glover apresenta o Node.js e explica por que sua simultaneidade conduzida por evento gerou tanto interesse, mesmo entre desenvolvedores Java dedicados. Em seguida, ele mostra como usar a estrutura Express de Node, Mongolian DeadBeef e MongoDB para desenvolver um aplicativo da web simultâneo, escalável e persistente.

Andrew Glover, CTO, App47

 Andrew GloverAndrew Glover é desenvolvedor, autor, palestrante e empreendedor com uma paixão por desenvolvimento direcionado por comportamento, integração contínua e desenvolvimento de software Agile. Ele é o fundador da easyb , estrutura Behavior-Driven Development (BDD) e é coautor de três livros: Continuous Integration, Groovy in Action, e Java Testing Patterns. Você pode acompanhá-lo em seu blog e seguindo-o no Twitter.



15/Dez/2011

JavaScript tornou-se, nos últimos anos, o herói subestimado do desenvolvimento de aplicativos da web. Esse reconhecimento vem sendo encarado com surpresa por desenvolvedores de software acostumados a considerar JavaScript uma "linguagem de brinquedo". Embora haja linguagens mais populares (no sentido de que desenvolvedores clamam sua lealdade a elas), o status exclusivo de JavaScript como a linguagem de script padrão, independente de navegador, fez com que ela pudesse perdurar. Para desenvolvimento na web no lado do cliente, é provavelmente a linguagem mais usada no mundo.

JavaScript para Desenvolvedores Java

JavaScript é uma ferramenta importante para o moderno desenvolvedor Java, e não é difícil de aprender. Acompanhe a apresentação de Andrew Glover para a sintaxe necessária para desenvolver aplicativos da web de primeira classe, incluindo variáveis, tipos, funções e classes de JavaScript.

JavaScript também tem lugar em scripts do lado do servidor, e esse nicho está crescendo. Embora tenha havido tentativas de JavaScript no lado do servidor no passado, nenhuma gerou tanta animação quanto Node.js, ou Node.

Projetado para auxiliar desenvolvedores a criar programas de rede escaláveis, Node é um ambiente de programação do lado do servidor que praticamente reinventou JavaScript para uma nova geração de desenvolvedores. Para muitos desenvolvedores Java, a principal atração do Node é sua abordagem nova para a simultaneidade de software. Embora a plataforma Java continue evoluindo em sua abordagem da simultaneidade (com melhorias muito esperadas em Java 7 e Java 8), o fato é que Node atende uma necessidade, e faz isso da forma mais leve que muitos desenvolvedores Java adotaram recentemente. Como os scripts do lado do cliente com JavaScript, os scripts do lado do servidor no ambiente Node são bons porque funcionam, e funcionam em uma área na qual muitos desenvolvedores Java enfrentam desafios atualmente.

Neste artigo, eu apresento a revolução dos scripts do lado do servidor que é o Node. Começaremos com uma visão geral arquitetural do que torna o Node especial, e em seguida eu mostrarei como desenvolver rapidamente um aplicativo da web escalável que usa MongoDB para persistência de dados. Você verá em primeira mão como o Node é divertido, e como ele pode ser usado rapidamente para montar um aplicativo da web funcional.

A simultaneidade conduzida por evento de Node

Node é um ambiente de E/S escalável, conduzido por evento, desenvolvido com base no mecanismo JavaScript V8 do Google. Google V8 na verdade compila JavaScript em código de máquina nativo antes da execução, o que resulta em desempenho extremamente rápido no tempo de execução — algo que não é geralmente associado a JavaScript. Dessa forma, Node permite desenvolver rapidamente aplicativos de rede extremamente rápidos e altamente simultâneos.

E/S conduzida por evento pode soar estranho para um desenvolvedor Java, mas não é tão novo assim. Em vez do modelo de programação multiencadeado com o qual estamos acostumados na plataforma Java, a abordagem de Node para simultaneidade tem um único encadeamento, com a adição de um loop de eventos. Esse desenvolvimento do Node permite E/S sem bloqueio ou assíncrona. No Node, chamadas que geralmente bloqueariam, como espera por resultados de consulta de banco de dados, não bloqueiam. Em vez de esperar que atividades caras de E/S sejam concluídas, um aplicativo Node emite um retorno de chamada. Quando um recurso é retornado, o retorno de chamada anexado é chamado de forma assíncrona.

Por que escolher Node.js?

A abordagem da plataforma Java para simultaneidade ajudou a estabelecer sua posição de liderança no desenvolvimento corporativo, e isso não deve mudar. Estruturas como Netty (e Gretty; consulte Recursos) e bibliotecas de núcleo como NIO, além de java.util.concurrent, tornaram a JVM uma escolha preferencial para simultaneidade. O que o Node tem de especial é que se trata de um ambiente de desenvolvimento moderno especificamente projetado para resolver os desafios da programação simultânea. O paradigma de programação conduzido por eventos de Node faz com que bibliotecas adicionais não sejam necessárias para fazer a simultaneidade funcionar, e isso é uma boa notícia para desenvolvedores de olho em hardware com diversos núcleos.

A simultaneidade simplesmente funciona em programas Node. Se eu quisesse executar o cenário anterior na plataforma Java, poderia escolher entre abordagens complexas e demoradas — de encadeamentos tradicionais a bibliotecas mais novas em Java NIO e até o pacote java.util.concurrent melhorado e atualizado. Embora a simultaneidade de Java seja eficiente, pode ser difícil de entender — o que se traduz em código! Em comparação, o mecanismo de retorno de chamada do Node está integrado na linguagem; não são necessários desenvolvimentos especiais como synchronized para fazê-la funcionar. O modelo de simultaneidade do Node é extremamente simples, e isso o torna acessível para um público maior de desenvolvedores.

A sintaxe de JavaScript do Node também economiza bastante digitação. Com pouco código é possível desenvolver um aplicativo da web rápido e escalável, capaz de lidar com diversas conexões simultâneas. Isso pode ser feito na plataforma Java, mas é necessário mais linhas de código e diversas bibliotecas e desenvolvimentos adicionais. E não precisa se preocupar em navegar um ambiente de programação novo: Node é fácil de aprender se você sabe um pouco de JavaScript, e eu aposto que você sabe.


Introdução ao Node

Como eu falei, Node é fácil de aprender e você encontrará diversos bons tutoriais on-line para ajudá-lo. Neste artigo (assim como na minha introdução a JavaScript para desenvolvedores Java) meu foco é ajudar desenvolvedores Java a aproveitar os benefícios do Node. Em vez de examinar o aplicativo de servidor da web "Hello, world" padrão, quero passar direto para um aplicativo útil, que realmente faz algo: pense nele como uma espécie de clone do Foursquare desenvolvido em Node.

Demo em vídeo: Introdução ao Node.js

Prefere uma abordagem diferente para começar a usar essa estrutura útil? Assista a esta demo em vídeo, também de Andrew Glover, para saber mais sobre Node.js e o que ele pode fazer para você. (Leia a transcrição.)

Instalar o Node requer seguir as instruções para sua plataforma em particular; caso esteja usando uma plataforma semelhante a UNIX, como OSX, recomendo usar Node Version Manager, ou NVM, que lida com os detalhes da instalação de uma versão apropriada do Node. Em todo caso, faça download do Node e instale-o agora.

Também usaremos algumas bibliotecas de terceiros para desenvolver este aplicativo, portanto instale NPMque é o gerenciador de pacote do Node. NPM permite especificar dependências com versão para seu projeto, que são depois transferidas por download e incluídas no seu caminho de desenvolvimento. NPM é muito semelhante ao Maven para a plataforma Java, ou ao Bundler do Ruby.


Node Express

Node está se tornando popular entre desenvolvedores da web devido à sua capacidade de lidar com simultaneidade e porque foi desenvolvido com o desenvolvimento para a web em mente. Uma das mais populares ferramentas de terceiros do Node é o Express, uma estrutura leve de desenvolvimento da web, que usaremos para desenvolver nosso aplicativo (consulte Recursos para saber mais sobre o Express).

Express está carregado de recursos, incluindo roteamento sofisticado, visualizações de modelo dinâmicas (veja a estrutura Node du jour: Jade) e negociação de conteúdo. Express também é muito leve, sem ORM integrado ou bagagem similar para pesar. Nesse sentido, Express não se compara a Rails, Grails ou qualquer outra estrutura da web completa.

A maneira mais fácil de instalar e usar o Express é declará-lo como uma dependência por meio do arquivo package.json do NPM, mostrado na Listagem 1. Esse arquivo é semelhante ao pom.xml do Maven ou ao Gemfile do Bundler, mas seu formato é JSON.

Lista 1. Arquivo package.json de NPM
{
  "name": "magnus-server",
  "version": "0.0.1",
  "dependencies": {
    "express": "2.4.6"
  }
}

Na Listagem 1, eu dei a este projeto do Node um nome (magnus-server) e uma versão (0.0.1). Também declarei que a versão 2.4.6 do Express é uma dependência. O bom do NPM é que ele irá obter todas as dependências transitivas do Express, carregando rapidamente qualquer outra biblioteca de terceiros do Node que o Express necessite.

Após definir as dependências do projeto por meio de package.json, é possível instalar os pacotes desejados por meio da linha de comando, digitando npm install. Você deverá ver o NPM instalar o Express junto com dependências como connect, mime e outras.

Criando um aplicativo de rede

Para começar a escrever nosso aplicativo de exemplo, Magnus Server, criamos um arquivo JavaScript; eu chamei o meu de web.js, mas você pode chamá-lo do que quiser. Abra esse arquivo em seu editor ou IDE favorito; por exemplo, você pode usar JSDT, o plugin de JavaScript do Eclipse (consulte Recursos).

No arquivo, inclua o código na Listagem 2:

Lista 2. Magnus Server: Primeira edição
var express = require('express');

var app = express.createServer(express.logger());

app.put('/', function(req, res) {
  res.contentType('json');
  res.send(JSON.stringify({ status: "success" }));
});

var port = process.env.PORT || 3000;

app.listen(port, function() {
  console.log("Listening on " + port);
});

Esse pequeno fragmento de código faz coisas importantes, portanto começarei do começo. Primeiro, se quisermos usar uma biblioteca de terceiros no Node, precisamos usar a frase require; na Listagem 2, estamos exigindo a estrutura Express, e também estamos obtendo uma manipulação por meio da variável express. Em seguida, criamos uma instância de aplicativo por meio da chamada createServer, que por sua vez cria um servidor HTTP.

Em seguida definimos um terminal por meio de app.put. Nesse caso, estamos definindo um PUT de HTTP como o método HTTP necessário ouvindo na raiz do aplicativo (/). A chamada put tem dois parâmetros: a rota e um retorno de chamada correspondente a ser executado quando a rota é chamada. O segundo parâmetro é uma função que é chamada no tempo de execução quando o terminal / é atingido. Lembre-se, esse retorno de chamada é o que queremos dizer quando falamos na E/S conduzida por evento ou eventualizada do Node — o retorno de chamada será chamado de forma assíncrona. Esse terminal pode lidar com diversas solicitações simultâneas sem a necessidade de criar encadeamentos manualmente.

Como parte da definição do terminal, nós criamos a lógica para lidar com um PUT para /. Para manter as coisas simples por enquanto, iremos definir o tipo de resposta como JSON e enviar de volta um documento JSON simples: ({"status":"success"}). Observe o elegante método stringify, que toma um hash e o converte em JSON.

JavaScript e JSON

JSON e JavaScript são praticamente irmãos, e essa afinidade se traduz no Node. Analisar JSON em um aplicativo Node não requer bibliotecas ou desenvolvimentos especiais; em vez disso, usam-se chamadas lógicas semelhantes a gráficos de objeto. Em suma, Node trata JSON como um membro da família, o que torna a programação de aplicativos da web baseados em JSON muito mais fácil.

Em seguida, criamos uma variável representando a porta na qual o aplicativo deve ouvir; para isso, obtemos a variável de ambiente PORT ou a definimos explicitamente como 3000. Por fim, iniciamos o aplicativo chamando o método listen. Novamente nós passamos um retorno de chamada, que será chamado caso o aplicativo esteja executando para imprimir uma mensagem no console (nesse caso, saída padrão).

Experimente!

Esse elegante aplicativo responde a qualquer PUT, portanto é possível executá-lo digitando simplesmente node web.js na linha de comando. Caso deseje testar melhor o aplicativo, recomendo fazer download do RESTClient de WizTools.org. Com RESTClient, é possível descobrir rapidamente se o Magnus Server funciona ao executar um PUT de HTTP para http://localhost:3000. Se tudo der certo, você deve ver uma resposta de JSON indicando sucesso. (Consulte Recursos para saber mais sobre a instalação e uso do RESTClient.)


Express cuida de JSON

JavaScript e JSON são parentes próximos, o que torna o gerenciamento de Json no Express o mais simples possível. Nesta seção, iremos incluir um pouco mais de código no aplicativo esqueleto da Listagem 2, para que possamos obter um documento JSON recebido e imprimi-lo na saída padrão. Após isso, iremos persistir tudo em uma instância do MongoDB.

O documento recebido será semelhante à Listagem 3 (observe que eu omiti informações de local devido ao espaço):

Lista 3. Comida de graça no Freddie Fingers!
{
 "deal_description":"free food at Freddie Fingers",
 "all_tags":"free,burgers,fries"    
}

A Listagem 4 inclui funcionalidade para analisar o documento recebido:

Lista 4. Express analisa JSON
app.use(express.bodyParser());

app.put('/', function(req, res) {
  var deal = req.body.deal_description;
  var tags = req.body.all_tags;

  console.log("deal is : "  + deal + " and tags are " + tags);
	
  res.contentType('json');
  res.send(JSON.stringify({ status: "success" }));
});

Observe que a Listagem 4 inclui uma linha que orienta o Express a usar bodyParser. Isso nos permitirá facilmente (e eu realmente quero dizer facilmente) obter atributos de um documento JSON recebido.

Dentro do retorno de chamada put há código para obter os valores dos atributos deal_description e all_tags de um documento recebido. Observe a facilidade com que podemos capturar os elementos individuais de um documento solicitado: neste caso, req.body.deal_description obtém o valor de deal_description.

Teste!

Também é possível testar essa implementação. Basta parar sua instância do magnus-server e reiniciá-la, e em seguida usar um PUT de HTTP para enviar um documento JSON para seu aplicativo Express. Primeiro, você deve ver uma resposta de sucesso. Em seguida, o Express deve registrar na saída padrão os valores enviados. Com meu documento de Freddie Fingers, eu recebo esta saída

deal is : free food at Freddie Fingers and tags are free, burgers, fries.

Persistência com Node

Temos um aplicativo funcional que recebe um documento JSON, analisa-o e retorna uma resposta. Agora precisamos incluir alguma lógica de persistência. Como sou fã do MongoDB (consulte Recursos), eu optei por persistir os dados por meio de uma instância do MongoDB. Para tornar as coisas ainda mais vivas, iremos usar a biblioteca de terceiros Mongolian DeadBeef, que usaremos para armazenar os valores de documentos JSON recebidos.

Mongolian DeadBeef é uma de várias bibliotecas do MongoDB disponíveis para Node. Eu a escolhi porque o nome me agrada, e porque o espelhamento do driver MongoDB nativo me faz sentir em casa.

Agora você já sabe que a primeira etapa para usar o Mongolian DeadBeef é atualizar o arquivo package.json, como mostra a Listagem 5:

Lista 5. Incluindo análise de JSON
{
  "name": "magnus-server",
  "version": "0.0.1",
  "dependencies": {
    "express": "2.4.6",
	"mongolian": "0.1.12"
  }
}

Como estamos conectando com um armazenamento de dados do MongoDB, também é preciso atualizar as dependências sólidas do projeto executando npm install. Para melhorar o desempenho do driver do MongoDB do Mongolian DeadBeef, poderíamos também instalar o analisador bson C++ nativo, algo no qual o NPM pode nos ajudar.

Para começar a usar o Mongolian DeadBeef, incluímos outro require na implementação atual, e em seguida conectamos a instância MongoDB desejada (como mostra a Listagem 6). Para esse exemplo, iremos conectar a uma instância hospedada no MongoHQ, um provedor de nuvem do MongoDB.

Lista 6. Incluindo Mongolian DeadBeef no magnus-server
var mongolian = require("mongolian");
var db = new mongolian("mongo://a_username:a_password@flume.mongohq.com:23034/magnus");

Dentro do retorno de chamada PUT, persistimos os valores do documento JSON recebido, como mostra a Listagem 7:

Lista 7. Incluindo lógica de inserção do Mongolian
app.put('/', function(req, res) {
  var deal = req.body.deal_description;
  var tags = req.body.all_tags;

  db.collection("deals").insert({
     deal: deal,
     deal_tags: tags.split(",")
  })
	
  res.contentType('json');
  res.send(JSON.stringify({ status: "success" }));
});

Examinando de perto, você verá que a instrução insert é idêntica a uma inserção dentro do shell do MongoDB. Isso não é coincidência — o shell do MongoDB usa JavaScript! Como consequência, podemos persistir facilmente um documento que tenha dois campos: deal e deal_tags. Observe que definimos deal_tags como um array, usando o método split na cadeia de caractere tags.

Posso começar? (Sim, pode!)

Caso deseje testar isso (e quem não iria querer?) reinicie sua instância, envie outro documento JSON e verifique sua coleção de deals no MongoDB. Você deve ver um documento JSON quase idêntico àquele que você enviou.

Lista 8. Incluindo lógica de inserção do Mongolian
{
  deal:"free food at Freddie Fingers",
  deal_tags: ["free", "burgers", "fries"],
  _id: "4e73ff3a41258b7423000001"
}

Em conclusão— é isso!

Se você acha que estou sendo preguiçoso por acabar tão cedo esta pequena introdução ao Node.js, tenho uma surpresa para você: já concluímos! Escrevemos apenas umas 20 linhas de código, mas elas representam um aplicativo completo e persistente — e essa é a beleza do Node. É muito simples de escrever e entender, e seus retornos de chamada assíncronos o tornam extremamente eficiente. Quando um aplicativo é escrito, pode ser implementado em qualquer número de provedores PaaS, para escalabilidade máxima.

Consulte a seção Recursos para aprender mais sobre as tecnologias discutidas neste artigo, incluindo Node.js, MongoDB e opções de PaaS como Google App Engine, Elastic Beanstalk da Amazon e Heroku.

Recursos

Aprender

Obter produtos e tecnologias

Discutir

  • Participe da comunidade do My developerWorks: Entre em contato com outros usuários do developerWorks e explore os blogs, fóruns, grupos e wikis voltados para desenvolvedores.

Comentários

developerWorks: Conecte-se

Los campos obligatorios están marcados con un asterisco (*).


Precisa de um ID IBM?
Esqueceu seu ID IBM?


Esqueceu sua senha?
Alterar sua senha

Ao clicar em Enviar, você concorda com os termos e condições do developerWorks.

 


A primeira vez que você entrar no developerWorks, um perfil é criado para você. Informações no seu perfil (seu nome, país / região, e nome da empresa) é apresentado ao público e vai acompanhar qualquer conteúdo que você postar, a menos que você opte por esconder o nome da empresa. Você pode atualizar sua conta IBM a qualquer momento.

Todas as informações enviadas são seguras.

Elija su nombre para mostrar



Ao se conectar ao developerWorks pela primeira vez, é criado um perfil para você e é necessário selecionar um nome de exibição. O nome de exibição acompanhará o conteúdo que você postar no developerWorks.

Escolha um nome de exibição de 3 - 31 caracteres. Seu nome de exibição deve ser exclusivo na comunidade do developerWorks e não deve ser o seu endereço de email por motivo de privacidade.

Los campos obligatorios están marcados con un asterisco (*).

(Escolha um nome de exibição de 3 - 31 caracteres.)

Ao clicar em Enviar, você concorda com os termos e condições do developerWorks.

 


Todas as informações enviadas são seguras.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=80
Zone=Tecnologia Java
ArticleID=780724
ArticleTitle=Node.js para desenvolvedores Java
publish-date=12152011