Chegamos ao terceiro artigo da série sobre o Arda, uma ferramenta para gestão de workloads para times de trabalho que está sendo desenvolvida/mantida pelo time de evangelistas da Microsoft Brasil.
No primeiro artigo falamos sobre a motivação para a criação da ferramenta bem como, sobre as premissas que deveriam nortear o projeto. No segundo falamos de alguns aspectos arquiteturais da ferramenta, recursos que estarão disponíveis na primeira versão e ainda, discutimos aspectos conceituais sobre microserviços (e nossa visão interna para este modelo). Se você ainda não teve a oportunidade de ler os dois primeiros textos, antes de seguir com a leitura deste, recomendo fortemente que o faça através dos links disponibilizados a seguir.
- Artigo #1: Arda – Motivação, arquitetura e tecnologias
- Artigo #2: Arda – Primeiros passos com microserviços
É importante lembrar também que a série está sendo atualizada em uma página específica aqui no site, disponível através deste link. Se você deseja seguir o assunto desde o início, este é o “caminho das pedras”.
Com o artigo de hoje começaremos a aterrissar (praticar) os conceitos dos quais temos falado até aqui. Falaremos de pequenos aspectos com os quais nos deparamos logo no início da construção do projeto e que nos levaram a tomar algumas decisões técnicas para que o mesmo pudesse andar na velocidade e com a qualidade que nós desejávamos.
Estruturação do projeto
No final do último artigo disponibilizamos um print de tela da solução do Arda no Visual Studio. Lá, você pode visualizar 6 projetos atachados (Arda.Authentication, Arda.Common, Arda.Kanban, Arda.Main, Arda.Permissions e Arda.Reports). Já falamos de maneira exaustiva nos dois primeiros artigos sobre as funções de cada um deles, portanto, estou assumindo que você possui este conhecimento para que possamos seguir. Quatro destes seis são Web APIs, um é Class Library e o outro é MVC 6 (lembre-se, estamos trabalhando com ASP.NET Core).
Todos sabemos que o conceito de microserviços é amplo e que sua implementação vai muito além de que simplesmente colocar Web APIs para conversarem entre si. Sabíamos disso. Entretanto, pergunto: “que melhor maneira existe para se iniciar o trabalho com microserviços do que colocar serviços para falarem uns com os outros?” Foi assim que iniciamos a implementação, de fato, do Arda.
Criamos a estrutura de projetos mencionada anteriormente e então começamos a implementar as primeiras lógicas de comunicação (com informações em hard coded no primeiro momento) entre os serviços. Esta “brincadeira” com as chamadas assíncronas entre os serviços nos ensinou algumas lições técnicas importantes, que foram primordiais para que pudéssemos definir padrões ao longo do projeto.
1. Startup.cs será o melhor amigo de cada serviço
Sim, é isso mesmo. O arquivo Startup.cs é o principal elemento em uma arquitetura de aplicação construída em ASP.NET Core. Todo processo de setup da aplicação passa por aqui, portanto, é de fundamental importância entender o que são, para o que servem e como utilizar recursos em cada um dos métodos lá disponíveis (Startup, ConfigureServices, Configure e Main). Antes de seguir com qualquer coisa, estude e brinque com as possibilidades dessa classe.
2. Uso correto do conceito de pipeline
Como você já deve saber, o conceito de pipeline para a execução de middlewares é central no ASP.NET Core. Descobrimos com estes testes iniciais a importância de entregar rotinas que deveriam afetar o projeto corrente (e também a aplicação como um todo) como métodos de extensão bem definidos e posicioná-los no momento correto na linha do tempo dentro deste pipeline.
No Arda entregamos alguns aspectos centrais da aplicação como middlewares e o resultado é amplamente satisfatório. Vou citar como exemplo aqui o middleware de verificação de permissões dos usuários. Quando o usuário autenticado no sistema solicita acesso a determinado recurso (por exemplo: adição de um novo workload), o middleware de segurança verifica (consultando informações no Azure Redis Cache e no Active Directory) se aquele usuário está ou não autorizado a ver/utilizar recursos daquela organização e ainda, quais recursos ele pode visualizar. Não se preocupe, vamos falar de maneira detalhada sobre o processo de autenticação distribuída do Arda em um artigo no futuro. A Listagem 1 apresenta a chamada do middleware de segurança ao qual me refiro.
Listagem 1. Chamada para o middleware SecurityAPIMiddleware
Dessa maneira, minha primeira recomendação é: entenda bem o conceito de middlewares e pipeline de execução do ASP.NET Core e utilize da maneira correta. Isso irá ajudar muito no trabalho com microserviços.
3. CORS
Criar uma aplicação distribuída implica necessariamente em se encontrar problemas com a configuração de CORS (Cross-Origin Resource Sharing) entre os atores da mesma. Não vou explicar o conceito de CORS aqui por não ser o foco deste artigo, entretanto, você pode encontrar uma excelente leitura sobre o assunto no site do W3C. O conteúdo está disponível aqui.
Se você trabalha com web já há algum tempo, sabe o quão complexo era fazer esta configuração em um passado não tão distante. Como no Arda tudo era novo, precisávamos entender portando qual seria o modus operandi do ASP.NET Core em relação a este problema. Novamente os testes de comunicação nos mostraram que, de fato, algo deveria ser feito em relação a isso. Para nossa agradável surpresa, descobrimos que o ASP.NET Core já entrega (através de middlewares) um eficiente mecanismo para o tratamento de CORS entre serviços Restfull. A configuração é simples:
Passo 1: Adicione a referência da biblioteca que faz o tratamento do CORS ao arquivo “project.json” do Web API (conforme apresenta a Listagem 2).
Listagem 2. Adicionando a biblioteca de tratamento do CORS
Em seguida, dirija-se ao arquivo Startup.cs e no interior do método ConfigurationServices, como primeira entrada deste método (lembre-se, a ordem importa no modelo de middlewares), adicione a linha apresentada pela Listagem 3.
Listagem 3. Adicionando as políticas de acesso ao CORS
Finalmente, você adiciona o momento correto para a habilitação do CORS no pipeline de execução do serviço. Copie e cole o trecho de código apresentado pela Listagem 4 no interior do método Configure, imediatamente antes do middleware do MVC (que deverá sempre ser o último).
Listagem 4. Adicionando o tratamento do CORS ao pipeline
Resumo das operações: primeiro adicionamos a biblioteca que implementa os métodos de tratamento do CORS. Em seguida determinamos as regras de acesso ao CORS do serviço. Em nosso caso, estamos liberando todo e qualquer tipo de acesso, entretanto, esta tratativa pode ser granularizada. Finalmente, adicionamos o tratamento do CORS ao pipeline de execução do ASP.NET.
4. Adição de um class library para servir aos serviços da aplicação
Quando iniciamos o Arda, o projeto “Arda.Common” não existia. Imaginávamos que todas as rotinas poderiam ser atendidas através do modelo de Repository Pattern (você pode saber mais sobre isso no MSDN seguindo este link) em cada serviço. Entretanto, com os testes, começamos a perceber que muitas rotinas iriam se repetir em todos os serviços e, portanto, tomamos decisão de centralizar ViewModels e demais implementações comuns a todos os serviços em uma nova class library comum. Gostamos do resultado.
5. Criação de um método genérico de comunicação entre os serviços
A brincadeira inicial com a comunicação entre os serviços nos mostrou outro aspecto superimportante para o projeto: deveria existir um modelo padronizado de comunicação entre os serviços. Discutimos por bom tempo tentando encontrar o melhor modelo para endereçar esta demanda e a conclusão a que chegamos foi: se definimos que JSON será o “idioma” que o Arda falará (essa definição foi uma das primeiras do projeto), o que precisamos fazer é criar um método genérico (que depois possa sofrer alguma sobrecarga) que me permita passar um objeto (ou uma lista deste) e que me devolva um JSON estruturado como resultado. A Listagem 5 apresenta nossa proposta para este fim.
Listagem 5. Método genérico de conexão a um serviço remoto
Este método fará mais sentido quando apresentarmos os detalhes do processo de autenticação do sistema (que está baseado no Active Directory), entretanto, em linhas gerais o que ele faz é: ao receber assincronamente um método HTTP de operação, o endereço do serviço remoto e os parâmetros uniqueName e code do AD (para validação), o método ConnectToRemoteService solicita que o serviço requisitado faça determinada operação com o objeto T e devolva uma resposta ao chamador em formato JSON.
Simples, elegante e funcional.
6. Secrets.json
Outro aspecto interessante que os testes mostraram foi a importância de se manter o arquivo Startup.cs tão enxuto quanto possível em relação a quantidade de código em seu interior.
Nesse sentido, implementamos uma tática que na equipe estamos chamando de “secrets”. Basicamente “escondemos” configurações de acesso a banco de dados, acesso a serviços de cache (Redis, por exemplo) e outros, em arquivos com a extensão JSON e na sequência apenas deixamos suas referências no Startup.cs. A Listagem 7 apresenta o arquivo “secrets.json” enquanto a listagem 8 apresenta sua chamada no “Startup.cs”.
Listagem 7. Secrets.json
Listagem 8. Referenciando o arquivo secrets.json em Startup.cs
aspnetcore { } versus dnx451 { }
Quando iniciamos a escrita do Arda, ainda não tínhamos a versão RC2 do ASP.NET Core e tão pouco, a RTM do .NET Core (ela saiu essa semana J ). Os desafios para se fazer qualquer coisa puramente com o framework ASP.NET Core foram aumentando de tal maneira que nos forçou a tomar a decisão de basear o desenvolvimento da ferramenta no “dnx451”.
Para que seja possível a você mensurar os tamanhos dos desafios, veja este exemplo: precisávamos de uma biblioteca que possibilitasse o disparo de e-mails através de algum provedor SMTP (como SendGrid). Naquele momento o ASP.NET Core ainda não entregava rotinas nativas para executar tal tarefa. Outro bom exemplo foi a implementação de rotinas nativas para acesso ao Redis Cache, que estavam indisponíveis naquele momento mas que estavam disponíveis no dnx451.
A migração do ambiente de desenvolvimento para dnx451 foi natural, uma vez que tínhamos a premissa de provar o ASP.NET Core em ambientes open source (como o Linux) e que o dnx451 entrega features baseadas no Mono.
Dessa forma, o arquivo Project.json de cada serviço do Arda ficou com a seção “frameworks” estruturada conforme apresenta a Listagem 9.
Listagem 9. Estrutura de frameworks do Arda baseada em dnx451
Com o projeto em andamento (já completando cerca de 70% do total previsto) vimos o ASP.NET Core sofrer uma importante atualização: da versão RC1 para a versão RC2. Chegamos a considerar a hipótese de atualizar o projeto para suportar esta nova versão, entretanto, reconsideramos em função da data de entrega e seguimos com a versão RC1 até a conclusão do mesmo. A versão 2 será atualizada e entregue sobre RC2 com .Net Core RTM.
Conclusões
O início do trabalho no Arda foi bem desafiador. Precisamos entender na prática como várias coisas funcionavam aplicadas ao contexto de um software distribuído onde ocorrências como, usar um dado necessário no processamento do microserviço X mas que está residente na base de dados do microserviço Y (falaremos no futuro sobre como resolvemos essa questão), CORS, comunicação assíncrona, etc.
No texto de hoje apenas iniciamos o processo de passagem de insights (falamos apenas a nível de testes iniciais e as lições que já pudemos aprender com isso) relacionados a projetos desta natureza. Acreditamos que desta forma conseguiremos poupar algum trabalho futuro quando você optar por construir sua própria solução baseada em microserviços e especialmente, se esta for estruturada sobre ASP.NET Core.
Espero que gostem e que seja útil. No próximo artigo falaremos de forma demorada sobre o processo de autenticação baseado no Active Directory.
Forte abraço e até lá!
Facebook
Twitter
Instagram
LinkedIn
RSS