Onion Architecture: variação e comparação com Clean
1. Origens e Fundamentos da Onion Architecture
1.1. Contexto histórico
Proposta por Jeffrey Palermo em 2008, a Onion Architecture surgiu como uma resposta direta ao acoplamento excessivo presente em arquiteturas tradicionais em camadas (layered architecture). Na época, era comum que camadas superiores dependessem diretamente de camadas inferiores, criando um acoplamento rígido que dificultava testes, manutenção e evolução do software. Palermo observou que a dependência da camada de domínio em relação à infraestrutura (bancos de dados, frameworks) violava princípios fundamentais de design.
1.2. Princípio central
O princípio fundamental da Onion Architecture é que todas as dependências devem apontar para o centro — o domínio. Isso significa que camadas externas (infraestrutura, interface do usuário) podem depender de camadas internas, mas o inverso é estritamente proibido. Essa inversão de controle é explícita e não apenas conceitual: ela se materializa por meio de interfaces definidas no domínio ou na camada de aplicação, com implementações concretas fornecidas pelas camadas externas.
1.3. Analogia da cebola
A analogia com uma cebola é precisa: assim como uma cebola possui camadas concêntricas, a Onion Architecture organiza o software em círculos concêntricos. O núcleo — o miolo da cebola — contém o modelo de domínio puro, sem qualquer dependência externa. Cada camada subsequente envolve a anterior, adicionando responsabilidades progressivamente mais voltadas à infraestrutura e à interação com o mundo exterior.
2. Estrutura de Camadas na Onion Architecture
2.1. Núcleo (Domain Model)
O centro da arquitetura contém entidades, value objects e regras de negócio fundamentais. Não há referência a bancos de dados, frameworks web ou bibliotecas externas.
// Domain/Entities/Order.cs
public class Order
{
public Guid Id { get; private set; }
public List<OrderItem> Items { get; private set; }
public OrderStatus Status { get; private set; }
public void AddItem(Product product, int quantity)
{
if (quantity <= 0)
throw new DomainException("Quantidade deve ser positiva");
Items.Add(new OrderItem(product, quantity));
RecalculateTotal();
}
}
2.2. Camada de Serviços de Domínio (Domain Services)
Quando uma operação envolve múltiplas entidades ou requer lógica que não pertence naturalmente a uma única entidade, utilizam-se serviços de domínio.
// Domain/Services/DiscountCalculator.cs
public class DiscountCalculator
{
public decimal CalculateDiscount(Order order, Customer customer)
{
if (customer.IsPremium && order.Total > 1000)
return order.Total * 0.15m;
return 0;
}
}
2.3. Camadas externas
As camadas externas incluem Application Services (casos de uso), Infrastructure (repositórios, acesso a banco) e Presentation (APIs, interfaces de usuário). Cada camada externa depende apenas da camada imediatamente interna.
3. Comparação Estrutural: Onion vs. Clean Architecture
3.1. Semelhanças
Ambas as arquiteturas compartilham o mesmo princípio fundamental: o domínio no centro e dependências direcionadas para dentro. Robert C. Martin (Uncle Bob) reconheceu explicitamente que a Clean Architecture foi inspirada pela Onion Architecture e pela Hexagonal Architecture.
3.2. Diferença no número e nome das camadas
A Clean Architecture define explicitamente quatro camadas: Entities, Use Cases, Interface Adapters e Frameworks & Drivers. A Onion Architecture é mais flexível — pode ter quantas camadas forem necessárias, desde que o princípio de dependência seja mantido.
3.3. Tratamento de "gateways" e "presenters"
A Clean Architecture define explicitamente o conceito de "gateways" (interfaces para acesso a dados externos) e "presenters" (adaptadores de interface). A Onion Architecture não nomeia esses elementos de forma tão explícita, deixando a cargo do arquiteto decidir como organizá-los.
4. Regra de Dependência e Inversão de Controle
4.1. Onion: dependências do exterior para o interior
A regra é absoluta: uma camada interna nunca deve saber da existência de uma camada externa. Se o domínio precisa acessar dados, ele define uma interface, e a implementação concreta reside na infraestrutura.
// Domain/Interfaces/IOrderRepository.cs
public interface IOrderRepository
{
Task<Order> GetByIdAsync(Guid id);
Task SaveAsync(Order order);
}
// Infrastructure/Repositories/OrderRepository.cs
public class OrderRepository : IOrderRepository
{
private readonly AppDbContext _context;
// Implementação concreta com EF Core
}
4.2. Papel da Injeção de Dependência
A Injeção de Dependência (DI) é o mecanismo concreto que viabiliza a inversão de controle. No ponto de composição da aplicação (geralmente na camada de apresentação), as implementações concretas são registradas e injetadas nas classes que dependem das interfaces.
4.3. Comparação com a regra de Clean
Ambas as arquiteturas proíbem rigorosamente o vazamento de infraestrutura para o domínio. A diferença está na formalidade: a Clean Architecture é mais explícita sobre os adaptadores de interface, enquanto a Onion confia mais na disciplina do time.
5. Vantagens Práticas da Onion Architecture
5.1. Testabilidade
O domínio puro pode ser testado sem qualquer infraestrutura. Testes unitários para entidades e serviços de domínio não requerem bancos de dados, servidores web ou mocks complexos.
5.2. Flexibilidade de camadas
A Onion Architecture se adapta bem tanto a monólitos quanto a microsserviços. Em um microsserviço, cada serviço pode ter sua própria "cebola" com poucas camadas.
5.3. Isolamento de mudanças
Trocar um ORM (Entity Framework por Dapper) ou um banco de dados (SQL Server por PostgreSQL) requer apenas alterações na camada de infraestrutura, sem tocar no domínio ou nos casos de uso.
6. Desvantagens e Armadilhas Comuns
6.1. Complexidade inicial
Para projetos simples (CRUD básico com poucas regras), a Onion Architecture introduz overhead significativo de interfaces, injeção de dependência e camadas adicionais.
6.2. Risco de "camada fantasma"
Serviços de aplicação que apenas delegam chamadas para repositórios sem adicionar valor real criam "camadas fantasma" que aumentam a complexidade sem benefício.
6.3. Dificuldade de rastreamento
Muitas abstrações podem tornar o fluxo de uma requisição difícil de seguir. Um desenvolvedor pode precisar navegar por cinco ou seis arquivos para entender uma operação simples.
7. Quando Escolher Onion em vez de Clean (e vice-versa)
7.1. Onion para equipes que preferem flexibilidade
Equipes maduras que entendem os princípios e desejam liberdade para nomear e organizar camadas conforme o contexto do projeto se beneficiam mais da Onion Architecture.
7.2. Clean para separação rígida
Projetos que exigem documentação formal ou equipes menos experientes se beneficiam da estrutura mais rígida e bem documentada da Clean Architecture.
7.3. Casos híbridos
É perfeitamente viável adotar a estrutura de camadas da Onion Architecture incorporando o conceito de Use Cases da Clean Architecture para maior clareza nos fluxos de aplicação.
8. Exemplo Prático de Estrutura de Pastas (Onion Style)
src/
├── Domain/
│ ├── Entities/
│ │ ├── Order.cs
│ │ └── Product.cs
│ ├── ValueObjects/
│ │ └── Money.cs
│ ├── Services/
│ │ └── DiscountCalculator.cs
│ └── Interfaces/
│ └── IOrderRepository.cs
│
├── Application/
│ ├── UseCases/
│ │ ├── CreateOrderUseCase.cs
│ │ └── CancelOrderUseCase.cs
│ ├── DTOs/
│ │ └── CreateOrderRequest.cs
│ └── Interfaces/
│ └── IOrderService.cs
│
├── Infrastructure/
│ ├── Persistence/
│ │ ├── AppDbContext.cs
│ │ └── OrderRepository.cs
│ └── ExternalServices/
│ └── PaymentGateway.cs
│
└── Presentation/
├── Controllers/
│ └── OrdersController.cs
└── Middleware/
└── ExceptionHandler.cs
Nesta estrutura, note que Domain não referencia nenhuma outra camada. Application depende apenas de Domain. Infrastructure implementa interfaces definidas em Domain e Application. Presentation orquestra a composição via DI.
A Onion Architecture, embora não seja uma bala de prata, oferece uma abordagem madura e flexível para construir software com domínio rico, testável e resiliente a mudanças. Sua principal força está na disciplina de manter as dependências apontando para dentro — um princípio que, quando seguido rigorosamente, produz sistemas que evoluem com graça ao longo do tempo.
Referências
-
Onion Architecture: A Practical Approach by Jeffrey Palermo — Artigo original que introduziu o conceito de Onion Architecture em 2008, com explicações detalhadas sobre as motivações e a estrutura.
-
The Clean Architecture by Robert C. Martin — Postagem seminal que define a Clean Architecture, incluindo comparações com a Onion Architecture e a Hexagonal Architecture.
-
Onion Architecture vs Clean Architecture: A Detailed Comparison — Análise comparativa prática entre as duas arquiteturas, com exemplos de código e discussão sobre trade-offs.
-
Microsoft .NET Architecture Guide: Onion Architecture — Documentação oficial da Microsoft sobre arquiteturas de aplicações web modernas, incluindo seção dedicada à Onion Architecture.
-
Implementing Onion Architecture in ASP.NET Core — Tutorial prático passo a passo de implementação da Onion Architecture em projetos .NET Core, com exemplos reais de código e estrutura de pastas.