Clean Architecture | Arquitetura
- Clean Architecture | Arquitetura
A Clean Architecture é um modelo arquitetural proposto por Robert C. Martin (Uncle Bob) que tem como objetivo principal isolar as regras de negócio de detalhes externos como frameworks, bancos de dados, interfaces de usuário e serviços de terceiros.
Essa separação permite maior flexibilidade, testabilidade e manutenibilidade do sistema ao longo do tempo.
Quando não usar Clean Architecture
Embora a Clean Architecture traga inúmeros benefícios, ela não é indicada para todos os cenários.
Considere não utilizá-la quando:
- O projeto é pequeno e não há previsão de crescimento significativo.
- O prazo de entrega é muito curto, exigindo simplicidade máxima.
- A equipe possui recursos limitados ou pouca experiência com esse tipo de arquitetura.
⚠️ A Clean Architecture é poderosa, mas também mais complexa. Em projetos pequenos, essa complexidade pode não se justificar.
Detalhes de implementação
Referência do Domínio no Repositório
É aceitável que o repositório conheça o domínio para:
- Definir tipos de retorno baseados nas entidades do domínio.
- Receber instâncias das entidades para persistência.
O importante é que o domínio não dependa do repositório, mantendo-se completamente isolado.
Sobre o uso de Factory e onde criá-la
A decisão sobre onde colocar uma Factory depende diretamente da responsabilidade envolvida na criação dos objetos:
- ✅ Se a criação estiver ligada às regras de negócio, a Factory deve ser colocada na camada de Domínio (Domain).
- ⚙️ Se a criação envolver adaptação de dados entre camadas ou conversão de entradas vindas da interface do usuário, posicione a Factory na camada de Apresentação (Controllers/Adapters).
O objetivo é proteger o domínio de detalhes de implementação específicos, como frameworks, bancos de dados ou manipulações de entrada.
Publisher e Consumer do RabbitMQ
- O
Publisherdeveria estar na camada infraestrutura porque ele lida com detalhes técnicos de transporte
// camada de application
public interface IEventPublisher
{
Task PublishAsync<T>(T @event) where T : DomainEvent;
}
// camada de infraestrutura
public class RabbitMqPublisher : IEventPublisher
{
public async Task PublishAsync<T>(T @event)
{
// Serializa e envia mensagem via RabbitMQ
}
}
- A camada de
Applicationchama oRabbitMqPublisher
- O
Consumerdeveria estar na camada infraestrutura porque ele lida com detalhes técnicos de fila, threading, ACKs, retries, etc
Visão da Arquitetura








Estrutura de Pastas
🧠 Camada de Domínio (Domain Layer)
A Camada de Domínio representa o núcleo do sistema, onde vivem as regras de negócio puras.
Ela é completamente independente de detalhes externos, garantindo que o domínio não seja afetado por mudanças em frameworks ou infraestrutura.
Elementos comuns dessa camada:
- Entidades
- Objetos de Valor (Value Objects)
- Agregados
- Eventos de Domínio
- Exceções
- Interfaces de Repositórios
Estrutura sugerida:
📁 Domain
├── 📁 DomainEvents
├── 📁 Entities
├── 📁 Exceptions
├── 📁 Repositories
├── 📁 Shared
└── 📁 ValueObjects
⚠️ O domínio não deve referenciar nenhum outro projeto da solução.
⚙️ Camada de Aplicação (Application Layer)
A Camada de Aplicação é responsável por orquestrar os casos de uso do sistema, utilizando o que foi definido no domínio.
Ela não contém lógica de negócio, apenas a coordenação das operações e a execução das regras de negócio através do domínio.
É aqui que aplicamos padrões como CQRS (Command Query Responsibility Segregation), separando operações de leitura e escrita.
Estrutura sugerida:
📁 Application
├── 📁 Abstractions
│ ├── 📁 Data
│ ├── 📁 Email
│ └── 📁 Messaging
├── 📁 Behaviors
├── 📁 Contracts
├── 📁 [Entidade1]
│ ├── 📁 Commands
│ ├── 📁 Events
│ └── 📁 Queries
└── 📁 [Entidade2]
├── 📁 Commands
├── 📁 Events
└── 📁 Queries
A pasta
Abstractionscontém interfaces que a camada de Aplicação depende, mas que são implementadas em camadas superiores (Infraestrutura, por exemplo).
🧩 Camada de Infraestrutura (Infrastructure Layer) | Context
Nessa camada que deve estar todos os CONTEXT
Nessa camada podemos ter services, porém sem lógicas de negócio, apenas para realizar uma consulta externa como requisições http, envio de e-mails, etc.
O repository continua existindo para realizar operações no banco de dados.
Documentação da microsoft: https://learn.microsoft.com/en-us/dotnet/architecture/modern-web-apps-azure/common-web-application-architectures

