Gente, pensando em DDD, é correto instanciar uma classe de domínio na camada de visão?
Pensei nisso porque pode haver, pensando em CRUD, uma Entity que tenha muitos atributos e seria melhor instanciar e popular na visão e então passar ao Service que orquestra a persistência. Criar um método com dezenas de parâmetros não parece adequado.
E da mesma forma se for uma atualização, popular o objeto com os atributos de atualização na visão.
Se isso for incorreto em Domain-Driven Design, qual seria a melhor saída?
[quote=BiraBoy]Gente, pensando em DDD, é correto instanciar uma classe de domínio na camada de visão?
Pensei nisso porque pode haver, pensando em CRUD, uma Entity que tenha muitos atributos e seria melhor instanciar e popular na visão e então passar ao Service que orquestra a persistência. Criar um método com dezenas de parâmetros não parece adequado.
E da mesma forma se for uma atualização, popular o objeto com os atributos de atualização na visão.
Se isso for incorreto em Domain-Driven Design, qual seria a melhor saída?[/quote]
Fala BiraBoy,
Essa é uma questão que surgiu recentemente no meu trabalho. A minha opinião é a seguinte:
Não diria que é incorreto do ponto de vista DDD mas acredito que o melhor é, sempre que for possível, manter os metodos do Service da aplicação com parametros de tipos básicos. Se você tem um entity com muitos atributos talvez esteja na hora de quenrar esse objeto de domínio em outros formando um agregado. Isso é correto do ponto de vista DDD!
Outra coisa, cuidado ao pensar em CRUD e DDD ao mesmo tempo!
[quote=cmoscoso] A minha opinião é a seguinte:
Não diria que é incorreto do ponto de vista DDD mas acredito que o melhor é, sempre que for possível, manter os metodos do Service da aplicação com parametros de tipos básicos.
[/quote]
[quote=rodrigoy][quote=cmoscoso] A minha opinião é a seguinte:
Não diria que é incorreto do ponto de vista DDD mas acredito que o melhor é, sempre que for possível, manter os metodos do Service da aplicação com parametros de tipos básicos.
[/quote]
O que ganhamos com isso?[/quote]
Se você tem uma facade na aplicacao vai ganhar uma interface simples do ponto de vista do cliente
long criaUsuario(String name);
long criaUsuario(Usuario usuario);
Pra quem está programando o cliente qual das duas opcoes lhe parece melhor? Afinal se aplicacao orquestra deixemos ela orquestrar!
Repito, não é errado do ponto de vista das regras de negocio, o que esta vazando na opcao 2 provavelmente é regra de aplicacao. Mas daí pra vazar regras de negócio é um pulo.
Quanto a quantidade de parametros necessarios para persistir um entity…
Sera mesmo que todos esses parametros sao necessários para apenas persistir o entity, ou seja, cria-lo no seu sistema? (geralmente vc precisa apenas de identificadores pra isso)
Deixando o CRUD de lado… Ou são todos esses parametros necessários para a execucao de alguma regra de negocio que tal entity participa?
Neste ultimo caso, modele o objeto de dominio em questao considerando a possibilidade dele existir no sistema mas nao estar pronto para alguma atividade de negocio relacionada. Tipo um usuario existe no sistema mas não pode fazer nada ainda pq nao preencheu um cadastro detalhado.
No caso de uma atualizacao nao vejo problemas em passar o proprio objeto de dominio a ser atualizado. Neste caso ele já é conhecido pelo usuarioda interface.
A assinatura de um método em DDD tem que dizer seu propósito, independente da infraestrura.
Se para isso for necessário passar um objeto populado que assim seja. Se para o negócio é mais claro tipo simples, tudo bem também.
Só não concordo em pensar:
… quem armazena informações no DDD são os Repositories. Eles não armazenam ou coletam identificadores, eles trabalham com Entities.
[quote=Lezinho]… quem armazena informações no DDD são os Repositories. Eles não armazenam ou coletam identificadores, eles trabalham com Entities.
[/quote]
Como estamos falando de camada de visão, abstraia repositorios por um momento…
Na opcao 1 do exemplo que usei o cliente do service da aplicacao passa apenas um identificador do entity a ser criado e persistido (o nome do usuario).
Camada de visão e aplicação não é domínio, portanto de nada tem haver com DDD. Pode usar EntityManager, Session, SQL direto na página via JSTL … Eu quando tenho CRUD simples sem intervenção do negócio não escrevo uma linha de código java, utilizo o DAO declarativo do Seam.
Um dos problemas de utilizar a opção 1 é que ela deixa explícitas todas as propriedades que um usuário tem, de modo qua assinatura do método tende a ficar muito grande e horrível de usar. Além disso, você perde totalmente a idéia de orientação a objetos, onde os atributos de determinada entidade do mundo real ficam em objetos, e não soltas em forma de parâmetros.
Os objetos de domínio de sua aplicação geralmente transitam entre todas as camadas.
public class Usuario {
private long id;
private String name;
private Date nascimetno;
private char sexo;
...
...
...
// construtor e metodos de usuario
}
public class AppService {
public long criaUsuario(String name) {
Usuario usuario = new Usuario(name);
// código que persiste usuario e retorna id
}
}
Onde tem “parâmetros soltos”?
Se você quiser instanciar e então passar o objeto de dominio para o método de AppService você estará fortalecendo a camada de visão, nada a ver com perder OO uma vez que não estamos falando da camada de domínio. Se isso é bom ou não, depende de cada caso, mas lembre-se que Smart UI é anti-pattern.
Não é realista isso que vc falou.
Se eu persisto a entidade eu quero que todos os campos - inclusive os que não são entidade e inclusive os que dizem respeito a VO e/ou outras entidades sejam persistidos junto.
Se vc não fizer isso, vc terá que reler o objeto entity do banco ( que virá apenas com os identificadores) , copiar os campos que quer persistir e persistir de novo. Ups! a persistencia só guarda os identificadores, logo nunca ira guardas os dados. O que vc escreveu não é realista.
A persistencia persiste todos os dados da entidade. Se eles estão vazios, paciencia. Mas a persistencia é controlada pela validação dos campos e alteração dos valores, e não apenas pela ordem do programador de persistir.
Do ponto de vista do DDD é errado usar partições da entidade quando o processo diz respeito a ela.
Voce pode achar que pode ter um façade cuja assinatura seja 1
Mas isso apenas encapsula a criação do objeto usuário que tem que ser possivel recriar apenas com aquelas informações. Mas o façade faz parte da camada da aplicação onde o DDD não mete o nariz.
Mas na camada de dominio usar (1) é errado , já que isso seria o mesmo que usar 2 DTO que é exactamente o que DDD não quer.
Portanto (1) está certo na camada de aplicação e errado na de dominio. (2) pode estar certo em qualquer camada. Pode estar certo ou errado dependendo do isolamento que vc quer. Se vc quiser isolar os objetos do dominio, então estão certo. Mas isolar as entidades rápidamente degenera em usar assinaturas imensas onde todos os campos são passados . Isso é errado.
public class Usuario {
private long id;
private String name;
private Date nascimetno;
private char sexo;
...
...
...
// construtor e metodos de usuario
}
public class AppService {
public long criaUsuario(String name) {
Usuario usuario = new Usuario(name);
// código que persiste usuario e retorna id
}
}
Onde tem “parâmetros soltos”?
Se você quiser instanciar e então passar o objeto de dominio para o método de AppService você estará fortalecendo a camada de visão, nada a ver com perder OO uma vez que não estamos falando da camada de domínio.
[/quote]
A camada de aplicação não pode persistir o entity. O que ela faz é adicionar o entity no repositorio. ( o repositorio irá persistir se, e apenas se, for necessário)
Vamos pensar que o usuario tem obrigatoriamente de ter uma password além de username e um perfil. Perfil é uma outra entidade.
(usuário não tem genero nem data de nascimento porque pode ser outro sistema)
A tela teria um campo para cada um com o perfil sendo um combobox.
Se eu fizer o que está sugerindo o sistema vai dar erro porque não é aceitável criar um usuário apenas com o nome. Ai eu tenho que passar o nome, a pass e o perfil no método para que ele crie o objeto internamente.
Isso é verboraico e rápidamente degenera para o uso de DTO ( por exemplo, passar um map com os valores)
Não é isto que queremos.
Depende do caso, existem diferentes “smarts” na ui.
Se a UI é MVC o model tem toda a liberdade de conversar com o resto do sistema usar as entities para isso.
A conversão entre os campos da tela e o entity é feita no proprio model ( que por def é um objeto de dominio) e portanto não ha nenhum problema nem ncessidade de usar façades com metodos com um monte de parametros.
Resumindo, não defensável que uma aplicação baseada em DDD use metodos com parametros em vez das entities, já que fazer isso é usar um mecanismo de DTO que é contrário a DDD.
Você não vai persistir apenas o login do usuário: vai querer diversas outras informações, como nome, email, etc. Vai passar tudo isso por parâmetro, como String e inteiros individuais? O seu código ficará horrível, com uma imensidão de parâmetros que são todos relacionados a um usuário, contudo, independentes do objeto usuário (ou seja, “soltos”).
Contudo, pelo que vi a sua intençao é criar o usuário apenas com o essencial, no caso de seu exemplo o identificador login, e depois popular as demais informações, certo? Qual é o sentido prático disso? Tudo isso para não permitir que sua entidade seja construída na camada de visão? Qual é o problema disso? Você está realmente disposto a fazer um acesso adicional desnecessário ao mecanismo de persistência?
Uma vez vi um código em que as informações iam e viam da visão para as demais camadas através mapas e coleções de tipos primitivos. Vi um caso de uma coleção de mapas, rsrs. O desenvolvedor argumentou que isso reduzia tremendamente o acoplamento, pois as classes de visão não conheciam as entidades do domínio.
Eu não vejo problema nenhum na camada de visão estar acoplada ao domain. Na verdade o problema é quando o domain está acoplado à camada de visão. Se você estiver usando um framework que faça o bind recusivo pra você, o framework já fará isso pra você quando receber os parametros. Um framework que faz isso é o Struts2. Ele tem uma interface que se chama ModelDriven e que permite que a Action seja tratada como um wrapper para uma classe de Domain. Algo assim:
[code]
public class SuaAction implements ModelDriven {
private Usuario user;
public Usuario getModel(){
return user != null ? user : new Usuario()
}
}[/code]
Dessa forma quando sua action receber um parametro nomeado “nome” ela executará
[quote=Lezinho]Camada de visão e aplicação não é domínio, portanto de nada tem haver com DDD. Pode usar EntityManager, Session, SQL direto na página via JSTL … Eu quando tenho CRUD simples sem intervenção do negócio não escrevo uma linha de código java, utilizo o DAO declarativo do Seam.
Mas tudo isso, de nada tem haver com DDD … [2][/quote]
Isso não acaba gerando regras de negócio fora do domain? Acho que o domain é reponsável por tratar e resolver todo o problema do sistema, e o CRUD está incluso como problema do sistema.
[quote=feliperod][quote=Lezinho]Camada de visão e aplicação não é domínio, portanto de nada tem haver com DDD. Pode usar EntityManager, Session, SQL direto na página via JSTL … Eu quando tenho CRUD simples sem intervenção do negócio não escrevo uma linha de código java, utilizo o DAO declarativo do Seam.
Mas tudo isso, de nada tem haver com DDD … [2][/quote]
Isso não acaba gerando regras de negócio fora do domain? Acho que o domain é reponsável por tratar e resolver todo o problema do sistema, e o CRUD está incluso como problema do sistema.[/quote]
Se vc preenche um formulário, clica no botão e os dados são persistidos e validados sem você precisar programar, não existe mal que isso fique em um framework (acredite, isso é possível com frameworks como o Jboss Seam). Não é preciso DDD para isso pois Domain Driven é para construir o Design do código, mas já que você não precisou codificar, portanto não precisou do design.
Se seu CRUD ficar mais complexo, então neste momento você constrói classes para isso com DDD… mas note que você não precisou disto no primeiro momento e pode ser que nao precise para o sistema inteiro. Programação incremental é uma ótima aliada a metodologias ágeis e não fere preceitos de design.
[quote=Lezinho]
Se vc preenche um formulário, clica no botão e os dados são persistidos e validados sem você precisar programar, não existe mal que isso fique em um framework (acredite, isso é possível com frameworks como o Jboss Seam). Não é preciso DDD para isso pois Domain Driven é para construir o Design do código, mas já que você não precisou codificar, portanto não precisou do design.
Se seu CRUD ficar mais complexo, então neste momento você constrói classes para isso com DDD… mas note que você não precisou disto no primeiro momento e pode ser que nao precise para o sistema inteiro. Programação incremental é uma ótima aliada a metodologias ágeis e não fere preceitos de design.[/quote]
Concordo com você em relação à aplicação ser simples o suficiente pra não usar DDD. Mas numa aplicação complexa, onde já estamos usando DDD, deixar o CRUD fora do domain não seria bobagem? O CRUD não acrescenta muito código ao domain.
E no caso de não utilizar o Seam? Mesmo caso. Você não terá um framework para isso.
Outra situação é se o domain é o mesmo para várias interfaces, então é bom que seu domain faça o trabalho todo do sistema, deixando só a persistência e a visão para ser trocada.
[quote]
Concordo com você em relação à aplicação ser simples o suficiente pra não usar DDD. Mas numa aplicação complexa, onde já estamos usando DDD, deixar o CRUD fora do domain não seria bobagem?[/quote]
Mas eu não me referi a aplicações simples, nem para aplicações que não usam DDD. Me referi a frameworks que lhe dão subsídios para que você não perca tempo com o arroz e feijão.
Você pode ter complexas aplicações modeladas em DDD e mesmo assim utilizar recursos prontos de terceiros que lhe dão produtividade e não impactam em sua modelagem. CRUD é CRUD, se alguém me oferece isso de graça, eu não quero gastar nenhuma linha de código para isso… SE precisar e QUANDO precisar especializar este processo, isso será feito sem impacto algum. Este processo pode ser simples ao Domínio, mas é muito rotineiro o que acaba impactando na produtividade.
Obviamente, caso não trabalhe com algum framework que ofereça estes serviços, a melhor saída é se manter com a própria modelagem… ou desenvolver seu próprio framework caseiro que cuide disso.