As 8 dúvidas técnicas mais comuns sobre NodeJS

Plataforma nova, dúvidas novas. Como muita gente (inclusive eu) têm começado agora a desenvolver aplicações em Node.js, por diversos motivos que já elenquei em outros posts, é comum que surjam dúvidas uma vez que é uma plataforma bem diferente do que as tradicionais C# e Java que muito de nós programam.

A ideia desse post é elencar as 8 principais dúvidas técnicas sobre Node.js. Caso esteja ainda mais cru do que eu na plataforma, recomendo ler primeiramente estes posts:

As dúvidas que serão respondidas neste artigo são:

  1. Qual a diferença entre til e circunflexo no packages.json?
  2. Como eu depuro programas Node.js?
  3. Qual é o propósito do module.exports e como eu uso ele?
  4. Como faço uso de todos meus processadores?
  5. Como ver completamente os objetos Node.js no console?
  6. Como executar Node.js como um serviço?
  7. Como enviar um email via Node.js?
  8. Como eu posso compartilhar código entre o servidor e o cliente?

Vamos lá!

#1 – Qual a diferença entre til e circunflexo no packages.json?

Então você abre o packages.json e rapidamente entende que as dependencies são os pacotes que sua aplicação usa, mas onde deveriam estar listadas as versões dos pacotes tem um monte de símbolos que não lhe dizem muita coisa…Resumidamente funciona assim:

  • O til garante que o pacote seja sempre carregado  respeitando o número do meio da versão. Ex: ˜1.2.3 pega o pacote mais recente da versão 1.2.x, mas não vai atualizar para 1.3. Geralmente garante que correções de bugs sejam atualizados no seu pacote.
  • O circunflexo garante que o pacote seja sempre carregado respeitando o primeiro número da versão. Ex: ˆ1.2.3 pega o pacote mais recente da versão 1.x, mas não vai atualizar para 2.0. Garante que bugs e novas funcionalidades do seu pacote sejam atualizados, mas não novas versões “major” dele.

A imagem abaixo ajuda a entender o template de versões dos pacotes do NPM, que aliás usa um padrão bem comum da indústria de software:

Outros símbolos incluem:

  • >, >=, <, <=1.0: a versão deve ser superior, superior ou igual, inferior, inferior ou igual à 1.0, respectivamente.
  • 1.2.x: equivalente a ˜1.2.0
  • *: qualquer versão do pacote
  • latest: a versão mais recente do pacote

Agora se você não tiver símbolo algum, aí o pacote deve ser sempre carregado usando a versão especificada.

Uma dica bem valiosa aqui (quem não gosta de um bônus?) para quando se quer atualizar todos pacotes é colocar * na versão de todos e rodar o comando “npm update –save” sobre a pasta do projeto.

#2 – Como eu depuro programas Node.jS?

Assim como o JS tradicional, em Node podemos usar qualquer editor de texto para programar nossas aplicações. No entanto, opções simplificadas demais como Notepad e editores de linha de comando (como nano), embora práticas de usar não são muito úteis quando precisamos depurar aplicações bugadas. Sendo assim, vou dar duas sugestões de como depurar programas Node.js.

Opção 1: troque seu editor de texto. O melhor jeito que eu faço atualmente é usando o Visual Studio Community (2015 com plugin para Node ou 2017 com suporte nativo). Nele você pode colocar breakpoints em arquivos .js, inspecionar variáveis, testar expressões no console e muito mais. E é uma ferramenta gratuita que roda em Windows e tem uma versão beta pra Mac.

Outra alternativa, mais leve, é o editor de texto Visual Studio Code, que vem com suporte nativo a Node.js. Também gratuito e roda em Windows, Mac e Linux.

Opção 2: use um depurador externo ao seu editor. Agora se você não quer abrir mão de usar editores de texto nativos do seu SO ou os mais clássicos que você já está acostumado, tem algum tempo que você pode depurar seus programas Node.js diretamente no Google Chrome também, usando o F12. Você consegue mais informações neste post do Medium.

