Posts Tagged ‘Spring’

Managed Beans. Não complique, simplifique.

Thursday, August 27th, 2009

Já é sabido de todos que JSF é um framework web MVC com uma filosofia voltada a component-based. E não diferentemente dos bons frameworks action-based existentes hoje em dia, o JSF também se utiliza de POJOs como parte do controller.

Sim, eu estou falando dos, já muito conhecidos, managed beans. Eles são os responsáveis por intermediar a comunicação entre nossas páginas e o nosso modelo. Até aí tudo bem, não existe qualquer mistério, basta entender um pouco sobre MVC que isso torna-se óbvio.

Se você observar, quando está trabalhando com JSF, notará que cerca de 50-70% do seu esforço é dedicado na implementaçao do managed bean. E que as futuras alterações e correções de bugs estão intimamente ligados a ele. Implementar corretamente um managed bean pode evitar muita dor de cabeça e facilitar na manutenção da aplicação.

Mas você já se perguntou como e qual seria a melhor forma de implementá-los? Não que exista apenas uma única maneira de escreve-los, longe disso, mas em contra partida existem inúmeras maneiras de torna-los realmente ruins.

Escrever um managed bean de forma porca incorreta pode dificultar e muito sua vida e da sua equipe. Falta de legibilidade, dificuldade para escrever testes de unidade e principalmente medo de alterar o código são apenas alguns dos possíveis problemas.

Agora pare e imagine a vida do próximo desenvolvedor que deverá manter tal código. É, não parece algo divertido.

Managed Beans mais responsáveis

A principal responsabilidade de um managed bean é intermediar a comunicação entre as páginas (componentes do JSF) e nosso modelo. Escutar eventos, processa-los e delegar para a camada de negócios são apenas algumas de suas responsabilidades.

Talvez devido a experiência com frameworks action-based muitos desenvolvedores acabam subutilizando os managed beans e sobrecarregando as páginas com lógicas e dados desnecessários. Os managed beans e as páginas usam a abusam do modelo “pull” durante a renderização e (re)construção da árvore de componentes, isto é, basicamente as páginas é quem decidem (através de EL) quais os dados e lógica necessária para que possam ser processadas.

Graças a este modelo nós conseguimos retirar toda lógica de renderização da página e colocando-a onde jamais deveria ter saído, no managed bean. Esta lógica estará localizada nos métodos públicos do managed bean que serão acessados através de EL pela página.

Não importa se a lógica é simples ou complexa, é quase que mandatório que ela esteja localizada no seu managed bean. Então bizarrices lógicas de apresentação nas páginas, que não são difíceis de se encontrar por aí, como esta deveriam ser evitadas:

<h:panelGrid id="pnl" rendered="#{loginBean.usuario.admin == 1 or loginBean.permissao('exibir_painel_de_usuarios')}" />
	...
</h:panelGrid>

Reparem que a lógica de apresentação está, representada através de EL, na página. Se você teve a infelicidade de encontrar códigos assim então há grandes possibilidades de você também encontrar regras de negócio nas páginas, o que é muito pior que encontra-las no controller.

E olha que este foi apenas um exemplo simples e ligeiramente legível, já encontrei códigos mais complicados que este de dificil leitura e horrível de dar manutenção.

O problema disso é se houver a necessidade de mudar a regra (o que muitas vezes ocorre), mas e se ela estiver duplicada por dezenas de páginas, como você faria? Como testa-la? Pense um pouco sobre isso.

Imaginem um código um pouco pior que este (com 3 ou 4 condicionais), mas dentro de um componente de iteração (como h:dataTable ou ui:repeat). É, você nem vai querer imaginar.

A regra de visualização acima deveria está encapsulada no managed bean, a página não deveria conhecer a regra, mas apenas quem a conhece. Então pensando nisso nós poderíamos alterar nosso código para algo melhor, algo como isto:

<h:panelGrid id="pnl" rendered="#{loginBean.permitidoExibirPainelDeUsuariosLogados}" />
	...
</h:panelGrid>

O componente não conhece a regra, mas sabe exatamente a quem perguntar. O código está bem mais legível pois revela sua intenção. Agora está bem mais fácil mudar a regra (pois temos apenas um único ponto de manutenção) e principalmente testa-la através de testes automatizados.

Um managed bean deveria ao máximo tentar esconder a complexidade das páginas através de métodos que revelem a devida intenção, ou seja, a nomenclatura dos métodos é realmente importante e você deveria dar importância a legibilidade do seu código.

