All posts by Kico (Henrique Lobo Weissmann)

Qualquer um pode programar?

Desde o TK 85, mais de 30 anos atrás, programar é o amor da minha vida e o ato ao qual me dedico inteiramente (das formas mais variadas). O ato de projetar e construir software é na minha opinião o nosso ápice intelectual. Talvez você nunca tenha se dado conta, mas quando está programando na realidade o vislumbre de boa parte da história da filosofia é realizado diante dos seus olhos.

Então, se programar é tão importante pra mim por que será que quando escuto o papo de que “qualquer um pode programar” me sinto tão incomodado? Se considero o nosso ápice cultural, não seria contraditório este meu sentimento, visto que quanto mais gente programando, melhor?

Primeiro me incomoda por que geralmente escuto esta história de quem está vendendo cursos/treinamentos ou mesmo de um mercado que está sedento por profissionais que possam se dedicar ao ofício (e que preferencialmente sejam baratos). Se programar é para todos, por que o mercado sente tanta falta de mão de obra? Não deveria existir muita gente programando hoje?

Já te adianto minha conclusão: qualquer um pode aprender a programar, mas muito poucos devem ou conseguirão de fato se profissionalizar.

Primeiro: programar é (muito) difícil

Quando digo programar não estou me referindo à configuração do seu DVD player ou a cozinhar: falo a respeito da criação de software (binário, que vai executar em um computador). É algo muito complexo e quem te diz o contrário está mentindo para lhe vender alguma coisa ou não faz a menor ideia a respeito do que fala.

Você precisa conhecer lógica de programação, algoritmos,  é bom saber como um computador funciona, o que é uma linguagem de programação, o que ela faz, como você a usa, e, indo além: também precisa ter ciência de que a época na qual precisávamos de apenas uma linguagem para escrever nossos sistemas acabou já faz mais de uma década (os tempos do VB6, Clipper, Delphi, PowerBuilder…).

(e não, você não vai escrever seus sistemas apenas com JavaScritpt também)

Precisa saber como seu software irá interagir com outros sistemas, tais como SGBDs, servidores, sistema operacional, rede, arquivos, memória. Precisa entender que são diversas abstrações, umas sobre as outras e que seu ferramental é enorme (o que é lindo): inúmeros frameworks, bibliotecas, ambientes de desenvolvimento e execução, paradigmas de desenvolvimento…

A coisa não acaba no seu primeiro “hello world” ou seu sisteminha web meia boca. Não: você precisa estar sempre melhor. Nem digo conhecer as últimas tecnologias, mas sim se aprimorar tecnicamente a cada dia. Tem que olhar pro seu código anterior e o achar um verdadeiro lixo perto do que está escrevendo agora.

Detalhe: tem de escrever código que possa ser mantido por outras pessoas também e talvez por um longo período de tempo.

(sempre fico maravilhado quando penso na complexidade envolvida ao implementar qualquer bobagem)

E esta é a parte fácil da coisa: o difícil é ter proatividade educacional, ou seja, realmente se interessar por isto. Ler, ir a eventos, se atualizar, ter pelo menos um super herói (tenho vários) na área, aprender coisas novas semanalmente (quiçá diariamente).

Vai por mim: a animação após ter conseguido escrever o primeiro programa dura muito pouco se este ânimo contínuo de querer sempre saber mais a respeito do ofício não durar. Sabe como chamo esta animação inicial? “ilusão de poder”. Especialmente se você estiver empregado na área.

Você realmente acredita que pode realizar muitas coisas após ter escrito o seu primeiro programa, mas se não tiver proatividade no seu aprendizado, acredite, vai dar com a cara na parede muito rápido e uma vida de frustração será iniciada.

Então o papo de que “qualquer um pode programar” baseado na ilusão de que é fácil está desmontado neste primeiro ponto, sigamos ao próximo.

Segundo: a responsabilidade envolvida

Você se sentiria seguro sabendo que qualquer um pode operar a sua mãe? Se sentiria bem sabendo que qualquer um projetou o viaduto sobre o qual seu carro está passando neste momento? Então por que qualquer um pode programar os sistemas que você precisa?

Por que não dizem por aí que qualquer um pode ser médico ou engenheiro, mas programador sim? Por que há um mercado que precisa de pessoas que saibam programar, independente do quão bem saibam (que sejam baratas) e que não se responsabiliza pela qualidade do que entrega (ainda). E também há outro mercado que vende cursos que precisa de novos alunos sempre, especialmente hoje, uma época na qual programar não tem mais o mesmo charme que tinha antes (muito poucos programadores milionários, né?).

