| Autor |
Mensagem |
|
|
sergiotaborda wrote:
peerless wrote:
algumas páginas atras o Gerson disse algo como wrote:.. gerentes burros que não sabem o que fazer, então delega isso para o cara certo..
Está bem confusa essa thread. Eu pensei que o Serviço fazia coisas que não fosse de responsabilidade especifica de ninguem do domain layer.. mas utilizando os componentes dele para se chegar a um objetivo em comum
Sim. Isso é o que um Service faz. Seja de que camada for. Ele não é um delegador de responsabilidade,ele tem a responsabilidade
de orquestrar os outros objetos da sua camada. Em particular , no dominio, ele orquestra entidades, repositorios, e/ou outros serviços.
Serviços de qual camada? Como eu já disse anteriormente, os serviços da camada da aplicação (Application Layer / ServiceLayer) não devem conhecer lógica de domínio. Agora, os serviços da camada de domínio sim, devem conhecer. A camada de aplicação existe principalmente para isolar a camada de domínio, de forma que fique bastante claro aquilo que realmente tem a ver com lógica de domínio e lógica de aplicação/workflow.
Sobre a analogia que eu fiz dos gerentes, como eu já disse também, ela se aplica aos serviços da camada de aplicação. É uma forma de pensar para que fique claro que lógica de domínio deve ficar na camada de domínio (Domain Layer), em outras palavras, os serviços da camada de aplicação devem delegar tudo que estiver relacionado com lógica do domínio para a camada de domínio.
[Editado:]
Tinha esrcito 'Application Service' no lugar de 'Service Layer' (PEAA)...
|
 |
|
|
Bruno Laturner wrote:
Gerson wrote:(...)
Tudo bem.
O usuário logado no sistema seleciona um outro usuário a partir de uma lista, dá uma pontuação para ele, de zero à cinco estrelas, e clica no botão pontuar.
Servlet recebe a requisição, e chama o Model.
O servlet (ou melhor, uma action/controller) chama um servico do application layer ('service layer', no PEAA). O application layer serve para você colocar o que o fowler chama de 'lógica de aplicação / workflow logic' (para diferenciar da lógica de domínio que deve ficar na camada de dominio, isto é, você isola a camada de domínio). Os serviços da 'camada de aplicação' funcionam como façades que você pode usar para representar os casos de usos do seu sistema. Além disso, é um ótimo lugar para demarcar o inicio e o fim de uma transação. Novamente, o importante é que nessa camada não tenha lógica de domínio, pois ela deve ficar totalmente na camada de domínio (que é aonde o DDD foca).
Bruno Laturner wrote:
Model será representado por um serviço que valida os dados e chama um repositório?
Sim, um conceito do domain model pode ser expresso atavés de um serviço que valida os dados (lógica de domínio) e, se necessário, poderia chamar um repositório para recuperar uma instância que representa o root de algum aggregate, por ex. É importante que todos esses conceitos estejam em torno do ubiquitous language, pois, sem isso, você está aplicando bons patterns apenas, mas não está praticando DDD.
Bruno Laturner wrote:
tnaires wrote:O ganho aqui foi em expressividade do código. A sentença ficou mais natural que a primeira, e o trabalho extra não é tão grande assim... Além disso, outros métodos poderiam complementar o Builder ( a não ser, claro, que Pontuacao tivesse apenas os atributos pontuado e valor da nota ).
Fluent Interfaces, pelo menos em Java, são um saco pra implementar. Expressividade tem um custo.
Expressividade através de fluent interfaces tem um certo custo mesmo. Mas tem milhares de outras formas simples de tornar o código expressivo... recomendo um livro bacana chamado Clean Code (do conhecido Robert Martin), lançado recentemente... muito bom.
[editado:]
Costumo dizer que os serviços do application layer são como gerentes que não sabem como executar as atividades, mas sabem para quem delegar, e, também, sabem especificar a ordem em que essas atividades devem ser executadas.
|
 |
