Domain Model e Banco de dados

Caros, ultimamente tenho lido bastante sobre Domain Model e gostei bastante do assunto, pois ele retrata exatamente como um desenvolvedor deve pensar quando desenvolve uma aplicação que retratar o mais próximo possível da vida real.

A minha dúvida é a seguinte; Eu possuo meu Domain Model onde devo ter apenas as minhas regras de domínio, por exemplo, eu tenho uma classe “Carrinho” e uma “Produto”. Lógicamente eu preciso adicionar produtos ao meu carrinho usando o método “adicionarProduto()”:

Obs: To chamando o carrinho estático somente para encurtar o código.

Até ai tudo beleza, o que ta confundindo minha cabeça é como os dados de carrinho e produto vão parar no banco de dados, visto que no meu domínio eu devo ter uma implementação própria do funcionamento da aplicação. Até onde eu entendi é como se fosse uma API com classes e métodos referentes ao fluxo do processo. O que - seguindo este conceito - não é certo fazer inserção de dados na tabela atraves das classes de domínio( por exemplo, se eu chamar Carrinho.fecharCompra() dentro dele não seria certo conter código de inserção na tabela ).

Se eu estiver errado, por favor, me corrijam. Mas como eu vou fazer essa inserção de dados mantendo toda a minha arquitetura bem dividida?( Controle da aplicação, visões, Modelo do Banco e Modelo de Domínio )

A resposta para essa pergunta está na utilização de Repositories, que são os locais onde seus objetos de domínio são armazenados e recuperados. O ideal é que os nomes dos repositórios façam parte da linguagem compartilhada entre a equipe de desenvolvedores e os especialistas nas regras de negócio. Por exemplo, em um sistema de votação, uma Urna é um repositório natural de Votos.

Pelo que eu entendi de Repositories, eles funcionam como uma fachada para a camada de persistência. Por exemplo, um DAO pode ser a implementação de um Repository.

Hmm… certo… acho que entendi!

Mas as classes que implementam o DAO devem ser chamadas no controle da minha aplicação?

Por que assim para cada objeto Voto eu teria que ter um VotoDAO para ele e depois teria que inseri-lo (Voto) em Urna quem tambem teria que ter um UrnaDAO!

O que mais ta pegando é o fato que não consigo pensar no contexto da Web utilizando MVC. Nesse caso o meu domínio seriam meus models?

No caso da Urna, você teria algo assim:

public interface Urna { // Adiciona um novo voto void depositar(Voto v); }
Seu modelo não sabe de nenhum detalhe da camada de persistência. Só sabe que existe uma Urna onde Votos podem ser depositados.
Porém, a implementação dessa Urna poderia ser a UrnaDAO, mencionada por você. Ela, por sua vez, poderia usar um VotoDAO para gravar os votos no banco.

MVC para Web é ainda um pouco nebuloso para mim, mas até agora eu sempre usei como Model as classes de domínio.

Ou ainda a Urna poderia ter uma referencia para UrnaRepository, e essa é implementada por UrnaHibernateDao.

A ideia é mesmo tirar qualquer interface/classe de infraestrutura do meio do seu domain model! Deixar tudo bem limpinho, em especial nas assinaturas de metodo (interface).

Se voce pensar bem, isso segue exatamente o principio definido pelo Gang of Four de “programe voltado a interface e nao a implementacao”. Quando for modelar, esqueça daos, utils, controllers, converters, etc. Isso é implementacao quando pensado num nivel mais macro…

Andei fuçando bastante e achei um pdf falando sobre isso. Nele há uma explicação sobre Domain Model e ele fala que para inserirmos esses dados no banco podemos utilizar recursos como Data Mapping ou Active Records, onde o primeiro é mais recomendado para aplicações de lógica complexa e o segundo para aplicações de Lógica simples.

No caso do Active Records é exatamente como voce usa, o domínio é justamente os models que você cria.

Mas com essas explicações consegui entender melhor o funcionamento. Agora é mãos à obra e ler sobre DDD.

Valeu!

Sim, mas veja que a Urna é um repositório natural, e dependendo dos requisitos, a Urna em si nem precisa ser persistida, e sim os Votos contidos na mesma. Além disso, é muito mais vantajoso utilizar um termo contido na linguagem comum entre desenvolvedores e especialistas em negócio do que um nome de padrão; seu modelo fica muito mais expressivo.

Pode colocar aqui o endereço do PDF nao?? Achei o assunto bem interessante e tambem sou cheio de duvidas nele!

Veja que implementar o padrão Active Record e usar camada de negócios como Model são coisas distintas. Não falei que utilizava Active Record.
Uma vez eu vi um usuário no fórum falando que Model é camada de negócios + camada de persistência + banco de dados. Faz todo o sentido.

Ah, em tempo: no exemplo que você deu no início, o carrinho de compras, conceitualmente, é um repositório de produtos. Tinha esquecido de comentar isso.

Veja que implementar o padrão Active Record e usar camada de negócios como Model são coisas distintas. Não falei que utilizava Active Record.
Uma vez eu vi um usuário no fórum falando que Model é camada de negócios + camada de persistência + banco de dados. Faz todo o sentido.

Ah, em tempo: no exemplo que você deu no início, o carrinho de compras, conceitualmente, é um repositório de produtos. Tinha esquecido de comentar isso.[/quote]

Hm… certo… então o que seria implementar o Active Record? Eu devo estar errado, mas entendi que no Active Record os Models seriam as próprias camadas de negócios e seriam responsaveis por “jogar” os dados no banco, assim cada Model conteria tambem métodos insert(), update(), delete() e find(), alem de métodos referentes a camada de negócios. É isso mesmo?

No caso do Repository nunca ouvi falar, mas vou fuçar atras pra saber como posso implementar!

Aqui vai: http://www.fe.up.pt/si/conteudos_service.conteudos_cont?pct_id=16833&pv_cod=26xraFgb5Ykp

Entendo o que você está querendo dizer, mas creio que você está usando as palavras erradas. Como assim, "os Models seriam as próprias camadas de negócio?"
DAO ( Data Mapper ) e Active Record são dois padrões utilizados para persistência. Enquanto o Data Mapper permite que o seu Domain Model nada saiba sobre lógica de persistência, o Active Record “funde” a camada de persistência com a camada de negócios, fazendo com que uma entidade do seu modelo saiba como se persistir no banco.

Exemplos:

// Data Mapper Entidade e = new Entidade(); DAO entidadeDAO = new EntidadeDAO(); entidadeDAO.save(entidade);

// Active Record Entidade e = new Entidade(); e.save();

Você precisa ler o livro Domain-Driven Design, de Eric Evans. É bom também dar uma olhada no artigo do Phillip Calçado na revista Mundo Java nº 17. E nesse post do GUJ há uma excelente discussão sobre Repositories.

Por favor, ignore isso que eu falei :oops:
Carrinho de compras não precisa ser necessariamente um repositório… É apenas um objeto para armazenamento temporário dos produtos selecionados pelo cliente.

[quote=brunoviana]Caros, ultimamente tenho lido bastante sobre Domain Model e gostei bastante do assunto, pois ele retrata exatamente como um desenvolvedor deve pensar quando desenvolve uma aplicação que retratar o mais próximo possível da vida real.

A minha dúvida é a seguinte; Eu possuo meu Domain Model onde devo ter apenas as minhas regras de domínio, por exemplo, eu tenho uma classe “Carrinho” e uma “Produto”. Lógicamente eu preciso adicionar produtos ao meu carrinho usando o método “adicionarProduto()”:

Obs: To chamando o carrinho estático somente para encurtar o código.

Até ai tudo beleza, o que ta confundindo minha cabeça é como os dados de carrinho e produto vão parar no banco de dados,(…)[/quote]

Parabens por ter escolhindo um exemplo tão simples. Algo que sempre faltou no topicos de DDD.
Ok, vc tem o seu carrinho e o seu produto e adicona um no outro. (provavelmente adciona através de um terceiro objeto ProdutoItem)

Persistencia é delegada ao Repositorio. Vc faria Repositorio.store(produto) ou Repositorio.store(carrinho)
Para ler os produtos vc usaria Repositorio.retriveList(Produto.class, query) , etc… [ou usando a mesma convensão de usar classes estáticas , mas seriam objetos)
Entenda que Repositorio é um conceito. O como ele executa aqueles métodos é irrelevante para o dominio. Ele pode persistir num banco como simplesmente usar um HashMap que vai embora quando a aplicação cai.

O eventos do sistema são tratados por serviços. Então vc teria um serviço


Invoice invoice = InvoiceService.makeInvoiceFor(carrinho, customer, date);

Vc tem agora o pedido. Que pode pode apresentar ou usuário e depois quando ele aceitar fazer


 InvoiceService.closeDeal(invoice invoice, paymentInformation);

onde paymentInformation contém informações de parcelamento , cartão de credito etc. Coisas necessárias a finalizar um pedido.

Provavelmento o closeDeal criaria mudaria o status do invoice , criaria lançamentos financeiros e ordem de movimento de estoque usando outros serviços do dominio. Em algum ponto um serviço de dominio produtiza dados ou receberá dados que ele sabe que precisa ser persistidos. Ele usará os repositorios necessários para isso.

O detalhe final é que nem todas as entidades têm repositorios, apenas as que são necessárias persistir. Por exemplo, Invoice pode não ser pesistido. Se a pessoas aborta o processo acabou. Da proxima vez ela criará outro invoice a partir do carrinho. Quando fizer o closeDeal vc pode criar outra entidade (por exemplo Sell) que será persistida. Neste caso Invoice é uma entidade mas não tem um repositorio associado.

Moral da historia: nem todas as entidades se trasnforma em tabelas no banco. Apenas as que forem persistidas.
Normalmente o banco é desenhado primeiro, em DDD não. Por isso ele consegue ser mais eficiente e claro e mais leve na hora de persistir. O que manda são as regras do dominio e do negocio e não o modelo de banco.