E por fim, uma outra alternativa para não largar seus editores de texto favoritos é usando o Node Inspector, um projeto open-source disponível no GitHub.

#3 – Qual é o propósito do module.exports e como eu uso ele?

Nos tutoriais simples que eu tenho aqui no blog de como programar usando Node.js com MongoDB eu sempre recomendo criar um arquivo JS db.js com a lógica de conexão do banco de dados. Ao final do arquivo, sempre vemos um modulo.exports que recebe um objeto JSON. Mais tarde, damos um require nesse db.js pra poder usar a conexão internamente criada nele. Mas final, o que o module.exports faz?

Resumidamente, module.exports define qual objeto deste arquivo JS será exportado (ou exposto) quando uma chamada require for feita à ele. Ele é um análogo ao return do arquivo JS como um todo.

Um atalho do Node permite que você use apenas a palavra exports ao invés de module.exports.

Um exemplo de uso bem comum é para criar uma biblioteca de funções dentro de um arquivo JS que precisa ser chamada por outros arquivos JS. Considere o seguinte arquivo mymodule.js:

Aqui expusemos as funções myFunc1 e myFunc2. Se quisermos usar essas funções em outro arquivo, basta usarmos o require, como abaixo:

#4 – Como faço uso de todos meus processadores?

O Node.js trabalha com uma única thread dentro de um único processo na sua máquina. Dessa forma, é natural que ele utilize apenas um processador, mesmo que você esteja rodando sua aplicação em um webserver com 16 núcleos ou mais. Sendo assim, uma dúvida bem comum é: como escalar um projeto Node para que use todo o poder do seu servidor?

Basicamente você tem duas opções:

Opção 1: usar uma arquitetura de micro-serviços. Cada módulo da sua aplicação deve ser uma sub-aplicação autônoma, que responde a requisições e realiza apenas as tarefas que são sua responsabilidade. Sendo assim, teríamos diversas aplicações pequenas escritas em Node.js, cada uma usando um core da sua máquina e recebendo (e processando) as requisições que lhe cabem. Uma aplicação principal recebe a requisição original do usuário e delega as tarefas para as demais sub-aplicações.

Opção 2: usar um webproxy na frente do Node. Você pode colocar um Apache, Nginx ou IIS à frente da sua aplicação e deixar com ele essa tarefa de controlar a carga de requisições, balanceando entre diferentes nós idênticos da sua aplicação, cada um em um processador. Você pode fazer isso com Node.js também, mas geralmente Apache e cia. já possuem muito mais maturidade pra isso.

Existem outras opções? Sim. No entanto, as duas que recomendo estão acima.

#5 – Como ver completamente os objetos em NodeJS no console?

Certas vezes quando temos objetos complexos em Node.js e queremos ver o que ele está guardando dentro de si usamos o console do Google Chrome ou mesmo do Visual Studio para entender o que se passa com nosso objeto. No entanto, dependendo do quão “profundo” é o nosso objeto (quantos objetos ele possui dentro de si), essa tarefa não é muito fácil.

Aqui vão algumas formas de imprimir no console o seu objeto JSON inteiro, não importando quantos níveis hierárquicos ele tenha:

Opção 1: console.log. Tente usar a função console.log passando o objeto or parâmetro, isso funciona na maioria dos casos.

Opção 2: util.inspect. Use o seguinte código abaixo para usara  função util.inspect e retornar todo o conteúdo de um objeto JSON.

Opção 3: JSON.stringify. Use a função JSON.stringify passando o objeto e o nível de identação que deseja dentro do objeto, como abaixo.

#6 – Como executar Node.js como um serviço?

Para quem escolher rodar suas aplicações Node.js em ambiente Windows, existe uma série de passos necessários para que funcione correta e ininterruptamente, que já abordei nesse post aqui, inclusive no Passo 6 eu ensino como instalar seu app Node como se fosse um Windows Service.

#7 – Como enviar um email via Node.js?

