Repositórios
Definição
Seção intitulada “Definição”Para Eric Evans, o Repositório fornece a ilusão de uma coleção em memória de todos os objetos de um tipo de agregado. Encapsula o mecanismo de armazenamento e recuperação, mantendo o domínio ignorante de SQL, ORM ou qualquer detalhe de infraestrutura.
Ponto crucial de arquitetura: a interface do repositório é declarada no domínio, expressa na Linguagem Ubíqua (buscarPorCliente, salvar). A implementação vive na infraestrutura. Isso concretiza o DIP - Dependency Inversion Principle (ver SOLID): o domínio depende de abstração, e a infra depende do domínio.
Repositório vs. DAO
Seção intitulada “Repositório vs. DAO”| Critério | Repositório (DDD) | DAO |
|---|---|---|
| Granularidade | Um por raiz de agregado | Frequentemente um por tabela |
| Abstração | Coleção de agregados | Operações CRUD sobre linhas |
| Linguagem | Ubíqua, orientada ao domínio | Técnica, orientada a dados |
| Retorno | Agregados completos e consistentes | Registros/DTOs |
O problema resolvido
Seção intitulada “O problema resolvido”Mantém o domínio puro e testável: regras de negócio não conhecem persistência. Permite trocar Postgres por Mongo, ou mockar a persistência em testes, sem tocar no modelo. É o pilar que viabiliza a Arquitetura Hexagonal e a Clean Architecture.
Regras de design
Seção intitulada “Regras de design”- Um repositório por raiz de agregado. Não crie repositório para entidades internas.
- Interface no domínio, implementação na infra. O domínio nunca importa
jakarta.persistencenem Spring Data. - Trabalhe com agregados inteiros e consistentes, não com fragmentos.
- Consultas complexas de leitura podem escapar do repositório de escrita (ver CQRS); force menos o agregado no lado de leitura.
Exemplo em Java + Spring
Seção intitulada “Exemplo em Java + Spring”Interface no domínio (Port), entidade JPA separada do modelo de domínio, e implementação como Adapter.
package com.loja.pedido.domain;
import java.util.Optional;
public interface PedidoRepository {
void salvar(Pedido pedido);
Optional<Pedido> porId(PedidoId id);
void remover(PedidoId id);}package com.loja.pedido.infrastructure.persistence;
import jakarta.persistence.Column;import jakarta.persistence.Entity;import jakarta.persistence.Id;import jakarta.persistence.Table;import java.math.BigDecimal;import java.util.UUID;
@Entity@Table(name = "pedido")public class PedidoJpaEntity {
@Id private UUID id;
@Column(name = "cliente_id") private UUID clienteId;
@Column(name = "status") private String status;
@Column(name = "total") private BigDecimal total;
protected PedidoJpaEntity() { }
public PedidoJpaEntity(UUID id, UUID clienteId, String status, BigDecimal total) { this.id = id; this.clienteId = clienteId; this.status = status; this.total = total; }
public UUID getId() { return id; }
public UUID getClienteId() { return clienteId; }
public String getStatus() { return status; }
public BigDecimal getTotal() { return total; }}package com.loja.pedido.infrastructure.persistence;
import java.util.UUID;import org.springframework.data.jpa.repository.JpaRepository;
public interface PedidoJpaRepository extends JpaRepository<PedidoJpaEntity, UUID> {}package com.loja.pedido.infrastructure.persistence;
import com.loja.pedido.domain.Pedido;import com.loja.pedido.domain.PedidoId;import com.loja.pedido.domain.PedidoRepository;import java.util.Optional;import org.springframework.stereotype.Repository;
@Repositorypublic class PedidoRepositoryImpl implements PedidoRepository {
private final PedidoJpaRepository jpa; private final PedidoMapper mapper;
public PedidoRepositoryImpl(PedidoJpaRepository jpa, PedidoMapper mapper) { this.jpa = jpa; this.mapper = mapper; }
@Override public void salvar(Pedido pedido) { jpa.save(mapper.paraJpa(pedido)); }
@Override public Optional<Pedido> porId(PedidoId id) { return jpa.findById(id.valor()).map(mapper::paraDominio); }
@Override public void remover(PedidoId id) { jpa.deleteById(id.valor()); }}graph LR
subgraph Dominio["Domínio (núcleo)"]
Svc["Use Case / Domain Service"]
Port["interface PedidoRepository"]
end
subgraph Infra["Infraestrutura (adapter)"]
Impl["PedidoRepositoryImpl"]
Jpa["PedidoJpaRepository (Spring Data)"]
Db[("Banco de Dados")]
end
Svc --> Port
Impl -.implementa.-> Port
Impl --> Jpa --> Db
Anti-padrões e erros comuns
Seção intitulada “Anti-padrões e erros comuns”- Vazamento de infraestrutura no domínio: anotar o modelo de domínio com
@Entityou fazer o domínio importar Spring Data. - Repositório por tabela/entidade interna: deve haver um por raiz de agregado, não por
ItemPedido. - Expor
JpaRepositorycomo se fosse o repositório de domínio: acopla o domínio ao Spring Data e ao paginado/CRUD genérico. - Retornar fragmentos inconsistentes: devolver metade de um agregado, violando invariantes ao salvar.
Relações
Seção intitulada “Relações”- Persiste Agregados (um por raiz)
- Contraste com DAO - Data Access Object (acesso orientado a tabela, do PoEAA)
- É um Port implementado por um Adapter na Arquitetura Hexagonal
- Depende de DIP - Dependency Inversion Principle e A Regra da Dependência
- Bloco de Design Estratégico e Tático e parte de Domain-Driven Design
- Voltar para Home
Perguntas de revisão
Seção intitulada “Perguntas de revisão”1. Onde fica a interface do repositório e onde fica a implementação?
Resposta
A interface no domínio (é um Port, expresso na linguagem ubíqua) e a implementação na infraestrutura (um Adapter com Spring Data). Isso concretiza o DIP - Dependency Inversion Principle.
2. Quantos repositórios deve haver por agregado?
Resposta
Um por raiz de agregado. Entidades internas (como ItemPedido) não têm repositório próprio; são acessadas via a raiz.
3. Como o Repositório difere de um DAO?
Resposta
O Repositório é uma coleção de agregados inteiros e consistentes, orientado à linguagem do domínio. O DAO costuma ser por tabela, orientado a CRUD e a dados, sem noção de agregado.
4. Por que separar PedidoJpaEntity do Pedido de domínio?
Resposta
Para evitar vazamento de infraestrutura no domínio: o modelo de domínio fica livre de anotações de persistência, e o mapeamento acontece no adapter, preservando a pureza e a testabilidade do núcleo.