E agora te faço uma pergunta direta: se você não está preparado e entregou seu primeiro sistema, você realmente dorme bem? Ok, qualquer um pode programar e você entrou na categoria “qualquer um”, pergunto: você deveria estar programando profissionalmente?

Terceiro: o custo

“Programar é maravilhoso, por que você pode criar um imenso valor a partir de quase nada”. Já escutei isto algumas vezes e minha resposta é a seguinte: “vai à merda amiguinho”.

O que chamam de “quase nada” na realidade são anos de estudo dedicados ao ofício: incontáveis horas de bunda na cadeira, páginas lidas, resumos, exercícios realizados, experimentos, participação em eventos e comunidades… É ter errado inúmeras vezes e conseguido se reerguer e ainda sair melhor ao fim de cada experiência. Isto é “quase nada” pra você?

E aqui pergunto: você estaria disposto a pagar este preço que mencionei acima? Aprender a programar não sai barato. Pode até existir materiais de baixo custo, mas o tempo que você irá investir no aprendizado não tem preço (e se você for casado, tiver filhos ou ter um emprego não relacionado à área, sabe muito bem do que estou falando).

Quarto: programar não é apenas difícil, está ficando mais difícil também

Mencionei no início deste post que houve uma era na qual era possível escrever sistemas usando uma única linguagem: Clipper, VB, Delphi, PowerBuilder, C/C++, etc. Conheço excelentes programadores do passado que aprenderam tudo o que precisavam em um único livro ou arquivo de ajuda da linguagem (também pelo fato de não terem tanto acesso à informação quanto hoje), será que isto se aplicaria hoje?

E se programar estivesse realmente ficando mais fácil com o tempo, já não deveria ter surgido tecnologias realmente eficientes que gerassem código pra nós? Por que programadores ainda existem? Cadê a bala de prata? Surgiram ferramentas que tornaram parte do desenvolvimento mais fácil (pense em Ruby on Rails, Grails, Node.js), mas o problema principal, que é justamente resolver problemas, continua complexo e possivelmente bem mais por que o próprio mundo ficou mais complexo.

(e sabe estas ferramentas que citei? São normalmente abstrações sobre algo muito mais complexo por baixo dos panos, e o conhecimento sobre este “algo muito mais complexo” normalmente diferencia as crianças dos adultos)

Faça uma experiência: chame um programador de décadas atrás para programar hoje e lhe pergunte o que acha. Talvez ele prefira o ferramental de hoje, mas o restante, duvido muito.

Então quer dizer que só uma elite deveria programar?

Tal como disse no início deste post, pra mim programar é um dos (talvez O) maiores exercícios intelectuais que a humanidade já construiu. Acredito que programar te torna uma pessoa melhor por causa de toda a complexidade envolvida na coisa, talvez te torne inclusive mais inteligente.

Como hobby recomendo a todos, inclusive para crianças (fui uma destas crianças nos anos 80 introduzidas à programação). Talvez este hobby inclusive sirva para que você cheque se realmente este é o caminho que deseja trilhar como ofício para sua vida.

Agora, profissionalmente, sabendo dos riscos, da responsabilidade e da dificuldade envolvida, creio que infelizmente minha visão é bem menos democrática. Sim, é para a elite que consegue superar os desafios que mencionei e ainda por cima continuar gostando da coisa e se aprimorando a cada dia.

Não me vejo fazendo outra coisa na vida e sou extremamente feliz por ter escolhido este caminho. Foi um dos meus maiores acertos sem sombra de dúvidas e mesmo hoje, mais de 20 anos depois ainda amo cada dia e cada linha que escrevo.

Me desculpe se joguei um balde de água fria sobre seus sonhos, mas é importante que alguém lhe diga das dificuldades envolvidas (especialmente neste mundo em que vivemos  com cada vez mais fábricas de doces).

(por mais estranho que pareça creio que as dificuldades tornam tudo mais interessante)

E sobre aqueles que dizem que “qualquer um pode programar”, bom: vocês estão desvalorizando o ofício, simples assim.

Minha expedição ao mundo do Node.js

Este final de semana resolvi mergulhar no Node.js: apesar de ser uma plataforma que acompanho desde o lançamento nunca lhe dei a devida atenção que esta merece, então resolvi corrigir esta desfeita.

Este mergulho foi uma experiência incrível, intensa e que me fez refletir sobre diversos assuntos. Aprendi horrores e então pra finalizar (dar o primeiro grande passo), nada melhor que compartilhar com vocês minhas conclusões iniciais.