Comunicação entre managed beans

O que eu tenho para falar, de longe, se iguala ao que pode ser encontrado no excelente conteúdo sobre comunicação no JSF neste post no blog do BalusC, além de que para mim ele aborda 99% sobre como managed beans podem se comunicar.

O que pretendo falar está mais relacionado em como manter uma conversa (troca de mensagens) saudável entre managed beans. Em como explicitar os parâmetros esperados e como passar parâmetros de um managed bean para outro de maneira coerente.

A comunicacão entre managed beans não difere da troca de mensagens entre componentes de software na orientação a objetos. Cada componente (managed bean) conhece a interface pública do outro componente para que eles possam trocar mensagens.

Sendo, ter esta interface pública bem definida pode facilitar muito a “conversa” entre os managed beans, facilitar os testes, evitar problemas inesperados, diminuir o acoplamento, aumentar a coesão e assegurar contratos e invariantes do componente.

Nada mais claro que um exemplo para assimilar a idéia:

<h:dataTable var="item" value="#{compraBean.itensNoCarrinho}">
    <h:column>
        <h:commandLink value="detalhe" action="#{itemBean.exibirDetalhesDoItem}">
            <f:setPropertyActionListener value="#{item}" target="#{itemBean.itemSelecionado}" />
        </h:commandLink>
    </h:column>
</h:dataTable>

O código acima não tem nada de errado ou anormal, nada do que não estejamos acostumados a ver quase todos os dias. Se repararem há um pequeno “dialogo” entre dois managed beans - compraBean e itemBean - que estão trocando informações.

O problema não está na comunicação em si, pois isso teria que acontecer de um jeito ou de outro, mas sim em como eles se comunicam. O managed bean compraBean conhece detalhes de como o itemBean se comporta, ou seja, ele sabe mais do que o necessário.

Um maneira de melhorar isso seria ter uma interface pública bem definida no itemBean. Algo semelhante ao código abaixo:

<h:dataTable var="item" value="#{compraBean.itensNoCarrinho}">
    <h:column>
        <h:commandLink value="detalhe" action="#{itemBean.exibirDetalhesDoItem(item)}" />
    </h:column>
</h:dataTable>

Além de todos os benefícios (baixo acoplamento, alta coesão etc) citados acima, nós ganharíamos de cara maior legibilidade no código, o que é algo realmente importante quando a comunicação foge do trivial.

Vale ressaltar que independente da comunicação ocorrer na página (por meio da JBoss-EL) ou diretamente dentro do managed bean, essa abordagem poderia -e até deveria- ser utilizada. Para o segundo caso, frameworks como JBoss Seam ou Spring ajudam a injetar as dependências de maneira simples através de anotações.

Um ou vários managed beans?

Não tenho uma opinião realmente formada quanto a isso, ainda não. Já pensei várias vezes sobre o assunto, e sempre me pego vislumbrando cenários nada comuns. Que no caso os considero como casos excepcionais.

Desde 2006 eu trabalho com JSF, ministro cursos e treinamentos e presto consultoria para algumas empresas. E posso dizer que somente três vezes eu precisei ter mais de um managed bean para resolver uma tarefa. Dentre todas eu tenho a ligeira impressão que segui o caminho errado mais complicado, e que se tivesse pensado mais um pouco eu poderia ter evitado tais soluções.

Managed beans são componentes, em sua grande maioria, intimamente ligados a(s) página(s) e que deveriam ter apenas o estritamente necessário para representar a GUI. Dificilmente você terá um managed bean genérico (CRUD não conta) que poderia funcionar em todo lugar. Você precisa fazer um esforço hercúleo para conseguir isso, e as vezes parece que não vale a pena.

A idéia de um managed bean ter dados (entrada pelo usuário e estados) e comportamentos (eventos e regras ligadas a apresentação) juntos segue o princípio básico da OOP, o que torna o trabalho mais simples e coeso. Tentar ir contra isso (ao estilo ActionForm e Action do Struts) pode te trazer muita dor de cabeça a médio-longo prazo.

Neste post do Neil Griffin, um dos autores do primeiro livro de JSF2.0, ele sugere alguns “rótulos” para os diversos tipos de managed beans que podem haver numa aplicação, e ainda por cima ele incita que seria uma boa prática trabalhar com vários managed beans por questões de SoC, baixo acomplamento etc.

