Consegui evitar os VOs e BOs?

O dominio é constituido de 3 “seres” : Entidades , Objetos de Valor (Value Objects , aka VO , mas não é a mesma coisa que DTO) e Serviços.

Entidades é tudo o que tem identidade (chave).
Objetos de Valor são classes auxiliares que agrupam muitos campos, como endereço, por exemplo
Serviços é aquilo que manipula as entidades para atingir um objectivo no dominio.

CRUD é um tipo de serviço com 2 operações que serve para alterar o universo de instancias de entidades e/ou objetos de valor. Mas um sistema real tem mais doque isso. Imagine a classica transação bancária. Vc tem conta (entidade) e dinheiro (objeto de valor) e quer fazer uma trasnferencia (entidade) . Vc cria um serviço que dada duas contas e um valor, cria uma transferencia. Poderiamos dizer que isto é uma operação CRUD especial , mas é mais do que isso, porque o lançamento da transação é um evento que provoca um monte de outras coisas.

Portanto, se a “função salvar transação” precisa de uma logica suplementar antes de persistir a trnasação, isso fica dentro do Serviço.

Atualizando o seu modelo teriamos

[code]
//Meu servlet ou algo do genero
public class Beta {

//Como eu deveria gravar um objeto usando DDD
private void DDD(){
	Pessoa pessoa = new Pessoa();
	pessoa.setIdade(20);
	
          CRUDService  service = ... 
          service.novaPessoa(pessoa);
}

}

public class CRUDService {

      public novaPessoa (Pessoa p){
            Repository.store (pessoa);
       }

}

}[/code]

Poderiamos argumentar que o serviço não deveria receber entidades, mas isso é outra conversa que não interessa agora.

Quanto a fazer uma classe Repository com métodos estáticos e genericos:

[code]public class Repository {

DAO dao =…

public static void store (Object entity ){
dao.store(entity);
}

}[/code]

Eu acho que vc fragmentou a objeto de dominio novamente, o seu servico esta se comportando como uma classe de negocio, vc so mudou de nome.

Lendo uma parte do artigo novamente eu frizo o seguinte:
Um modelo rico traduz o mundo real para software da maneira mais próxima possível, ao utilizar classes de dados separadas das classes de lógica esta vantagem é simplesmente jogada fora. No mundo real não existe lógica de um lado e dados de outro, ambos combinados forma um conceito.

Ainda podemos analizar a seguinte imagem

Aqui nos vemos claramente que o Servlet nao tem acesso ao repositorio, se vc criar essa classe de servico, ela sera dependente dos objetos de valor e das entidades, e o servlet tera novamente que popular um objeto(VO) e depois acessar a logica de negocio(BO) do objeto em outro objeto

Eu ainda frizo mais uma parte do artigo:
Num modelo anêmico existem objetos que parecem modelar a realidade, como os VOs, mas na verdade não utilizam a característica básica de objetos que é manter dados e comportamento num mesmo componente: o tão falado objeto!

Observacoes:
Eu nao quero ficar defendendo o artigo, pois acho ele confuso e sem exemplos, mas prestando mmmuuuiitta atenção acho que ele esclarece tudo.
Agora uma coisa que eu nao faço é ficar indicando livros, mandar ler denovo o artigo, tenha mais aulas de OO, leia tudo denovo ou coisas do genero, eu acho que citar partes importantes para tentar esclarecer um assunto nao tem nada de errado, e depois quem estiver lendo esses posts e quiser conhecer como tudo funcione ae sim acho que esta na hora de comprar um livro, ter aulas e etc.

ronildobraga [quote]
Eu acho que vc fragmentou a objeto de dominio novamente, o seu servico esta se comportando como uma classe de negocio, vc so mudou de nome.

Lendo uma parte do artigo novamente eu frizo o seguinte:
Um modelo rico traduz o mundo real para software da maneira mais próxima possível, ao utilizar classes de dados separadas das classes de lógica esta vantagem é simplesmente jogada fora. No mundo real não existe lógica de um lado e dados de outro, ambos combinados forma um conceito.
[/quote]

Na verdade Ronildo, o que o Sergio tentou explicar é que os objetos de domínio necessitam de alguém para coordenar a execução de algumas tarefas.
Para isto faz se necessário um Service.
Imagine o exemplo da transação bancária.

Um objeto Conta, representa a instancia de uma Conta em um banco. Onde ficaria o Serviço de transferência entre 2 contas ?
Em um Service.

Ele vai instanciar as 2 contas e passar o valor de uma pra outra.
Observe que não estamos colocando responsabilidades referentes ao objeto Conta no Service. Ele apenas organiza os passos da execução e delega as responsabilidades para os objetos de domínios.

[quote=GutomCosta]
Para isto faz se necessário um Service.
Imagine o exemplo da transação bancária.

Um objeto Conta, representa a instancia de uma Conta em um banco. Onde ficaria o Serviço de transferência entre 2 contas ?
Em um Service.

Ele vai instanciar as 2 contas e passar o valor de uma pra outra.
Observe que não estamos colocando responsabilidades referentes ao objeto Conta no Service. Ele apenas organiza os passos da execução e delega as responsabilidades para os objetos de domínios.[/quote]

