Clean Architecture - Uma introdução revisitada


 Hoje vamos revisitar os conceitos relacionados à Clean Architecture.

Antes de apresentar os conceitos da Clean Architecture vamos rever o conceito de Arquitetura em Camadas.

Vamos iniciar com arquitetura clássica em N-Camadas ou N-Tier. Isso já existe há mais de 20 anos e ainda é muito usada atualmente.

A vertente mais usada da arquitetura em Camadas ou N-Tier é a arquitetura implementada em 3 camadas:

Cada camada só tem permissão para se comunicar com a próxima camada inferior (ou seja, a IU não pode se comunicar diretamente com os Dados).

Superficialmente, essa limitação pode parecer uma boa ideia, mas, na implementação, significa um conjunto diferente de modelos para cada camada, o que resulta em muito código de mapeamento. Esse problema é ampliado quanto mais camadas você adiciona.

A seguir veremos cada uma das camadas e seu componentes:

User Interface Layer

Esta estrutura é típica de aplicações ASP.NET Core MVC ou Web API.

Business Logic Layer

É nesta camada que esta a essência das aplicações que usam a arquitetura em Camadas ou N-Tier.

Data Layer

A camada de acesso aos dados define a lógica para acessar os dados na aplicação.

Agora vamos apresentar os conceitos da Clean Architecture comparando com a arquitetura em camadas.

Apresentando a Arquitetura Limpa

Esta arquitetura teve muitos nomes ao longo dos anos. Onion Architecture, Hexagonal Archecture, Screaming Architecture e outros. Essa abordagem não é nova, mas também não é tão comum quanto deveria ser.

Então, em comparação com a arquitetura em camadas ou N-Tier, o que é Arquitetura Limpa e como ela é diferente?

Vamos iniciar com uma figura que representa a Clean Architecture:

A primeira coisa a notar aqui é a direção das dependências.

Todas as dependências fluem para as camadas mais internas. Camadas externas podem se comunicar com QUALQUER camada interna (compare com N-Tier, onde cada camada só pode se comunicar com a camada abaixo).

Isso segue o Princípio de Inversão de Dependência, o que significa que as dependências são injetadas em vez de serem criadas explicitamente. Outro nome para isso é o Princípio de Hollywood: não nos chame, nós ligaremos para você.

As camadas Application e Domain são considerados o "núcleo" do aplicativo. A camada Application depende da Domain, mas o domínio não depende de nada.

Quando o aplicativo precisa de funcionalidade da infraestrutura (por exemplo, acesso ao banco de dados), o aplicativo definirá suas próprias interfaces que a infraestrutura implementará.

Esse desacoplamento é enorme e é um dos principais benefícios dessa abordagem. Isso não apenas permite testes de unidade mais fáceis, mas também significa que ela ignora a persistência.

Ao consultar dados, o armazenamento de dados subjacente pode ser um banco de dados, um serviço da web ou até mesmo um arquivo simples. O aplicativo não se importa e não precisa saber. Como os detalhes de implementação estão fora do núcleo, isso nos permite focar na lógica de negócios e evita a poluição com detalhes menos importantes.

Ela também fornece flexibilidade, pois hoje os dados podem vir de uma fonte de dados, mas no futuro podem precisar vir de uma fonte de dados diferente. Devido ao acoplamento fraco, apenas a camada de infraestrutura precisará ser alterada para oferecer suporte a isso.

Assim destacamos as seguintes características da Clean Architecture:

O objetivo disso é tornar mais fácil para os desenvolvedores fazerem as coisas certas e tornar difícil para eles fazerem as coisas erradas.

A seguir vamos apresentar as camadas e suas particularidades.

Camada Domain

A camada Domain é o coração de seu aplicativo e responsável por seus modelos principais. Os modelos devem ignorar a persistência e encapsular a lógica sempre que possível. Queremos evitar acabar com modelos anêmicos (ou seja, modelos que são apenas coleções de propriedades).

A  camada Domain pode ser incluída na camada Application, mas se você estiver usando uma estrutura de entidade semelhante a ORM, a Camada de Infraestrutura precisará fazer referência aos modelos de domínio, caso em que é melhor dividir em uma camada separada.

