Este é o segundo artigo da série que irá apresentar o “passo-a-passo” da criação do Arda, uma ferramenta para gestão de workloads em times corporativos desenvolvida pelo time de evangelistas da Microsoft Brasil e que faz uso massivo do conceito de microserviços. Se você está chegando agora para este contexto, recomendo fortemente realizar a leitura do primeiro artigo, disponível no link abaixo. Ele apresenta nossa motivação para criação da ferramenta bem como premissas em termos de tecnologias, metodologias e conceitos.
Link: Arda – Introdução, Motivação e Arquitetura
Conforme mencionamos no primeiro artigo desta série, iniciamos o desenvolvimento do Arda com um set de recursos (básicos) bem definidos para que a gestão dos times pudesse ocorrer de maneira minimamente satisfatória. Não nos preocupamos em um primeiro momento em criar funcionalidades excepcionais, diferenciadas ou algo do tipo. Nos preocupamos sim em criar uma estrutura baseada em microserviços de fato, para que pudéssemos aí sim, provar este conceito (neste momento mais importante para nosso time). A Figura 1 apresenta nossa visão em termos de recursos iniciais e visão de como novos recursos (ou módulos e módulos futuros deverão ser implementados na ferramenta) deverão ser “plugados” à ferramenta.
Figura 1. Recursos core e visão de futuras implementações
Acredito que uma breve explicação em relação aos recursos se faz necessária aqui. Note:
- Fiscal Years (Anos Fiscais): esta é uma informação super relevante aqui na Microsoft, uma vez que nossas estratégias e ações são segmentadas por ano fiscal e não por ano calendário. Se determinada empresa trabalha com o ano calendário ao invés de ano fiscal, sem problemas. Basta adicionar o ano calendário como ano fiscal e seguir desta maneira. Tudo deverá funcionar perfeitamente.
- Scorecard (métricas): não é novidade para ninguém que uma das formas mais eficientes de se medir o desempenho das equipes de trabalho é atrelar as mesmas a métricas saudáveis e que façam sentido para o business das empresas. Como na Microsoft isso não é diferente, deverá estar disponível um mecanismo de associação de workloads a métricas bem definidas no sistema. Dessa forma, empresas que optarem por utilizar nossa ferramenta em seu dia-a-dia, terão a possibilidade de “amarrar” o trabalho a KPIs de produtividade e visualizar relatórios com base neles.
- Complexities (complexidades): tratam-se de informações simples de complexidade associadas aos workloads. Isso possibilitará ao gerente do time ter uma visão apurada sobre alocação x tempo de trabalho. É um mecanismo simples, que deverá estar disponível (para seleção) no momento em que um novo workload ou backlog é adicionado ao sistema. Os administradores poderão definir suas próprias complexidades através de um cadastro simples.
- Categories (categorias): as categorias são os elementos que agrupam as métricas em unidades conceituais correlacionadas. Por exemplo, a métrica “Número de projetos no GitHub” poderia estar associada a categoria “Evangelismo”, assim como “Palestras em eventos” também o poderia. Muito embora estas métricas sejam distintas em seu modus operandi, elas possuem o mesmo objetivo final: evangelizar. As categorias podem ser dinamicamente adicionadas ao sistema no momento em que uma nova métrica é criada.
- Activities (atividades): elementos que estão associados aos workloads. Nossa visão é que uma entrega de um profissional em um time se dá necessariamente em um ramo de atividade. Por exemplo: uma migração de aplicação para o Azure poderia ser classificada como uma atividade de “Migrações”, assim como, uma palestra em evento poderia ser classificada como uma atividade de “Palestras em eventos”. Se preferir, você pode inferir que o Arda entende uma atividade como uma granularização de uma categoria. As atividades também podem ser dinamicamente adicionadas ao Arda pelos administradores da ferramenta.
- Technologies (tecnologias): estamos chamando de Technologies o recurso que classifica determinado workload pela(s) tecnologia(s) sobre as quais a tarefa será estruturada (e posteriormente executada). Por exemplo, se determinado workload está sendo alocado para a execução de uma integração de solução existente com Office 365 e posterior publicação no Azure, este workload poderá ser alocado para as tecnologias “Microsoft Azure” e “Office 365”.
- Workloads/backlogs: para o Arda, um worload é uma unidade de execução de tarefa. O workload poderá ser de qualquer tamanho (o manager deverá definir sua extensão e padrão) e poderá ser atribuído a qualquer tipo de tarefa e deverá ter seu estado alterado conforme as operações atreladas a ele vão evoluindo na linha do tempo de entregas. Aqui não buscamos granularidade. Não queremos as minúsicas do que será executado. Queremos apenas a visão macro do processo, como por exemplo: “Fabrício está trabalhando na tarefa Migração do sistema BlaBla da AWS para o Azure de 01/06/2016 até 30/06/2016”. Como você já deve estar imaginando, as marcações indicadas anteriormente (categorias, tecnologias, atividades, etc.) são elementos que serão extremamente úteis no momento em que visões dos dados (relatórios) precisarem ser geradas. Um backlog é um workload que não está ativo no momento mas que é elegível a se tornar um workload a qualquer momento. Simples, eficiente e direto.
- Kanban: estamos chamando de Kanban a área que exibe workloads ativos em todos os seus 4 estados: “To do”, “Doing”, “Done” e “Approved”. Do ponto To do até o Done, o(s) profissional(is) alocado(s) para o workload tem autonomia para movimentar workloads. Já para o Approved, apenas o manager da equipe poderá movimentar. Isso indica que uma verificação adicional da entrega foi realizada e ele (gerente) reconhece esta entrega como aprovada. Esta área permite ao usuário também interagir administrativamente com os workloads (criar, visualizar e editar).
- Reports (relatórios): não é preciso ser muito inventivo para entender o papel deste módulo. Trata-se do elemento responsável por entregar os relatórios do sistema. Na primeira versão serão entregues relatórios próprios (gerado pelo próprio Arda). Na próxima geração da ferramenta vemos o roadmap indicando a entrega deste recurso através do Power BI embedded.
Além dos recursos mencionados, existe ainda uma vertical a parte, que é a de gestão de usuários e suas respectivas permissões. Todo o processo de atribuição de permissões deverá ser dinâmico, isto é, módulos e suas respectivas funcionalidades devem ser atribuídas pelo manager de maneira granular de acordo com aquilo que o usuário em questão deverá visualizar. Tanto módulos quanto funcionalidades podem ser dinamicamente adicionados ao sistema seguindo a seguinte convenção:
- Module name (nome do módulo): controller
- Resource name (nome do recurso): action
Desta forma temos um exemplo hipotético:
- Módulo de usuários: Users
- Recurso de listar usuários: List
- URL no navegador: Users/List
Vale lembrar que estamos utilizando o ASP.NET MVC 6, daí a convenção por controllers e actions. Faz sentido? É importante ressaltar que esta é apenas uma maneira de se fazer tal aspecto (de navegação). Existem diversas outras metodologias que poderiam ser adotas. Entendemos que esta abordagem atenderia tranquilamente o escopo do Arda e portando, a adotamos.
As informações apresentadas pelos parágrafos anteriores (funcionalidades) estão bem definidas hoje, inclusive com distribuição em módulos (como apresenta a Figura 1). Entretanto, chegar neste modelo proposto não foi tarefa simples. Isso porque, como tínhamos a premissa de trabalhar com microserviços, precisávamos necessariamente pensar em uma arquitetura que não acoplasse recursos desnecessários e que dificultasse o mínimo possível o trabalho com bases de dados distribuídas.
Estruturação em microserviços conceituais
Especialmente no último ano, muito tem se falado sobre microserviços. Dessa forma, muito embora já houvéssemos (os membros do time) lido diversos posts e whitepapers sobre o assunto, concordamos que obter uma visão conceitual mais profunda seria fundamental para que pudéssemos implementar as rotinas do Arda de maneira mais eficiente.
Existem basicamente duas visões (entendimentos) holísticas em relação a microserviços. A primeira olha sob o prisma de aplicações distribuídas (como posso distribuir minha aplicação ao longo de múltiplas instâncias de maneira segura e desacoplada e ainda ganhar performance com isso?). Já a segunda olha sob o prisma da arquitetura de software (como posso desacoplar minha aplicação internamente de modo que o isolamento entre as entidades tenda a infinito?).
Diante destas duas visões, nos pusemos a analisar algumas situações práticas pelas quais a aplicação (Arda) poderia passar em seu ambiente produtivo no futuro para que, só então, pudéssemos ter a clara visão de qual dos dois modelos melhor nos atenderia. Alguns fatos que levantamos estão listados a seguir.
- A aplicação necessariamente terá uma camada de visualização (como toda aplicação web) que terá a responsabilidade de gerenciar as requisições http e devolver as respectivas respostas para o usuário final.
- A aplicação deverá servir diferentes dispositivos e versões de navegadores.
- Já tínhamos a premissa de que no futuro uma aplicação específica para dispositivos móveis seria criada para facilitar a comunicação nestes ambientes, portanto, uma API deveria ser exposta para o consumo dos dados.
- Sabíamos também que, provavelmente, outras ferramentas poderiam / deveriam se integrar ao Arda para consumir ou enviar dados da / para aplicação. Outro fator que justificaria a API.
- Imaginamos que, por conta de todos estes aspectos, uma funcionalidade ou outra poderia em momento ou outro, ficar sobrecarregada (servindo para múltiplas requisições simultâneas).
- Como o ambiente web evolui muito rapidamente, imaginamos que no futuro provavelmente iríamos querer trocar o framework de comunicação no frontend.
- Queríamos utilizar o ASP.NET Core para verificar a eficiência deste novo framework (MVC 6) de desenvolvimento e sabíamos, portanto, de sua estrutura modular e baseada em pipeline de middlewares.
- Queríamos trabalhar com APIs REST para facilitar a comunicação com outros sistemas.
- Queríamos publicar a solução em alguma estrutura de containers (Docker era o nosso favorito).
- Dentre algumas outras coisas.
Esta série de fatores nos levou a acreditar (e hoje já temos certeza após realizar diversas implementações) que na verdade, um sistema baseado em microserviços de fato deve privilegiar a isonomia de entidades em ambas as esferas: tanto em relação a distribuição dos assets em ambiente de host quanto em relação a separação de entidades em nível de software (DDD pode ajudar muito neste segundo aspecto).
A estratégia de desenvolvimento em microserviços pode ser melhor concebida se você realmente tentar tangibilizar a história do “dividir para conquistar”. Pense na situação hipotética: possuo uma aplicação única, monolítica, que implementa diferentes contextos dentro dela? Pergunte-se: será que consigo “quebrar” esta aplicação em pequenas unidades lógicas especialistas (microserviços) de modo que, sempre que houver uma motivação para sua execução, eu possa chama-las individualmente (atendendo a uma motivação funcional) para que elas me respondam com a informação desejada? Se você conseguir estruturar sua aplicação pensando desta forma, você estará dando um grande passo rumo a distribuição da aplicação em microserviços.
Não existem regras que definem uma arquitetura de microserviços, entretanto, existem convenções muito bem aceitas (e que, portanto, se tornaram quase que regras). São elas:
- Um microserviço deve ser relativamente pequeno.
- Um microserviço deve ser uma unidade de “deployavel” de forma isonômica.
- Um microserviço deve possuir sua própria fonte de dados.
- Um microserviço deve ter a capacidade de ser escalado individualmente.
- Um microserviço deve ser uma unidade resiliente.
- Um microserviço deve, preferencialmente (não obrigatoriamente), falar REST.
- Um microserviço pode ou não ter endpoints públicos ou privados.
Existe ainda um aspecto associado aos microserviços que são de suma importância aqui: um core de microserviços não necessariamente precisam falar apenas com outros microserviços. Note, é comum que uma aplicação distribuída desta maneira “fale”, em um ambiente heterogêneo, com aplicações monolíticas já existentes, diretamente com bases de dados de sistemas legados que não dispõe de APIs expostas ou com suas próprias, etc. Neste caso, a diferença única é que cada microserviço da aplicação possuirá autonomia para se comunicar de maneira direta, sem necessariamente passar por um core comum. A Figura 2 clarifica este conceito.
Figura 2. Possibilidades com microserviços
No Arda procuramos respeitar tais convenções de forma literal (e ainda utilizamos duas metodologias citadas mais adiante neste texto), durante o processo de implementação. O resultado? Vários os desafios se apresentaram. Mas, ao final, de fato, uma estrutura de microserviços literal e robusta se apresentou. Mas este, é assunto para o próximo artigo.
Metodologias e patterns que foram úteis
Existem diferentes metodologias que podem ser adotadas em um projeto de microserviços para que uma “quebra” eficiente de entidades possa ser realizada. A nível de software (delineador de conceitos), como já mencionamos, DDD é uma das melhores. Já em termos de distribuição de aplicações, a metodologia conhecida como “The Scale Cube” é uma das principais. No Arda tentamos seguir ambas.
Tanto sobre DDD quanto sobre The Scale Cube, você pode encontrar boas leituras seguindo os dois links a seguir (em inglês). Não vou me ater a estes aspectos por não ser o foco aqui.
- DDD: https://digitalpolis.co.uk/software-thoughts/ddd-mvc-entity-framework/
- The Scale Cube: http://microservices.io/articles/scalecube.html
É importante frisar a esta altura que existem muitos ótimos conteúdos (em sua maioria em inglês) que fundamentam de maneira bem sólida a abordagem de microserviços e que poderão lhe ajudar a consolidar este conceito. Este texto não pretende (nem de longe) esgotar a teoria de microserviços. Pretende apenas mostrar nossa experiência prática com esta metodologia.
Arda em microserviços
Em termos práticos, o Arda implementa cinco microserviços (conforme mencionamos no primeiro artigo da série) e ainda, um projeto do tipo “Class Library” com código útil para todos os microserviços. A estrutura do projeto pode ser visualizada através da Figura 3. Ela apresenta uma visão macro da Solution Explorer do projeto.
Figura 3. Visão geral dos projetos
Alguma explicação aqui é necessária. Também conforme mencionado no primeiro artigo da série, estamos utilizando Visual Studio 2015 Enterprise (mas não seria necessário, você poderia utilizar qualquer editor de código no sistema operacional de sua preferência) por uma questão de preferência do time, ASP.NET Core (que implementa MVC 6) e recursos associados (EF Core, e o tooling web do Visual Studio).
Na Solution temos 4 projetos Web API, 1 MVC e 1 Class Library. São eles:
- NET MVC
- Arda.Main
É o serviço de visualização, que consome as informações do backend e as entrega de maneira formatada para o usuário final.
- Arda.Main
- NET WEB API
- Arda.Authentication
É o serviço de autenticação autônomo do Arda. Este serviço trata o processo de autenticação do usuário de maneira independente, sem depender de um provedor de identidade como o Active Directory, por exemplo. Deverá ser utilizado apenas por empresas que não utilizam AD. Quando finalizado, Arda.Authentication deverá possuir sua própria base de dados. - Arda.Kanban
É o coração do Arda. Implementa as rotinas que dão vida ao Kanban (área que apresenta workloads, backlogs e demais aspectos importantes para que o mesmo possa existir). Pelo menos 60% da versão 1 do Arda está implementada neste microserviço. Arda.Kanban possui sua própria base de dados. - Arda.Permissions
É o serviço de autenticação baseado em Active Directory (ou outro provedor de identidade que o Arda venha a ter no futuro) do Arda. Usuários são adicionados e suas permissões de acesso gerenciadas neste microserviço. Arda.Permissions também possui sua própria fonte de dados. - Arda.Reports
É o serviço de relatórios do Arda. Toda a informação que precisa ser exibida em relatórios é solicitada para o Arda.Reports. Ele então gera as informações, envia a resposta para o Arda.Main (visto anteriormente) e então as informações são exibidas.
- Arda.Authentication
- CLASS LIBRARY
- Arda.Common
Não se trata de um microserviço. É uma unidade isolada que implementa rotinas úteis a todos os projetos (como por exemplo a ponte de comunicação entre os microserviços, os View Models de retorno para Arda.Main, etc.).
- Arda.Common
Preciso parar por aqui. Isso porque no próximo artigo pretendo passar pelas configurações iniciais do projeto, problemas que encontramos (e como solucionamos durante este processo) e alguns outros aspectos de implementação.
Portanto, fique ligado. Estamos só começando com este assunto. Um forte abraço e não se esqueça de deixar seu comentário.
Pingback: Arda – Configurações iniciais e algumas decisões técnicas – Fabrício Sanchez