|
|
Bruno Laturner wrote:
Gerson wrote:Como o Philip Calçado já disse algumas vezes aqui no fórum, embora seja possível um entity acessar o repository (= não viola DDD), normalmente o service costumar fazer isso. E, como já disse no inicio dessa thread, o service tem caracteristicas que facilitam bastante o acesso a um repository sem precisar tornar a aplicação muito complexa (ex. uso de AOP).
Num caso simples como esse, isso não viraria um jogo de empurra?
Alguém pede pro Usuário pontuar
Usuário pede pro serviço atualizar
serviço pede pro repositório atualizar
repositório pede pro DAO(?) atualizar
DAO(?) acessa o banco e atualiza.
A partir de que ponto/tamanho/requisito o sistema passa a colher as vantagens de ter um serviço e um repositório no meio?
Esse fluxo não é bem assim...
Colocarei um outro exemplo aqui de um service. Esse domain service (que, como o nome diz, está no domain layer) pode ser chamado por qualquer objeto do application layer como um 'application service'. A regra de autenticação está no domain service! Ótimo, pois ele não fica na camada de aplicação... aliás, essa camada existe exatamente para isolar o domínio.
Um application service serve apenas para coordenar tarefas... funciona como um façade, pois ele sabe para quem delegar, e sabe também a ordem em que as coisas são executadas. É que nem um gerente.
Obs.: Lembre-se de que existem várias forma de implementação do domain layer que pode estar compatível com a prática de DDD... DDD não é um pattern de implementação... pra pratica-lo bem é necessário entender bem os conceitos, porque é isso que vai dizer se a sua implementação está dentro deles. Sem entender os conceitos e seus objetivos, naturalmente, não vai encontrar grandes vantagens e vai acabar se tornando um jogo de empurra mesmo. Uma outra coisa importante também é lembrar que ao redor de tudo isso está o ubiquitous language...
|
 |
|
|
saoj wrote:Por que vc diz que é gambiarra o código abaixo? (Pode até ser, a discussão é sobre isso mesmo)
Minhas opções são chamar o DAO diretamente na camada de serviço OU chamar o DAO indiretamente por dentro da entidade, o que vc diz ser gamb.
Atualmente eu faço a primeira, mas nesse tópico mesmo sugeriram a segunda porque fica mais OO.
Bruno Latuner wrote:
Respondendo a pergunta: Além de ficar mais bonito, a vantagem é que você deixará de mexer tanto com persistência, e passará a desenvolver somente para teu negócio.
Considerando que você não está falando de Repository (DDD), o problema em fazer o acesso direto ao DAO através de um Entity é que este não deve saber que, por uma limitação da tecnologia (memória), é necessário armazenar/recuperar os objetos em/a partir de um mecanismo de persistência como o banco de dados. É preciso lembrar que o banco de dados, idealmente, deve ser utilizado para suportar a persistencia de objetos, e não para complementar os dados que a sua aplicação usa e os objetos de domínio nem se quer tem conhecimento deles... um teste seria verificar quantos dados você armazena no banco que seus objetos do domínio não os conhecem.
Complementando com DDD, é por isso que o Repository, que deve ter um nome associado ao ubiquitous language, vem criar um certo tipo de indireção para dar a ilusão de que os objetos estão em algum 'deposito' de objetos em memória. A implementação do Repository, por sua vez, pode ser um DAO (diretamente, ou através de um strategy (GoF), por ex.). Nesse caso, um Entity, por ex., que é um dos responsáveis por expressar o modelo em DDD, poderia sim ter acesso ao repository para, por ex., buscar algo. Por isso, conceitualmente, Repository é bem diferente de DAO (as pessoas, normalmente, não querem saber de conceitos, e justificam que são iguais só porque a implementação é parecida... infelizmente).
[Editado:]
Como o Philip Calçado já disse algumas vezes aqui no fórum, embora seja possível um entity acessar o repository (= não viola DDD), normalmente o service costumar fazer isso. E, como já disse no inicio dessa thread, o service tem caracteristicas que facilitam bastante o acesso a um repository sem precisar tornar a aplicação muito complexa (ex. uso de AOP).
|
 |