As anotações de dados devem ser deixadas de fora dos modelos de domínio. Isso deve ser adicionado na camada de infraestrutura usando sintaxe fluente. Se você está acostumado a usar as anotações de dados para sua validação, eu recomendo usar a Fluent Validation na Camada de Aplicação, que fornece mais capacidade para eventos do que as anotações.

Camada Application

Este é a Application do seu Domain usado para implementar os casos de uso para o seu negócio. Isso fornece o mapeamento de seus modelos de domínio para um ou mais modelos de visualização ou DTOs.

A validação também vai para essa camada. Pode-se argumentar que a validação vai para o domínio, mas existe o risco de que os erros levantados possam fazer referência a campos não presentes no DTO / Modelo de Visualização, o que causaria confusão. Assim, é melhor ter validação potencialmente duplicada do que validar um objeto que não foi passado para o comando / consulta.

Considere usar comandos e consultas CQRS para lidar com todas as solicitações de aplicativos. O MediatR pode ser usado para facilitar isso e adicionar comportamento adicional como registro, armazenamento em cache, validação automática e monitoramento de desempenho para cada solicitação. Se você optar por não usar o CQRS, poderá trocá-lo pelo uso de serviços.

A Camada de Aplicativo SOMENTE faz referência à Camada de Domínio. Ele não sabe nada de bancos de dados, serviços da web, etc. No entanto, define interfaces (por exemplo, IContatoRepository, IContatoService, IMessageBus), que são implementadas pela camada de infraestrutura.

Camada Infrastructure

A camada de infraestrutura implementará interfaces da camada de aplicativo para fornecer funcionalidade para acessar sistemas externos. Eles serão conectados pelo contêiner IoC, geralmente na Camada de Apresentação.

A camada de apresentação geralmente terá uma referência à camada de infraestrutura, mas apenas para registrar as dependências com o contêiner IoC.

Camada Presentation

A camada de apresentação é o ponto de entrada para o sistema do ponto de vista do usuário. Suas principais preocupações são o roteamento de solicitações para a camada de aplicativo e o registro de todas as dependências no contêiner IoC.  Se você estiver usando ASP.NET, as ações nos controladores devem ser muito finas e, na maioria das vezes, simplesmente passar a solicitação ou o comando para MediatR.

Variações

As camadas descritas até agora constituem a abordagem básica da Arquitetura Limpa. Você pode precisar de mais camadas, dependendo do seu aplicativo.

Se você não estiver usando um ORM, poderá combinar as camadas de domínio e de aplicativo para simplificar. Você pode querer dividir a infraestrutura em outros projetos (por exemplo, Persistência). Essa abordagem funciona bem com o Domain-Driven Design, mas funciona igualmente bem sem ele.

O CQRS é a abordagem recomendada para o ponto de entrada na camada de aplicativo. No entanto, você também pode usar serviços típicos se não se sentir confortável com isso.

Conclusão

Aplicar as diretrizes da Clean Architecture resulta em uma arquitetura e design que é:

Independente de Frameworks -  O núcleo da aplicação ou Core que inclui as camadas Domain e Application, não deve depender de frameworks externos, como Entity Framework;

Testável - A lógica dentro do Core pode ser testada independentemente de qualquer coisa externa, como interface do usuário, bancos de dados, servidores. Sem dependências externas, os testes são muito simples de escrever.

Independente da Interface do Usuário (UI) - É fácil trocar a IU da Web por uma IU de Console ou Angular para Vue. A lógica está contida no Core, portanto, alterar a IU não afetará a lógica.

Independente de banco de dados - inicialmente você pode escolher SQL Server ou Oracle ou MySql, mas pode mudar para Mongo DB ou Cosmos DB.

Independente de qualquer fator externo  - O Core da sua aplicação simplesmente não sabe nada sobre o mundo exterior;

E estamos conversados...

"Que diremos, pois, a estas coisas? Se Deus é por nós, quem será contra nós?"
Romanos 8:31

Referências:


José Carlos Macoratti