Não entendi direito. O Service neste caso poderia normalment eapenas estimular os objetos, ou seja em vez de:

public void transfere(Conta a, Conta b, int quantia){

 a.diminui(quantia);
 b.aumenta(quantia);

}

podemos ter:

public void transfere(Conta a, Conta b, int quantia){

 a.transfere(quantia, b);

}

[quote=ronildobraga][quote=sergiotaborda]
Portanto, se a “função salvar transação” precisa de uma logica suplementar antes de persistir a trnasação, isso fica dentro do Serviço.

Poderiamos argumentar que o serviço não deveria receber entidades, mas isso é outra conversa que não interessa agora.
[/quote]
Eu acho que vc fragmentou a objeto de dominio novamente, o seu servico esta se comportando como uma classe de negocio, vc so mudou de nome.
.[/quote]

Como o GutomCosta já elucidou não foi isso que eu fiz.
Vc precisa de um terceiro “ser” que manipula os objetos do dominio. Porquê?
Imagine um banco verdadeiro no tempo em que não havia computadores.
Contas eram apenas livros e transferencias eram apenas numeros escritos nesses livros. Se as contas eram livros (objectos inanimados) e transferencias era a escrita de numeros quem escrevia os numeros nos livros ? O escriturário. Ele prestava um serviço importante. Ele tinha que garantir que eram colocados os numeros certos nas contas certas e que a operação era atómica (ou o dinheiro era transferido ou não era. sem mais hipoteses) Quando a operação não era atomica ou as contas não eram as que deveriam acontecia um erro.

Em software. Conta é um entidade, o dinheiro é um valor e o responsável por manipular tudo isto é o serviço. Repare que serviço é ainda da camada de dominio. Ele é o cara que entende o que ha a ser feito, e sabe como fazer. No softtware o serviço é responsável por iniciar uma transação (aqui transação JTA) alterar os valores nas contas e fazer o commit. Repare que esta operação não pode ser responsabilidade da conta porque a conta não sabe o que uma transacção entre contas é ( da mesma forma que um livro não sabe o que um escriturário é).
Mas tem mais detalhes … na realidade uma transacção bancária não é uma operação entre contas é :

  1. verificação de saldo disponivel
  2. verificação de limite
  3. o lançamento atómico de dois movimentos pareados (partidas obradas) um numa e um noutra.
    Que em codigo seria mais ou menso assim

transfere (Conta a , Conta b , Dinheiro m ) throws TransferException{

 JTATransaction T = ...
     try {
T.begin();

       // a conta tem salso suficiente para pagar ?
    if (a.limiteSaque () < m){
 // o limite depende do saldo e do credito do cliente, que por sua vez 
//depende de outras coisas. Tudo isso é responsabilidade do objeto Conta
           throw TransferException("Salso insuficiente");
    }

    

    Transferencia t = new Transferencia (a,b,m , Data.hoje());

     t.executa();
     
    Repository.store(t);

    T.commit();
 } catch (TransferException e) {
          T.rollback();
           throw e;
 } 

}


Tranferencia {

   public void executa (){
             // tira de a
             MovimentoConta ma = new MovimentoConta(a, m.times(-1) ,b , data);
             // da a b
             MovimentoConta mb = new MovimentoConta(b, m, a , data);
         
              Repository.store (ma);
               Repository.store (mb);
   }
}

A aplicação (a camada de aplicação) chamará o serviço passando os parametros necessários e nunca verá a logica do dominio. Ou seja, o servlet passa a responsabilidade ao serviço (da mesma forma que o atendente do balcão passava ao escriturário)

A “logica de negocio” está na realidade distribuida entre os objectos do dominio , cada uma coma a sua responsabilidade e não mais do que essa.
É preciso deixar claro que o Serviço não é apenas uma mera fachada, ele é o cara que o resto do mundo vê (é o atendente no balcão)
Objetos como Transferencia , MovimentoConta tb existem e é necessário ter um historio deles. Eles são entidades, possuem dados , estado, mas possuem tb tomadas de decisão. Por outro lado, eles existem porque ha que separar a responsabilidade dentro das proprias entidades do dominio.
Conta é apenas um agrupador, o saldo é alterado pelos movimentos de conta , que forma o extrato da conta e portanto têm datas associadas a eles. E cada movimento na sua conta causa um movimento numa outra conta de alguém (partida-dobrada). Se continuar esmiuçando o problema encontrará muito mais entidades necessárias. Se pensar en outros dominios - controle de estoque , por exemplo - verá que algumas entidades se repetem, mas têm papeis diferentes. E tudo isso é a complexidade do dominio que a DDD visa simplificar ao abusar das capacidades oferecidas pela OO.


