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 sln

Esta 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 Guid em vez de int para maior flexibilidade e compatibilidade em sistemas distribuídos

  • Abstração: A classe é marcada como abstract, prevenindo instanciação direta

  • Localizaçã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: Product herda de Entity, obtendo automaticamente a propriedade Id

  • Propriedade Simples: A propriedade Title é definida com inicialização padrão para prevenir valores null

  • Localizaçã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:

  1. Testabilidade: O domínio pode ser testado sem dependências complexas

  2. Portabilidade: Pode ser reutilizado em diferentes contextos (web, desktop, mobile)

  3. Longevidade: Independência de tecnologias específicas que podem se tornar obsoletas

  4. 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 : Entity garante que apenas tipos derivados de Entity possam ser utilizados

  • Interface 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: IProductRepository está especificamente associada à entidade Product

  • Operaçõ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-bloqueantes

  • Suporte a CancellationToken: Permite o cancelamento cooperativo de operações longas

  • Retorno Nullable: Product? indica que o método pode retornar null se 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:

  1. Inversão de Dependência (DIP): O domínio define os contratos (interfaces), e a infraestrutura os implementa

  2. Independência Tecnológica: O domínio não depende de como os dados são persistidos

  3. Testabilidade: Testes de domínio podem utilizar implementações simuladas (mocks/fakes)

  4. 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

Aspecto
Abordagem Tradicional
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

  1. Desacoplamento Máximo: O domínio é completamente isolado de detalhes de implementação

  2. Foco nas Regras de Negócio: A complexidade técnica fica confinada às camadas externas

  3. Facilidade de Teste: Testes de unidade podem ser escritos sem configuração complexa

  4. Longevidade Arquitetural: O domínio permanece válido mesmo com mudanças tecnológicas

  5. 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

  1. Dependency Inversion Principle (DIP): Interfaces no domínio, implementações na infraestrutura

  2. Interface Segregation Principle (ISP): Interfaces específicas para cada necessidade

  3. Single Responsibility Principle (SRP): Cada projeto tem uma responsabilidade bem definida

  4. Separation of Concerns: Domínio, aplicação e infraestrutura são claramente separados

Recomendações para Implementações Reais

  1. Considerar Value Objects: Para tipos complexos que não possuem identidade própria

  2. Implementar Aggregates: Agrupar entidades relacionadas com uma raiz de agregado

  3. Adicionar Domain Events: Para comunicação entre diferentes partes do domínio

  4. Utilizar Specifications: Para encapsular regras de consulta reutilizáveis

  5. 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