[PARTE 02] Criando arquitetura em camadas com DDD + Injeção de dep. + EF

Eric Ferreira
7 min readNov 3, 2018

--

Se você está aqui e ainda não viu a PARTE 01, eu aconselho a você dar uma lida nela clicando aqui, lá explico como funciona a arquitetura que iremos montar na teoria, já que neste artigo (parte 02) é a parte prática onde montaremos toda a arquitetura do zero.

Atenção: A seguir vamos utilizar a linguagem C#, onde todos os projetos foram criados em .NET Core versão 2.1 no Visual Studio. Também é importante ressaltar que conhecimentos de polimorfismo e encapsulamento são premissas para este artigo, uma vez que iremos criar classes genéricas para poupar muita repetição de código.

Criando os Projetos

Para ficar um cenário legal, vamos montar a arquitetura para uma aplicação de cadastro de Restaurantes e pratos.

No Visual Studio, para criar uma Solution é precisamos criar um Projeto junto, e como vamos criar um projeto para cada camada, vamos criar a Solution com o projeto Serviço (para a camada “02 — Serviços”) de uma vez. Neste caso vamos criar um projeto do tipo “ASP.NET Core”, repare nos comentários abaixo de cada imagem:

Vamos sempre dar o nome dos projetos assim “Restaurante.{CAMADA}”. Como estamos criando um projeto para a camada Serviços e neste caso se trata de uma API, damos o nome ao projeto de “Restaurante.Servicos.Api”, pois se trata de um projeto do tipo API na camada de Serviços.
Depois de darmos OK, a solution foi criada com projeto. Conforme a imagem que a seta indica, crie uma pasta para a camada Serviços e coloque o projeto dentro dela.
Em seguida crie pastas para cada camada, conforme a imagem acima mostra.

Próximo passo é criar os projetos para as demais camadas, e neste caso vamos usar o projeto do tipo “Class Library” (Biblioteca de classes) para todos.

Na imagem acima criamos o projeto “Restaurante.Aplicacao” para a camada Aplicação. Faça o mesmo para todas as outras camadas.

Com todos os projetos criados (conforme imagem abaixo), podemos dar início à codificação.

Codificando cada camada

Domínio

Vamos iniciar codificando pelo domínio, pois como vimos anteriormente ele é o único que não depende de nenhuma outra camada.

Atenção: repare bem os códigos, pois estamos criando classes “Base” para tudo, isso nos permite reaproveitar propriedades e métodos de forma genérica.

Entidades: crie uma pasta “Entidades” para depois criar as duas classes a seguir, como mostra imagem abaixo:

Interfaces: as interfaces que criaremos a seguir, são as mesmas que serão implementadas nas classes de serviço desta camada (Domínio) e nas classes de repositório da camada Infra.Data.

  • Interface para Repositórios:
  • Interface para Serviços

Serviços: classes que terão métodos básicos de um CRUD. Perceba que abaixo é esperado como parâmetro a interface de repositório que criamos acima, mas não vamos falar sobre o repositórios agora, isso é assunto para a camada de Infra.Data, que vamos ver mais abaixo.

Perceba que criamos uma classe base totalmente genérica, que nos da a possibilidade de estende-la nas demais classes (Prato neste caso) para que seja reutilizado os mesmos métodos sempre.

Aplicação

Clique com o botão direito em “Dependências”, “Adicionar referência”, procure o projeto e o adicione.

Após preparar a camada Domínio, vamos agora criar a estrutura da cama de Aplicação, a qual se comunicará diretamente com o Domínio, por isso adicione a dependência do projeto “Restaurante.Dominio”, para que tenhamos acesso as informações da mesma.

Atenção: Aqui também iremos criar classes bases genéricas.
Pacote NuGet: vamos precisar deste pacote do NuGet para usamos o AutoMapper: AutoMapper.Extensions.Microsoft.DependencyInjection (3.2.0)

Assim como nos outros, vamos criar as pastas e classes, conforme a imagem abaixo (os códigos vêm a seguir):

DTO: São classes muito parecidas com as Entidades do Domínio, e geralmente são usadas para retornar à sua aplicação (Apresentação) informações bem peculiares a ela, então é comum você vê classes Entidade e DTO com mesmos nomes (ou conteúdos), assim: Prato.cs e PratoDTO.cs.

Interfaces: estas interfaces são para as classes de serviços desta camada, que vêm logo a seguir.

Veja que aqui temos “Generic types” TEntidade e TEntidadeDTO, eles são informados (como na interface “IPratoApp”) para que seja possível fazer uma conversão de DTO para Entidade e vice-versa, veja abaixo na classes de serviços.

Serviços: estas são as classes de serviços desta camada que implementam as interfaces que criamos anteriormente.

Perceba que no construtor ele recebe as instancias iMapper e servico, respectivamente são: mapeia (converte) Entidade/DTO; métodos da classe de serviço do domínio.

MappingEntidade.cs
Esta classe serve para que registremos no AutoMapper as classes Entidade e DTO, para que seja possível realizar a conversão de uma para a outra.

Infra

Já deixamos prontas as camadas Domínio e Aplicação, agora iremos dar início a preparação da camada Infra, onde ela se divide em IoC e Data.

Infra.Data: Esta subcamada é praticamente o coração da camada Data, é onde persistiremos todas as informações, onde comunicaremos com o banco de dados propriamente dito.

