Micro serviços e Node.js

Uma das plataformas que mais vem ganhando adeptos, quando se trata de desenvolvimento back-end, é o Node.js. Ele utiliza como base a engine V8 da Google para processar JavaScript do lado do servidor. Com o início de sua adoção, muitos módulos e pacotes começaram a surgir para resolver uma infinidade de problemas, ou para propôr soluções alternativa aos que já existem.

Além disso, houve um enorme crescimento no número de usuários acessando os serviços web de várias plataformas nos últimos anos. Desta maneira, se tornou essencial que um bom serviço seja disponibilizado de forma eficiente para todas as principais plataformas. Daí surgiu uma necessidade de distribuir as aplicações de forma que fosse possível oferecer o melhor dessa experiência de uma maneira eficiente e pouco custosa para os desenvolvedores.

Quando se fala de um mesmo serviço ser utilizado por várias plataformas, é necessário que o sistema seja desacoplado de modo que seja possível acessar os dados por todas as plataformas abrangidas. Por isso torna-se interessante a implementação de uma API de serviços web que permita abstrair esse acesso de maneira simples e segura.

Quando o desacoplamento da aplicação se torna um ponto crucial para sua manutenção, a arquitetura monolítica de software passa a não atender a demanda da aplicação. Por isso grandes empresas de software renomadas, como Netflix, Amazon ou eBay, estão adotando o modelo de micro serviços para atendar às demandas de flexibilidade, facilidade e performance na hora de construir ou manter o código do software, ou até de entregar a experiência ao cliente.


Arquitetura monolítica x micro-serviços

O modelo de arquitetura monolítica de software é a abordagem tradicional de arquitetura de software e ainda é utilizado em muitos projetos até hoje. Esse modelo se mostra bastante vantajoso quando a aplicação não possui um nível de complexidade muito grande.

Conforme a complexidade vai crescendo, vai se tornando necessário uma equipe maior, que precisará de treinamento para aprender como funciona toda a aplicação, uma máquina com mais recursos, para poder suportar as necessidades da aplicação e uma infra-estrutura que garanta que aquele servidor, ou conjunto de servidores, que provê a aplicação na rede nunca vai parar de funcionar completamente. Isso significa um ou mais servidores com a aplicação inteira carregada e prontos para realizar o load balance, no caso de uma bom projeto de arquitetura, e atender a demanda, todos ao mesmo tempo. O gasto de recurso, nesse caso, é enorme, já que os servidores sempre estarão no limite se a aplicação for muito pesada e os recursos da máquina forem limitados.

Uma arquitetura de software que tem ganho muita atenção nos últimos anos é a de micro serviços. Ela é uma alternativa a arquitetura de aplicação monolítica e, basicamente, consiste em dividir uma aplicação grande em várias aplicações menores e com propósitos específicos.

O princípio é bem parecido com o design das aplicações do núcleo do sistema Unix, que possui um grande número de aplicações independentes e cada uma tem um propósito específico (Ex.: grep, cat, find, …). Caso você precise, pode, inclusive, combinar seus recursos por meio de troca de mensagens ou APIs. Essa arquitetura é uma ótima solução para sistemas robustos e complexos e garante uma série de vantagens.

Um grande problema que deve ser levado em conta ao desenvolver micro-serviços, é que as aplicações passarão a se comunicar por outras vias, sejam elas locais ou pela rede. Por isso é necessário garantir a conectividade entre os processos que se comunicam para que a aplicação não venha a falhar.


Vantagens da arquitetura de micro-serviços

Diminuição da complexidade

Conforme a aplicação vai crescendo, é necessário que se crie a aperfeiçoe classes e suas relações, novas regras de negócio, novos casos de uso, etc. Em uma aplicação robusta, é comum o código adquirir um nível de complexidade muito alto, dado o número de classes e a forma como interagem.

Ao dividir a aplicação (um serviço por casos de uso, por exemplo), essa complexidade é dividida em fatias menores e enxutas. Isso, inclusive, ajuda a equipe a enxergar quais são os pontos que devem ou não estar interligados para que se possa otimizar a aplicação.

Desacoplamento

Ao repartir uma aplicação em pedaços menores, esses pedaços devem ficar completamente desacoplados. Para que dois ou mais serviços interajam, eles devem conhecer apenas a API através da qual se comunicam, conhecendo o método de comunicação e os dados que cada solicitação precisa para ser efetuada. Uma forma comum de fazer essa comunicação é por uma API REST, onde a comunicação é feita via requisições HTTP e os dados são trocados em padrão JSON.

