Android Studio: Tutorial completo do básico ao avançado (10 lições!)

Em 2012 eu comecei a me interessar por Android. Não me orgulho de ter entrado tão atrasado no mercado, uma vez que um colega de faculdade já havia me mostrado a plataforma em 2010, quando estava me formando. Se eu tivesse dado atenção à época, quando qualquer app alcançava um volume grande de downloads, talvez toda minha carreira tivesse sido diferente. Não que eu esteja reclamando do que consegui alcançar nestes 11 anos como desenvolvedor, mas né!

Mas o que eu estava me lembrando agora é que em 2012 era muito difícil programar para Android. Os aparelhos ainda eram poucos, menos ainda os que prestavam.  Android 2.3 era luxo e as ferramentas, terríveis. Usávamos muito Eclipse com os plugins do ADT. Quando um atualizava, quebrava o outro, perdia muito tempo configurando a ferramenta. Logo descobri o MotoDev, um Eclipse modificado pela Motorola que já vinha pronto para programar para Android. Foi a ferramenta que mais utilizei até o lançamento oficial do Android Studio.

Ah, o Android Studio (suspiro)!

Tenho uma relação de amor e ódio com a ferramenta. Ao mesmo tempo em que ela tornou o desenvolvimento nativo para a plataforma muito mais fácil, ela acaba com os recursos da máquina onde você usa ela, principalmente seu espaço e IO de disco. Mas fazer o quê, não há bônus sem ônus.

E é dessa ferramenta que vou falar hoje. Não apenas falar, vou destrinchar tudo que sei sobre ela (e o que não sei vou pesquisar) para lhe entregar o post mais completo que você possa encontrar na Internet sobre o assunto. Um tutorial completo de Android Studio, do básico ao avançado.

Vou falar aqui de (clique para ver algum tópico específico que mais lhe interesse):

  1. Como baixar e instalar a ferramenta?
  2. Como e por que manter atualizado?
  3. Como instalar os pacotes corretos do Android?
  4. Como criar e executar seu primeiro AVD?
  5. Como criar meu primeiro app Android?
  6. Como fazer testes mais avançados?
  7. Como copiar e inserir arquivos no AVD?
  8. Dicas de performance
  9. Como gerar o APK para publicação?
  10. IDEs concorrentes do Android Studio

Tem algum tópico que você gostaria de saber e que eu não cobri aqui? Me manda nos comentários!

#1 – Como baixar e instalar o Android Studio?