Eu e o Node.js

Talvez a melhor expressão para descrever meu relacionamento com Node.js até agora seja “curiosidade distante”. Meu primeiro contato com a plataforma foi quando surgiu: escrevi alguns mocks de webservices e APIs REST lá pelos idos de 2009/2010.

Se não me falha a memória estes mocks foram escritos usando o módulo HTTP mesmo. Na época fiquei muito impressionado pois com pouquíssimo código eu conseguia implementar aqueles servidores. Parecia fantástico (e era).

Mas na época (e ainda hoje) a JVM dominava minha vida (estou nela desde o Java 1.1 1996/97). Pra piorar, desde então vi muitas histórias de terror envolvendo o mau uso: essencialmente a má compreensão do modelo assíncrono, apresentações muito ruins sobre o assunto (muito ruins mesmo), hype excessivo, fanboys… Tudo isto gerou uma péssima impressão em mim, o que acabou me distanciando da plataforma.

(eu sei que devia focar minhas impressões em aspectos objetivos, mas é inegável (e perigoso) o poder do subjetivo)

De lá pra cá meu uso do Node.js sempre foi indireto: ou tendo como base ferramentas como o Apache Cordova, Vue.js, até mesmo a escrita de pequenos scripts internos para resolver coisas pequenas do meu dia a dia (usava o comando Node como calculadora). Nada de avançado. Nunca fiz uma aplicação web real.

Além disto sou da geração de programadores que não via o JavaScript com bons olhos. Me surpreende a popularidade da linguagem que, todos sabemos, não foi construída sobre a melhor das bases. E esta primeira impressão ainda exerce influencia sobre mim. Curiosamente mesmo assim JavaScript sempre foi uma das linguagens que mais dominei. Um sentimento do tipo: “sei que você tem muitos problemas, mas os ignoro e gosto de vocẽ”.

Começa a expedição ao redor do meu quarto

Um bom livro: recomendo!

Navegando pelo Udemy topei com uma promoção envolvendo este curso: The Complete Node.js Developer Course (2nd Edition). Custava R$ 20,00, os livros em português que havia lido a respeito detestei (idem os cursos), vi a ementa, li muitos reviews positivos, tinha um fim de semana livre, o negócio era barato e me bateu aquela vontade de aprender Node.js. Comprei. (a propósito, o curso é maravilhoso, recomendo)

De onde bateu esta vontade de aprender Node.js? Honesta e pura curiosidade e vontade de tirar a má impressão que tinha da coisa. E dado que já estou há mais da metade da minha vida na JVM, que se tornou uma espécie de “ilha de Lost” pra mim, por que não tentar sair um pouquinho deste mundo e minimizar meu determinismo linguístico? De quebra eu ainda aprenderia um pouco mais sobre o ES6 e algumas ferramentas novas. Começava a expedição.

(spoiler: ainda considero a JVM como a melhor plataforma de todos os tempos)

Já acessou hoje? Devia!

Mas este meu mergulho deveria ter um objetivo final: eu saberia se Node.js valeria à pena se construísse uma prova de conceito que o validasse enquanto tecnologia. Qual prova de conceito? Simples: reescrever parcialmente o /dev/All em Node.js e descobrir se o negócio escala mesmo, assim como se o ferramental me fornece produtividade similar à que tenho com Grails.

(o resultado foi muito interessante, aguarde e verá)

/dev/All – Node.js ou Grails?

O /dev/All tem dois componentes: o “Feed Hunter”, que é o responsável por obter os links que aparecem no site (escrito em Java usando Spring, Apache Camel e outras cositas sobre as quais escreverei em breve por que vêm surpresa aí) e o “Front-end”, feito inteiramente em Grails (3.1.9) e Vue.js.

Um dos nossos objetivos na evolução do Front-end é transformá-lo em um SPA, desacoplando-o completamente do código Grails (sim, eventualmente haverá um app, no qual já estou trabalhando). Já demos alguns passos nesta separação, o que se manifesta na adoção do Vue.js: o código Grails seria então apenas uma API REST dali pra frente.

Apesar de todos os nossos esforços, ainda acho este componente pesado: ocupa no mínimo algo em torno de 300 a 400 Mb de RAM no servidor. A vida inteira escuto que Java devora memória. Sendo assim decidi que minha prova de conceito seria a implementação de uma API que já existe no /dev/All: aquela responsável por obter os posts apresentados na página inicial. Este endpoint aqui.

Um pouco mais sobre o modelo de desenvolvimento atual e o da prova de conceito