De fato, devido ao modelo “pull” podemos ter managed beans atuando como componentes menores, mais reutilizáveis e mais orientados a objetos. Ter componentes (managed beans ou não) de granularidade fina colaborando para construção da página é algo bastante comum, e eu mesmo me utilizo muito disso. Mas não são destes tipos de componentes que falo, muito menos o Neil.

Eu, particularmente, não concordo com quase nada no post do Neil. Para mim ele se utilizou de argumentos isolados e vagos para defender sua idéia. Managed beans por sua natureza deveriam ser simples, contudo a abordagem do Neil, definifitivamente, vai contra tudo isso. Eu a considero um overkill, e ela torna qualquer aplicação web difícil de manter.

Bem, se dois ou mais managed beans relacionados -delimitados a um contexto- estão servindo para você e sua equipe, ótimo. Continue assim, não tem porque mudar. O framework (JSF) te permite isso, contudo eu tenho sérias dúvidas se essa abordagem vale a pena.

Conclusão

Este post estava em draft faz um bocado de tempo, mas a falta de tempo e a coragem não me permitiam finaliza-lo. Felizmente resolvi tira-lo do baú e posta-lo.

Tudo que comentei aqui está mais ligado a minha experiência e o que aprendi durante estes anos como desenvolvedor (e conversando com outros profissionais) do que eu pude encontrar em livros de JSF sobre o assunto. Existem muitos livros bons, assim como artigos em blogs e sites especializados sobre o assunto, mas nada melhor que a experiência do dia a dia para nos mostrar caminhos mais adequados de como solucionar determinados problemas.

Por mais longo que o post tenha ficado, eu ainda sinto que falta complementa-lo em alguns aspectos e pontos. Pois o que falei acima acaba te levando a aderir outras soluções não menos importantes, mas que já foram bastante citadas neste blog e discutidas em listas de discussão.

Entre os três tópicos abordados aqui eu ainda tenho algumas dúvidas quanto ao último, principalmente depois desta resposta do @edburns a minha pergunta no Twitter. Hoje minha opinião está mais para o lado “um managed bean é suficiente” por não ter encontrado respostas que me convencessem do contrário.

Enfim, como disse antes, se vários managed beans intrinsecamente relacionados estão resolvendo teu problema por algum motivo, ótimo! Continue assim. Se você tiver um tempinho e puder comentar sobre tua decisão eu ficaria grato.

O que todo bom desenvolvedor JSF deveria saber

Monday, January 19th, 2009

Dificuldades todos temos, principalmente quando estamos aprendendo uma nova tecnologia, framework ou paradigma, e isso torna-se ainda pior quando não temos qualquer interesse em aprender sobre os mesmos.

Não é de hoje que percebo que a maioria das dúvidas postadas sobre JSF em listas de discussão e fóruns estão intimamente ligadas a falta de conhecimento base sobre a tecnologia ou mesmo sobre os conceitos na qual o framework (JSF) foi construído - sim, estou falando de conceitos sobre desenvolvimento web e component-based.

É óbvio que JSF existe para tentar abstrair toda a complexidade existente no desenvolvimento web Java, complexidade esta que deveríamos evitar, mas é indispensável termos o mínimo de conhecimento sobre a mesma. Pois se você acha que apenas conhecendo os componentes você construirá uma aplicação decente então você está enganado.

Assusto-me com o número de dúvidas na javasf em que o mínimo de conhecimento sobre web seria suficiente para solucionar o problema, independente do framework utilizado. Evidente que muitas das dúvidas estão ligadas a tecnologia, JSF no caso, mas estes mesmos problemas também seriam facilmente resolvidos se os desenvolvedores se dessem ao trabalho de tentar entender os fundamentos do framework.

Quando falo dos fundamentos de JSF eu estou me referindo ao ciclo de vida, comunicação entre managed beans, escopos de conversação, árvore de componentes, a idéia por trás dos converters e validators, phase listeners, modelo dos componentes etc.

Desenvolver aplicações JSF guiado por “brute-force” é algo que todo desenvolvedor deveria evitar, de fato, ver um exemplinho (ou demo) básico de um componente, copiar o código, joga-lo na aplicação e ainda por cima achar que deveria funcionar é algo ingénuo demais até mesmo para um programador iniciante.

Pior que isso é continuar tentando fazer o componente ou bloco de código funcionar a todo custo sem nem ao menos ler a documentação do mesmo [por isso o termo "brute-force"].

