Introdução
Clean Architecture é uma arquitetura que mantém o foco no domain. Seu objetivo principal é isolar e manter independência do domínio. A Clean propõe que o domínio (domain) nunca deve depender de detalhes externos.
O conceito foi baseado nas boas práticas e nas arquitetureas hexagonal e cebola, dentre outras, que já propunham a separação das responsabilidades em camadas e tinham como objetivo produzir sistemas com as seguintes características.
- Independente de framework
- Testáveis
- Independentes da interface do usuário
- Independentes do banco de dados
- Independente de qualquer agente externo
Isto é:
- Se amanhã trocar a interface (Web → Mobile), a regra de negócio continuam a mesma.
- Banco de dados, controllers, bibliotecas externas e frameworks são considerados plugáveis. Desse modo, há um desacoplamento entre a infraestrutura
- Testabilidade: como o domínio não depende de frameworks e banco de dados, você pode testar os casos de usos em memória, sem precisar rodar a infra.
Camadas
A princípio essa arquitetura possui 4 camadas mínimas, o número suficiente manter o isolamento funcional (apesar de não haver restrição de número máximo).
Entidades (Entities)
No centro da arquitetura, temos as classes responsáveis pelas regras de negócios, que podem ser dois tipos: Entidades e Casos de Uso.
Entidade: conjunto de regras de negócios relacionadas que são críticas para o funcionamento do aplicativo.
- As regras seriam agrupadas como métodos em uma classe
- As regras existem mesmo se não existir a aplicação
Como as entidades não conhecem as outras camadas elas não dependem de nada
Casos de uso (Use cases)
Nessa camada contém as regras de negócio específica do aplicativo. Dizem como automatizar o sistema determinando o seu comportamento.
- Orquestram o fluxo de e para as entidades
- Direcionam as entidades a usar as regras de negócios.
Alguns exemplos de casos de usos são:
- Obter informação de um produto: nome, preço, quantidade…
- Montar catálogo de produtos
- Verificar estoque
Como vimos na imagem acima, os casos de usos interagem e dependem das entidades, mas não sabem nada mais sobre as camadas mais distantes.
Adptadores (Adpters)
Na terceira camada a partir do centro, temos classes e interfaces chamadas de Adaptadores. A função dela é converter os dados de um formato para outro. São os tradutores entre domínio e a infraestrutura.
Eles convertem os dados do formato mais convenientes para os casos de usos e entidades
Esssa é a camada que vai conter a implementação MVC de uma UI com apresentadores, vizualizações e controladores, ou que poderá realizar a implementação dos endpoints de uma API REST
Nenhum código dentro desse círculo deve saber absolutamente nada sobre o banco de dados
Camada mais externa
Essa camada é para onde vão todos os componentes de entrada ou saída (input, output), a interface com o usuário (UI), o banco de dados, os frameworks, os dispositivos, etc.
Essa camada é para onde vão todos os detalhes como as interfaces e banco de dados. Ela é a camada mais volátil, pois pode mudar com frequência. E por isso, essa camada é mantida o mais longe possível das camadas de domínio.
Como elas são mantidas separadas, é fácil fazer alterações ou trocar um componente por outro. (por exemplo UI, banco de dados, estruturas e dispositivos)
Considerações finais das camadas
Desse modo, podemos dizer que
As camadas internas são mais estáveis
As camadas externas são mais sujeitas a mudanças
As entidades raramente devem ser modificadas
Alterações nos Use Cases não devem ser motivadas por mudanças na tecnologia, banco de dados, frameworks, etc.
A Regra de dependência garante que as entidades e os casos de usos sejam classes limpas de qualquer tecnologia ou serviço externo ao sistema
The Dependency Rule
The Dependency Rule. Essa é a regra de ouro dessa arquitetura: Dependências sempre apontam para dentro. Ou seja, a camada interna nunca depende de uma externa.
Relação da Clean com o DDD
A Clean Architecture não é um substituto do DDD, ela é na verdade uma arquitetura que facilita o DDD.
- O Domínio do DDD (Entidades, Objetos de Valor, Agregados) está na camada de Entities da Clean
- Os Casos de Usos/Application Services do DDD estão na camadas de Use Cases
- Os repositórios, Gateways e Adapters (interfaces do comunicação com o mundo externo) ficam nas camadas externas.
Desse modo, podemos afirmar que o DDD define o que modelar (o negócio), e a Clean define como organizar (a arquitetura protege o negócio)
Clean na prática com .NET
Como já vimos na teoria tudo começa pelo domínio, e as dependências sempre apontam para dentro. O fluxo existe para garantir que as dependências sempre apontem para dentro, mas nunca ao contrário. É o que Uncle Bob chama de Dependency Rule. Então, abaixo mostrei o fluxo de execução conceitual e das dependências.
Fluxo conceitual (de execução)
Quando o sistema roda, o fluxo natural de execução é:
Usuário → API → Application → Domain → Infrastructure
ou, em palavras:
- O usuário chama um endpoint (ex: POST /pedidos).
- O Controller (camada API) recebe a requisição e aciona o Use Case.
- O Use Case orquestra as regras e cria entidades do Domain.
- O Domain aplica suas regras, invariantes e validações.
- O Use Case pode então chamar um repositório (definido como interface no Application), cuja implementação concreta está na Infrastructure (ex: gravação no banco).
Então o fluxo de execução vai “pra baixo” — mas o fluxo de dependência vai pra dentro.
O fluxo das dependências (de código-fonte)
Agora o segredo:
Mesmo que o fluxo de execução vá da API → Infra, o código e as referências entre projetos apontam no sentido oposto:
MyApp.Api ──→ MyApp.Application ──→ MyApp.Domain
↑
│
MyApp.Infrastructure (implementa interfaces)
- A API conhece a Application, porque chama os Use Cases.
- A Application conhece a Domain, porque usa as Entidades.
-
Mas nenhuma das duas conhece a Infrastructure —
apenas definem interfaces (ex:
IPedidoRepository
). -
A Infrastructure é quem conhece as outras, porque precisa:
- Implementar
IPedidoRepository
; - Registrar as implementações no container de injeção (
DependencyInjection
).
- Implementar
então, resumidamente, as dependências possuem esse tipo de papel:
Camada | Papel | Depende de |
---|---|---|
Domain | Regras puras (núcleo) | Ninguém |
Application | Usa as regras do domínio | Domain |
API (ou UI) | Mostra o sistema pro mundo | Application |
Infrastructure | Conecta o sistema ao mundo real | Domain + Applicatio |
Estrutura típica de um projeto .NET
Geralmente a solução .sln
fica assim:
CleanOrders/
│
├── src/
│ ├── CleanOrders.Domain/
│ ├── CleanOrders.Application/
│ ├── CleanOrders.Infrastructure/
│ └── CleanOrders.Api/
│
├── tests/
│ ├── CleanOrders.UnitTests/
│ └── CleanOrders.IntegrationTests/
│
└── CleanOrders.sln
O projeto de saída deve ser do tipo ASP.NET Core Web App (ou outro tipo de projeto executável compatível). Os demais projetos da solução devem ser configurados como Class Library, de modo que sirvam como bibliotecas de apoio e não como pontos de entrada da aplicação.
Vamos destrinchar toda essa estrutura?
1. Domain (Camada mais interna)
Aqui é o coração do sistema, onde tem as regras de negócios puras. Sem referência externa.
CleanOrders.Domain/
│
├── Entities/
│ ├── Pedido.cs
│ └── ItemPedido.cs
│
├── ValueObjects/
│ └── Email.cs
│
├── Enums/
│ └── StatusPedido.cs
│
├── Exceptions/
│ └── DomainException.cs
│
└── Common/
└── EntityBase.cs
2. Application (Casos de uso / Regras de aplicação)
Orquestra o domínio e depende apenas dele
CleanOrders.Application/
│
├── Interfaces/
│ └── IPedidoRepository.cs
│
├── DTOs/
│ ├── PedidoDto.cs
│ └── ItemDto.cs
│
├── Features/
│ ├── Pedidos/
│ │ ├── Commands/
│ │ │ ├── CriarPedido/
│ │ │ │ ├── CriarPedidoCommand.cs
│ │ │ │ ├── CriarPedidoCommandHandler.cs
│ │ │ │ └── CriarPedidoValidator.cs
│ │ │ └── FinalizarPedido/
│ │ │ ├── FinalizarPedidoCommand.cs
│ │ │ └── FinalizarPedidoHandler.cs
│ │ └── Queries/
│ │ └── GetPedidoById/
│ │ ├── GetPedidoByIdQuery.cs
│ │ └── GetPedidoByIdHandler.cs
│ │
│ └── Common/
│ └── PaginatedList.cs
│
└── DependencyInjection.cs
3. Infraestructure (Implementações técnicas)
Implementa interfaces da camada application. Contém EF Core, Dapper, serviços externosm, etc.
CleanOrders.Infrastructure/
│
├── Persistence/
│ ├── CleanOrdersDbContext.cs
│ ├── Configurations/
│ │ ├── PedidoConfiguration.cs
│ │ └── ItemPedidoConfiguration.cs
│ └── Migrations/
│
├── Repositories/
│ └── PedidoRepository.cs
│
├── Services/
│ └── EmailSender.cs
│
└── DependencyInjection.cs
4. API (Camada de apresentação / interface externa)
Exposição via HTTP (REST) ou Interface da aplicação
CleanOrders.Api/
│
├── Controllers/
│ └── PedidosController.cs
│
├── Middlewares/
│ └── ExceptionHandlingMiddleware.cs
│
├── Filters/
│ └── ValidationFilter.cs
│
├── appsettings.json
├── Program.cs
└── DependencyInjection.cs
Testes (Unitários e de integração)
tests/
├── CleanOrders.UnitTests/
│ └── Application/
│ └── Pedidos/
│ └── CriarPedidoCommandHandlerTests.cs
└── CleanOrders.IntegrationTests/
└── Api/
└── PedidosEndpointsTests.cs
Top comments (0)