O modelo de desenvolvimento atual usa como base aquilo que o Grails nos provê por padrão: usamos o GORM como ORM e a própria estrutura de controladores do framework para implementar estas APIs. É notório portanto que há aqui um custo adicional de memória/desempenho relativo ao ORM, entretanto no que diz respeito à produtividade, comparando o custo do desenvolvedor e do servidor, produtividade ganha e portanto o ORM fica.

O SGBD adotado é o MySQL: e aí entra a primeira dificuldade em relação ao material existente sobre o Node.js: 99% do que existe hoje usa o MongoDB como base de dados. Eu teria de aprender portanto como usar o MySQL com Node.js. Usei o módulo mysql na versão 2.5.4 (e o aprendizado foi super rápido).

No caso do Node.js não encontrei um módulo de ORM com bases relacionais e, sinceramente, desta vez quis evitar. Um dos meus objetivos foi também fugir um pouco do desenvolvimento estritamente orientado a objetos e partir para uma abordagem mais funcional (quem acompanha este blog sabe que tenho lá meus problemas com OO).

As impressões

JavaScript  – ES6

Foi uma excelente oportunidade para aprender de vez o ES6 e aqui aquela minha antiga impressão a respeito da linguagem foi embora. Querendo ou não eu acabava escrevendo código JavaScript tal como havia o conhecido lá no início da minha carreira no final dos anos 90: de repente veio um upgrade gigantesco e muitas das coisas que não conseguia entender se tornaram claras.

Já faz algum tempo que estava me dedicando ao estudo da linguagem, mas ainda não havia me debruçado sobre o ES6. Foi sem sombra de dúvidas uma verdadeira reciclagem neste aspecto. Muitas coisas que não entendia agora fazem sentido:funções arrow, a modularidade, e muitos aspectos envolvendo melhorias da própria sintaxe.

Ferramental do Node.js e tempo de execução

Uma surpresa maravilhosa: tal como no Grails, tudo o que preciso para trabalhar é da interface de linha de comando e um editor de textos. Mas mais do que isto, as ferramentas em si são bastante produtivas: nodemon para carregamento automático das mudanças que realizo no código fonte,  as ferramentas de depuração nativas do Node, o próprio npm (que já conhecia e inclusive devemos lançar um guia esta semana)… Fantástico pra dizer o mínimo.

O carregamento do código e o tempo de execução foram surpreendentes: muito mais rápido que o que eu esperava. Sobre isto vou inclusive falar mais à frente.

Escrita de testes com Mocha, Expect e Supertest

Sempre que vou aprender algo novo os testes viram meu laboratório. Até então escrevia meus testes no navegador usando o Jasmine. É uma solução legal, mas nesta expedição acabei conhecendo o Mocha, que é inclusive muito parecido. Não houve grandes mudanças para mim neste ponto portanto.

O interessante veio com o Expect: ele tem uma funcionalidade muito interessante chamada “spy”. Essencialmente é um “AOP para testes”, que te permite verificar se um método foi ou não chamado.

O Supertest também achei muito bacana: é usado para escrever testes em cima de requisições HTTP geradas pelo Express, ou seja, me permite escrever os testes funcionais de uma forma bastante simples.

O bacana é que com o nodemon podemos ter os testes executando a cada alteração que fazemos no código, isto se mostrou uma mão na roda no meu laboratório interno.

O ExpressJS

Do lado JVM já temos alternativas que seguem a direção do ExpressJS, como o Ratpack (não conhece? devia!) e o Vert.x (literalmente o Node na JVM). É o modelo de desenvolvimento que considero ideal quando estamos escrevendo APIs: fácil, direto, focado no que vamos fazer (a implementação dos endpoints).

Confesso que apenas amei o ExpressJS. A documentação não é tão boa quanto a do Grails, mas te fornece o essencial para que você possa fazer praticamente tudo com ele, e de uma forma muito simples.

Nem tudo é claro: o uso de sessões, por exemplo, não é tão óbvio (mais a frente conto o por quê das sessões), idem no que diz respeito à implementação de coisas como o CORS. Entretanto, quando você conhece o conceito de middlewares (o equivalente aos filtros da API Servlet) a coisa deslancha.

Sobre os templates, sim: há a renderização de páginas tal como o JSP do Java EE ou o GSP do Grails. Para tal experimentei o Mustache, Pug e EJS. Comparado ao que temos do lado Java são soluções muito primitivas: o GSP sem sombra de dúvidas está anos luz na frente. Mas é natural isto: a pegada do Node.js sempre foi muito mais no desenvolvimento de aplicações que seguem o padrão SPA, o que joga este tipo de solução para o segundo plano. Acabei optando pelo hbs (Handlebars) na minha prova de conceito.

