Skip to main content

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 Publisher deveria 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 Application chama o RabbitMqPublisher
  • O Consumer deveria estar na camada infraestrutura porque ele lida com detalhes técnicos de fila, threading, ACKs, retries, etc

Visão da Arquitetura

Untitled
Untitled
Untitled
Untitled
Untitled
Untitled
alt text
alt text


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 Abstractions conté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

success

Nessa camada que deve estar todos os CONTEXT

danger

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 alt text

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 Persistence para 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

alt text