image

Accede a bootcamps ilimitados y a más de 650 cursos

50
%OFF

EA

Erickson Augusto07/11/2025 21:10
Compartir

Clean Architecture: Compreendendo e Aplicando a Arquitetura Limpa

    Aprendendo a construir APIs RESTful em C# com .NET Core seguindo os princípios da Clean Architecture. Neste guia, você vai descobrir como organizar seu projeto em camadas bem definidas, Domain, Application, Infrastructure e API, garantindo manutenibilidade, testabilidade e escalabilidade. Ideal para desenvolvedores que querem escrever código limpo, desacoplado e pronto para crescer junto com o negócio. Estas anotações eu realizei após assistir ao módulo 14.° “NET8 — Usando Clean Archtecture” do curso “O essencial para criar APIs da Web na plataforma .NET” do professor José Carlos Macoratti

    Press enter or click to view image in full size

    image

    Entendendo o Problema

    Quando criamos um projeto, vemos que sempre virá com um template padrão. Se observarmos esse template, veremos que todos os projetos apresentarão uma arquitetura monolítica com um único projeto.

    Sendo assim, a criação de pastas é o meio que utilizamos para organizar todo o nosso código.

    O que traz as seguintes consequencias: forte acoplamento entre os componentes do projeto, forte acoplamento a UI (Interface do Usuário), acesso aos dados e a ferramentas ORM

    Dessa forma, as manipulações feitas dentro destes componentes irá afetar a aplicação como um todo, assim deixando o sistema dificil de se manter e quase impossível de se sustentar.

    Criando a Solução

    Para resolver esse cenário e permitir que a aplicação evolua sem se tornar caótica com o tempo, surgiu o conceito de Clean Architecture, ou Arquitetura Limpa. A ideia principal é separar a aplicação em camadas independentes, deixando cada parte responsável apenas por uma função específica. Com isso, conseguimos reduzir o acoplamento e tornar o código mais fácil de manter, testar e escalar.

    Nesta solução iremos estruturar o projeto em quatro camadas principais. Cada uma delas possui um papel claro dentro da aplicação.

    Domain

    Onde ficam as regras de negócio. Aqui estão as entidades, os serviços de domínio e as interfaces que descrevem o comportamento central do sistema. Esta camada representa o coração da aplicação e não deve depender de nada externo.

    Application

    Responsável por orquestrar os casos de uso da aplicação. Aqui ficam as regras de aplicação, DTOs, validações e interfaces que descrevem como o domínio deve ser acessado. Ela depende apenas da camada de domínio.

    Infrastructure

    Implementa as interfaces definidas nas camadas superiores. Neste ponto ficam os repositórios, contexto de banco de dados, serviços externos e qualquer tecnologia que permita a execução real dos comportamentos. A ideia é que esta camada possa ser trocada sem afetar o núcleo da aplicação.

    API

    Responsável pela interface com o usuário ou com outros sistemas. Aqui construímos os controladores, endpoints e configurações de entrada da aplicação. Esta camada recebe as requisições, chama os casos de uso na camada de Application e retorna as respostas.

    Ao criar essa estrutura, garantimos que o domínio permaneça isolado e protegido, permitindo evoluções constantes sem comprometer toda a base do projeto. Esse padrão ajuda tanto em aplicações pequenas quanto em soluções corporativas de grande porte, pois fornece uma base sólida e organizada desde o início.

    Características Desejadas

    Há algumas características que desejamos ao escolher essa arquitetura. Ela foi pensada para nos ajudar a construir sistemas robustos, flexíveis e preparados para mudanças constantes no ambiente de desenvolvimento. O objetivo é criar uma base que permita evolução contínua sem comprometer a integridade do projeto.

    Ao adotar a Clean Architecture, buscamos especialmente alcançar:

    Independência da interface de usuário

    A aplicação não deve depender da forma como o usuário interage com ela. Podemos trocar o front end, criar uma aplicação mobile ou até adicionar uma interface via linha de comando sem alterar o núcleo da solução.

    Independência de banco de dados

    O domínio não deve estar amarrado a um banco específico. É possível trabalhar com PostgreSQL, SQL Server, MySQL ou até mesmo trocar para outro mecanismo sem reescrever toda a lógica central.

    Testabilidade elevada

    A separação clara entre as camadas facilita a criação de testes unitários e de integração, permitindo validar regras de negócio sem necessidade de executar toda a aplicação.

    Baixo acoplamento e alta coesão

    Cada camada possui responsabilidades bem definidas, evitando dependências desnecessárias e permitindo que as partes funcionem de modo isolado e organizado.

    Evolução facilitada

    Mudanças podem ocorrer em uma parte do sistema sem obrigar refatorações profundas em outras áreas. Isso aumenta a vida útil do projeto e reduz o custo de manutenção.

    Estrutura da Solução

    Com base nesses princípios, o projeto será reorganizado em cinco camadas separadas, cada uma com uma responsabilidade:

    Domain Entidades, regras de negócio, interfaces

    Application Casos de uso, serviços, mapeamentos, DTOs

    Infrastructure Acesso a dados, contexto, ORM, repositórios

    CrossCutting Configuração de injeção de dependência e serviços compartilhados

    API Endpoints, controllers, filtros e configuração Web API

    O projeto API será o único projeto ASP.NET Core, enquanto os demais serão bibliotecas de classes.

    A transição da estrutura monolítica para a Clean Architecture promove um ambiente mais modular, coeso e preparado para evolução. Esse modelo permite maior flexibilidade tecnológica e facilita a escrita de testes, além de reduzir o acoplamento entre camadas.

    A próxima etapa consistirá na criação prática dessa estrutura, definição de dependências e detalhamento de cada módulo.

    Este conteúdo serve como base conceitual para compreender as motivações e a importância da adoção de uma arquitetura limpa na construção de Web APIs profissionais.

    Estruturação de um Projeto Web API com Clean Architecture

    Esta seção descreve o processo de criação da estrutura de uma solução Web API seguindo os princípios da Clean Architecture. O objetivo consiste em organizar o projeto em camadas independentes, cada uma com responsabilidades específicas, promovendo manutenibilidade, testabilidade e desacoplamento entre as partes do sistema.

    Criação da Solução e Projetos

    1. Criar uma Blank Solution chamada Catálogo no Visual Studio.
    2. Adicionar quatro projetos do tipo Class Library:
    • Catálogo.Domain
    • Catálogo.Application
    • Catálogo.Infrastructure
    • Catálogo.CrossCutting

    3. Adicionar o projeto Catálogo.API, do tipo ASP.NET Core Web API, com suporte a HTTPS e OpenAPI (Swagger) habilitado.

    4. Remover arquivos gerados por padrão que não serão utilizados, como WeatherForecast e o controller gerado automaticamente.

    5. Remover também as classes padrão Class1 criadas nos projetos de biblioteca.

    Ao final deste processo, a solução conterá a base estrutural para distribuição adequada das responsabilidades.

    Definição das Referências entre Projetos

    Com os projetos criados, estabelece-se o fluxo de dependências conforme o princípio de que camadas externas podem depender de camadas internas, mas nunca o contrário:

    Catálogo.Domain → Nenhum

    Catálogo.Application → Domain

    Catálogo.Infrastructure → Domain

    Catálogo.CrossCutting → Domain, Application, Infrastructure

    Catálogo.API → CrossCutting

    Essa configuração garante que o domínio permaneça isolado e seja o núcleo da aplicação, enquanto as demais camadas orbitam ao seu redor.

    A solução final apresenta:

    • Separação entre domínio, aplicação, infraestrutura e API.
    • Fluxo de dependências controlado, conforme boas práticas da Clean Architecture.
    • Base preparada para receber lógica de negócios, regras de aplicação, componentes de infraestrutura e endpoints REST de maneira organizada e escalável.

    A estrutura criada fornece o alicerce necessário para implementar os próximos componentes, como entidades, interfaces, repositórios, serviços, DTOs e configurações de DI, mantendo a integridade arquitetural ao longo do desenvolvimento.

    Organização das Pastas e Responsabilidades por Camada

    Esta seção descreve a criação das pastas dentro de cada projeto da solução, bem como o papel que cada diretório desempenha dentro da arquitetura. O objetivo consiste em consolidar uma estrutura modular, robusta e alinhada aos princípios da Clean Architecture, preservando o isolamento do domínio e garantindo fluxo correto de dependências.

    Projeto Catálogo.Domain

    O projeto Domain representa o núcleo estratégico do sistema. Aqui residem o modelo de domínio, as regras de negócio e os contratos essenciais. Esta camada não referencia nenhuma outra e não possui dependências externas.

    Pastas criadas:

    • Entities
    • Conteúdo: Classes de domínio (por exemplo, Produto, Categoria)
    • Função: Representação do modelo de negócio com estado e comportamento

    Características fundamentais:

    • As entidades devem conter lógica de domínio e validações pertinentes ao negócio.
    • Não utilizar atributos de validação como Data Annotations nesta camada, para evitar acoplamento a frameworks externos.
    • Interfaces de repositório garantem inversão de dependência, permitindo implementação em outro projeto.

    Projeto Catálogo.Application

    Esta camada orquestra regras de aplicação, processa casos de uso e realiza transformações de dados. Ela depende exclusivamente do domínio.

    Pastas criadas:

    • DTOs
    • Função: Objetos de transferência de dados expostos externamente, contendo validações com Data Annotations
    • Interfaces
    • Função: Contratos para serviços de aplicação (casos de uso)
    • Mappings
    • Função: Configurações de mapeamento entre entidades e DTOs
    • Services
    • Função: Implementação das interfaces de aplicação, utilizando o domínio e os repositórios

    Diretrizes importantes:

    • DTOs evitam exposição direta do modelo de domínio.
    • Validações orientadas à entrada de dados são feitas nos DTOs.
    • Casos de uso são implementados nos serviços da camada Application.

    Projeto Catálogo.Infrastructure

    Esta camada implementa detalhes de infraestrutura, especialmente persistência. Ela depende apenas do domínio.

    Pastas criadas:

    • Context
    • Conteúdo: DbContext com EF Core
    • Função: Configuração do contexto e mapeamento base
    • EntityConfigurations
    • Conteúdo: Configurações Fluent API
    • Função: Mapeamento e restrições de banco para as entidades
    • Repositories
    • Conteúdo: Implementação das interfaces de repositório do domínio
    • Função: Persistência e consulta de dados

    Observações técnicas:

    • O mapeamento de entidades com EF Core ocorre aqui, não no domínio.
    • Esta camada contém referências a packages ORM, APIs externas ou serviços de persistência.

    Projeto Catálogo.CrossCutting

    Responsável por recursos transversais, como injeção de dependências e serviços compartilhados.

    Pasta criada:

    • IoC
    • Função: Registro de serviços, repositórios e contexto

    Objetivo:

    • Centralizar configuração e exposição de serviços para outras camadas, principalmente a API.

    Projeto Catálogo.API

    Camada de apresentação que expõe a API Web. Depende apenas do CrossCutting.

    Pasta já existente:

    • Controllers
    • Função: Endpoints públicos para interação com consumidores

    Conformidade Arquitetural

    A estrutura resultante respeita os princípios fundamentais:

    • Domínio sem dependências externas.
    • Aplicação depende apenas do domínio.
    • Infraestrutura depende apenas do domínio.
    • API depende apenas de CrossCutting.
    • Fluxo de dependências flui do mais externo para o mais interno.

    Este arranjo garante autonomia ao núcleo do domínio e flexibilidade para substituição ou evolução de infraestrutura, serviços e camadas externas.

    A estrutura pode ser expandida de acordo com a complexidade do projeto, sempre observando isolamento do núcleo e fluxo de dependência direcionado de fora para dentro.

    Essa organização reforça integridade arquitetural, testabilidade e baixo acoplamento, fornecendo base sólida para o desenvolvimento seguro e escalável do sistema.

    A Implementação em cada projeto da solução

    Agora será apresentada a implementação realizada em cada projeto da solução, começando pelo projeto Domain.

    Projeto Domain

    Na pasta Entities foram criadas as classes CategoriaProduto e Entity. As entidades Categoria e Produto representam o modelo de domínio. A classe Categoria utiliza o modificador sealed, impedindo herança e garantindo isolamento. Foram definidos dois construtores: um para criação regular de objetos e outro para inserção inicial de dados (seed). As propriedades possuem private set, assegurando que valores sejam atribuídos apenas via construtor.

    Foi implementado o método ValidateDomain, responsável pela validação das regras de domínio. Para suportar essa lógica, foi criada a classe DomainExceptionValidation, na pasta Validation, herdando de Exception. A entidade Produto segue o mesmo padrão, com construtor, propriedades privadas, método de atualização e validação. A classe Entity é abstrata e oferece a propriedade Id, herdada por todas as entidades.

    Na pasta Interfaces foram criadas as interfaces ICategoriaRepository e IProdutoRepository, que definem os contratos para acesso ao domínio. Essas interfaces serão implementadas na camada Infrastructure, garantindo baixo acoplamento. O projeto Domain não possui dependências externas.

    Projeto Application

    O projeto Application referencia o Domain e utiliza AutoMapper. Na pasta Dto foram criadas CategoriaDto e ProdutoDto, responsáveis por expor apenas os dados necessários ao consumidor da API, preservando o domínio. Aqui são utilizadas anotações de validação (DataAnnotations), reforçando que validações estruturais ficam nesta camada, enquanto validações de regra de negócio residem no domínio.

    Na pasta Mapping foi definida a configuração AutoMapper para mapear entidades para DTOs e vice-versa. Na pasta Interfaces foram criadas ICategoriaService e IProdutoService, expondo métodos que retornam e recebem DTOs. A implementação dessas interfaces foi feita na pasta Services, onde o repositório e o AutoMapper são injetados via construtor. O serviço executa operações no repositório, mapeia os resultados e retorna DTOs.

    Projeto Infrastructure

    O projeto Infrastructure referencia o Domain e inclui os pacotes do Entity Framework Core e o provedor Pomelo para MySQL. Na pasta Context foi criado ApplicationDbContext, herdando de DbContext, com definição de DbSet para as entidades. No método OnModelCreating são aplicadas as configurações definidas na pasta EntitiesConfiguration.

    Foram criadas classes de configuração para Categoria e Produto, utilizando Fluent API. Foram definidas constraints e, no caso de Categoria, foi utilizado HasData para inserção inicial. As migrações do EF Core são geradas nesta camada por se tratar da abordagem Code First. Se necessário, esta camada também seria responsável por configurações adicionais, como Identity.

    Os repositórios concretos são implementados nesta camada, atendendo aos contratos definidos no Domain.

    Projeto CrossCutting

    O projeto CrossCutting referencia Application, Domain e Infrastructure. Nele foi criada a pasta IOC com uma classe de extensão para IServiceCollection, registrando contexto, provedores, serviços, repositórios e AutoMapper no container de injeção de dependência nativo do ASP.NET Core.

    Projeto API

    Por fim, no projeto API, a classe Startup utiliza o método de extensão configurado no CrossCutting para registrar todas as dependências. Na pasta Controllers foram definidos CategoriasController e ProdutosController, injetando os serviços da camada Application e retornando DTOs em todas as respostas.

    Com a solução executada, a interface do Swagger exibe os endpoints para categorias e produtos, permitindo testes como listagem geral, busca por ID e validação das entidades populadas. A arquitetura demonstra aderência aos princípios da Clean Architecture, separando claramente responsabilidades, facilitando manutenção, testabilidade, evolução e troca de tecnologias, como o provedor de banco de dados.

    Compartir
    Recomendado para ti
    Binance - Blockchain Developer with Solidity 2025
    Neo4J - Análise de Dados com Grafos
    Cognizant - Mobile Developer
    Comentarios (0)