Quanto ao ActiveRecord. Muito simples: na prática não funciona. A razão é simples: quebra de responsabilidade. Os livros não se guardam a si mesmos nas estantes : os objetos de dominio tb não se devem guardar a si mesmos.
Se tentar usar ActiveRecord de uma forma mais gerenciável ,como vc fez, delegando ao repositorio dentro de pessoa, vai acabar com um monte de cdogio repetido, desnecessário, pois chamar o repositorio directamente dá no mesmo e na prática tem mais vantagem (como dilimitar melhor o controlo o commit e o roolbak da persitencia, etc…)

O ActiveRecord é um padrão mencionado em muitos lugares e tem o seu lugar ao sol em determinados usos (DataSet é um exemplo). Mas refere-se a record (registro) e em DDD uma entidade não é vista como um registro porque a persitência é abstraida e portanto existe uma incompatibilidade natural entre ActiveRecord e DDD.

[quote=sergiotaborda]
O ActiveRecord é um padrão mencionado em muitos lugares e tem o seu lugar ao sol em determinados usos (DataSet é um exemplo). Mas refere-se a record (registro) e em DDD uma entidade não é vista como um registro porque a persitência é abstraida e portanto existe uma incompatibilidade natural entre ActiveRecord e DDD. [/quote]

Huh?! :shock:

Dá para explicar isso? Aliás, você realmente entendeu o que você acabou de escrever ou você acredita de fato nisso que você falou?

[quote=sergiotaborda][quote=ronildobraga][quote=sergiotaborda]
Portanto, se a “função salvar transação” precisa de uma logica suplementar antes de persistir a trnasação, isso fica dentro do Serviço.

Poderiamos argumentar que o serviço não deveria receber entidades, mas isso é outra conversa que não interessa agora.
[/quote]
Eu acho que vc fragmentou a objeto de dominio novamente, o seu servico esta se comportando como uma classe de negocio, vc so mudou de nome.
.[/quote]

Como o GutomCosta já elucidou não foi isso que eu fiz.
Vc precisa de um terceiro “ser” que manipula os objetos do dominio. Porquê?
Imagine um banco verdadeiro no tempo em que não havia computadores.
Contas eram apenas livros e transferencias eram apenas numeros escritos nesses livros. Se as contas eram livros (objectos inanimados) e transferencias era a escrita de numeros quem escrevia os numeros nos livros ? O escriturário. Ele prestava um serviço importante. Ele tinha que garantir que eram colocados os numeros certos nas contas certas e que a operação era atómica (ou o dinheiro era transferido ou não era. sem mais hipoteses) Quando a operação não era atomica ou as contas não eram as que deveriam acontecia um erro.

Em software. Conta é um entidade, o dinheiro é um valor e o responsável por manipular tudo isto é o serviço. Repare que serviço é ainda da camada de dominio. Ele é o cara que entende o que ha a ser feito, e sabe como fazer. No softtware o serviço é responsável por iniciar uma transação (aqui transação JTA) alterar os valores nas contas e fazer o commit. Repare que esta operação não pode ser responsabilidade da conta porque a conta não sabe o que uma transacção entre contas é ( da mesma forma que um livro não sabe o que um escriturário é).
Mas tem mais detalhes … na realidade uma transacção bancária não é uma operação entre contas é :

  1. verificação de saldo disponivel
  2. verificação de limite
  3. o lançamento atómico de dois movimentos pareados (partidas obradas) um numa e um noutra.
    Que em codigo seria mais ou menso assim

transfere (Conta a , Conta b , Dinheiro m ) throws TransferException{

 JTATransaction T = ...
     try {
T.begin();

       // a conta tem salso suficiente para pagar ?
    if (a.limiteSaque () < m){
 // o limite depende do saldo e do credito do cliente, que por sua vez 
//depende de outras coisas. Tudo isso é responsabilidade do objeto Conta
           throw TransferException("Salso insuficiente");
    }

    

    Transferencia t = new Transferencia (a,b,m , Data.hoje());

     t.executa();
     
    Repository.store(t);

    T.commit();
 } catch (TransferException e) {
          T.rollback();
           throw e;
 } 

}


Tranferencia {

   public void executa (){
             // tira de a
             MovimentoConta ma = new MovimentoConta(a, m.times(-1) ,b , data);
             // da a b
             MovimentoConta mb = new MovimentoConta(b, m, a , data);
         
              Repository.store (ma);
               Repository.store (mb);
   }
}

A aplicação (a camada de aplicação) chamará o serviço passando os parametros necessários e nunca verá a logica do dominio. Ou seja, o servlet passa a responsabilidade ao serviço (da mesma forma que o atendente do balcão passava ao escriturário)

A “logica de negocio” está na realidade distribuida entre os objectos do dominio , cada uma coma a sua responsabilidade e não mais do que essa.
É preciso deixar claro que o Serviço não é apenas uma mera fachada, ele é o cara que o resto do mundo vê (é o atendente no balcão)
Objetos como Transferencia , MovimentoConta tb existem e é necessário ter um historio deles. Eles são entidades, possuem dados , estado, mas possuem tb tomadas de decisão. Por outro lado, eles existem porque ha que separar a responsabilidade dentro das proprias entidades do dominio.
Conta é apenas um agrupador, o saldo é alterado pelos movimentos de conta , que forma o extrato da conta e portanto têm datas associadas a eles. E cada movimento na sua conta causa um movimento numa outra conta de alguém (partida-dobrada). Se continuar esmiuçando o problema encontrará muito mais entidades necessárias. Se pensar en outros dominios - controle de estoque , por exemplo - verá que algumas entidades se repetem, mas têm papeis diferentes. E tudo isso é a complexidade do dominio que a DDD visa simplificar ao abusar das capacidades oferecidas pela OO.