Não adianta correr para tentar usar os componentes se você não possui os fundamentos básicos sobre JSF ou mesmo sobre desenvolvimento web.

Saber o básico é importante

Saber o básico de qualquer tecnologia é obrigatório, e com JSF não seria diferente. Acredito que em primeiro lugar é importante entender o que é JSF e qual a diferença entre uma implementação e um conjunto de componentes.

Criar e configurar um projeto web JSF faz parte do aprendizado, independente da IDE, claro. Como disse, o interessante é não depender exclusivamente da IDE, mas sim conhecer o mínimo necessário para configurar e rodar um projeto com faces (como as libs necessárias e configuração do web.xml).

Entenda que um managed bean é apenas um POJO e que deveria ser o mais simples possível (refletindo estritamente o necessário da GUI). E por favor, coloque uma vez por todas na sua cabeça que os componentes (através de EL) acessam os valores dos managed beans através dos métodos assessores (getters e/ou setters) e não das propriedades.

Depois disso eu aconselharia o entendimento sobre converters e validators, pois eles tornam o desenvolvimento bem mais simples se comparado a outros frameworks MVC. Principalmente os converters, pois eles sim “quebram um galho” danado!

Entenda como o framework e os componentes disparam/tratam os eventos e listeners, e principalmente quando utiliza-los, pois utilizar um listener incorreto para um determinado cenário pode dificultar muito a sua vida, mesmo que no final a coisa funcione. Praticamente tudo o que você precisa saber estará na documentação do componente.

Procure entender o sistema de regras de navegação entre páginas do JSF, principalmente quando e porquê você deveria usar redirect ao invés de um simples forward. E claro, lembre-se que JSF trabalha (submete formulários) apenas com o método POST, não com GET.

Quando as páginas tornam-se grandes e até complexas vale a pena organizar os blocos de componentes através de componentes “maiores”, ou seja, componentes do tipo naming containers, com eles se torna possível manipular os componentes tanto no lado cliente quanto no lado servidor de forma mais simples.

Os fundamentos chaves do framework também fazem parte do conhecimento básico, ou você acha que apenas saber utilizar os componentes, navegar entre páginas e criar seu próprio validator são suficientes?

Sendo, é muito importante que você os compreenda da melhor forma possível. Provavelmente alguns deles você terá alguma dificuldade de entender no inicio, isto é normal, mas é interessante que você ao menos conheça superficialmente cada um deles.

Comece entendendo como e quando a árvore de componentes é gerada (está muito ligado ao ciclo de vida), busque entender como o JSF persiste o estado da árvore de componentes entre requests e porque utilizar JSTL no momento certo é importante.

Os passos necessários para estender ou construir seu próprio componente é algo também importante, mesmo que você não seja um expert nisso, conheça estes passos. Eu particularmente nunca tive a necessidade de criar um componente, apenas estendi um [uma única vez], e com a gama de componentes hoje em dia eu acho muito difícil -mas não improvável- você precisar criar seu próprio componente.

Um fundamento extremamente importante é conhecer as maneiras como os objetos e managed beans se comunicam entre si numa aplicação JSF, pois sem este conhecimento provavelmente você cometeria erros e subutilizaria o framework na sua aplicação.

E por fim, o mais importante fundamento, sem sombra de dúvidas, é entender o ciclo de vida (lifecycle) das requisições no JSF. Procure entende-lo muito bem, pois assim você evitará horas quebrando a cabeça com problemas relativamente simples (quem nunca teve dificuldades de entender como funciona o atributo immediate?).

Vale salientar que independente do(s) conjunto(s) de componentes que você pretenda utilizar os conceitos acima te permitirão trabalhar de forma prática, correta e produtiva.

Mas vá além do básico

Os conhecimentos básicos são obrigatórios quando se pretende desenvolver qualquer aplicação com JSF, por menor que ela seja, mas a partir do momento que se desenvolve aplicações maiores e até complexas se faz necessário adotar certos frameworks, abordagens e até conhecer ou saber que existem algumas soluções mais interessantes.

Assim como a maioria dos frameworks web, JSF trabalha com páginas, muitas páginas para falar a verdade, e isto nos leva a necessidade de um framework para templating. E sempre que falamos em um framework com esta finalidade para JSF nós não devemos esquecer: Aplicações sérias em JSF usam Facelets.