|
|
sergiotaborda wrote:
Agora, no Value Object vc já está forçando a barra. O BigDecimal é um Value Object. Ele não contem nenhuma ação sobre o sistema. Um Value Objeto, por definição, só contém acções sobre si mesmo (add, multiply, etc... são acções sobre o proprio objeto)
Você leu alguma literatura sobre DDD mesmo?
Pelo amor de deus, defina o que são "ações sobre si mesmo"! Bom, tomando como exemplo o BigDecimal que você citou, e considerando que, obviamente, você deve saber que ele é imutável, o que você quer dizer com isso?
"ação sobre o sistema" é algo que você está inventando. Não sabe o que dizer, e, por isso, de forma generalizada, diz simplesmente "ação sobre o sistema" e "ação sobre si mesmo". Essa sua classificação entre "ações sobre o ***sistema***" e "ações sobre si mesmo" foi você que inventou? Defina-o... é muito fácil decidir usar isso como um critério só porque você quer. Aliás, um entity "tem uma ação sobre si mesmo" (usando seu termo vago), então o sistema não é alterado? Confuso, não acha?
Bom, quando você definir melhor o que inventou, aí podemos conversar sobre isso.
sergiotaborda wrote:
Essa é quanto a mim uma noção ingénua de DDD. Na prática nenhum sistema funcionaria assim.
Bom, eu uso e funciona. É só saber usar direito. Estude Domain Model (PEAA).
sergiotaborda wrote:
A razão é simples : a ação entre as entidades é uma entidade em si mesma. Então quando o joao casa com a maria um objeto casamento será criado , e ele é que contém as ações sobre o sistema.
Bom, novamente, defina primeiro "ações sobre o sistema". Do contrário, fica dificil discutir.
sergiotaborda wrote:
Não , não pode. Ele contém logica relativa a ele. VO não invocam serviços nem repositorios nem coisa nenhuma. eles são invocados e usados por esses outros objeto. O método que eles têm reference ao estado que eles detêm. Só isso. Não ao estado do sistema.
É obvio que ele contém lógica relativa a ele, a não ser que você não saiba o que é coesão.
E, novamente, VOs do domain layer, inclusive, contém lógica de domínio sim. A não ser que você tenha criado uma outra definição para 'lógica de domino' (ou lógica de negócio).
|
 |
|
|
sergiotaborda wrote:
Ações no sistema tevem estar contidas em Serviços.
Depende... essa "ação" que você diz pode ser de um Entity ou de um Value Object, também. Não obrigatoriamente, essa operação deve ser colocada em um service, seja este de domain, de application, de insfrastructure, ou da camada que for. Um domain service, por ex., deve ser usado para representar (e explicitar) uma operação que não tem uma relação natural com um Entity ou um Value Object.
sergiotaborda wrote:
Isto porque em objetos de entidade só faz sentido colocar métodos que alterem o estado dos próprios objetos e não do sistema como um todo.
Bom, não entendi bem o que você quer dizer com "Sistema como um todo", mas, de qualquer forma, se o seu domínio usa um modelo de objetos (Domain Model - PEAA) poderiamos ter:
Naturalmente, se necessário, poderia também ter um domain service quando a lógica de avaliação é importante e complexa, como:
E uma possível implementação para Usuario poderia ser...
Neste caso, podemos assumir que Usuario e Avaliacao fazem parte do mesmo aggregate. O root dele, naturalmente, é o Usuario.
sergiotaborda wrote:
O ponto era: Se o seu objeto contém logica de negocio ele ou é uma entidade ou é um serviço.
Um Value Object, no domínio, pode conter lógica de negócio também.
sergiotaborda wrote:
A escolha caberia então entre colocar o método num Serviço ou na entidade usuário. Porque o método não altera o usuário, é mais claro que seja um serviço a fazer isso.
Bom, não é simplesmente porque não 'altera' o próprio objeto que deve ficar no Service. Acho que é uma regra muito simplória.
|
 |
|
|
sergiotaborda wrote:
O seu objeto userRepo está atuando no sistema (to score é um verbo), portanto ele deveria estar em um objeto do tipo Serviço.
E o serviço deveria ser assim:
O que faz ser um domain service não é o 'userRepo' estar atuando no sistema (afinal de contas, tudo está atuando no sistema), e, muito menos, o nome do método ser um verbo (deve ser um verbo!).
Afinal de contas, o que você quis dizer?
|
 |