Este é um problema bem comum para quem quer fazer coisas simples como um formulário de contato em uma aplicação web. Algo tão trivial em linguagens como PHP se torna uma dor de cabeça em Node. Claro, não estou falando de envio massivo de emails, que nunca deve ser feito usando SMTPs tradicionais (como o da sua conta de email) e sim com serviços de SMTP Gateway como Sendgrid e Mandrill. Estou falando de envios pontuais.

Existem algumas bibliotecas em Node que prometem resolver esse problema para você. Algumas oferecem suporte a contas Gmail,outras não, mas em geral todas funcionem em menor ou maior grau com os padrões atuais de envio de email. Elas são (em ordem de relevância):

  • Nodemailer: outra opção, mais focada no envio dos emails do que na personalização dos mesmos, muito popular desde 2010, quando hão havia opção alguma na plataforma para envio de emails. Em menos de 2 minutos você tem ele funcionando e enviando emails.
  • Node Email Templates:  O pacote mais completo da Internet para envio de emails via Node.js. Permite construir mensagens agradáveis usando a sua view engine e pré-processadores CSS. É um projeto ativo com atualizações frequentes no Github, mas um pouco complexo para quem está começando.
  • EmailJS: para quem tem problemas com anexos no Nodemailer, esse aqui é o pacote ideal, no mais, Nodemailer é melhor.
  • AlphaMail: uma solução completa “as-a-Service” onde você dispara emails usando a infraestrutura da AlphaMail mesmo. Não sei o quão bom os caras são no envio de emails, mas me pareceu muito simples e particularmente útil para quem não quer se preocupar com SMTP e coisas do gênero.

Para não ficar apenas indicando bibliotecas,a qui vai um código JS de envio de email usando Nodemailer, o mais recomendado dentre os pacotes citados:

#8 – Como eu posso compartilhar código entre o servidor e o cliente?

Muitas pessoas chegam até o Node com a promessa de escrever tanto o client-side quanto o server-side na mesma linguagem. No entanto, para que realmente isso seja vantajoso tem de ser possível o reuso de software em ambos os lados da aplicação, certo?!

Eu vou mostrar aqui uma forma de conseguir reutilizar os seus módulos JS tanto no browser quanto no Node.js.

Primeiramente, em Node quando queremos expor um módulo, usamos um código semelhante a esse:

No entanto, no browser isso dá erro uma vez que exports é undefined neste ambiente. Sendo assim, para contornar este problema, o primeiro passo é verificar a existência ou não do exports, caso contrário, teremos que criar um objeto para o qual possamos exportar as funções:

O problema com essa abordagem, é que no browser as funções que não foram exportadas também ficam disponíveis como funções globais, o que não é algo desejável. Resolvo isso usando closures, como no exemplo abaixo:

O uso do objeto this representa o browser, e o uso de this[‘mymodule’] é o local de exportação no browser. Esse código está pronto para ser usado tanto no browser quanto no server. Considerando que ele está em um arquivo mymodule.js, usamos esse módulo da seguinte maneira em Node:

E no browser usamos assim:

Claro, existem códigos JS escritos em Node que não serão suportados pelo browser, como o comando require por exemplo. Sendo assim, os módulos compartilhados entre os dois terão de ser o mais genéricos possíveis para que haja compatibilidade.

Também tome cuidado com as features mais recentes da linguagem Javascript que muitas vezes são suportadas pela engine V8 que o Node usa mas não pelos demais browsers.

Até a próxima!

Boas práticas de arquitetura com NodeJS + Express

Workshop IFRS
Workshop IFRS

Quando trabalhamos com uma plataforma nova como o Node.js, é muito comum ficarmos em dúvida de como proceder com a escala de nossas aplicações e principalmente com a arquitetura da mesma, conforme vão crescendo.