No frigir dos ovos é um framework extremamente produtivo. No meu caso, que só conhecia (e muito pouco) o módulo http, foi uma bela surpresa.

O poder e a ilusão de poder

Quase tudo que vi no Node achei muito produtivo: e é mesmo, mas apenas se você sabe o que está fazendo. Parece óbvio, né? Mas não é: JavaScript ainda é aquela linguagem que a maior parte das pessoas diz conhecer mas nunca estudou a respeito.

Lembra as histórias de terror que mencionei no início deste post? Pelo que pude ver sempre surgiram das mesmas causas:

  • Falta de conhecimento acerca do modelo de desenvolvimento assíncrono que o Node adota (o não conhecimento do loop de eventos é fatal).
  • Tem de conhecer o paradigma funcional.
  • A falta de conhecimento sobre desenvolvimento backend – Node foi feito para ser executado no servidor. Vi muita gente sem conhecimento algum desta área, mas muito de JavaScript cometendo erros absurdos aqui.
  • Desconhecimento das nuances do JavaScript (coisas como == e ===, por exemplo, o próprio escopo de variáveis, etc)

A ferramenta é realmente muito poderosa, é  muito fácil de usar e você de fato tem as coisas rodando num tempo muito menor. Mas quando ignora estes pontos acima a coisa fica feia, muito feia.

A armadilha surge no fato do Node ter uma única thread (é possível ter um servidor com mais de um processo, basta usar o módulo cluster, mas não é o padrão). Qualquer operação de I/O que agarre, prende todas as requisições que chegam no seu servidor: sendo assim você não “tem de pensar assincronamente”, você é obrigado.

Mais do que pensar assincronamente, você precisa pensar funcionalmente. Se o desenvolvedor não tiver bem fixados os conceitos do paradigma funcional é quase certo que vai dar merda. E quer saber de uma coisa? Acho isto fantástico, por que sair um pouco do OO foi uma experiência quase terapêutica para mim (já mencionei que não curto tanto OO?).

Se não souber estas coisas, você não tem poder: tem a ilusão de poder e a garantia de estar criando mais histórias tristes que se propagarão por aí. Rapadura é doce, mas não é mole não.

E a sua prova de conceito, como ficou?

Bom, vamos aos resultados então. Comecei pela implementação de um único endpoint: o responsável por realizar a busca por posts no /dev/All (este aqui). Foi algo fácil de fazer: este endpoint me retorna a lista de posts, e cada elemento no post tem uma estrutura similar à seguinte:


{
 id:"id do post",
 titulo:"titulo do post",
 resumo:"o resumo do post",
 dataPublicacao:"a data em que o post foi publicado no post",
 dataInclusao:"a data em que o /dev/All encontrou o post e o incluiu no banco de dados",
 cliques:"quantos cliques recebeu o post",
 site:{
  id:"identificador do blog que contém o post",
  nome:"o nome do blog",
  url:"a URL do blog",
  autor:{
  id:"o identificador do autor do blog",
  nome:"O nome do autor do blog"
 }
 }
}

Há portanto três tabelas no banco de dados unidas por join: post, site e autor. Lembre: não estou usando MongoDB aqui, mas sim o MySQL. Será que a coisa escala? Comecei a realizar então alguns testes de desempenho e o resultado foi “apenas” assustador como mostrarei na sequência.

A chamada padrão a este endpoint retorna os últimos 20 posts cadastrados no /dev/All. Em média o tamanho da resposta é 20kb.

Teste de desempenho e escalabilidade

Para realizar o teste usei uma ferramenta chamada “siege“, que me permite realizar testes de carga usando o protocolo HTTP. Caso esteja usando Linux, você pode instalá-la usando o comando apt-get install siege.

Inicialmente peguei a mesma implementação feita em Grails e a instalei em um servidor Tomcat local (exatamente como se encontra em produção). Na sequência, executei os testes usando o Siege levando em consideração o tempo de um minuto e 255 usuários simultâneos. Vamos aos valores aproximados para a versão escrita em Grails:
Transactions:       21046 hits
Availability:      100.00 %
Elapsed time:       59.95 secs
Data transferred:      245.47 MB
Response time:        0.47 secs
Transaction rate:      351.06 trans/sec