Como vamos usar recursos da camada Domínio, vamos adicionar a dependência da mesma a esta camada.

Pacotes NuGet: vamos precisar instalar 3 pacotes do NuGet:
- Microsoft.EntityFrameworkCore.Design (2.0.1).
- Microsoft.EntityFrameworkCore.Tools (2.0.1).
- Pomelo.EntityFrameworkCore.MySql (2.1.0): Pois vamos usar o MySql e esta DLL do EF nos permitirá fazer conexão com o mesmo, além de inserir e trazer dados com facilidade.

Veja abaixo como ficará tudo após todas as referências importadas:

Agora vamos criar as classes, conforme a imagem abaixo (os códigos vêm a seguir):

Data.Contextos: Classe que herdamos o DbContext do EntityFrameWork, responsável por abrir transações e commita-las após término da persistência.

Data.Mapeamentos: Classes onde fazemos o mapeamento das entidades como tabelas do banco de dados, onde a nome da tabela é a própria entidade e as colunas são as propriedades desta entidade.

Data.Repositorios: estes serão os repositórios, onde são realizadas as consultas e inserções do banco de dados, tudo isso usando o contexto, que criamos acima. Ah! E é aqui que iremos implementar as interfaces de repositórios criadas no Domínio.

Infra.Data: Esta subcamada é responsável por ter referências de todas as demais camadas (exceto serviços), pois é ela quem coleta toda a.

Portanto, coloque as seguintes dependências nesta camada: Dominio, Aplicacao e Infra.Data.

Pacotes NuGet: vamos precisar instalar somente um pacote do NuGet:
- Microsoft.Extensions.DependencyInjection (2.1.0).

Veja abaixo como ficará tudo após todas as referências importadas:

Temos apenas uma classe nesta camada, a “InjetorDependencias.cs”:

Registramos todas as classes e interfaces possíveis de nossa arquitetura, para que possamos realizar a árvore de instância quando necessário.

Serviços (API)

Terminamos de codificar as camadas Domínio, Aplicação e Infra, agora vamos fazer a nossa última camada.
Como escolhemos fazer uma API para a camada de Serviço, sabemos que é através dela que as aplicações se comunicarão com a nossa arquitetura, para que possamos buscar ou persistir informações.

Dependência de outras camadas: adicione referência das camadas:
- Aplicacao
- Infra.IoC

Pacotes NuGet: vamos precisar instalar dois pacotes do NuGet:
- Pomelo.EntityFrameworkCore.MySql (2.1.0): Para que a API reconheça o futuro contexto que criaremos para conexão ao banco MySQL.
- Microsoft.Extensions.DependencyInjection (2.0.1): Para que possamos realizarmos a injeção de tudo o que já fizemos na nossa API.

Veja como ficará abaixo:

Se você já criou uma API em ASP ET, sabe que além de Controllers, temos as classe “Startup.cs”. Então abaixo temos as implementaççoes dos Controllers e da classe “Startup” que iremos usar, conforme imagem abaixo. (os códigos vêm a seguir):

Perceba que também criamos uma classe base genérica para os Controllers. A classe “Program.cs” não será necessário altera-la.
Veja que no método “ConfigureServices” é adicionado o “Contexto.cs”, que criamos na camada Infra.Data, e também é chamada a classe “InjetorDependencias.cs”, que criamos na camada Infra.IoC, para registrar todas as classes na API.

Arquitetura em camadas com DDD está pronta!!

Depois de termos feito tudo isso, precisamos tentar entender de forma mais prática como o fluxo disto funcionará.

Portanto, de maneira mais direta e resumida, a imagem abaixo mostra fielmente como o fluxo da estrutura funciona quando uma aplicação chamar nossa API para solicitar qualquer coisa.

Desta forma, a arquitetura vai avançando dentre as camadas desde a API até a Infra.

Vendo a figura acima, podemos ver que uma camada chama a outra, atendendo de forma clara as suas responsabilidades únicas, assim como vimos na PARTE 01.

Agora, para fecharmos, veremos mais uma imagem que ilustra também a ligação que as camadas possuem entre cada uma, seguindo o fluxo desde a camada de “Apresentação” até a camada de “Infraestrutura”.

É importante vermos que a camada de Domínio se comunica com a camada de Infraestrutura, porem vimos que ela não possui referência de nenhuma outra camada. Mas se observamos bem nos códigos, vemos que é devido a interface dos Repositórios que se faz possível a ponte de comunicação entre o Domínio e Infra.

Vale a pena ressaltar que esta arquitetura que construímos, serve para qualquer aplicação, seja ela WindowsForms, Xamarim ou qualquer outra aplicação front-end que atenda o conceito da camada de “Apresentação”.

Conclusão

O grande objetivo deste artigo foi mostrar e explicar um pouco sobre DDD e criar uma arquitetura robusta e escalável em camadas que consiga aplicar os paradigmas impostos pelo DDD.

Espera-se que este artigo tenha contribuído com o conhecido que foi passado aqui e ter ajudado muitas pessoas que tem dúvidas ou dificuldades para implementar um arquitetura com DDD que realmente atenda.

Este projeto não foi totalmente criado pelo autor do artigo, muitas coisa foram inspiradas em artigos e códigos de Eduardo Pires.

--

--