Além disso, considerando os fundamentos do Node.js, o fato de trabalhar com Javascript e sua inerente dinamicidade e pouco apreço por tipagem, orientação à objetos e muito mais, torna a transição de programadores mais tradicionais (Java, C#, etc) para esta plataforma um tanto confusa.

Eu mesmo, tenho feito apenas pequenos projetos em Node.js pois ainda não me sinto confortável para construir (se é que devo) grandes projetos com ele.

Esse post é para compartilhar as melhores dicas e boas práticas de arquitetura que tenho encontrado na Internet sobre a construção de aplicações Node.js, especialmente usando o Express, o framework de aplicações web mais famoso para Node.

O quão grande é a sua aplicação?

Aplicações web não são sempre a mesma coisa e, da mesma forma, não há uma única arquitetura e/ou estrutura de código que possa ser aplicada à todas aplicações express.js.

Sim, é possível criar grandes aplicações em Node.js uma vez que grandes empresas estão fazendo exatamente isso nos últimos anos, como Walmart, Netflix e Uber, só para citar algumas. A questão aqui é: sua aplicação realmente é grande e precisa de uma arquitetura como a deles?

Se sua aplicação é pequena, você não precisa de uma estrutura complexa de diretórios como a que vou mostrar aqui. Mantenha sua aplicação simples, garanta que os arquivos mais importantes estarão na raiz do diretório e está feito.

Agora, se sua aplicação é gigantesca, em algum ponto você pode precisar quebra’-la em pacotes NPM separados (semelhante ao que fazemos com as class libraries em Java e C#). Em geral, o que se recomenda a fazer com Node.js é sempre trabalhar com pacotes pequenos, especialmente para bibliotecas, uma vez que o fato de usar a linguagem Javascript não ajuda muito em manter o controle e previsibilidade de funcionamento em uma aplicação conforme ela fica muito grande. Sendo assim, conforme sua aplicação for crescendo e partes do seu código comecem a se tornar reutilizáveis, mova-os para um pacote como se fosse um subsistemas ou biblioteca, tornando-o independente no NPM.

Com iso em mente, o restante deste artigo foca em dicas e princípios para construção de uma estrutura funcional boa para aplicações médias que contenham as seguintes características:

  • O site tem algumas páginas e templates estáticos
  • A parte dinâmica do site é desenvolvida usando um estilo SPA
  • A aplicação expõe uma API no estilo REST/JSON para o navegador consumir
  • Os modelos da aplicação são de um único domínio de negócio, como por exemplo um site de revenda de automóveis.

Dito isso, vamos às dicas.

Princípios e Motivações Principais

Acima de qualquer estrutura que eu possa propor aqui, vale ressaltar alguns princípios e motivações que devem estar acima de quaisquer convenções em seu código:

Ajude seu cérebro a entender o projeto. Conseguimos lidar com apenas pequenas quantidades de informação de cada vez. Por isso que usamos pastas. Por isso que criamos funções. Elas nos ajudam a lidar com a complexidade do sistema nos permitindo mexer em pequenas porções dele de cada vez.

Crie apenas os diretórios que precisa. Não saia criando dezenas de diretórios que acabarão vazios ou com apenas um arquivo dentro. Comece com o básico de pastas que você precisa e vá adicionando conforme a complexidade for aumentando. Afinal, você não compra um ônibus como primeiro veículo pensando no dia em que pode querer dar carona para muita gente, certo?

Torne fácil localizar arquivos de código. Os nomes de pasta devem ser significativos, óbvios e fáceis de entender. Código que não é mais usado, bem como arquivos antigos, devem ser removidos do projeto, e não apenas comentados ou renomeados. Além disso, todos os códigos ficam dentro de um diretório app na raiz e seus subdiretórios, para facilitar buscas posteriores, especialmente via linha de comando. Ah, e o padrão do npm é usar nomes sempre em minúsculo para as pastas, sem acentos, e com os espaços substituídos por hífens (-). Então é melhor seguir esta regra, por mais que não goste dela.

Agrupe por feature, não por responsabilidade. Esta é uma sugestão que vai contra o que a maioria de nós está acostumado, de separar os arquivos por responsabilidade (controller, model, etc). Cada feature da sua aplicação Node possui uma série de arquivos que, se estiverem juntos (em uma pasta por feature), fica mais fácil de dar manutenção depois. Ex: preciso adicionar um novo campo em um model, na mesma pasta eu já posso mexer no controller que usa aquele model.

Guarde seus testes perto do seu código. Essa ideia vai de encontro à anterior. Coloque o arquivo JS de testes de cada feature na mesma pasta da feature, para facilitar os testes e correção dos bugs encontrados. Também ajuda a lembrar das features que ainda não possuem testes codificados.

Para não se perder com os nomes de arquivos a sugestão é usar uma convenção de nome baseada em sufixo, por exemplo:

  • o arquivo JS original é foo.js
  • o arquivo de teste do original é foo.test.js

Diminua o acoplamento e aumente o reuso de software. A ideia com essas duas últimas dicas é tornar sua aplicação mais modular, com cada feature sendo um módulo mais independente. Aqui a ideia permanece. Uma vez que você tenha módulos independentes, sua aplicação fica menos acoplada e a manutenção mais simples. Uma dica para aumentar o reuso de software mantendo o acoplamento baixo é não colocar código “especializado” nas suas chamadas de model e controller. Ex: após salvar um cliente no banco você precisa enviar um email pra ele. Não coloque o código que envia email logo após o salvamento no banco. Ao invés disso, dispare uma função de um módulo de email.

Priorize configuration over convention. Não faça coisas mágicas como assumir que o nome de um arquivo é x ou que os uploads vão parar sempre em uma pasta y. Isso é frágil e facilmente quebra sua aplicação quando alguma coisa muda e você não lembra de todas as convenções que criou para sua arquitetura. Programe de maneira que o código em si possa fazer com que o programador entenda todo o projeto.

Convencione nomes de arquivos no formato ‘lower-kebab-case’. Use apenas minúsculas e ‘-‘ como separador entre palavras. Isso evita problemas de sistemas de arquivos em SOs diferentes que sua aplicação Node possa rodar. Ex: cadastro-cliente.js

Outras dicas úteis

Somente app/server.js deve carregar o módulo app/config.js. Assim, ele se encarrega de passar os objetos options menores para configurar os demais subsistemas ao invés de ficar todo mundo carregando um arquivo cheio de informações globais, causando acoplamento desnecessário.

Centralize a criação de conexões ao banco. Passe as conexões criadas para os subsistemas ao invés de ficar passando informações de conexão por parâmetro e permitindo que eles criem suas próprias conexões.

Centralize o acesso às variáveis de ambiente NODE_ENV, mais especificamente no app/config.js. Os demais locais da sua aplicação que necessitem de variáveis de ambiente devem esperá-las por parâmetro.

Para mais dicas e exemplos de projetos usando estes princípios, dê uma olhada nesse repositório do Github, que serviu de inspiração para esse post.

O que é Node.js e outras 5 dúvidas fundamentais

Node.js é um fenômeno tem alguns anos. Diversos players gigantes da indústria de Internet tem adotado a plataforma, seja como uma ferramenta auxiliar, seja como sua principal tecnologia. O fato é que funciona, é eficiente e eficaz.

A ideia do post de hoje é explicar de uma vez por todas o que é Node.js e também solucionar outras dúvidas mais fundamentais, ao mesmo tempo em que apresento os principais conceitos de Node.js, suas principais características, vantagens, desvantagens, tecnologias concorrentes e falar das principais extensões.

Vamos ver nesse post (clique para ir direto ao tópico):

  1. O que é?
  2. Quais as vantagens?
  3. Quais as desvantagens?
  4. Para quê serve?
  5. Quais são os concorrentes?
  6. O que é usado em conjunto?

Caso prefira assistir um vídeo, eu palestrei sobre estes mesmos assuntos + MongoDB durante o IX Telecomptec na Universidade LaSalle, em Canoas/Rs, que você pode conferir ali pelo minuto 15 do vídeo abaixo:

#1 – O que é?

Node.js é uma tecnologia assíncrona que trabalha em uma única thread de execução. Por assíncrona entenda que cada requisição ao Node.js não bloqueia o processo do mesmo, atendendo a um volume absurdamente grande de requisições ao mesmo tempo mesmo sendo single thread.

Imagine que existe apenas um fluxo de execução. Quando chega uma requisição, ela entra nesse fluxo, a máquina virtual Javascript verifica o que tem de ser feito, delega a atividade (consultar dados no banco, por exemplo) e volta a atender novas requisições enquanto este processamento paralelo está acontecendo. Quando a atividade termina (já temos os dados retornados pelo banco), ela volta ao fluxo principal para ser devolvida ao requisitante.

Isso é diferente do funcionamento tradicional da maioria das linguagens de programação, que trabalham com o conceito de multi-threading, onde, para cada requisição recebida, cria-se uma nova thread para atender à mesma. Isso porque a maioria das linguagens tem comportamento bloqueante na thread em que estão, ou seja, se uma thread faz uma consulta pesada no banco de dados, a thread fica travada até essa consulta terminar.

Esse modelo de trabalho tradicional, com uma thread por requisição é mais fácil de programar, mas mais oneroso para o hardware, consumindo muito mais recursos.

Node.js não é uma linguagem de programação. Você programa utilizando a linguagem Javascript, a mesma usada há décadas no client-side das aplicações web. Javascript é uma linguagem de scripting interpretada, embora seu uso com Node.js guarde semelhanças com linguagens compiladas, uma vez que máquina virtual V8 (veja mais adiante) faz etapas de pré-compilação e otimização antes do código entrar em operação.

Node.js não é um framework Javascript. Ele está mais para uma plataforma de aplicação (como um Nginx?), na qual você escreve seus programas com Javascript que serão compilados, otimizados e interpretados pela máquina virtual V8. Essa VM é a mesma que o Google utiliza para executar Javascript no browser Chrome, e foi a partir dela que o criador do Node.js, Ryan Dahl, criou o projeto. O resultado desse processo híbrido é entregue como código de máquina server-side, tornando o Node.js muito eficiente na sua execução e consumo de recursos.

Node.js não é uma bala de prata. Ele não resolve todos os problemas. Na verdade nenhuma tecnologia vai resolver todos os seus problemas da melhor maneira possível. Quem acha que apenas uma tecnologia é a melhor opção para todos os cenários ou é ingênuo ou só inexperiente mesmo.

#2 – Quais as vantagens?

Node.js é programado com Javascript. Javascript tem algumas décadas de existência e milhões de programadores ao redor do mundo. Qualquer pessoa sai programando em JS em minutos (não necessariamente bem) e você contrata programadores facilmente para esta tecnologia. O mesmo não pode ser dito das plataformas concorrentes (veja mais adiante).

Node.js permite Javascript full-stack. Uma grande reclamação de muitos programadores web é ter de trabalhar com linguagens diferentes no front-end e no back-end. Node.js resolve isso ao permitir que você trabalhe com JS em ambos e a melhor parte: nunca mais se preocupe em ficar traduzindo dados para fazer o front-end se comunicar com o backend e vice-versa. Você pode usar JSON para tudo.

Claro, isso exige uma arquitetura clara e um tempo de adaptação, uma vez que não haverá a troca de contexto habitual entre o client-side e o server-side. Mas quem consegue, diz que vale muito a pena.

Node.js é muito leve e é multiplataforma. Isso permite que você consiga rodar seus projetos em servidores abertos e com o SO que quiser, diminuindo bastante seu custo de hardware (principalmente se estava usando Java antes) e software (se pagava licenças de Windows). Só a questão de licença de Windows que você economiza em players de datacenter como Amazon chega a 50% de economia, fora a economia de hardware que em alguns projetos meus chegou a 80%.

#3 – Quais as desvantagens?

Node.js é programado com Javascript. Para quem gosta de linguagens estritas como Java e C# (como eu), isso incomoda bastante. Não ter orientação à objetos, não ter tipagem, não ter uma compilação bacana, etc.

Node.js é recente. Apesar de já ter muita coisa criada pra ele, isso é uma desvantagem em relação à linguagens mais maduras como Java (21 anos) e Python (27 anos). Mesmo o C# (15 anos) já está bastante calejado e maduro, o que nos garante mais confiança para executar projetos maiores e mais pesados.

Node.js é assíncrono. Isso complica bastante dependendo da complexidade de cada uma das suas requisições, uma vez que o uso demasiado de callbacks pode gerar o chamado callback hell com um aninhamento extenso de funções e uma complexidade absurda de depuração.

#4 – Para quê serve?

Serve para fazer o que você quiser, desde sites à scripts de automação. No entanto, usos ideais de Node.js seriam:

Node.js serve para fazer APIs. Esse talvez seja o principal uso da tecnologia, uma vez que por default ela apenas sabe processar requisições. Não apenas por essa limitação, mas também porque seu modelo não bloqueante de tratar as requisições o torna excelente para essa tarefa consumindo pouquíssimo hardware.

Node.js serve para fazer backend de jogos e apps de mensagens. Sim eu sei, isso é praticamente a mesma coisa do item anterior, mas realmente é uma boa ideia usar o Node.js para APIs nestas circunstâncias (backend as a service) devido ao alto volume de requisições que esse tipo de aplicações efetuam.

Node.js serve para fazer aplicações de tempo real. Usando algumas extensões de web socket com Socket.io, Comet.io, etc é possível criar aplicações de tempo real facilmente sem onerar demais o seu servidor como acontecia antigamente com Java RMI, Microsoft WCF, etc.

#5 – Quais são os concorrentes?

Embora muitos costumem comparar Node.js com tecnologias mais comuns como PHP, Python e Ruby, elas não são de fato concorrentes do Node se a gente comparar o propósito específico de cada uma. Sendo assim, os concorrentes mais adequados para o Node.js seriam:

Node.js vs Go. Linguagem criada pelo Google, o Go tem um modelo alternativo para lidar com threads também, que é muito mais leve do que o modelo tradicional do Java, C#, etc tornando-o muito poderoso e leve como um Node.js mas mais parecido com o C (mais estrito).

Node.js vs Scala. Considerado por muitos uma evolução do Java, é apontado por muitos como o sucessor definitivo do mesmo, embora ainda esteja engatinhando. Em tese ela tem as mesmas vantagens do Java (escala, segurança, velocidade), sem a desvantagem do consumo excessivo de recursos.

Node.js vs Elixir. O mais desconhecido dos 3, ficou popular após a ascensão do Whatsapp como maior mensageiro instantâneo do mundo. Para quem não sabe, o Whatsapp usa Elixir, que roda sobre uma máquina virtual Erlang, com características parecidas com as do Node.js e paradigma funcional.

#6 – O que é usado em conjunto?

Como mencionei anteriormente, o Node.js por si só não tem muita coisa pronta, você tem de criar do zero tudo que quiser fazer, desde um handler de requisições até um renderizador de HTML. Felizmente, há muita coisa bacana pronta criada pela comunidade, que você pode instalar via NPM:

Node.js + Express. Boilerplate e framework web mais famoso para Node.js. Inclui suporte a diferentes view engines, funciona no padrão MVC, possui JSON e HTTP na caixa, trabalha com URLs amigáveis nativamente e muito mais, sem deixar de ser bem leve, o tornando indispensável para APIs e aplicações web escritas em Node.

Já usei ele aqui em alguns tutoriais aqui do blog.

Node.js + Mongoose. Biblioteca ORM para uso de Node.js com MongoDB. Não é a única existente, mas de longe a que possui a maior performance (50% mais rápido que seu principal concorrente, o Monk), sendo a número um do mercado. Os mesmos tutoriais de uso do Express que tem aqui no blog usam Mongoose também.

Node.js + EJS. É um renderizador de páginas HTML (view engine) para quem gosta de escrever HTML. Não é necessariamente idolatrado, mas uma boa opção para diminuir a curva de aprendizado do Jade/Pug (view engine padrão do Express) e atrair profissionais de front end mais facilmente pra sua equipe.

Node.js + Socket.io. Extensão muito poderosa e popular para uso de sockets com Node.js, usada especialmente em jogos e aplicações de tempo real que exigem comunicação instantânea e conexões persistentes entre cliente e servidor.

E aí, esqueci de cobrir alguma coisa?

Está curtindo os conteúdos de Node.js aqui do blog?

Deixe aí nos comentários!