3. Integração contínua

Quando o código está bem desacoplado, fica mais fácil escrever testes automatizados que garantem a consistência da aplicação(ver TDD). Com boas rotinas de testes escritas, é possível configurar um serviço, seja interno ou externo, de integração contínua. Esse serviço pode ser configurado para, a cada novo commit no sistema de versionamento do projeto, será agendada uma nova tarefa de teste. Essa tarefa irá executar todos os testes configurados na aplicação e, caso nenhum falhe, a suite faz o deploy da nova versão do sistema no ambiente de execução.

4. Escalabilidade

Quando se fala em micro-serviços, isso é ótimo, já que todos os serviços estão bem desacoplados. Isso garante que um serviço não depende de nenhum outro, portanto a sua atualização pode ser feita sem que isso quebre algum outro serviço, a menos que haja mudanças na API de comunicação entre os processos.

5. Produtividade

Outro problema que encaramos ao trabalhar em aplicações muito grande é a curva de aprendizado. Conforme a aplicação cresce, o tempo mínimo para se conhecer toda a sua lógica e as regras de negócio também cresce. Isso torna bastante difícil a produtividade de um novo membro de equipe, por exemplo, já que demandará um treinamento complicado sobre uma ferramenta complexa. Se a aplicação é menor, é bem mais fácil conseguir se adaptar ao seu funcionamento e aprender seu ciclo de vida.


API de acesso a dados

Quando se fala em API, REST e Node.js, uma ótima abordagem para a construção é o uso do middleware ExpressJS, um módulo especializado no tratamento de requisições HTTP, que se tornou padrão no desenvolvimento de servidores HTTP na plataforma. Ele se aproveita da arquitetura orientada a eventos do JavaScript para garantir grande agilidade, estabilidade e escalabilidade no tratamento das requisições e construção do serviço.


Boas práticas para o design da arquitetura de micro-serviços

Um bom case para se estudar quando se fala nesse tipo de arquitetura é o Netflix, que possui uma intra-estrutura robusta e distribuída, que garante uma enorme estabilidade e qualidade no serviço de streamming da plataforma. Sua equipe de desenvolvimento estabeleceu um conjunto de boas práticas para o design e implementação de uma boa arquitetura de micro-serviços.

Separe os repositórios de dados dos micro-serviços

Não utilize o mesmo repositório de dados para toda a aplicação. Deixe que a equipe responsável por cada serviço decida qual tecnologia se encaixa melhor no problema. Embora com um único banco de dados seja mais fácil para equipes diferentes compartilharem estruturas no banco, o que diminui a redundância de trabalho, você pode acabar em situações onde, se um serviço atualizar sua estrutura no banco, outros serviços podem ser afetados.

Mantenha o código em um nível similar de maturidade

Em outras palavras, caso você precise adicionar funcionalidades ou reescrever o código de um serviço em produção que funciona bem, a melhor abordagem seria criar um novo micro-serviço com o código novo deixando o original funcionando.

Desta maneira você pode lançar atualizações iterativamente e testar o código até que esteja livre de bugs e com a melhor eficiência sem comprometer o funcionamento do micro-serviço existente.

Quando o novo micro-serviço estiver tão estável quanto o original, você pode avaliar a possibilidade de juntá-los novamente, caso eles realizem uma mesma função.

Execute os micro-serviços em containers

Executar os serviços em containers é importante porque isso faz com que você só precise de uma ferramenta para gerenciar todas as instâncias. Enquanto o serviço estiver em um container, não importa como ele seja, a ferramenta sempre saberá como executá-lo. Uma ferramenta de conteinerização que acabou se tornando padrão no mercado, hoje, é o Docker.

Não rotule seus servidores

Trate seus servidores, principalmente aqueles que rodam aplicações que interagem com o usuário, como membros cambiáveis de um grupo. Todos devem poder realizar as mesmas tarefas para que você não precise se preocupar com nenhum deles individualmente. Sua única preocupação deve ser se há um número suficiente de servidores prontos para produzir o trabalho que você precisa executar. E você pode configurá-los para escalar para mais ou para menos, dependendo de sua demanda. Se um deles parar de funcionar, ele automaticamente será substituído por outro. Isso evita que seu sistema tenha um gargalo em um único servidor para realizar tarefas específicas.


One clap, two clap, three clap, forty?

By clapping more or less, you can signal to us which stories really stand out.