Quanto ao ActiveRecord. Muito simples: na prática não funciona. A razão é simples: quebra de responsabilidade. Os livros não se guardam a si mesmos nas estantes : os objetos de dominio tb não se devem guardar a si mesmos.
Se tentar usar ActiveRecord de uma forma mais gerenciável ,como vc fez, delegando ao repositorio dentro de pessoa, vai acabar com um monte de cdogio repetido, desnecessário, pois chamar o repositorio directamente dá no mesmo e na prática tem mais vantagem (como dilimitar melhor o controlo o commit e o roolbak da persitencia, etc…)

O ActiveRecord é um padrão mencionado em muitos lugares e tem o seu lugar ao sol em determinados usos (DataSet é um exemplo). Mas refere-se a record (registro) e em DDD uma entidade não é vista como um registro porque a persitência é abstraida e portanto existe uma incompatibilidade natural entre ActiveRecord e DDD. [/quote]

É preciso tomar muito cuidado com analogias, justamente para evitar erros assim. Um modelo OO é justamente isso, um modelo do mundo real com uma finalidade específica e não uma representação fiel. E uma aplicação é um modelo da realidade da mesma maneira que um mapa é um modelo da superfície terrestre. Em um mapa países diferentes são pintados em cores diferentes, porque a eficiência do mapa enquanto modelo da realidade é função direta do quanto ele atende o requisito original (identificar claramente fronteiras entre países), mesmo assim, no mundo real, não conheci ainda nenhum país roxo. Da mesma maneira, em uma aplicação Orientada a Objeto, as atribuições de responsabilidades e os papéis exercidos por cada classe não visam a uma “cópia” do mundo real, mas à obediência à uma série de princípios fundamentais que tem finalidades específicas muito concretas de engenharia. Então, pode ser ridículo no mundo real que uma conta corrente “credite-se um DOC”, mas pode fazer todo o sentido do mundo isso (conta::recebe_doc) em uma aplicação OO, uma vez que Conta é o Information Expert definitivo quando se trata de receber um DOC. De saída, eu ganho em coesão, e também diminuo o acoplamento, o que não é o caso do seu código, coisa que podemos comprovar facilmente ao ver que seria muito difícil escrever Unit Tests para seu exemplo. (Aliás, isso é outra vantagem de TDD, a dificuldade em escrever testes é sempre um sinal de que nosso design poderia ser melhorado).
Outro ponto é que você confunde Serviço com Facade. Embora possam parecer coisas similares, não são. Um Facade expõe um interface simplificada para um subsistema complexo, mas ainda expõe operações em termos de objetos nativos de uma aplicação (por exemplo, se eu faço um Facade para JavaMail, eu tenho uma interface com parâmetros e retornos que ainda são tipos pertencentes ao namespace original de java mail). Já um serviço expõe uma operação de um processo de negócios desacoplando as duas pontas. Por exemplo, se eu tenho um serviço de consulta de crédito, a interface desse serviço deverá ser genérica o suficiente para poder ser acessada por qualquer cliente que tenha acesso apenas a definição do meu serviço, sem a necessidade de ter conhecimento da estrutura interna da minha aplicação. Em outros termos, eu não preciso importar um jar do correio para acessar o serviço de CEP. Mas no seu exemplo, nem mesmo Facade o seu objeto transferência consegue ser, ele é apenas um método disfarçado de objeto, tire o construtor e o método execute do seu objeto Transferência e coloque um método estático no lugar e não vai ter diferença alguma entre as duas versões, o que demonstra de maneira inequívoca o caráter procedural do seu modelo.
Não vou nem comentar ainda a mistura de código de transação com código de negócios. Também é lamentável que em pleno 2007 ainda tenha gente que use controle de transação de maneira programática e não declarativa, isso realmente me dá muito desgosto.
Sinceramente, acho que você deveria ler o livro do Evans, e o Object Design da Wirfs-Brock. Depois de ler os dois, leia Refactorings do Fowler pra consertar esse seu código aí em cima.

Cordialmente,
Marcos Eliziário

Eu recebi uma mensagem privada do Phillip e peço desculpas publicamente pela mensagem se referindo a ele. Eu e o Phillip nao somos amigos e nao nos conhecemos e por isso nao tenho direito de fazer qualquer comentario relacionado a ele.

Com relação as criticas do artigo, eu espero que ele possa possa receber elas de boa vontade.
 Eu acho confuso pelos motivos:
 1) Ele nao possui exemplos e peço que observe o texto abaixo, palavras do proprio Martin Fowler em seu artigo sobre IOC