Agora, vamos aos resultados na mesma API, implementada em Node.js usando as mesmas configurações:
Transactions:       32596 hits
Availability:      100.00 %
Elapsed time:       59.06 secs
Data transferred:      131.28 MB
Response time:        0.21 secs
Transaction rate:      551.91 trans/sec

Na média a mesma API escrita em Node.js consegue um throughput maior: 40 a 50% a mais de transações por segundo.

E sobre o consumo de memória? Na média enquanto o Tomcat consome 1 Gb durante o teste, a instância do Node consome 170Mb. 80% a menos.

Mas este benchmark não é preciso, então não comemore ainda

Não comemore ainda: pra começar este é um benchmark muito vagabundo. Você deve levar em consideração os seguintes pontos:

  • O código escrito em Grails usa o GORM e contém uma série de funcionalidades carregadas junto com a aplicação que não existem ainda no código escrito em Node.js.
  • O código escrito em Node.js usa apenas SQL nativo para obter os dados, o que dá um ganho de desempenho em relação à adoção de qualquer ORM.

Não cheguei a implementar uma versão usando apenas SQL do mesmo endpoint na aplicação, entretanto creio que o resultado seria muito parecido mesmo assim, pois ainda há uma enorme pilha por trás. Além disto, é fato conhecido que sim, Java sempre consome uma quantidade significativamente maior de memória.

Os testes foram além: depois executei verificações com 500, 1000 usuários simultâneos. A disponibilidade e escalabilidade do Node.js ganhou nestes casos (note: estou testando apenas um endpoint).

Resumindo: obtive resultados melhores do ponto de vista empírico com Node: mas minha metodologia de teste é muito furada e não deve ser levada como palavra final.

E depois de ter implementado a API?

Bom: aí eu empolguei e implementei quase todo o comonente Frontend do /dev/All em Node.js. Há uma versão muito tosca online caso queira conferir: ela tem apenas a página inicial, mas dá pra pelo menos você experimentar. Basta acessar http://devall.com.br:3000 (não sei até quando este link estará disponível, pois é apenas para testes).

Escrevi a página inicial usando o hbs, ou seja, não é uma aplicação SPA: meu objetivo era apenas aprender e testar a tecnologia, sendo assim leve isto em consideração quando a estiver accessando, ok?

Minhas considerações finais

Node.js com certeza faz parte agora do meu cinto de utilidades, e saibam que em pouquíssimo tempo teremos um novo front-end do /dev/All 100% implementado nesta tecnologia pelas seguintes razões:

  • Nosso front-end é muito pequeno, então é viável de ser reescrito (todo o trabalho pesado é feito pelo Feed Hunter).
  • O consumo de memória é realmente muito menor, o que nos permite aproveitar melhor nossos servidores e reduzir o custo de operação.
  • A escalabilidade se mostrou bastante superior.
  • E nesta minha empolgação já estou com 80% disto implementado e, no processo, sem os vícios das versões anteriores do código fonte. :)

É vital no entanto lembrar do que escrevi acima a respeito da ilusão de poder. É assustadoramente fácil escrever código lento e que não escalará em Node.js. Ficou óbvio pra mim a origem das histórias tristes que havia mencionado antes. Se você não souber programação funcional, entender o modelo assíncrono e de eventos do Node.js, é quase certo que vai dar errado.

(é importante lembrar que JavaScript ainda é aquela linguagem que a maioria julga saber mas nunca estudou de verdade, e isto é a origem de inúmeros problemas)

Sobre a produtividade em relação ao Grails

Do ponto de vista de produtividade, comparado ao Grails, sinceramente não posso dizer que seja mais produtivo que este. Os plug-ins do Grails, além do próprio GSP o tornam matador quando há renderização do lado servidor. Isto sem mencionar que a linguagem Groovy também é melhor que JavaScript (ao menos é construída sobre bases bem mais sólidas).

Ainda sobre produtividade comparado ao Grails: aqui nós pensamos de forma síncrona, que é muito mais natural para a esmagadora maioria das pessoas. No Node.js pensamos essencialmente em callbacks e promises e código que escrevemos para ser executado no futuro, e não no agora. E sim: se adequar a esta outra realidade leva tempo e, portanto, boa parte da sua produtividade também.

Entretanto no que diz respeito ao carregamento do código fonte e sua modificação durante a execução, Node.js chuta a bunda do Grails diversas vezes. É muito mais rápido, e isto é fundamental quando vamos executar uma grande bateria de testes.

Sobre modularidade e grandes bases de código