|
|
saoj wrote:
Se for repositório do DDD, que serve para guardar/reconstituir objetos, acho bem estranho o método se chamar scoreUser().
A única coisa que eu faria no exemplo do Bruno é inverter as ordem dos parâmetros para aumentar a expressividade (nesse caso, a fluência do código). Outros exemplos:
Ao invés de injetar um repositorio em Usuario, vc tem a opção de criar um 'domain service' (DDD) como:
Ou, se preferir...
Lembrando que esse service é de domain (domain layer), e, deve ser stateless. Assim, como sua construção é simples e facilmente gerenciado por um IoC container como o Spring (diferente de um Entity, por ex., ainda mais quando se tem um framework ORM envolvido), facilita que seus colaboradores sejam providos com facilidade, como é o caso dos repositórios.
Não confundir com o service layer do fowler.
saoj wrote:
o user que está na sessão (usuário logado) deve ter o repository dentro? Acredito que não...
Pra que repository? Normalmente o 'usuário logado' que fica na session não é o próprio 'usuário', já que são dois conceitos diferentes. 'Usuario logado' deveria ter apenas informações como identidade, permissões, nome completo, nome de usuário, e alguma outra coisa a mais que vale a pena ter deixar na session. Muitas vezes pode ser um 'value object' (!=DTO) criado durante a autenticação. Na realidade, 'usuario logado' e 'usuario' deveriam ser implementados em classes separadas, mas o que acontece na prática é que muita gente usa uma mesma classe para representar dois conceitos diferentes. Isso causa grandes problemas, já que os dois conceitos normalmente possuem diferentes comportamentos/estados, possuem invariantes diferentes, participam de aggregates (DDD) diferentes, etc. E, outra, como ficam os métodos toString(), hashCode(), equals() que não podem ser compartilhados entre os dois conceitos? É o mesmo problema daqueles que reutilizam a classe 'Usuario' para representar dados de login... a única coisa comum entre os dois talvez poderia ser o atributo 'String usuarioLogin', já que a própria senha tem semântica diferente nos dois conceitos (no Usuario provavelmente você tem uma hashSenha, e não exatamente senha). Resumindo, normalmente não faz sentido o 'usuario logado' ter acesso a um repository.
|
 |
|
|
Acho um lixo...
Toda a abstração que ele te oferece na view (ciclo de vida, arvore de componentes, managed model, etc.) na minha opinião, só ajuda enquanto você não faz nada de diferente do que ele propõe... pois, pela minha experiência, o custo de fazer alguma "coisinha" um pouco fora deste padrão é terrível, tendo que apelar pra "código sujo". E, no meu caso, nem o Seam ajudou a reduzir consideravelmente esses problemas... tirou alguns problemas, mas introduziu outros. E que o JSR 299 se exploda também (junto com EJB3 e cia)...
Continuo com o bom e velho Spring (2.5.x), JSP, JSTL e etc., mesmo. Muito mais poder e flexibilidade. Recomendo...
|
 |
|
|
cv wrote:Nao acho que essa discussao importe muito - a escolha entre ruim e pessimo nao me interessa muito. IntelliJ, alguem? 
Aproveitando, uma coisa que me chamou bastante atenção no IntelliJ recentemente foi o suporte para o Maven, que considero o melhor, principalmente em multi-module projects. O Netbeans (Mevenide2) até que é bacana, mas, o eclipse (q4e ou M2Eclipse), tem que melhorar muito ainda... e nem estou dizendo do 'hierachical project layout' que o eclipse não suporta, mas sim utilizando o bom e velho 'flat layout' mesmo.
|
 |