Para ajudar a tornar isso tudo mais concreto, eu usarei um exemplo funcional. Como todos os meus exemplos, este é um daqueles exemplos super-simples; pequeno o bastante para ser irreal, mas o suficiente, espero, para que se possa visualizar o que está ocorrendo sem cair na complexidade de um exemplo real

 2) O assunto do artigo esta fragmentado em dois artigos, se vcs perceberem no começo do post eu adicionei os dois artigos.

 3)  A conclusão nao da uma solução, a conclusao abordou que o problema do modelo anemico ocorreu devido ao EJB 2, e isso foi devido a pessoas nao conhecerem a tecnologia.

 4) Peço que olhe o artigo do Martin Fowler retratando o mecanismo de IOC, vc verá os seguintes topicos: Componentes e Serviços, Um Exemplo Simples, Inversão de Controle, Decidindo qual opção usar, Mais algumas questões, Pensamentos Conclusivos, Revisões Significantes.

Espero que tenham entendido que nao tenho nada pessoal contra o Phillip, pois seus artigos é o motivo da discussão desse e demais posts, porem so acho que os artigos podem ser revisados, assim como todo bom Editor faz.
Se a comunidade inteira entendeu claramente os artigos sem qualquer duvida, peço que ignorem esse post e nao facam comentarios

sergiotaborda,

O que você acha que há de errado na seguinte abordagem:

public class Conta {
    ...
    public void transferirPara(Conta conta, Double valor) {
        ...
    }
    ....
}

Eu considero isso bem intuitivo e funcional…

Se bem entendo vc está dizendo que Orientação a Objetos não visa ser uma copia do mundo real. É apenas uma tecnologia para satisfazer necessidades em informática.
Eu concordaria consigo de estivessemos falando de classes de alguma biblioteca ou classes de infraestrutura. Não concordo se estivermos falando de classes de dominio.

Se nem as classes de dominio têm que traduzir o mundo real, então nem são necessárias em primeiro lugar. Usemos TO e pronto.

Teoricamente isso poderia ser verdade. Mas num sistema real não é assim. Não ha vantagem nenhuma em deixar a conta ser um information expert quando na realidade ela não o é. A conta é apenas um marcador, uma referencia para vários processos dentro do sistema. Ela não contem nenhuma lógica de processo, ela transporta atributos para os processos tomarem decisões.

Mas imprenga “Conta” com um monte logicas. E quando houver uma alteração a manutenção é dificil.

Cara, é uma exemplo rápido, num contexto de um topico de um forum… não vai querer que eu perca meio dia escrevendo um codigo testável , funcional, etc, etc… só para dar um exemplo. Quem souber programar não terá problemas em criar um codigo verdadeiro, funcional, testável, etc etc… o dilema no topico é o que é DDD , qual a sua vantagem/diferença em relação a DTO+BO e não TDD.
Se TDD o procupa neste contexto, sinta-se à vontade de apresentar um exemplo de DDD devidamente programado, que funcione , e seja testável.

Todos temos problemas… é uma maravilha como neste forum todo o mundo gosta de apontar os problemas dos outros. Vc também tem problemas. Vc não leu o topico inteiro. Se tivesse lido iria ver que escrevi:

Eu sei muito bem a diferença entre Façade e Serviço. Isso não é um problema para mim, e pelo visto para si tb não. Só que eu não quiz poluir a discussão com esse detalhe. Eu sei que ao fazer isso iriam dizer que afinal estaria usando objetos que não são do dominio (aka TO) para passar a informação , e voltariamos ao ponto inicial da conversa.
Como o objetivo é entender DDD e no caso, explicar que DDD incorpora a noção de serviço , além de entidade de objeto de valor.

Mas já que vc levantou a lebre … DDD não vive isolado do mundo, e não é a palavra final em desenvolvimento de software. Para que DDD funcione, ou seja, para que haja um foco efetivo no dominio, tem que existir um infraestrutura que lhe dê suporte. Por exemplo, é chato conectar framewroks web com DDD sem alguém no meio que traduza os requests em chamadas ao serviço do dominio. A camada de aplicação é necessária mesmo com DDD. E é por isso que DDD é muita parra e pouca uva. O assunto era explicar como evitar TO e vc simplesmente acaba de mostrar que DDD não evita TO, aliás necessita deles para serem passados como parametros dos serviços.
Lamento Ronildo, eu não queria desapontá-lo antes do tempo, mas o eliziario não quiz brincar do mesmo jogo, então aqui fica a verdade. DDD não evita TO.

A mim tb me dá desgosto que em pleno 2007 existam pessoas que não sabem ler - anafalbetos funcionais - e ficam fazendo comentários fora de contexto. A mim tb me dá desgosto que em pleno 2007 existam pessoas que não sabem distinguir didática de técnica. E eu poderia lamentar profundamente a existência destas pessoas, não fosse a existencia de outras que são inteligentes o suficiente para não colocar o carro na frente dos bois. É vida é f#$@ por causa dos primeiro, mas vale a pena por causa dos segundos, tal e qual este forum.

