Mais 4 Recomendações Práticas para Projetos de Microsserviços em .NET

Neste post, compartilho mais algumas ideias que tenho adotado, com êxito, em meus projetos envolvendo Microsserviços e que podem ajudar você a ser mais efetivo em suas implementações.

Se você ainda não leu, recomendo que acesse um post anterior sobre esse tema, com mais recomendações, antes de avançar.

1. Comece pelos comandos e pelas consultas que vai suportar

Antes de definir qualquer aspecto mais técnico, ter clareza sobre quais comandos e consultas seu microsserviço deverá suportar irá ajudar você a ser mais efetivo e mais alinhado com as necessidades do negócio.


No exemplo, apenas ilustrativo, o microsserviço irá manter um “contador”.

Tenho optado (não faz muito tempo) por usar o Mediatr para intermediar a chamada dos handlers, orquestrar validação das mensagegens, etc.

using System.Threading;
using System.Threading.Tasks;
using CountingMicroservice.Application.Services;
using MediatR;

namespace CountingMicroservice.Application.CommandSide.Commands
{
    public class IncrementCommandHandler
        : IRequestHandler<IncrementCommand, bool>
    {
        private readonly ICounterRepository _repository;

        public IncrementCommandHandler(ICounterRepository repository)
        {
            _repository = repository;
        }

        public Task Handle(
            IncrementCommand request, 
            CancellationToken cancellationToken
            )
        {
            if (request == null)
            {
                return Task.FromResult(false);
            }

            _repository.Increment();
                
            return Task.FromResult(true);
        }
    }
}

2. Mantenha sua WebApi simples (se essa for sua interface)

Manter um projeto específico para a aplicação permite que o projeto da Web API seja extremamente simplificado. Caberá a WebAPI, apenas, fazer as devidas inicializações e prover features que “chamam” os comandos e consultas no momento apropriado.

Aliás, para aliviar acoplamento, tenho adotado por hábito fazer inicializações específicas da aplicação no código da aplicação (fora da web api)

using CountingMicroservice.Application.Services;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using ServiceStack.Redis;

namespace CountingMicroservice.Application
{
    public static class StartupExtensions
    {
        public static IServiceCollection AddCounterApplication(
            this IServiceCollection services, 
            IConfiguration configuration
            )
        {
            var redisConnectionString = configuration["REDIS_CONNECTIONSTRING"] ?? "-counter.data";
            services
                .AddSingleton(sp => 
                    new RedisManagerPool(redisConnectionString)
                    )
                .AddSingleton<ICounterRepository, RedisCounterRepository>();

            return services;
        }

        public static IApplicationBuilder UseCounterApplication(
            this IApplicationBuilder app
        )
        {
            return app;
        }
    }
}

Fica dentro da WebAPI apenas inicializações que são específicas dela (Swagger, por exemplo)

using System;
using Autofac;
using Autofac.Extensions.DependencyInjection;
using CountingMicroservice.Application;
using CountingMicroservice.Application.CommandSide.Commands;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Swashbuckle.AspNetCore.Swagger;

namespace CountingMicroservice.WebApi
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        public IServiceProvider ConfigureServices(IServiceCollection services)
        {
            services.AddMvc(options =>
            {
                options.RespectBrowserAcceptHeader = true;
            });

            services.AddSwaggerGen(options =>
            {
                options.SwaggerDoc("v1", new Info()
                {
                    Title = "Counting Microservice",
                    Version = "v1",
                    Description = "Basic Microservice Example"
                });
            });

            services.AddCounterApplication(Configuration);

            var container = new ContainerBuilder();
            container.RegisterModule(
                MediatrModule.Create(typeof(StartupExtensions).Assembly)
                );
            container.Populate(services);
            return new AutofacServiceProvider(container.Build());
        }

        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseMvcWithDefaultRoute();

            app
                .UseSwagger()
                .UseSwaggerUI(options =>
                {
                    options.SwaggerEndpoint(
                        "/swagger/v1/swagger.json",
                        "Counting Microservice v1"
                        );
                });

            app.UseCounterApplication();
        }
    }
}

3. Use e abuse do Docker

