Repository -DDD

Em uma discussão com uma amigo ele me perguntou pq eu não posso ter a implementação do repositório dentro do próprio dominio e eu expliquei que iria contra a idéia de que o dominio nao pode depender de nenhum framework ou projeto, mas ele colocou da seguinte forma:

A interface ou classe abstrada do repository pertence ao domínio até ai ok e pq eu não posso ter também a implementação do repositório lá, sendo que o meu repositório receberia via IoC meu DAO ou meu objeto de contexto do ORM. A dúvida ficou, será que alguém tem alguma colocação interessante a fazer sobre isso?

Oi Diego, td bem?

A questão não é nem que você não possa, dentro dos suas entidades e value objects utilizar algum framework. Se for necessário para a tarefa, não tem o pq nao utilizar. O problema é o acoplamento gerado entre essas classes, diminuindo a testabilidade.

A ideia pelo que entendi que vc quer fazer é no fundo um Active Record, onde o próprio objeto saberia como se persistir.

Recentemente, o Philip Calçado postou no blog dele umas dicas sobre repositories, questão de nomenclaturas e como melhor ajustá-lo ao domínio da sua app. Vale dar uma lida lá e posta aqui depois o que você acha para continuarmos a discussão.

Olá Diego.

Acho que o repository não deve habitar o meu domínio, exceto se eu precisar executar alguma regra de negócio específica que implica alguma consulta na minha base.
Porque, querendo ou não, o repository na prática, ele não só traz o que “preciso” mas também contém toda a responsabilidade de conectividade com banco, por exemplo, montagem de query e tal, e acho que ao crescer o projeto vai bagunçar um pouco o meu domínio…

veja abaixo um exemplo prático, onde preciso cadastrar um usuário com email único, ai antes valido o email dele, se está formatado e se já existe um email cadastrado na base, se for td OK eu peço ao dao genérico (meu repository) para persistir:

OBS: esse exemplo usa VRaptor e Hibernate, mas qualquer dúvida posta aqui:

@Resource
public class UserController {
    
    private final Result result;
    private final UserDao dao;
    private final EmailValidator emailValidator;

    public UserController(Result result, UserDao dao, EmailValidator emailValidator) {
        this.result = result;
        this.dao = dao;
        this.emailValidator = emailValidator;
    }

    @Post
    public void create(User user) {
       // se a validação do "register" estiver OK ele chama o dao para salvar, do contrário não faz nada o.O
        if (user.register(dao, emailValidator)) {
          dao.save(user);
          result.include("msg", "Usuario salvo com sucesso");
        }
    }

}
@Entity
public class User extends EntityModelAb {

    @Id    
    @GeneratedValue
    private Long id;
    private String email;

    @Overread
    public Long getId() {
        return this.id;
    }

    public String getEmail() {
        return this.email;
    }

// regra de negócio
    public boolean register(UserDao dao, EmaiLValidator emailValidator) {
        return emailValidator.validate(this.email) && dao.isUniqueEmail(this.email));
    }

}
@Component
public class UserDao {

    private final Repository<User> repository;

    public UserDao(Repository<User> repository) {
        this.repository = repository;
    }

    public boolean isUniqueEmail(String email) {
        Query query = this.repository.getQuery("select us.email from user us where :email = email");
        query.setParameter("email", email);
        return (query.getResult() == null || query.getResult().isEmpty()) ? true: false;
    }
}
public interface Repository<T> {
    // CRUD methods

    Query getQuery(String queryStr);
}
@Component
public class GenericDao<? extends EntityModelAb> implements Repository<T> {
    // JPA, Hibernate, Objectfy, ...
}
@MappedSuperClass
public abstract class EntityModelAb {
    public abstract Long getId();
}

espero ter ajudado.
sugiro que faça esse mesmo questionamento no www.tectura.com.br pois la o foco maior é arquitetura, daí mais gente pode entrar na discussão!
Se postar la me avisa que vou postar esse mesmo tópico la, afinal tbm quero participar dessa discussão, que é mto interessante, rs

abraço!

A questão na verdade é: Eu posso ter a implementação do meu repositório dentro do meu domínio, assim como tenho seu contrato? Uma vez que eu vá injetar no meu repositório o meu DAO ou meu objeto de contexto no caso de um ORM como Hibernate. Seria o mesmo que ter a class UserDao no meu dominio… Isso ao meu ver não cria acoplamento já que a UserDAO recebeu por IoC o objeto que de fato vai consultar e persistir dados pra mim. Eu não trabalho desta forma mais em uma discussão fui questionado sobre isso e a minha respota se resumia ao fato do acoplamento e também dos termos usados já que no dominio temos que usar termos de dominio “ubiquitous language” e também o lance da dependência do domínio. Mais não sei se isso é suficiente pra justificar já que com a injeção do objeto de persistência muito disso acaba.

Você quer dizer a nivel “fisico” das classes/pacotes referentes a implementação ?

Se for isso, não há certo e errado pois, teoricamente, a implementação não afeta seu dominio, visto que ele é injetado via IoC e a dependencia que esta lá é a interface. Mas, um bom exercicio para separar as coisas é: há imports das classes de implementação dentro das classes de domínio? Não? Então deve estar num pacote diferente! :slight_smile:

[quote=alabeduarte]Olá Diego. ... ...

abraço!
[/quote]

Neste caso não é o Repository que deveria acessar o DAO ou então o DAO Implementar o Repository?