A questão da modularidade também é importante mencionar: já trabalhei em projetos gigantescos com Grails (e Java em geral). No caso do Node.js, ainda não peguei um projeto com uma grande base de código. Entretanto, para escrever micro-serviços, Node.js se mostrou uma ferramenta extremamente interessante e com certeza está no centro do meu radar para estes casos.

Sobre o consumo de recursos e escalabilidade

Não há muito o que dizer: consome uma quantidade muito menor de memória e quando bem projetado escala maravilhosamente bem. É portanto um forte candidato em situações nas quais temos servidores limitados (que é justamente uma área na qual venho pesquisando bastante nos últimos anos).

O consumo da CPU também se mostrou muito inferior. No caso dos testes que realizei, código na JVM chegava a consumir 350% da CPU fácil, enquanto o Node ficava na faixa dos 120%.

Resumindo: se você souber o que está fazendo o resultado é lindo.

Renderização do lado servidor

Não é algo lindo: tal como mencionei as opções que encontrei ainda são muito primitivas quando comparadas ao que temos em Java, Groovy ou PHP. Natural, não é o foco deste público. Para aplicações que requeiram a criação de vários CRUDs algo como Grails ainda é uma solução bem mais interessante.

Mas aqui leve em consideração minha pouca experiência no assunto. Pode ser que existam soluções que eu ainda não conheça.

E finalmente

Este foi um final de semana maravilhoso e estas foram as minhas conclusões iniciais sobre aquilo que estudei (por isto o post longo).

Neste primeiro momento recomendo o Node para pequenos projetos, especialmente se for projetos nos quais você implementará apenas uma API. É uma tecnologia muito bacana e que vale à pena estudar.

Conforme progrido no estudo conto mais pra vocês aqui.

Novo guia da Itexto: SDKMan