Sinceramente acho que a sua opinião é válida e correta, mas fora de contexto. Os seus destaques quanto à incorreta implementação do codigo são absurdos porque estamos num forum e não numa empresa discutindo a melhor implementação. Eles são até válidos , mas vc poderia simplesmente corrigi-los ou indicar os problemas , entendendo que é um exemplo de um forum, e que não eu não sou obrigado a escrever codigo profissional aqui. Ainda para mais com tantos profissionais que sabem escrever codigo tão melhor e dar exemplos tão melhores…
Moral da historia, vc deve primeiro ler o topico inteiro para não assumir coisas demais. Depois não deve assumir que o codigo escrito aqui como exemplo é um codigo funcional e depois não deveria assumir que eu não li os livros que vc leu. Se isto continua vou ter que escrever uma assinatura com todos os livros que já li na vida… e por ultimo, vc deveria ser mais tolerante.

quanto às transações: se vc usar um container e transações declarativas, as responsabilidade da transacção sai do serviço. Por outro lado, existem ocasiões em que a transação é um conceito mais amplo que JTA , ou foge ao seu escopro (como transações aninhadas) e tem que ser controlado pelo serviço - da mesma forma que um escriturário lida com problemas como falta de tinta na caneta… Mas tudo bem, eu entendi o seu recado: 'cuidado com analogias". Ignore-se então a chamada a commit e roolbak.
Seria muito bom para quem está lendo este topico que vc , ou alguem, desse um exemplo real de uso de DDD num sistema que tenham ai funcionando (com os devidos testes de unidades e tudo o mais) para que os novatos não caiam no erro de chamar a transação na mão … (como fizeram na javamagazine deste mês … )

[quote=J2Alex]sergiotaborda,

O que você acha que há de errado na seguinte abordagem:

public class Conta {
    ...
    public void transferirPara(Conta conta, Double valor) {
        ...
    }
    ....
}

Eu considero isso bem intuitivo e funcional…

[/quote]

Otimo. Então use. Não tenho nada contra isso.
O meu argumento é apenas :

  1. Isso não mostra a necessidade dos objetos do tipo serviço que existem em DDD. E era esse o meu ponto.
  2. Isso não funciona num sistema real de banco. (eu já tentei usar)
    2.1.) Não funciona porque não é responsabilidade da conta fazer essa operação. É como usuário.autentica() : não é responsabilidade do usuário se autenticar, é o serviço de segurança que tem que fazer isso.

Mas , como disse, se funciona para si, use.
Me responda apenas:

  1. quem vai invocar conta.transferePara(outra, valor) ?
  2. E,porque não , outra.transfereDe(conta, valor) ?

[quote=sergiotaborda]2) Isso não funciona num sistema real de banco. (eu já tentei usar)
2.1.) Não funciona porque não é responsabilidade da conta fazer essa operação. É como usuário.autentica() : não é responsabilidade do usuário se autenticar, é o serviço de segurança que tem que fazer isso.[/quote]

Não, não considero que seja a mesma coisa que usuário.autentica().

conta.transfere(…) pra mim ter a ver com negócio, autenticação de usuário não.

Me explique melhor porque isso não funciona em um sistema real? Cite argumentos concretos que justifiquem isso, por favor.

[quote=J2Alex][quote=sergiotaborda]2) Isso não funciona num sistema real de banco. (eu já tentei usar)
2.1.) Não funciona porque não é responsabilidade da conta fazer essa operação. É como usuário.autentica() : não é responsabilidade do usuário se autenticar, é o serviço de segurança que tem que fazer isso.[/quote]

Não, não considero que seja a mesma coisa que usuário.autentica().

conta.transfere(…) pra mim ter a ver com negócio, autenticação de usuário não.
[/quote]

Não estamos falando de negocio , estamos falando de dominio.
transfere é uma operação do mesmo dominio de conta, autentica é uma operação do mesmo dominio de usuário. autentica não é uma operação do dominio de conta.

Já expliquei, mas aqui vai de novo. Na realidade uma transferencia não é a alteração do saldo da conta , o qual não é um atributo da conta. Transferencia é a criação de pares de movimentos de conta. Eu preciso saber a conta para construir os movimentos, mas a conta são se altera. Os movimentos são necessários porque criam uma historia do uso da conta: o extrato. O extrato é o que o cliente vê. O saldo é uma função em cima dos movimentos/do extrato. Os movimentos podem ser de diferentes tipos (DOC,TED, interno, externo , etc…) e cada uma tem as suas regras , que nada têm a ver com as contas. Como disse a conta é um identificador que é usado pelo resto do sistema.
Para as funções de report vc não quer a conta, vc quer os movimentos.
Para as funções de contabilidade vc quer a contraparte dos movimentos e não a conta.

Em concreto: uma conta não tem um campo saldo, nem as operações setSaldo(), getSaldo(); Tem o método saldo() que consulta os movimentos (na realidade pode consultar um cache com o saldo, mas não pode alterá-lo). Também não têm as funções aumentaSaldo e diminuiSaldo.
Por outro lado, existem mais informações necessárias à transferencia, como quem a autorizou, quando e porquê.

