Domínios e Repositórios
Arquitetura Limpa
Criação da Solução e Estrutura de Projetos
Uma nova solução é iniciada para demonstrar a implementação do Repository Pattern dentro do contexto da Arquitetura Limpa. A estrutura multi-projeto é estabelecida para separar claramente as responsabilidades conforme os princípios da Clean Architecture.
Inicialização da Solução
A solução é criada utilizando o comando:
dotnet new slnEsta ação gera o arquivo CleanArchitectureStore.sln, servindo como contêiner para todos os projetos que serão adicionados à estrutura.
Projeto de Domínio (Domain Layer)
O projeto de domínio é criado como uma biblioteca de classes independente:
dotnet new classlib -o CleanArchitectureStore.Domain
dotnet sln add .\CleanArchitectureStore.Domain\O projeto CleanArchitectureStore.Domain constitui o núcleo da aplicação, contendo as regras de negócio e entidades fundamentais, sem dependências externas de frameworks ou infraestrutura.
Modelagem das Entidades de Domínio
Entidade Base Abstrata
Uma classe base abstrata Entity é criada para fornecer propriedades comuns a todas as entidades do domínio:
Características da entidade base:
Identificador Universal: Utilização de
Guidem vez deintpara maior flexibilidade e compatibilidade em sistemas distribuídosAbstração: A classe é marcada como
abstract, prevenindo instanciação diretaLocalização Estratégica: Armazenada no diretório
Abstractions, indicando seu propósito fundamental
Entidade Específica: Product
A entidade Product é definida como uma especialização da entidade base:
Considerações de design:
Herança Estrutural:
Productherda deEntity, obtendo automaticamente a propriedadeIdPropriedade Simples: A propriedade
Titleé definida com inicialização padrão para prevenir valoresnullLocalização Organizacional: Armazenada no diretório
Entities, agrupando logicamente as entidades do domínio
Nota sobre Modelagem de Domínio Rico: Em implementações completas de Domain-Driven Design (DDD), as entidades frequentemente possuem:
Construtores privados ou protegidos
Métodos de fábrica para criação controlada
Validações de invariantes no próprio domínio
Comportamentos encapsulados em métodos
Propriedades com setters privados para garantir integridade
Para fins didáticos focados no Repository Pattern, utiliza-se uma abordagem simplificada com propriedades públicas, conhecida como "entidade anêmica".
CLR Puro no Domínio
Conceito de CLR Puro
O termo "CLR puro" refere-se à prática de manter a camada de domínio completamente independente de frameworks e bibliotecas externas, utilizando apenas recursos nativos da Common Language Runtime do .NET.
Benefícios da abordagem CLR puro:
Testabilidade: O domínio pode ser testado sem dependências complexas
Portabilidade: Pode ser reutilizado em diferentes contextos (web, desktop, mobile)
Longevidade: Independência de tecnologias específicas que podem se tornar obsoletas
Clareza Arquitetural: Separação explícita entre regras de negócio e detalhes de implementação
Exemplos do que é evitado no domínio:
Referências ao Entity Framework
Atributos de mapeamento de dados (
[Key],[Column], etc.)Bibliotecas de serialização específicas
Dependências de infraestrutura (HTTP, banco de dados, sistemas de arquivos)
Definição de Repositórios no Domínio
Interface Base de Repositório
A interface genérica IRepository<T> é definida na camada de domínio, estabelecendo o contrato básico para operações de persistência:
Análise da interface base:
Restrição de Tipo:
where T : Entitygarante que apenas tipos derivados deEntitypossam ser utilizadosInterface Vazia: Serve como marcador (marker interface) para agrupar semanticamente repositórios relacionados
Separação de Responsabilidades: Define o "o quê" sem especificar o "como" da implementação
Interface Específica de Repositório
Para cada entidade do domínio, uma interface específica é criada, estendendo a interface base:
Características da implementação:
Especialização por Entidade:
IProductRepositoryestá especificamente associada à entidadeProductOperações Específicas do Domínio: Apenas métodos necessários para o domínio são definidos (não necessariamente um CRUD completo)
Abordagem Assíncrona: Utilização de
Task<T>para operações não-bloqueantesSuporte a CancellationToken: Permite o cancelamento cooperativo de operações longas
Retorno Nullable:
Product?indica que o método pode retornarnullse o recurso não for encontrado
Princípios de Dependência na Arquitetura Limpa
Hierarquia de Dependência
Na Clean Architecture, as dependências seguem uma direção específica:
Regra fundamental: Camadas internas (Domínio) não conhecem camadas externas (Infraestrutura).
Justificativa para Interfaces no Domínio
A colocação das interfaces de repositório no projeto de domínio é intencional e alinhada com os princípios da Arquitetura Limpa:
Inversão de Dependência (DIP): O domínio define os contratos (interfaces), e a infraestrutura os implementa
Independência Tecnológica: O domínio não depende de como os dados são persistidos
Testabilidade: Testes de domínio podem utilizar implementações simuladas (mocks/fakes)
Flexibilidade: A implementação de persistência pode ser alterada sem impactar o domínio
Estrutura Completa do Projeto de Domínio
A organização final do projeto CleanArchitectureStore.Domain reflete os princípios da Clean Architecture:
Análise do Arquivo de Projeto
O arquivo .csproj do domínio deve manter-se minimalista:
Ausência de dependências externas: Nenhuma referência a pacotes como Microsoft.EntityFrameworkCore é adicionada, mantendo o domínio independente.
Comparação com Abordagens Tradicionais
Arquitetura Tradicional vs. Clean Architecture
Localização das Interfaces
Junto com implementações
No domínio (camada mais interna)
Dependências do Domínio
Referencia infraestrutura
Nenhuma dependência externa
Testabilidade
Requer infraestrutura real
Testável com objetos simulados
Flexibilidade
Acoplada à tecnologia
Independente de tecnologia
Benefícios da Abordagem Adotada
Desacoplamento Máximo: O domínio é completamente isolado de detalhes de implementação
Foco nas Regras de Negócio: A complexidade técnica fica confinada às camadas externas
Facilidade de Teste: Testes de unidade podem ser escritos sem configuração complexa
Longevidade Arquitetural: O domínio permanece válido mesmo com mudanças tecnológicas
Clareza de Responsabilidades: Cada camada tem um propósito bem definido
Próximas Etapas na Implementação
Com o domínio estabelecido, a implementação prossegue com a criação das camadas restantes:
Camada de Aplicação (Application Layer)
Responsável por:
Casos de uso e serviços de aplicação
Orquestração de operações do domínio
Validações de entrada
Mapeamento entre DTOs e entidades
Camada de Infraestrutura (Infrastructure Layer)
Responsável por:
Implementações concretas dos repositórios
Configuração do Entity Framework
Migrações de banco de dados
Integrações com serviços externos
Camada de Apresentação (Presentation Layer)
Responsável por:
Controllers/Endpoints da API
Autenticação e autorização
Documentação da API
Tratamento de erros HTTP
Boas Práticas e Considerações Finais
Princípios Aplicados
Dependency Inversion Principle (DIP): Interfaces no domínio, implementações na infraestrutura
Interface Segregation Principle (ISP): Interfaces específicas para cada necessidade
Single Responsibility Principle (SRP): Cada projeto tem uma responsabilidade bem definida
Separation of Concerns: Domínio, aplicação e infraestrutura são claramente separados
Recomendações para Implementações Reais
Considerar Value Objects: Para tipos complexos que não possuem identidade própria
Implementar Aggregates: Agrupar entidades relacionadas com uma raiz de agregado
Adicionar Domain Events: Para comunicação entre diferentes partes do domínio
Utilizar Specifications: Para encapsular regras de consulta reutilizáveis
Implementar Unit of Work: Para gerenciar transações complexas
Verificação de Independência do Domínio
Para validar que o domínio permanece independente, pode-se executar:
O resultado deve mostrar zero pacotes ou apenas dependências fundamentais do .NET, confirmando que o domínio está livre de acoplamento tecnológico.
Esta estrutura estabelece uma base sólida para o desenvolvimento de sistemas complexos que podem evoluir mantendo a integridade das regras de negócio no núcleo da aplicação, enquanto permitem flexibilidade na escolha e mudança de tecnologias de suporte.
Atualizado