Infelizmente o Jenv (http://jenv.io) ficou fora do ar por um bom tempo (pelo menos os últimos cinco dias). Então, junto com Daniel Altarmiro, escrevemos um novo guia, desta vez sobre o SDKMan, tendo como base o nosso antigo guia do Jenv.

Entrei em contato com a equipe responsável pelo desenvolvimento e manutenção do projeto pelo Gist, e por lá pude ver que a situação já dura um bom tempo infelizmente.

Vocês podem baixar o guia clicando aqui.

Iniciando a Semana JavaScript

Mais um avanço no JavaScript Brasil: lançamos esta semana a newsletter, chamada “A Semana JavaScript”. O objetivo é compartilhar eventos, treinamentos, vagas de emprego, material e tudo o mais relativo ao JavaScript para que possamos manter a comunidade bem informada semanalmente.

Naturalmente este é um esforço da comunidade, sendo assim, qualquer um poderá compartilhar links para que sejam publicados na newsletter. Para tal vamos incluir um formulário no site do JavaScript Brasil para que todos possam compartilhar conteúdo (inclusive anonimamente se preferirem): o importante é divulgar coisas importantes para a comunidade.

Caso deseje se inscrever, basta preencher os dados presentes neste formulário.

E acessar o JavaScript Brasil para acompanhar as novidades!

Uma instância do Tomcat atendendo dois domínios? Configurando Virtual Hosts

Imagine a seguinte situação: você tem um único servidor e duas aplicações distintas que serão hospedadas na mesma máquina. Cada uma destas aplicações tem, por sua vez, seu próprio domínio (www.aplicacaoquente.com.br (aplicação A) e www.aplicacaofervente.com.br (aplicação B), por exemplo). Como você resolve esta questão usando apenas o Tomcat?

Se você tiver o servidor Apache instalado, é possível usá-lo como front-end do seu servidor e, configurando o recurso do proxy reverso, simplesmente fazer o direcionamento das requisições vindas dos dois domínios acima para as aplicações A ou B. Mas e quando você tem apenas o Tomcat? Razoavelmente simples: você usa o recurso dos hosts virtuais (virtual hosts daqui pra frente).

(A documentação oficial do Tomcat sobre este tema é muito ruim, e isto me motivou a escrever este post.)

O que é um host virtual?

Um host virtual representa o direcionamento que o Tomcat fará quando receber solicitações para um dado domínio. No exemplo deste post, temos os dois domínios, um para cada uma das aplicações. Vamos ver aqui agora como realizar esta configuração na versão 8.0 e 8.5 do Tomcat.

Como configurar os virtual hosts

Antes de iniciar, uma simples convenção. CATALINA_HOME representa o diretório no qual o Apache Tomcat encontra-se instalado em seu servidor.

O primeiro passo consiste em editar o arquivo CATALINA_HOME/conf/server.xml. Busque pela tag <Engine> cujo atributo name seja igual a “Catalina”, tal como no exemplo a seguir:


<Engine name="Catalina" defaultHost="localhost">

<!--For clustering, please take a look at documentation at:

É no interior desta tag que iremos inserir as configurações de nossos virtual hosts. A configuração é bastante simples. Em nosso exemplo, basta incluir duas tags <Host>, tal como no exemplo a seguir:


<Host name="aplicacaofervente.com.br" appBase="webapps" unpackWARs="true" autoDeploy="true">
<Alias>www.aplicacaofervente.com.br</Alias>

<Valve className="org.apache.catalina.valves.AccessLogValve"
directory="logs"   prefix="aplicacaofervente_access_log" suffix=".txt"
pattern="%h %l %u %t %r %s %b" />
</Host>

<Host name="aplicacaoquente.com.br" appBase="webapps2" unpackWARs="true" autoDeploy="true">
<Alias>www.aplicacaoquente.com.br</Alias>

<Valve className="org.apache.catalina.valves.AccessLogValve"
directory="logs" prefix="aplicacaoquente_access_log" suffix=".txt"
pattern="%h %l %u %t %r %s %b" />
</Host>

Muita atenção a alguns atributos muito importantes presentes na tag <Host>:

  • appBase – define o diretório “webapps” daquele host. No caso de virtual hosts, é uma boa ideia você ter um diretório “webapps” por host. Em nosso exemplo, criei dois diretórios: CATALINA_HOME/webapps e CATALINA_HOME/webapps2
  • name – identifica o domínio para o qual serão direcionadas as requisições. Observe que defini o domínio sem o “www” na frente. Isto por que no interior da tag <Host> podemos incluir aliases, observe a tag <Alias>: ela inclui o prefixo no nome do domńio, o “www”.

A tag <Valve> neste caso é usada para configurar uma válvula do Tomcat (um recurso poderosíssimo e muito pouco conhecido pelos desenvolvedores) responsável por registrar as requisições que chegam ao servidor em um arquivo de log. Observe que criei um arquivo de log por domínio.

Muita atenção em relação à pasta appBase

É possível ter dois virtual hosts apontando para a mesma pasta appBase. Entretanto, em diversas situações você observará que as aplicações, durante sua inicialização, entram em “loop de boot”, ou seja, são iniciadas e reiniciadas infinitas vezes.

Não sei ao certo o que causa este problema, mas sei como solucioná-lo: uma pasta appBase por host. Simples assim.

Alguns links úteis

É interessante que você conheça os atributos que podem ser inseridos nas tags <Engine> e <Host>. Sendo assim, recomendo que leia sobre a primeira tag aqui e sobre a segunda aqui.

Definindo o host padrão

Com isto nosso servidor está praticamente pronto. O mesmo endereço IP irá atender aos dois domínios. Mas e se alguém tentar acessar o servidor diretamente pelo seu IP? Neste caso definimos qual o host padrão na tag <Engine>, tal como exposto no exemplo a seguir:


<Engine name="Catalina" defaultHost="localhost">

Neste exemplo criei uma tag <Host> cujo nome é “localhost” (é inclusive o host padrão da configuração limpa do Tomcat).

Sobre o contexto das aplicações em um domínio

Se você já usou o Tomcat sabe que é possível ter mais de uma aplicação instalada na pasta CATALINA_HOME/webapps. Voltando ao nosso exemplo, imagine que para o domínio aplicacaofervente.com.br tivéssemos os seguintes arquivos WAR na sua pasta webapps:

  • ROOT.war
  • administrativo.war

A aplicação padrão do domínio seria o ROOT.war. Já se você quiser aplicar o administrativo, teria de usar o endereço http://www.aplicacaofervente.com.br/administrativo

Melhorias no consumo de memória

Talvez as aplicações que você hospeda em seus virtual hosts tenham bibliotecas em comum. Apenas se você tiver certeza absoluta de que compartilham exatamente as mesmas versões destas bibliotecas, considere a configuração de uma pasta compartilhada de libs. Recomendo a leitura desta página na documentação oficial do Tomcat sobre class loading.

Concluindo

Reinicie o seu Tomcat e faça testes enviando requisições para os dois domínios que apontam para o mesmo IP e veja o resultado. Na sequência, acesse o servidor diretamente por seu IP e verá ser retornada a aplicação padrão definida na tag <Engine>.

O Tomcat é cheio de recursos muito interessantes que os desenvolvedores desconhecem. Em um futuro próximo talvez escreva mais dicas sobre estes assuntos (dica: leia sobre as válvulas).