Para vc como usuário de banco transferencia parece simples, mas para o banco não é. É coisa séria. Esta diferença de visão deve-se ao encapsulamento. O serviço pede apenas como parametros duas contas e um valor, mas o sistema tem muito mais coisas a criar a partir dai.

Eu dei o exemplo da transfrencia bancária porque é classico nestas situações em que um serviço é requerido. Mas sintam-se à vontade de implementar de outra forma.

P.S. Vc não respondeu Às perguntas:

  1. quem vai invocar conta.transferePara(outra, valor) ?
  2. E,porque não , outra.transfereDe(conta, valor) ?

sergiotaborda,

Responderei às suas questões assim que sair do trabalho. Hoje tá meio complicado aqui… rs.

Portanto, quando a logica de negocio envolve mais um dominio, nos criamos entao um servico para este gerenciar estes dominios, e o servlet pode acessar diretamente esse serviço, pois ele faz parte do dominio

Apesar de vc citar que a logica esta distribuida nos objetos de dominio, nos vimos que parte da logica na verdade esta no servico, porem como o servico faz parte do dominio vc pode dizer que a logica continua no dominio. Portanto digamos assim: Uma Pessoa(Objeto de dominio) pode conter um repositorio, porem quando a logica de negocio envolver outra dominio, sera necessario criar um servico que ira gerenciar os dominios e seus respectivos repositorios. correto ?

Realmente DDD nao evita o TO, pois precisamos passar parte dos objetos de dominio atraves de parametros para os servicos do dominio, porem isso so ocorre quando precisamos trabalhar com mais de um dominio, seja eles iquais ou diferentes.
O que eu nao entendi foi Façade e Serviço, o que isso tem haver ?

Porem eu estou com duvida em uma coisa: Servico realmente retrata a situação quando precisamos resolver a logica dentre 2 dominios ? Eu me pergunto isso pois no exemplo inicial vc usou um servico ele resolve a logica de um dominio especifico, por isso eu devo ter feito confusão achando que vc estaria fragmentando o dominio.

 //Meu servlet ou algo do genero
 public class Beta {
 	
 
 	//Como eu deveria gravar um objeto usando DDD
 	private void DDD(){
 		Pessoa pessoa = new Pessoa();
 		pessoa.setIdade(20);
 		
              CRUDService  service = ... 
              service.novaPessoa(pessoa);
 	}
 	
 }

[quote=eliziario]
Não vou nem comentar ainda a mistura de código de transação com código de negócios. Também é lamentável que em pleno 2007 ainda tenha gente que use controle de transação de maneira programática e não declarativa, isso realmente me dá muito desgosto.
Sinceramente, acho que você deveria ler o livro do Evans, e o Object Design da Wirfs-Brock. Depois de ler os dois, leia Refactorings do Fowler pra consertar esse seu código aí em cima.[/quote]
É obvio que o exemplo nao retrata uma situção real, cito um trexo que ja citei aqui novamente
Para ajudar a tornar isso tudo mais concreto, eu usarei um exemplo funcional. Como todos os meus exemplos, este é um daqueles exemplos super-simples; pequeno o bastante para ser irreal, mas o suficiente, espero, para que se possa visualizar o que está ocorrendo sem cair na complexidade de um exemplo real.

Não entendi de onde vc tirou a ideia de que ha mais do que um dominio no exemplo.
Dominio = Entidades + Objetos de Valor + Serviços
Sendo que a quantidade de cada um é variável.
Repositório é uma forma padronizada dos objetos do dominio se encontrarem entre si. (Na prática é uma forma de encapsular a persistencia, mas em teoria não é esse o seu objetivo principal, já que eu posso persistir coisas que não são do dominio e/ou não persistir coisas que uso no dominio)
O repositorio é por dominio.

Servlet não pertence ao dominio. Ele pertence à aplicação ou à intraestrutura ,dependendo das responsabilidades que ele tem.

“logica de negocio” e “logica de dominio” não necessáriamente são a mesma coisa. A logica de negocio é um conjunto de logicas de dominio.
Se a sua aplicação só tem um dominio, a logica de negocio é sobre um dominio. Mas, por exemplo, num ERP existem vários dominio (finaceiro, contábil, produção, estoque, etc… ), e uma só logica de negocio (a integração dos dominios para um determinado fim)

Primeiro : Pessoa não contém um repositorio. Ela usa um repositorio.
Segundo: Se a logica de negocio envolve mais do que um dominio a aplicação é diferente. Exemplo: O dominio Contabilidade vê ContaContábil e o dominio Financeiro , ContaFinanceira , o dominio Contabilidade não vê Produto e o dominio de produção não vê ContaContábil.
Isto, se vc quer isolamento de dominio, que é o amago da questão. Estou supondo que vc quer, pois o objetivo do DDD é encapsular a logica de dominio de forma que elas sejam reutilizáveis. Já pelo reutilizáveis vc entende que ; como cada negocio tem a sua maneira de ser, ele usará os objectos do dominio de forma diferente, mas de forma muito semelhante a um outro negocio.