O Android Studio é a ferramenta oficial para desenvolvimento Android. Apesar dos seus contras e de existirem alternativas (como listo na dica #12), ele ainda é a melhor opção.

Para baixar, acesse o site oficial da ferramenta neste link. A página detecta seu sistema operacional e lhe fornece a versão mais atualizada da ferramenta. Após baixar, dê um duplo-clique nele para instalar na sua máquina.

Assim que ela terminar de instalar, execute-a para que sejam efetuadas as primeiras atualizações e você possa finalmente utilizá-la.

#2 – Como e por que manter o Android Studio atualizado?

Assim que você instala a ferramenta, a mesma já executa uma atualização de suas dependências. No momento em que escrevo este post ela está versão 2.3.1, mas todo mês sai alguma atualização nova: updates de segurança, de performance, para corrigir bugs, etc. Além disso não é apenas o Android Studio em si que atualiza, mas sempre tem alguma de suas dependências para atualizar. E são muitas:

  • novos SDKs surgem para as novas e antigas versões do Android
  • atualização da ferramenta de compilação (Android Build Tools)
  • novos Add-ons para facilitar a sua vida enquanto desenvolvedor
  • novas versões do Gradle, o gerenciador de build do Android Studio

E essas são apenas algumas!

Para manter o Android Studio atualizado é bem simples, pois a própria ferramenta te avisa quando saem novas atualizações dela própria, bastando aceitar o download e reiniciar a mesma quando solicitado. Ainda assim, você pode mandar verificar atualizações manualmente, usando a opção Android Studio > Check for updates.

É importante manter sua ferramenta atualizada para evitar exploits de segurança que possam ser usados por pessoas maliciosas e até mesmo para que a performance da ferramenta (que não é lá grande coisa) fique um pouco melhor.

#3 – Como baixar os pacotes corretos do Android SDK Manager?

O Android Studio possui integração com o SDK Manager, a ferramenta que gerencia as versões e add-ons de desenvolvimento Android presentes na sua máquina. Você consegue acessar o SDK Manager a partir da splash screen, no meu Configure como abaixo:

Por dentro da ferramenta você também pode acessar o SDK Manager a partir do menu Tools > Android > SDK Manager:

E usando o ícone presente na toolbar (é o Android com a seta de download):

Qualquer uma das opções vai te levar até a seguinte tela do SDK Manager:

Nesta janela temos algumas informações bem importantes que valem ressaltar:

No topo, temos o caminho onde o SDK do Android está instalado na sua máquina. Certifique-se de que este local possui muito espaço em disco disponível, tipo uns 20GB, só pra garantir.

Logo abaixo, temos três abas, sendo a primeira a que mostra as versões de plataforma Android que você possui na sua máquina e que consequentemente conseguirá criar apps. O jeito mais fácil (e que mais ocupa espaço) de instalar esses SDKs é apenas marcando o checkbox correspondente e mandando instalar. Mas há uma maneira mais inteligente, que vou falar mais adiante.

Por ora, certifique-se de que você possui ao menos a versão mais recente instalada, Nougat no meu caso, como pode ver na imagem.

A segunda aba mostra as ferramentas e add-ons das plataformas, como na imagem abaixo:

Aqui não precisamos de muita coisa, mas ao menos você terá de ter sempre a versão mais recente instalada do Android SDK Build-Tools, do Android Emulator, do Android SDK Platform-Tools e do Android SDK Tools. Quando sai alguma atualização desses elementos geralmente a ferramenta avisa, mas não custa nada abrir essa tela de vez em quando para checar por você mesmo.

A terceira aba mostra apenas as URLs dos repositórios de onde as dependências estão sendo baixadas e, a menos que você tenha certeza do que está fazendo, não deve mexer aí.

E por fim, eu mencionei no início desse tópico de que tinha um jeito melhor de baixar as dependências que não apenas marcando o checkbox da versão do Android, não é mesmo?

Pois bem, primeiro, volte à aba inicial do SDK Manager e marque o checkbox inferior-direito que diz “Show package details”. Agora você deveria ver uma árvore de dependências muito mais intrincada, como segue:

Note que abaixo da raiz do Android 7.1.1 que eu tenho instalado no meu note, que apenas três opções estão marcadas: Android SDK Platform 25 (essa é obrigatória), Sources for Android 25 (opcional, para melhorar o debugging) e Google APIs ARM EABI v7a System Image. Neste último que está o segredo para economizar espaço em disco!

Para realizar os testes dos seus apps, como mostrarei adiante, você precisar ter imagens das máquinas virtuais Android baixadas no seu computador. As System Images, que nesse caso eu tenho apenas uma dentre as diversas disponíveis. Uma breve explicação sobre as imagens que aparecem nessa listagem, e que praticamente são as mesmas em todas as versões de Android:

  • Android TV …: é a imagem para testar apps feitos para Smart TVs;
  • Android Wear …: é a imagem para testar apps feitos para wearables (Smart Watches, por exemplo);
  • Google APIs …: é a imagem para testar apps feitos para smartphones e tablets, que usem APIs do Google (Mapas, por exemplo)
  • ARM …: imagens que comecem com esse nome são de smartphones/tablets usando CPU ARM;
  • Intel x86: imagens que comecem com esse nome são de smartphones/tables usando CPU Intel;

Estas são as opções mais frequentes que aparecem para download, e aqui entra mais uma explicação importante:

  • se você possui um computador com processador Intel recente (uns 3 anos pra cá), instale o Add-on Intel Accelerator HAXM que vai melhorar a performance dos testes na sua máquina, bem como baixe somente imagens que possuam arquitetura Intel x86 no nome.
  • agora, se você possui um computador mais antigo ou que não tenha processador Intel, sugiro baixar somente imagens que contenham arquitetura ARM EABI v7 mais fáceis de emular

Mas o mais importante é: você não precisa ter todas essas imagens instaladas em sua máquina. Eu costumo ter apenas uma da versão mais recente do Android e outra da versão 4 (Kitkat, por exemplo), para criar apps com maior suporte na Google Play.

Como assim?

Se você faz um app usando a plataforma 4, por exemplo, todos os smartphones com Android 4+ poderão instalar o seu app. Agora, se você faz um app apenas para Nougat (7), somente quem tem smartphones de ponta, na data em que escrevo este post, é que conseguirá utilizá-lo.

Capicce?!

#4 – Como criar meu primeiro AVD?

Primeiro, você sabe o que é um AVD?

AVD é a sigla para Android Virtual Device, ou Dispositivo Virtual Android. Basicamente um AVD é uma máquina virtual Android que você usa para testar seus apps enquanto desenvolve, para que não precise ter um ou mais dispositivos Android de verdade. É especialmente útil para testar diferentes configurações de smartphone e principalmente dispositivos mais difíceis de termos, como wearables.

Sendo assim, saber como criar um AVD é muito importante para poder prosseguir nos estudos com Android. E o primeiro passo para isso é acessar o AVD Manager, que fica no menu Tools > Android > AVD Manager, por dentro da ferramenta:

Ou ainda, pela toolbar (é o ícone do smartphone com a cabeça do Android no canto direito):

Independente da opção escolhida, o AVD Manager se abrirá, como abaixo:

Neste meu print, já tenho dois AVDs criados, mas isso não importa no momento. Para criar seu primeiro ou décimo, os passos são os mesmos. Primeiro, clique no botão “Create Virtual Device”, no canto inferior esquerdo, isso irá abrir o assistente de criação de AVD:

Na primeira tela, selecione a categoria Phone e depois Nexus One, um modelo de smartphone simples porém suficiente para testarmos nossos apps. Na verdade essa escolha afeta mais a resolução do seu dispositivo do que qualquer outra coisa, então não importa tanto assim neste momento. Avance para a próxima tela no botão inferior direito.

Aqui você escolhe qual versão do Android que seu AVD vai ter, dentre as opções que você já tem baixadas na sua máquina e as demais, que possuem o link para download aqui mesmo, o que facilita bastante o gerenciamento das mesmas. Neste print estou selecionando uma imagem de Nougat que já tenho baixada e que encontra-se na aba “Other images”. Na aba x86 você encontra as imagens de smartphones Intel e na aba Recommended, bem, você tem as recomendas pelo Android Studio, sabe-se lá o que isso signifique…

Avance novamente e verá a seguinte tela.

Aqui você define o nome do seu AVD, revisa a resolução e plataforma do dispositivo, se ele iniciará em posição retrato ou paisagem (que pode ser alterado depois) e se a performance dos gráficos será via software ou via hardware (deixe automático, a menos que for desenvolver algum jogo).

Note que tem um botão ali de “Show Advanced Settings”. Se você clicar nesta opção, poderá personalizar melhor as configurações de hardware do seu aparelho, sendo as mais importantes:

  • Câmera: você decide se o dispositivo vai ter câmera ou não, e se ela usará a webcam do seu notebook ou apenas uma imagem da sua pasta de imagens;
  •  Network: a velocidade da rede do seu celular, podendo simular redes lents e antigas como GPRS, EDGE, etc ou deixar Full para usar a Internet completa do seu computador.
  • Memory & Storage > RAM: define a quantidade de memória RAM o seu dispositivo vai ter. Sugiro 1024MB para a maioria dos AVDs.
  • Memory & Storage > Internal Storage: espaço de armazenamento interno disponível no seu AVD. A menos que vá armazenar muitos arquivos ou um banco de dados muito grande, a sugestão de 800MB é suficiente.
  • Memory & Storage > SD Card: define se você vai ter um SD gerenciado pela ferramenta ou salvo em um arquivo externo que simulará o SD. Em ambos os casos, você deve definir a capacidade do SD virtual em MB.

Caso não tenha certeza do que fazer com cada uma dessas configurações, deixe as mesmas como estão, alterando apenas a RAM para 1024MB. Clicando em Finish finalizará o processo e voltará à tela de gerenciamento dos AVDs, que deve demorar alguns segundos e ficar travada enquanto o AVD está sendo criado.

Note que cada AVD consome um significativo espaço no seu HD (Size on Disk), então não fique criando um monte deles ao mesmo tempo que não vale a pena.

Para editar o AVD, clique no ícone de lápis e o assistente de configuração será aberto novamente. A seta para baixo exibe opções como formatar (Wipe) o AVD e excluí-lo. Obviamente o play verde manda executar o AVD.

A execução pode demorar mais ou menos, dependendo da configuração do seu AVD vs a configuração da sua máquina. Em geral, algo em torno de 1-5 minutos é normal. Sim, a inicialização é bem lenta e consome muitos recursos da máquina. Quem já mexeu com máquinas virtuais antes sabe do que estou falando.

Ao término do processo de inicialização do Android, você terá uma máquina virtual Android para mexer à vontade, sendo o comportamento e aparência equivalentes ao de um Android nativo completo, incluindo funcionalidades como instalar apps e navegar na Internet.

Uma dica: depois que você inicializa seu AVD, não feche ele. Assim, a cada projeto que precisar testar, basta mandar executar no AVD que já está rodando, sem precisar inicializar um novo. Somente encerre o AVD depois que terminar todos seus testes. Também encerre se ele estiver travado ou se demorar mais de 5 minutos para inicializar.

#5 – Como criar meu primeiro app Android?

Eu não vou entrar em detalhes neste passo, uma vez que já fiz isso em diversas outras oportunidades aqui no blog. Sendo assim, leia um dos seguintes materiais antes de prosseguir nesse tutorial:

Com o app criado, use o botão verde de play que fica na toolbar para executá-lo:

O Android Studio vai levar alguns segundos para compilar seu projeto e empacotar usando o Gradle e depois vai lhe perguntar onde deseja testar o mesmo:

Neste exemplo, meu AVD já está inicializado por completo, por isso que aparece na lista de dispositivos conectados. Basta selecionar ele e dar um Ok para que o app que estamos testando seja instalado e executado no mesmo.

#6 – Como fazer testes mais avançados?

Consulte este post aqui que está bem completo, focado nesta questão de testes de apps usando diferentes configurações e recursos, incluindo como testar no seu smartphone.

#7 – Como copiar e inserir arquivos no AVD?

O AVD se comporta como um autêntico dispositivo Android, certo? E num dispositivo Android você consegue colocar e tirar arquivos do armazenamento interno dele, certo? Logo, o mesmo é possível de ser feito com o AVD!

A tarefa é simples, primeiro execute o seu AVD e deixe-o inicializar completamente. Em seguida, abra a ferramenta DDMS da sua IDE, no caso Android Studio é o Android Device Monitor, que fica no menu Tools > Android.

Uma vez com o Device Monitor aberto, que permite entre outras coisas ver como anda o consumo de recursos de hardware do seu AVD, você tem a aba File Explorer que permite mexer nas pastas e arquivos do mesmo (dê uma olhada na imagem e como estou mostrando o que está salvo dentro do AVD)! Use os botões da toolbar da direita da imagem para fazer as operações:

  • ícone do disquete para copiar um arquivo do seu smartphone pro computador;
  • ícone do smartphone para copiar um arquivo do seu computador pro smartphone.

Para quê você iria querer copiar arquivos do AVD? Para fazer um dump da sua base SQLite, por exemplo. Ou o inverso, para colocar arquivos estáticos dentro do AVD e usar eles no seu app. Na verdade você faz o que quiser com esse conhecimento, eu só queria te mostrar que era possível. 😀

#8 – Dicas de Performance

A melhor dica de performance é usar o seu próprio smartphone para os testes, conforme mencionado na dica #3 deste outro post aqui. Caso não seja possível, use a dica #11 para conhecer VMs concorrentes ao Android emulator padrão.

Melhorar a performance dos seus testes é talvez o maior ganho de performance que você possa ter, sem muito esforço. No entanto, também existem outras dicas, a saber:

  • troque seu HD por um SSD, a diferença de performance é gritante pois o maior gargalo da ferramenta é IO de disco;
  • crie seus AVDs com no mínimo 1GB de RAM, e certifique-se que seu computador tem essa memória sobrando pro AVD usar (caso contrário ele fará swap no disco);
  • se você usa notebook, mantenha-o na tomada, isso permite que ele opere com o máximo de performance;
  • só use um AVD por vez e somente um Android Studio por vez;
  • na verdade, use só o Android Studio e de repente um navegador com poucas abas abertas. O bicho é pesado…
  • tenha espaço em disco sobrando, curiosamente tudo fica muito lento quando há pouco espaço em disco no computador;
  • mantenha seu Android Studio atualizado, conforme dica #2;
  • rode a versão mais antiga de Android que puder no AVD, tipo 4.0 ou pior, 2.3 (!!!);
  • se você usa Windows, mantenha-o atualizado, ele fica muito lento quando está com atualizações pendentes ou rodando em background;
  • esteja conectado à Internet, o Android Studio fica mais lento quando está sem conexão (antigamente ele nem funcionava sem Internet);
  • se o processador do seu computador for antigo (2014 ou anterior) ou não for Intel em geral, use AVDs com arquitetura ARM, conforme mencionei na dica #3;
  • se o processador do seu computador for Intel recente (2014 ou mais), instale o Acelerador HAXM no SDK Manager e use somente AVDs com arquitetura X86 (dica #3 novamente);

Se tiver mais dicas de performance, deixe nos comentários!

#9 – Como gerar o APK para publicação?

O APK é o arquivo que permite a instalação do seu app em outros smartphones, ou seja, você precisa ter o APK do seu app criado para poder vendê-lo ou mesmo dá-lo de graça, não importa.

Eu falo em mais detalhes dessa dúvida aqui em ambos meus livros Meu primeiro app Android e Criando apps para empresas com Android, incluindo como configurar seu app pra download na Google Play e tudo mais. Pra resumir a geração do APK e não ser repetitivo, use o menu Build > Generate Signed APK, crie suas chaves de assinatura caso nunca tenha criado elas (elas assinam o seu app com seus dados pessoais, pra garantir depois que ele é seu mesmo) e escolha em qual pasta o APK será salvo.

Fácil, fácil!

#10 – IDEs concorrentes do Android Studio

Existem diversas maneiras de programar para Android usando desde a linguagem Lua com Corona SDK até HTML + CSS + JS com Phonegap. Mas se você ainda quiser se manter no Java, usando o SDK nativo tradicional, existem duas excelentes opções para programar seus aplicativos Android:

Clique nos links das ferramentas para ver tutoriais completos de como prepará-las para uso com Android, visto que elas não oferecem suporte nativo à plataforma.

E por hoje é só (chega né!). Tem mais alguma dúvida de Android Studio que eu não abordei aqui? Me manda aí embaixo nos comentários ou dá uma olhada no meu livro, que tem o link a seguir!

Criando apps para empresas com Android

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.

Introdução à Arquitetura de Micro Serviços

Workshop IFRS
Workshop IFRS

Tem uns 2 anos que passei a ouvir falar de micro serviços (microservices) mas faz poucos meses que passei a me interessar realmente pelo tema, uma vez que comecei a estudar Node.js para uso em meus projetos.

Micro serviços é uma maneira particular de desenvolver aplicações de maneira que cada módulo do software é um serviço standalone cujo deploy e escala acontecem de maneira independentes da “aplicação principal”. Enquanto na arquitetura tradicional de software, chamada monolítica, quebramos uma grande aplicação em bibliotecas, cujos objetos são utilizados in-process, em uma aplicação modular como proposta na arquitetura de microservices cada módulo recebe requisições, as processa e devolve ao seu requerente o resultado, geralmente via HTTP.

A ideia não é exatamente nova, é usada em ambientes Unix desde a década de 60, mas recentemente se tornou o epicentro de uma grande revolução na forma como as empresas estão desenvolvendo software ágil baseado em equipes enxutas responsáveis por componentes auto-suficientes.

Neste post irei abordar os conceitos, detalhes, vantagens, desvantagens e principais dúvidas dessa arquitetura, bem como porque ela está sendo tão utilizada atualmente e como começar a organizar suas aplicações orientadas dessa maneira.

Veremos neste artigo:

A motivação por trás dos micro serviços

Muitas são as buzzwords do mundo de desenvolvimento de software e esta me pareceu mais uma quando a ouvi pela primeira vez. Apesar do seu nome ser auto-explicativo, é interessante estudarmos os reais impactos que uma arquitetura composta por diferentes módulos conversando via um canal lightweight como HTTP pode causar na forma como programamos e nos resultados que obtemos com software.

Resumidamente, o estilo de arquitetura em microservices é uma abordagem de desenvolver uma única aplicação como uma suíte de pequenos serviços, cada um rodando o seu próprio processo e se comunicando através de protocolos leves, geralmente com APIs HTTP. Estes serviços são construídos em torno de necessidades de negócio e são implantados de maneira independente geralmente através de deploy automatizado (pelo menos em um cenário ideal deveria ser assim). Existe um gerenciamento centralizado mínimo destes serviços e cada um deles pode ser escrito em uma linguagem diferente e utilizando persistências de dados diferentes também.

Para entender melhor a motivação por trás de microservices vale relembrar como os projetos são programados hoje, geralmente em três grandes partes: um client-side com a interface do usuário, uma base de dados com as informações do sistema, e uma camada server-side com a lógica da aplicação. A camada server-side lida com as requisições do usuário, executa a lógica de negócio, retornar e atualiza dados da base e disponibiliza informações prontas para o client-side exibir. Isto é um monólito ou aplicação monolítica, uma vez que gera uma única e grande aplicação com tudo junto. Qualquer mudança no sistema envolve em compilar tudo novamente e implantar uma nova versão do server-side inteiro no servidor.

Toda a aplicação roda em um único processo, usando uma única linguagem server-side e geralmente uma única tecnologia de persistência de dados. Para escalar esse tipo de aplicação você pode adicionar mais recursos no mesmo servidor (escala vertical) ou fazer cópias desse servidor e colocá-las atrás de um load balancer (escala horizontal).

Aplicações monolíticas não são ruins e podem ser muitíssimo bem sucedidas. No entanto, cada vez mais equipes estão frustradas com suas limitações, principalmente quando estão implantando projetos na nuvem. Nestes cenários, os ciclos de mudanças, geralmente rápidos e pontuais como os propostos no Lean Startup, acabam afetando toda a aplicação pois o deploy é monolítico, assim como a aplicação. A escala horizontal requer um custo alto, pois sempre deve ser duplicada a aplicação inteira, e não apenas a parte que necessita de mais desempenho.

Vale lembrar também que aplicações monolíticas exigem que todo o codebase server-side seja escrito na mesma linguagem de programação, o que impede que você tire o máximo proveito de cada cenário usando a ferramenta mais apropriada à ele. Também impede que cada time desenvolva com a maior velocidade possível uma vez que a base de código é a mesma entre todos times.

Estas frustrações levam à arquitetura microservices de construir aplicações como um conjunto de serviços. Como os serviços são implantados de maneira independente, a escala se dá individualmente, tanto na vertical quanto na horizontal, para os serviços que estão precisando de mais desempenho. Usando protocolos comuns e contratos (interfaces) bem definidos, você consegue usar linguagens de programação diferentes de cada serviço, bem como mecanismos de persistência auxiliares que possam ser necessários para cada um deles, como mecanismos de cache, filas, índices, etc.

Para finalizar esta seção, a imagem abaixo do blog do Martin Fowler ilustra bem a diferença da escala entre as duas arquiteturas: monolítica e de micro serviços:

Vantagens e desvantagens de microservices

Não existe uma definição formal de como uma aplicação baseada em micro serviços deve ser construída, mas depois de muito ler a respeito e estudar o assunto notam-se algumas particuliaridades frequentes que podemos denominar como um padrão comum para microservices.

Sempre existiu o desejo dentro da indústria de software de construir programas apenas plugando componentes. Os primeiros esforços neste sentido foram as bibliotecas de funções, mais tarde as bibliotecas de classes e atualmente está em voga os serviços. Note que a componentização sempre existiu, mas o que propõe-se com microservices é que cada componente seja uma aplicação separada e especializada em apenas uma parte da aplicação “completa”. A principal razão por trás dessa escolha, de serviços ao invés de bibliotecas, é que serviços podem ser implantados de maneira separada. Você já tentou atualizar seu software apenas subindo para produção uma DLL ao invés de todas (ou ao menos todas as suas)? É um risco que não vale a pena correr, pois o acoplamento entre as DLLs é muito alto e o ideal é sempre a recompilação do sistema como um todo.

Claro, existe uma desvantagem clara no uso de serviços ao invés de bibliotecas: performance. Bibliotecas rodam no mesmo processo da aplicação, usam memória compartilhada, etc. Serviços dependem de canais de comunicação, como HTTP, para conseguirem tratar e responder as requisições. Exigem também uma coordenação entre os contratos de serviço para que os consumidores consigam “conversar” com os serviço da maneira que eles esperam, bem como receber as respostas que estão preparados.

Esse problema é especialmente preocupante conforme você tenha muitas chamadas síncronas entre seus serviços, pois o tempo de espera total para seu sistema responder será igual à soma de todos os tempos de espera das chamadas síncronas. Neste momento você tem duas opções: mudar para uma abordagem assíncrona ou reduzir o máximo que puder o tempo de espera (e a quantidade) das requisições síncronas. Node.js é uma tecnologia que tenho estudado bastante recentemente e trabalha muito forte com o conceito de chamada assíncronas, muito usado pelo Netflix para não bloquear a experiência do usuário. No entanto, quando isso não é possível, como foi o caso do site do jornal The Guardian, tente limitar o número de chamadas síncronas que você vai precisar, o que no caso deles é a regra de apenas uma chamada síncrona por requisição do usuário.

Apesar desses problemas citados, os benefícios parecem superar os downsides dessa abordagem, pois cada vez mais empresas estão adotando-na.

O que você deve ter em mente

Os serviços irão falhar. Talvez não todos juntos, talvez não rapidamente, mas vaia acontecer. Sendo assim, você deve estar sempre preparado para a falha de um ou mais serviços.

Essa é uma consequência de usar serviços como componentes e sua aplicação deve ser projetada de maneira que possa tolerar a falha de serviços. Qualquer chamado a um serviço pode falhar devido à indisponibilidade de um fornecedor e você tem de saber lidar com isso de maneira amigável com o restante do sistema. Esta talvez seja a maior desvantagem dessa arquitetura se comparada ao jeito monolítico tradicional, uma vez que adiciona uma complexidade adicional significativa. Times que trabalham com micro serviços devem constantemente refletir como a falha de cada serviço afetará a experiência do usuário. No Netflix por exemplo, partes da bateria de testes diária deles inclui derrubar servidores e até datacenters para ver como a aplicação se comporta nestas situações.

Uma aplicação em micro serviços deve ser monitorada em um nível muito superior ao de uma aplicação monolítica tradicional, uma vez que os serviços podem falhar a qualquer momento e se possível, restaurar o funcionamento completo automaticamente. Monitoramento em tempo real deve ser enfático no processo de desenvolvimento, implantação e operação dos serviços. Não que você não tenha de ter esse mesmo cuidado com aplicações monolíticas, mas apenas que com micro serviços isso não é uma opção.

O quão grande é/deve ser um micro serviço?

Uma pergunta bem comum e que cai como uma luva para o próprio nome da “arquitetura’ é: o quão grande deve ser um micro serviço?

Infelizmente o nome micro serviço nos leva a perder tempo demais pensando no que exatamente micro quer dizer. Diversas empresas, de Amazon a Netflix, usam micro serviços de variados tamanhos e não há um consenso sobre eles. Especificamente na Amazon, considerando que cada micro serviço é (e deve) ser tratado como um produto separado e tem seu próprio time (squad, na verdade), eles usam a regra Two Pizza Team: se o time precisa de mais de duas pizzas por refeição para se manter alimentado é porque está grande demais, o que significa não mais de que 12 pessoas. No outro extremo, os menores times recomendados pela Amazon possuem 6 pessoas, o que eu pessoalmente, em minhas experiências como Scrum Master, acredite ser o ideal (você ainda pode chamar meus times de Two Pizza Team considerando que todo mundo gosta de comer vários pedaços de pizza!).

Resumindo, embora não exista uma regra, podemos assumir que se você precisa de uma equipe de mais de 12 pessoas para desenvolver e manter um serviço (considerando tudo: programação, infra, testes, etc), ele está grande demais e você deveria quebrá-lo em serviços menores.

Como começar com micro serviços?

Projetos usando micro serviços geralmente não nascem assim do dia para a noite. O que nota-se na maioria das implementações bem sucedidas é que elas vieram de um design evolucionários, vendo a decomposição em serviços como uma ferramenta que vai aos poucos ajudando a quebrar uma aplicação monolítica que está com problemas de escala, qualidade, etc em diversos componentes menores.

Neste cenário, o maior desafio é saber como que o monólito irá ser quebrado em serviços. O quê deve ser agrupado em conjunto? O que deve estar separado? Quais bases de dados serão usadas por quais serviços?

Um dos princípios-chave por trás dessas decisões é o de deploy e escala independentes entre os serviços. Se dois serviços sempre tem de ser colocados em produção em conjunto, eles deveriam ser um serviço só. Agora se eu tenho um serviço cujas publicações acontecem sempre por causa de alterações pequenas em um dos seus módulos internos, esse módulo interno deveria ser transformado em um serviço per se.

O site do jornal britânico The Guardian é um bom exemplo de aplicação que foi projetada e construída como um monólito e que vem evoluindo na direção de micro serviços. O monólito ainda é o core do site, mas eles têm adicionado novas funcionalidades usando micro serviços que consomem a API do site principal. Esta abordagem é particularmente interessante pra eles principalmente nos casos de módulos temporários, como um hotsite para cobrir um evento esportivo.  Estes hotsites podem ser programados rapidamente na linguagem que for mais conveniente e jogados fora uma vez que não fazem mais sentido.

E aí, motivado para trabalhar com essa abordagem? Vamos trocar experiências nos comentários!