A Camada de Infraestrutura contém as implementações concretas de serviços externos e dependências técnicas do sistema.
O que costuma estar nessa camada:
- Acesso a banco de dados (PostgreSQL, MongoDB, etc.)
- Provedores de identidade (Auth0, Keycloak)
- Serviços de e-mail
- Armazenamento de arquivos (AWS S3, Azure Blob Storage)
- Mensageria (RabbitMQ, Kafka)
Estrutura sugerida:
📁 Infrastructure
├── 📁 BackgroundJobs
├── 📁 Services
│ ├── 📁 Email
│ └── 📁 Messaging
├── 📁 Persistence
│ ├── 📁 EntityConfigurations
│ ├── 📁 Migrations
│ ├── 📁 Repositories
│ └── 📝 ApplicationDbContext.cs
└── 📁 ...
É comum mover a pasta
Persistencepara um projeto separado, isolando toda a lógica de persistência de dados.
🌐 Camada de Apresentação (Presentation Layer)
A Camada de Apresentação é a porta de entrada da aplicação — normalmente implementada como uma API Web.
Ela lida com requisições HTTP, validação de entrada e mapeamento entre modelos de exibição (ViewModels) e objetos de domínio.
Estrutura sugerida:
📁 Presentation
├── 📁 Controllers
├── 📁 Middlewares
├── 📁 ViewModels
├── ...
└── 📝 Program.cs
Os Controllers devem apenas receber requisições, delegar o processamento à camada de Aplicação e retornar o resultado apropriado.
🔗 Dependência entre Camadas
Na Clean Architecture, as dependências fluem de fora para dentro, sempre em direção ao núcleo (Domínio).
Isso garante que o domínio permaneça isolado e independente de detalhes externos.
+----------------------+
| Presentation | → Interface / API / UI / HTTP (REST) / GRAPHQL
+----------------------+
↓
+----------------------+
| Application | → Casos de uso / Orquestração
+----------------------+
↓
+----------------------+
| Domain | → Regras de negócio
+----------------------+
↑
+----------------------+
| Infrastructure | → Banco / serviços / context / AMQP (RabbitMQ, Kafka)
+----------------------+
---------Outra perspectiva---------
[ API ] → [ Application ] → [ Domain ]
↑(DI)
[ Infrastructure ]
OBS: O DI deve acontecer onde está a implementação concreta da interface ou na API. Não terá problema na API porque ela vai fazer apenas o DI
Regras de dependência:
- Domain → Independente de todas as outras camadas.
- Application → Depende de Domain.
- Presentation → Depende de Application (e indiretamente de Domain).
- Infrastructure → Pode depender de Application e Domain, mas nunca o contrário.
🎯 Resumo: as camadas externas conhecem as internas, mas as internas não conhecem as externas.
Uma explicação mais facilitada do que seria dependência
// Domain
public class Order { /* lógica de negócio */ }
// Application
public interface IOrderRepository
{
Task SaveAsync(Order order);
}
// Infraestrutura
public class SqlOrderRepository : IOrderRepository
{
public async Task SaveAsync(Order order)
{
// salvar no banco SQL
}
}
A dependência flui assim:
Infraestrutura → Application → Domain
- Infraestrutura implementa a interface da Application.
- Application usa a interface.
- Domain é o núcleo usado pelas duas camadas acima.
Inversão de dependência (DIP)
Essa organização inverte a dependência natural: Tradicionalmente, pensaríamos que Application depende de Infrastructure, porque precisa de repositório.
Mas na Arquitetura Limpa, é o contrário:
A Application define a interface, e a Infrastructure implementa. Esse é o famoso "D" do SOLID – Dependency Inversion Principle.
Como deve estar as camadas
📁 MyApp.Domain
📁 MyApp.Application (ref MyApp.Domain)
📁 MyApp.Infrastructure (ref MyApp.Application + MyApp.Domain)
📁 MyApp.API (ref MyApp.Application)
🧪 Exemplo de Projeto com Clean Architecture e Arquitetura Hexagonal