|
|
saoj wrote:
EJB = sistemas distribuídos que precisam se comunicar entre si remotamente via mensagens assincronas ou rmi/rpc. Se algum dia eu precisar "distribuir" minha aplicação web eu usaria xFire em cima dos meus "services".
Da onde tirou isso? Essa foi uma das piores definições (ou 'explicações rápidas', que seja) que eu já lí sobre EJB, ainda mais se considerarmos que se trata de EJB 3 (que é a versão compatível com o Seam).
saoj wrote:
O JSF é component-based, então se o seu desenvolvimento vai ser voltado para COMPONENTES, então vc deve ir de Seam.
E só isso? É tão fácil assim o critério para utilizar ou não um framework como o Seam?
Não seria mais justo você dizer que não conhece JBoss Seam e se limitar em apresentar as características desse outro seu framework apenas?
saoj wrote:
JSF na minha opinião é um mar de XML, complexidades desnecessárias, chatices, etc. Dá uma procurado no forum que vc verá que outras pessoas compartilham tb desse sentimento.
Eu não sou fã também de JSF, mas seus argumentos estão um pouco "pobres" (pelo menos para alguem que acha que pode julgar quando usar ou não o Seam).
Bom, só pra lembrar, estamos falando de JSF + Seam... O que é um "mar de XML" pra você? Você conhece as melhorias que o Seam trouxe para o JSF, justamente quando se trata de "XML hell"? Se ainda assim você o acha horrível tudo bem, mas do contrário, é melhor ler um pouco sobre Seam antes.
E as "complexidades desnecessárias", quais são elas exatamente (obviamente, aquelas que o Seam ainda não as resolveu, pois estamos falando de Seam + JSF)?
Eu não estou falando que o Seam é lindo, maravilhoso e que resolve todos esses problemas, mas parece que você está baseando puramente em "achismos". Se não o conhece suficiente (ou quase nada) para avaliar, não faça conclusões, ainda mais conclusões tão simples como as suas sem nenhum argumento real.
barluciano wrote:
Claro que se não for utilizar EJB3, não existe a necessidade de usar o Seam.
barluciano, ainda que EJB 3 seja a opção mais recomendada pelos desenvolvedores do Seam, há a opção de não usar EJB também. Nesse caso, dá até para integrar com o Spring (mas é uma integração básica, com limitações, como qualquer outro framework que se diz integrar com Spring tem). Não considere (ou desconsidere) o Seam por causa do EJB3, somente, ou muito menos porque a view é component-based ou não. Eu tenho utilizado Seam (com EJB 3), e estou gostando de muitas coisas, principalmente em relação a facilidade de integração com JSF 1.2 (nada de declarar os "managed beans" nos XMLs) e a possibilidade de elevar escopo do 'persistence context' para Conversation (na verdade, o EJB3/JPA já ajuda bastante com a possibilidade de usar especificar 'type=EXTENDED' em @PersistenceContext, dentro do SFSB). Este último dá pra fazer com Spring Web Flow + JSF também. Bom, dê uma olhada na documentação oficial do Seam, no JSR 299, e, indico muito o livro 'Persistence with Hibernate' que tem um capítulo dedicado para Seam... não fala sobre a 2.x, mas de todos os livros que eu lí sobre o assunto, é um dos melhores para entender o conceito. Ah, procure também por Dan Allen... ele tem vários bons artigos, está escrevendo um livro , e, recentemente, entrou para o time do JBoss Seam.
Para muitos projetos, principalmente para os novos (>= JEE5), eu estudaria a possibilidade de usar o JBoss Seam. O que não pode é sair confiando em tudo que o pessoal diz... você mesmo tem que ir atrás e analisar para ver se atende o seu projeto, pois como qualquer framework, tem seu prós e contras. E, se tiver alguma dúvida específica, fique a vontade para perguntar. Por ex, estou com um projeto novo (>=JEE5) que, por uma série razões, decidí por não utilizar Seam nem EJB3. Mas para a empresa onde trabalho, em um projeto específico, por uma série de outras razões, decidimos utilizar Seam.
|
 |
|
|
Aproveitando o assunto, quem tiver um "tempinho" (eu tive!), pode dar uma lida no que rolou nessa thread do forum do spring "DAO Reference Inside an Entity Domain Object"... É o tipo de discussao que nao se chega a uma conclusao definitiva, mas faz vc ver um monte de ideias e problemas que talvez vc nunca tivesse pensado antes.
http://forum.springframework.org/showthread.php?t=15294
|
 |