Voltemos então ao exemplo de um só dominio. Imagine o dominio como um circulo. Vc tem no centro do dominio as entidades. Elas pertencem apenas a um dominio e não mais do que um. As entidades encontram-se umas às outras por meio de um repositorio. Que fica dentro do circulo, sem tocar na fronteira. A fronteira do circulo é onde os serviços estão.
Então, todos os pedidos são enviados pelo exterior (a camada de aplicação) aos serviços. Os serviços usam as entidades e os objetos de valor para executar uma funcionalidade que as entidades por si mesmas não podem. No executar desta funcionalidade metodos das entidades e dos objetos de valor são usados. Esses métodos executam “mini-logicas” e podem delegar a outras entidades e/ou serviços certas funções.

Entenda que o dominio é apenas uma camada do sistema. Existem muitas outras.

Pensemos agora que vc precisa organizar funcionalidades de dois domínios. Aqui vc usaria outro tipo de desenvolvimento. Eventos/notificações (EDD), SOA ou BPM. Isso é outro assunto.

Lembre-se que os objetos do dominio ficam dentro do dominio (dentro do circulo) eles são invisiveis a quem está fora do circulo.
Deste ponto de vista passar Pessoa como parametro para o serviço (ou conta, etc…) é uma violação desse principio, e por isso é errado usar Pessoa num servlet por exemplo. E por isso vc teria que usar um TO para compor os dados de pessoa necessários ao serviço.
Então, um serviço de dominio não tem como parametro os objetos do dominio, mas sim outros objetos utilitários (que chamarei de TO).

Então, o seu servlet lê um request. Algum framework, ou vc na mão, lê os dados do request e decide o que fazer com ele. transforma os dados do objeto request num objecto comestivel ao serviço que executará a funcionalidade necessária. O serviço recebe esse objeto burro e entende o que vc pretende dele. Ele invoca os objetos de dominio necessários e executa o processo. Se ele tiver que retornar alguma coisa , essa coisa tb será um TO, que a camada que chamou o service converterá para um response, que o servlet enviará ao browser.

Quanto à diferença entre façade e serviço , isso é assunto para outro topico. Mas, resumidamente , façade é uma condensação e encapsulação de execuções de serviços. (O objeto que vc usa é uma fachada dos objetos verdadeiros e/ou a funcionalidade que vc requesita é uma fachada para o requesito de várias outras funcionalidades )

Parece que vc está entendendo que CRUD é um dominio. Se é isso, não.
CRUD não é um dominio. No exemplo eu deixei o CRUD ser um serviço cujo objetivo é popular o repositorio de entidades de forma direta ( ou seja, sem logicas acopladas). Mas isso foi um exemplo.
Teoricamente nenhum crud deveria ter logicas acopaldas, mas sabemos bem que isso é mentira. Então a ideia é deixar o dominio validar e responder ao crud. Mas só isso não é suficiente e depende muito da aplicação. Num ERP , por exemplo , fazer crud interage com vários dominios e ai o CRUDService não faz sentido.

Moral da historia: Em boa verdade, CRUD é uma operação sobre o repositorio do dominio. Que tem que ser executada com a conivência do dominio (para validação por exemplo) mas cuja responsabilidade final não é do dominio per se mas sim da aplicação.

Era exatamante isso que eu queria dizer, acho que não fui feliz na mensagem. Imaginei que seria mais fácil entender da forma que escrevi. :oops:

Valeu.

[quote=Daniel Quirino Oliveira][quote=sergiotaborda]
O ActiveRecord é um padrão mencionado em muitos lugares e tem o seu lugar ao sol em determinados usos (DataSet é um exemplo). Mas refere-se a record (registro) e em DDD uma entidade não é vista como um registro porque a persitência é abstraida e portanto existe uma incompatibilidade natural entre ActiveRecord e DDD. [/quote]

Huh?! :shock:

Dá para explicar isso? Aliás, você realmente entendeu o que você acabou de escrever ou você acredita de fato nisso que você falou?[/quote]

Explicar o quê ?

Agora acho que consegui entender tudo, muito obrigado, ficou bem claro, eu criei uma imagem mais nao consegui add aqui no post, peço que acesse o link para ver http://bp2.blogger.com/_i4__yipflbg/RnwLQi3uq1I/AAAAAAAAAAk/YD0lRgkGuHg/s1600-h/ddd.JPG

Eu gostaria de saber como fazer isso, vc pode ser mais claro ?

***** EDITADO ********
Consegui anexar a imagem


[quote=ronildobraga]Agora acho que consegui entender tudo, muito obrigado, ficou bem claro, eu criei uma imagem mais nao consegui add aqui no post, peço que acesse o link para ver http://bp2.blogger.com/_i4__yipflbg/RnwLQi3uq1I/AAAAAAAAAAk/YD0lRgkGuHg/s1600-h/ddd.JPG
[/quote]

É isso aí. Isso é a base da proposta de DDD.

[quote=ronildobraga]

Eu gostaria de saber como fazer isso, vc pode ser mais claro ?[/quote]

Eu tb gostaria de saber fazer isso. :lol:
As tecnologias estão ai, o dificil nesta historia é encaixa-las…