Provavelmente seu microsserviço irá rodar em um container;. Aproveite-se do suporte do Visual Studio para Docker e já comece seu projeto rodando e depurando em containers.

O efeito positivo dessa escolha é que ficará muito mais fácil gerenciar dependências de softwares tecerceiros. Veja o docker-compose.yml da aplicação exemplo

version: '3'

services:
  countingmicroservice.webapi:
    image: countingmicroservice.webapi
    build:
      context: .
      dockerfile: CountingMicroservice.WebApi/Dockerfile
    depends_on:
      - redis

  redis:
    image: redis

No exemplo, não preciso mais me preocupar em ter um servidor redis rodando em meu Windows. Ao começar a rodar minha aplicação, uma imagem do Redis irá ser baixada e um container iniciado.

4. Use variáveis de ambiente para configuração

É muito mais fácil configurar sua aplicação usando variáveis de ambiente do que utilizando arquivos de configuração. No Asp.net Core, é simples fazer isso.

namespace CountingMicroservice.WebApi
{
    public class Program
    {
        public static void Main(string[] args)
        {
            BuildWebHost(args).Run();
        }

        public static IWebHost BuildWebHost(string[] args) =>
            WebHost.CreateDefaultBuilder(args)
                .UseStartup()
                .ConfigureAppConfiguration((builderContext, config) =>
                {
                    config.AddEnvironmentVariables();
                })
                .Build();
    }
}

Além disso, variáveis de ambiente são perfeitas combinadas ao Docker. No exemplo, configuro endereço do Redis no arquivo de composição. Isso simplificará muito o deploy mais tarde.

version: '3'

services:
  countingmicroservice.webapi:
    environment:
      - ASPNETCORE_ENVIRONMENT=Development
      - REDIS_CONNECTIONSTRING=redis
    ports:
      - "5000:80"

  redis:
    ports:
      - "6379:6379"

Concluindo

Novamente, “são as cicatrizes que contam a história do guerreiro”.

  • Sempre achei tedioso fazer o link entre meus Controllers e o código do domínio. Mediatr é uma “mão na roda” e a separação do microsserviço em projetos “adaptadores” e um “core” me ajuda a manter focado no negócio.
  • A ideia de implementar comandos e consultas me faz manter o foco nas histórias de negócio ao invés de dados colecionados.
  • Sempre achei péssimo instalar bancos de dados e outros artefatos em meu computador apenas para desenvolver – Docker é vida!
  • Sempre odiei o web.config! Felizmente, não preciso mais dele. Adoro a ideia de poder usar simples variáveis de ambiente para configurar minha aplicação.

Novamente, há bem mais que poderia ser compartilhado. Entretanto, mais uma vez, é hora de pedir a sua opinião.

 

Compartilhe este insight:

Elemar Júnior

Sou fundador e CEO da EximiaCo e atuo como tech trusted advisor ajudando diversas empresas a gerar mais resultados através da tecnologia.

Elemar Júnior

Sou fundador e CEO da EximiaCo e atuo como tech trusted advisor ajudando diversas empresas a gerar mais resultados através da tecnologia.

Mais insights para o seu negócio

Veja mais alguns estudos e reflexões que podem gerar alguns insights para o seu negócio:

Minha opção para “vender” os meus serviços, bem como os da EximiaCo, sempre foi buscar o reconhecimento, no lugar do...
Nessa semana, em uma dessas conversas que valem a pena, surgiu uma breve discussão sobre um texto antigo de Rubem...
Agora em fevereiro, depois de 18 meses, fechei meu ciclo como CTO na Guiando para integrar o conselho consultivo da...
I’ve been spending some time learning from the “Designing Data-Intensive Applications” book. I am reading it for the third time,...
In the previous post, I shared some good things about our new query language: RQL. Now, I will show you...
Em todos esses anos tenho recebido relatos de desenvolvedores projetando sistemas com belas arquiteturas. Muitos deles tem levantado um bocado de questões...
Oferta de pré-venda!

Mentoria em
Arquitetura de Software

Práticas, padrões & técnicas para Arquitetura de Software, de maneira efetiva, com base em cenários reais para profissionais envolvidos no projeto e implantação de software.

× Precisa de ajuda?