|
|
felipesp wrote:Eu só trabalho com aplicações web (struts), e acho que o singleton geralmente gera problemas.
Embora considerado anti-pattern, quem gera problemas de concorrência não é o singleton, mas sim aquele quem usa de maneira indevida! A documentação do Struts é clara em relação a thread-safe!
felipesp wrote:
Em especial, tive um problema muito grande com uma classe chamada DAO que era um singleton, compartlhado entre vários contexts. O verdadeiro inferno, que demoramos algumas semanas para resolver.
Será que esse "context" tá no lugar certo? Seu DAO precisa mesmo manter estado específico de uma chamada? Será que o problema tá com o singleton mesmo?
Se, por ex, o DAO for um singleton e estiver mantendo uma Connection em sua instancia, e não houver nenhum tratamento para garantir thread-safe, aí claramente terá problemas de concorrencia!
O Spring Framework, por exemplo, internamente, usa ThreadLocal para manter todo o contexto que é específico de uma thread, como o objeto Connection (de forma que cada thread atua em uma transação diferente).
Poiati:
Respondendo a sua pergunta, o pattern pode ser aplicado ao DAO sim, desde que sejam tomados alguns cuidados de concorrencia. Se utilizar o Spring Framework, melhor ainda, pois além de não ter que se preocupar com a concorrencia sobre os objetos Connection/Session, nao tem que implementar o padrao singleton em sua classe, pois isso é apenas um detalhe de configuração no Application Context (que, por default, já é singleton).
Bom, é claro, a não ser que voce tenha um bom motivo pra nao fazer nada disso! Normalmente nao..
|
 |
|
|
Ah, mais uma outra coisa! Esse seu "Active Record" tá meio esquisito!...
Por que passar um objeto do tipo Pessoa por parametro? Ele nao está atuando na instancia da própria classe Pessoa? Os métodos Finders tudo bem, inclusive eles devem ser implementados como static (static finders), mas os métodos de inserção, atualização, por ex, não tem porque não utilizar a própria instancia! Aliás, o legal no AR é isso, e não criar uma classe que simplesmente mistura um model e métodos do "DAO". No caso dos métodos finders, é possível separar em uma outra classe, como acontece no Row Data Gateway (do PEAA tambem).
Rafael Nunes wrote:
|
 |
|
|
Rafael,
Depende...!
Active Record (AR) é interessante para aplicações onde a lógica de negócio não é muito complexa. Por que? Porque esse padrão cria um acoplamento dos seus objetos com a estrutura do banco, tornando seu domain model menos flexivel. Se você precisa lidar com uma lógica de negócio mais complexa, provalmente irá querer fugir da estrutura do seu banco relacional e criar relacionamentos diferentes (e MUITO mais completos) no seu domain model. Nesse caso, se vc estiver usando Domain Model (objetos de domínio que contém dados + comportamentos, em oposição ao Anemic Domain Model), você poderá usar o padrão Data Mapper (atrás de um outro padrão chamado Repository)! Mas se estiver usando Transaction Script, dê uma olhada no TDG (Table Data Gateway). Ah, mas é possível misturar um pouco de Active Record com Transaction Script também, onde todo código orientado a dados estaria no AR, e o resto em Transaction Scripts.
TDG é o que conhecemos por DAO? Bem, mais ou menos! DAO (Data Access Object, catalogado no J2EE Design Patterns) é mais genérico, e não fica preso a um tipo de data source específico (ex. banco). Já o TDG é voltado exclusivamente a bancos relacionais. Aliás, pra mim, DAO tem um significado tão vago que, na prática, é preciso ver se esse "DAO" está servindo apenas para isolar o acesso a dados ou, mais do que isso, fazendo o papel de permitir a troca de implementação do tipo de persistencia (através do uso de Abstract Factory). DAO se parece mais com os padrões Gateway e Repository, ambos catalogados no PEAA (Fowler).
Sou mais um que irá aconselhar a leitura do livro PEAA. Aliás, uma outra boa leitura é o 'POJO in Action', que, entre outras coisas, explica como resolver alguns problemas encontrados ao usar Rich Domain Model com frameworks de persistencia e IoC, que é proximo ao cenário que voce descreveu, onde o seu domain model precisa acessar um Repository para persistencia. E se não conhece os patterns do GoF, então esqueça tudo, e comece por ele primeiro!
Confuso? Esse é o mundo da arquitetura...
É seu papel, como arquiteto, escolher a arquitetura mais adequada aos requisitos. E, para escolher o próximo da melhor, só conhecendo mesmo os prós e os contras de cada arquitetura.
Ultimamente tenho acompanhado o projeto Active Record, do Castle Project (só que para C#/.NET). Ele trabalha em cima do NHibernate. Pode ser uma boa dar uma espiada, pois é bem simples de entender!
|
 |
|
|
|
|