Muito do que você encontra na internet sobre design e arquitetura de aplicações em java o remete ao JEE e ao famigerado EJB. Já foi o tempo em que EJB era condição sin qua non para criarmos aplicações corporativas e especialmente sites.
Hoje com o advento do Seam parece que EJB vai ser novamente necessário para fazer sites. Veja que Seam utiliza os EJB como back-beans do JSF o que significa que não funcionará fora de um Application Server. A maioria dos sites não precisa das capacidades contidas em um Application Server, bastando um Web Container. A própria especificação JEE 6 vai oficializar este divisão entre o que é web site e o que é realmente uma aplicação corporativa.
Ao falar de aplicação corporativa todos imediatamente pensam em bancos de dados, ou melhor, em SGBD (Sistema Gerenciador de Banco de Dados) e imediatamente pensam em DAO e depois em Hibernate e JPA. O problema aqui é que DAO é obsoleto, JPA é infantil e Hibernate não tem concorrência. Se você está pensando em criar um software e em usar DAO, esqueça. Isso é coisa do passado. Hibernate e JPA são encarnações no novo padrão que matou o DAO, o DomainStore. Então é neste padrão que você deve se concentrar hoje, e não no DAO. Para web site, você precisa no máximo de um Hibernate.
Por que não JPA? Porque o JPA tem o mesmo problema do EJB 2.x. A especificação é simplista e falha. Ela viola explicitamente o propósito de mapeamento agnóstico o que significa que usando JPA você não poderá usar qualquer banco de dados. Aliás, se você usa algum tipo de SELECT esqueça JPA. Não que o hibernate o vai liberar de criar código especial para este ou aquele banco, mas vai minimizar muito essa necessidade e adiá-la o máximo possível. Mas o grande problema com o JPA é a criação de pesquisas. As pesquisas do JPA não são OO e não são agnósticas. As do Hibernate são OO se usar Criteria e agnósticas, quer usando Criteria ou HQL.
As pesquisas são o elemento esquecido do CRUD. O objetivo de ter um mecanismo de CRUD é poder pesquisar os dados depois. Poderíamos até argumentar que todo o objetivo de ter um banco de dados é permitir as pesquisas. E onde escrevemos estas pesquisas?
Obviamente teremos que as escrever em algum objetos cuja responsabilidade principal seja montar critérios do Hibernate. Estes objetos são os repositórios. Os repositórios concentram todas as responsabilidades CRUDL (CRUD + Listagem) e normalmente precisamos de vários deles.
É muito comum a ideia de que ao termos um mecanismo com o Hibernate poderíamos criar um DAO para encapsular as chamadas a ele, mas isso é um erro tático e técnico muito importante. Primeiro que apenas queremos na realidade facilitar o uso de classes como a Session e talvez adicionar um pouco mais de tipagem forte. Isso não é um DAO, é no máximo um Adapter. Nada contra construir um Adapter deste tipo, mas existe um ponto mais importante aqui. Se o repositório é responsável por montar objetos de Criteria, ele já está acoplado ao Hibernate; logo criar mais um objeto no meio é fútil. Por outro lado, se quisermos desacoplar o Hibernate dos repositórios (veja, o Hibernate é apenas um, os repositórios são vários) precisamos, na realidade, de uma estratégia para criar os Criteria sem usar as classes do hibernate e depois delegar a algum outro objeto que as traduza para essa tecnologia. A forma mais realista de fazer isto é criar um mecanismo agnóstico de Query Object e Interpreter. Funciona assim: o repositório é agnóstico (ou seja, não depende da tecnologia de persistência) e depende de um objeto PersistanceStrategy (o nome pode variar). Este objeto é, na verdade, uma interface, um serviço, cujo contrato também é agnóstico. PersistanceStrategy aceita entidades para operações como save e delete, e aceita objetos Query Object para pesquisas. Objetos Query Object são como os Criteria do hibernate mas sem a dependência com o Hibernate.
Depois criamos uma implementação HibernatePersistanceStrategy. Este objeto delega as operações ao Hibernate e sabe como traduzir Query Object agnóstico para Criteria do Hibernate.
Dessa forma, se um dia você quiser remover o Hibernate, você pode. E esse dia não é lá no futuro não. É amanhã, quando você começar a escrever os seus testes unitários e de integração.
Recapitulando: Repositório conversa com PersistanceStrategy através de Query Object. Repositório é responsável pelo CRUDL da Entidade.
Do outro lado, queremos manipular as entidades para conseguir criar valor. Controlar uma venda, uma compra, uma transação de qualquer tipo. Para isso precisamos encapsular as regras para essa transação. Precisamos, principalmente, de objetos capazes de validar os dados de entrada e de objetos capazes de realizar o processo. Os primeiros são validadores e os segundos, serviços.
Serviços seguem o padrão interface + várias implementações e temos dois grandes grupos. Serviços de aplicação (como enviador de email) e serviços de domínio (como o que realiza a transação de compra). O próprio PersistanceStrategy de antes é um serviço de aplicação.
Validadores são usados dentro dos serviços para validar os dados de entrada. Neles mantemos todas as regras que permitem realizar a operação. Validadores podem ser usado fora dos serviços para acelerar as coisas e nem sequer chamar os serviços caso haja problema, mas devem sempre ser chamados dentro dos serviços independentemente de serem chamados antes. É como a validação javascript que não substitui a validação no servidor. Entenda-se: estes validadores não apenas validam os dados de input do usuário, mas aplicam regras de negócio a esses dados.
Recapitulando: Serviços de Aplicação e Serviços de Domínio. Serviços utilizam Validadores para evitar corrupção.
Finalmente, um pouco sobre actions. “Action” é qualquer classe onde você controla o fluxo de uma aplicação web. O nome ficou famoso devido ao Struts e muita gente ainda chama estas classes de controladores (quando na realidade são apenas Strategy) erradamente. Todos os frameworks web, de uma forma, ou de outra, acabam delegando a uma classe ou conjunto de classes a decisão de processamento de um certo request. Essa classe é a action.
A action só pode conversar com Serviços de Domínio e executar pesquisas em Repositórios. Não podem invocar mecanismos save/delete nos repositórios. Para não cair nesta tentação é mais seguro você criar um serviço de dominio que medie a comunicação action-repositorio, garantindo que apenas métodos de pesquisa são invocados. A responsabilidade das actions é converter os dados da UI em dados que os serviços entendem. Isso normalmente significa Entidades, mas não apenas. Vários Value Objects como BigDecimal e Date pode necessitar de conversão também. Eventualmente a Action pode invocar validadores antes de invocar os Serviços. Isto especialmente para ser capaz de informar o usuário e proteger o sistema de dados corrompidos ou que não satisfazem as regras de negócio.
Enfim, as requisições do usuário são mastigadas nas actions onde se transformam em objetos do que os serviços aceitam. Os serviços são invocados. Os serviços chamam outros serviços e/ou têm lógicas internas que produzem alterações em objetos existentes ou criam novos objetos. Os serviços utilizam os repositórios para realizarem pesquisas e persistir as alterações. Os repositórios delegam ações de persistência e pesquisa a implementações de PersistanceStrategy que as traduzem para ações reais sobre o banco de dados ou sobre um DomainStore como o Hibernate.
Não há por que complicar a arquitetura e design das sua aplicações web. Estes poucos elementos são normalmente suficientes para realizar sistemas em que há muito mais leitura do que escrita. Mas, mesmo que você esteja desenvolvendo aplicações web-RIA (ou seja, simulando aplicações desktop de cadastro em web) esta arquitetura ainda é suficiente.
Não continue se iludindo com o uso de EJB ou desenhando aplicações como se fazia nos anos 90. Já se passaram 20 anos. Estamos em 2010.
Cara, na boa, na boa mesmo, revise seu texto. Há uma série de erros e comentários no mínimo duvidosos aqui.Quero deixar claro que não estou aqui para desmerecer seu trabalho, aparecer nem pra te ofender, apenas percebi algumas incoerências que julgo importantes para passarem despercebidas. Não precisa nem publicar esse comentário.
Vou citar alguns erros, mas espero que você releia e reflita.
1 – “Hoje com o advento do Seams parece que EJB vai ser novamente necessário para fazer sites.”
Já começou errando o nome. É Seam, JBoss Seam. E o Seam não te obriga a usar EJB nem JSF. E por falar nisso, a implementação padrão do CDI não é o Seam, mas um framework chamado Weld.
2 – “Veja que Seams utiliza os EJB como back-beans do JSF o que significa que não funcionará fora de um Application Server.”
Como já foi dito antes, o Seam não te obriga a usar EJB. Trabalhei mais de um ano com o JBoss Seam sem escrever um único EJB. E inclusive você pode rodar o Seam no Tomcat ou outro web-container, o que reforça essa afirmação.
3 – “A própria especificação JEE 6 vai oficializar este divisão entre o que é web site e o que é realmente uma aplicação corporativa.”
O que a especificação fez foi criar profiles(perfis) de acordo com a frequência de uso dos serviços do servidores de aplicação. A grande maioria dos desenvolvedores não utiliza Message Driven Beans ou integração com CORBA, o que não significa que a aplicação não seja corporativa. Na verdade, até mesmo o profile web vai permitir o uso de EJB numa versão light, então se você chamou de “aplicação corporativa” sistemas que usem EJB pode notar claramente o erro de conceito.
Perceba que citei alguns erros importantes de apenas um parágrafo. Vou ficar por aqui, qualquer coisa me manda um e-mail.
Legal o seu artigo Sérgio.
Você teria um projetinho de exemplo com esta idéia de arquitetura ?
Certo. o nome é Seam. Minhas desculpas.
quanto ao resto vou citar o próprio site do JBoss Seam
“Seam integrates technologies such as Asynchronous JavaScript and XML (AJAX), JavaServer Faces (JSF), Java Persistence (JPA), Enterprise Java Beans (EJB 3.0) and Business Process Management (BPM) into a unified full-stack solution, complete with sophisticated tooling.”
“Seam is based on the Java EE platform. That’s why reinvestment in Java EE standards is crucial to Seam’s future”.
O ponto não é que é possível ou não deixar de usar EJB, o ponto é que existe uma “força” que pende para ai. Por isso que eu disse ‘parece” e não “é”. Tudo bem que forcei quando disse que não funciona fora do AS. Faltou explicar o que eu estava realmente pensando. A frase deveria ser “A JBoss não ganha nada se vc rodar o Seam fora do AS”
No resto concordo. É uma questão de como dizer as coisas. Eu não considero sites aplicações corporativas e o web profile é exatamente essa separação.
Bom, o http://www.javabuilding.com é escrito nessa arquitetura. Agora, se vc está pedindo por código, o que eu posso dizer é que arquitetura não se entende no código. Se você entendeu os componentes e o que cada um deve fazer, vc cria seu próprio código.
Pelos vistos várias pessoas querem ver um exemplo prático. Então, gente, mandem sugestões de programas simples onde demonstrar isso e posso fazer uma segunda parte do artigo. O problema é que é muito código para escrever num blog….
Sergio,
Excelente texto e brilhante colocação, aos comentários leigos não percebi sequer algo que me convencesse.
Um grande abraço !!!
Olá Sergio,
Como ja comentaram aqui, o Seam roda em simples servlets containers e totalmente independente de EJBs. E não é que a utilização do Seam em projetos “pede” ou “tende” a usar EJBs como vc comentou e sim o contrário, se vc pretende usar EJB 3.0, é bastante recomendável usar o Seam – existe uma larga diferença aqui. Inclusive no JavaEE 6, o CDI (engine do Seam 3, implementado com Weld), tbm roda em ambiente Desktop JavaSE, conforme demonstrei ao vivo no TDC-2009. Tenho vários projetos Seam sem o uso de EJB, e se você ler o livro Seam In Action verá que Dan Allen tbm não gosta muito do uso de EJB em seus projetos.
Outro ponto é que existe um grande equívoco na afirmação: “Ela (JPA) viola explicitamente o propósito de mapeamento agnóstico o que significa que usando JPA você não poderá usar qualquer banco de dados. (..) As pesquisas do JPA não são OO e não são agnósticas. As do Hibernate são OO se usar Criteria e agnósticas quer usando Criteria ou HQL.”
O JPA e sua JPQL oferece a mesma abstração e agnoticismo que o HQL, na verdade as diferenças são mínimas. Inclusive a versão 2 do JPA tbm suporta Criteria.
No mais parabéns pelo novo site, tenho certeza que fara sucesso.
[]s
A. Lazarotti
O fato do JPA só suportar criteria na versão 2 suporta exatamente o que eu quero dizer. JPA não é completo o suficiente e não é OO o suficiente. Ficar remendando uma má idéia não a torna uma boa idéia.
Eu acho, sempre achei, um absurdo que o JPA tenha sido lançado sem criteria. O JPA sobre do mesmo problema que o EJB sofre. É instável por design.
Mas vejam, não sei porque essa defesa tão ferrenha do JPA. Se querem usar JPA , façam-no. Na realidade é irrelevante qual mecanismo de persistência usam desde que não usem DAO.
Na realidade eu não uso nenhum dos dois, JPA ou Hibernate, se puder escolher.
O ponto é que para usar persistencia, o uso do DAO é obsoleto e um uso de Repositorios e estratégias de persistência mediados pelo uso de Query Object agnóstico.
Sergio, note que não foi uma defesa, mas apenas uma correção. A maioria dos meus projeto utilizam hibernate e apenas bootstraps do JPA e DI de EntityManager.
E ainda bem que existem estes remendos, o mundo seria pior apenas com softwares 1.0.
De qualquer forma, o design do JPA é igual o design da maioria dos ORMs, principalmente em sua nova versão. Com a diferença da propagação e integração dos seus serviços a todos os demais container JEE.
Abraços
Da pra ver que é uma boa arquitetura mesmo: a home page esta exibindo zilhares de ??messages:architecture?? no chrome. Bom fazer antes de falar…
E esses erros sobre o Seam, falando que ele precisa de EJB, e que a JPA não tem Criteria… pesquise um pouco antes. Não era preciso ler muito para descobrir esses graves erros.
Caro robson,
Primeiro, obrigado por ter referido o problema das mensagens eu não está consciente desse problema. Vou corrigir assim que possível.
Segundo. Julgar a arquitetura pela apresentação é simplesmente um fraco argumento. Aliás nem sequer é argumento, é uma piada de mau gosto. Você sabe quanto demorei para colocar a feature de search no site ? 3 horas. E isso porque tive que aprender a usar o Compass nesse tempo. Vc sabe que esse site não usa banco de dados ? Vc sabe que quando usar, não preciso mexer em nada do mecanismo de pesquisa ? Para mim isto que é arquitetura.
Terceiro, JPA atualmente ainda não está na versão 2.0. Apenas a versão 2.0 terá, quando sair, no futuro, uma Criteria API. O JPA hoje, agora, não tem api de criteria. Dizer que o JPA tem criteria é simplesmente anacrônico.
Sim, o design do JPA é igual aos dos ORM, por isso mesmo ele deveria ser o JORM não o JPA. Eu não disse que o design dele é ruim, eu disse que ele não serve um propósito maior e por isso ele é inutil face às alternativas. A unica coisa que ele tem a oferecer é neutralidade mas todo o mundo que mexeu com JPA já teve que fazer alguma coisa “por fora” , portanto, essa neutralidade tem um preço e não é possivel criar sistemas reais apenas com JPA. Da mesma forma que não era possivel apenas com EJB 2.x. Quem passou por esse tempo sabe muito bem que CPM era uma porcaria e BPM dava tanto trabalho que tínhamos que usar DAO. Hoje DAO não é mais necessário, mas o trabalho de isolar a aplicação do banco de dados ainda não terminou.
Persistência é mais lato que apenas banco de dados. Só posso supor que vc não tem problema algum em simular um banco de dados em memoria quando usa JPA e que todos os seus testes executam rapidinho… Gostaria de ser no seu blog como vc consegue isso.
O JPA funciona fora do aplication server, portanto é bom não confundir os recursos do AS com os do JPA. Por exemplo, injetar o Entity Manager não é uma feature do JPA.
Parece que as pessoas não entendem o que “parece” significa. eu disse :
E todo o mundo leu “O Seam precisa de EJB”. Não entendo essas conclusões. A lógica é simples. Se vc usa Seam com EJB vc precisa de um EJB container, e isso significa que precisa de um AS. Ainda não estamos usando embeded EJB porque isso ainda não saiu. Se vc não usa EJB com Seam, porque usaria EJB ? qual vantagem EJB tem que não pode ser alcançada de outra forma ? Ou seja, hoje em dia EJB serve para quê ?
A única vantagem nestas condições é neutralidade. Session e Message beans sempre foram neutros, mas esses vc simula muito facilmente. A real neutralidade está nos entity beans que agora não existem mais. Então o EJB 3 é apenas Session e Message beans, ou seja , a parte facilmente replicável de outras formas. E o problema real ficou na mão do JPA que continua sendo “neutral demais”.
O Seam é um exemplo de algo que revive o EJB e isso é necessário para reviver o uso do JBoss como um todo e não apenas o Tomcat. Mas para fazer sites, não precisamos do JBoss…
“Terceiro, JPA atualmente ainda não está na versão 2.0. ”
http://www.jcp.org/en/jsr/detail?id=317
“Final Release 10 Dec, 2009”
Por favor, um minimo de pesquisa… Já tem mais de 4 meses. Um cara escreve um jornal de arquitetura e não sabe nem sobre o release da JPA2? EclipseLink e Hibernate (3.5cr1) já são compatíveis.
E sobre sua frase do Seam, na primeira frase voce diz “parece”, na segunda você é bem claro, e afirma categoricamente: ” Veja que Seam utiliza os EJB”. Não, não utiliza.
Primeiro, alguma confusão ai, eu não escrevo um jornal, muito menos de arquitetura. É apenas um blog. Um blog sobre desenvolvimento. Arquitetura é um dos itens.
Sim, embora soubesse que o hibernate e o eclipse estavam se mantendo compativeis e o eclipse link fosse a RI não sabia que já tinha saido. Obrigado por me esclarecer.
Como já disse antes, se dependesse de mim JPA não seria usado nunca.
Mas nada disso muda o argumento do post. O ponto é que o JPA não pode ser “mokado” para testes ou usado para persistir em outra “media” que não SGBD
e que o EJB atual é dispensável para web. Esse é a questão. Se vc vai fazer um site, EJB é totalmente dispensável. A referencia ao Seam era apenas para mostar que para o olhar mais superficial
pode parecer que o EJB ainda tem algum papel no jogo. Não tem.
Quando a Seam usar EJB, não vamos ficar aqui brincando com as palavras :
O EJB 3 vai rodar do mesmo jeito que o 2.x. O problema ainda se mantém só mudou de nome. Entity Beans agora são JPA.
O modelo de persistencia do java vai mudar numa versão 4 da vida. Mas no mundo real JPA não é e nunca foi um beneficio. E com o movimento NoSQL e os bancos não-relacionais no virar da esquina ele está cada vez mais inutil. Algo que nos pode valer são coisas como o Projeto Siena ou o MiddleHeaven que ainda são projetos em gestação.
Sem uma API à altura de resolver o problema da persistencia ( e não apenas do mapeamento objeto-relacional ) JEE com EJB e JPA continua obsoleto.
Não tou proibindo ninguem de usar ( nem poderia), estou apenas mostrando uma alternativa. Usa quem quiser.
[…] Em 2010 insisti no conceito do Repositório como peça fundamental do andar de domínio.Era a mudança de paradigma mais relevante na época. Este tempo todo depois e parece não ter vingado. As pessoas ainda pensam em termos de DAO. Mas isto me pôs a pensar o que mais falta nos designs de hoje em dia. Além do isolamento da UI que falei outro dia, que é um assunto mais complexo, um ponto importante é a proteção do domínio. […]