Para quem ainda acha que deve criar seu converter apenas para formatar e remover máscaras de strings deve se interessar por abordagens mais práticas e produtivas de se trabalhar com componentes e conversão de entidades de domínio da aplicação.

Um dos grandes problemas para quem está começando com JSF e componentes AJAX é a maneira como estes desenvolvedores subutilizam os recursos AJAX do framework e dos componentes. Sendo, vale a pena estudar e adotar uma abordagem mais eficiente para isso, uma abordagem com foco em navegação orientada a estados.

Uma abordagem orientada a estados é realmente eficaz e produtiva, mas em certos momentos precisamos “tunar” as requisições AJAX dos componentes ou mesmo diminuir os gargalos em determinadas páginas, buscar melhores práticas para os conjuntos de componentes e/ou frameworks AJAX adotados para um projeto é dever do desenvolvedor, sejam estas práticas para JBoss Richfaces, Myfaces Trinidad ou qualquer outro.

A Expression Language (EL) do JSF por padrão ainda é bem limitada, porém muito extensível, e muitas vezes precisamos de features bem mais arrojadas, logo, não podemos abrir mão de extensões como a JBoss EL para que assim evitemos implementar soluções bizarras.

Como havia dito antes, JSF trabalha apenas com POST, porém algumas vezes precisamos submeter formulários via GET ou disponibilizar links (bookmarking) que acessam recursos ou executam algum método no managed bean antes de renderizar uma página. E antes que você implemente seu próprio phase listener ou alguma solução nada elegante eu indico a você o framework Restfaces.

Nem todas as aplicações web necessitam de um mecanismo arrojado de segurança, muitas vezes uma simples página de login para autenticação e um Servlet Filter (ou phase listener) para autorização de recursos resolve o problema. Mas qualquer coisa além disso você deveria, obrigatoriamente, partir para um framework especializado no assunto: como o Spring Security ou JAAS.

Já cansei muito de bater na tecla que não existe arquitetura de referência (aka bala-de-prata) para solucionar todos os problemas de softwares, já discuti muito isso na lista do javasf, cejug e já comentei sobre isso em vários posts meus e de colegas.

Mas também sei que muitos desenvolvedores/arquitetos tem dificuldades em dar inicio numa arquitetura base que se integre bem com JSF, desta forma, eu aconselho a leitura de dois excelentes posts do Cagatay como referência básica. 1) sobre a integração de JSF+JPA+Spring com o uso massivo de anotações e 2) com a integração anterior mais o Spring Security e Myfaces Orchestra.

Se por algum motivo você não gosta ou não se dá bem com Spring então vale a pena dar uma olhada em um projeto recente de integração entre JSF e Guice, o Guicesf. O Guicesf foi uma iniciativa do Volnei, um dos membros do JavaServer Faces International Group (javasf), e que está caminhando muito bem diga-se de passagem.

Ainda assim, acredito que se você tem tempo para estudar e levantar uma arquitetura para seu projeto então corra e dê uma olhada no JBoss Seam, pois todos os problemas (escopos conversacionais, LazyInitializationException, bookmarking etc) que você encontrará com JSF e solucionará com a integração de alguns frameworks e componentes você com toda certeza poderá ter a mesma solução muito mais simples e muito melhor implementada no JBoss Seam, ou seja, soluções prontas!

Concluindo

A maior parte do conhecimento que você precisa para se tornar um bom desenvolvedor JSF está ligada aos fundamentos do framework, e aos fundamentos sobre desenvolvimento web. Com estes conhecimentos alinhados você não terá muitas dificuldades.

Além do mais, não se assuste se você tiver alguma dificuldade no inicio, principalmente se você já trabalhou com algum framework action-like, como Struts ou Webwork, pois a maioria dos desenvolvedores vindos do “mundo” action-like são os que mais possuem dificuldades em desenvolver aplicações com JSF.

Não pare por aqui, continue pesquisando e estudando sobre a tecnologia, principalmente sobre as novidades do JSF2.0 que estão por vir. Se você já possui experiência com JSF integrado a outros frameworks então aproveite seu tempo e dê uma chance ao JBoss Seam, pois sem dúvida alguma ele está trazendo grande produtivade no desenvolvimento “Enterprisey”.

Enfim, o intuito do post é abrir os olhos de novos desenvolvedores -e até de alguns veteranos- sobre como desenvolver melhor com JSF, e claro, disponibilizar fontes de estudos (quase todos os links levam a outros posts).

No final de tudo, este post nada mais é do que a minha opinião.