O uso de sessão em aplicações web

junho 5th, 2010 § 7

Há uma corrente de pensamento que diz que aplicações web deveriam ser stateless. É um pouco confuso, pois certos requisitos naturalmente possuem estado; porém, ser stateless não significa ignorar que o mundo real possuem transições, significa que o armazenamento do estado deve ser empurrado o máximo possível para o lado cliente.

Mas programadores Java EE não tão nem aí. O HttpSession é tão acessível e tão simples de usar que o programador não pensa duas vezes antes utilizá-lo. E talvez aí seja a fonte dos problemas: usa-se demais! As pessoas não se dão conta de que é difícil escalar aplicações web que usam muito Session; e que também pode ir contra a uma boa experiência de usuário, como o voltar ou o favoritar que deixa de funcionar. Acredito que existam alternativas tão melhores que o HttpSession que este só seria raramente lembrado. Veja as seguintes situações e suas alternativas.

Preciso fazer cache de entidades

Veja, o cache é sobre entidades obtidas através de classes da camada de persistência; mas a HttpSession é uma classe de arquitetura que somente a camada de apresentação depende. Entretanto, ao guardar e obter objetos na sessão de usuário, a camada de apresentação está ido além de seu escopo, que é simplesmente mostrar a tela para o usuário; é uma solução ruim.

Uma solução boa é usar bibliotecas de cache de verdade como Memcached ou JBoss Cache. Pois você pode colocá-las na camada de persistência, e ainda assim, não se amarrar à tecnologia Web. Sem falar que o cache, com essas ferramentas, é único por todo o sistema (e não único por usuário, como na Session), o que lhe garante maior controle sobre os dados não-atualizados.

Minha dica é, se não houver uma configuração de cache automatizado, como no Hibernate, ponha-os em classes que funcionam como decorator de DAOs, mas isso eu já falei antes.

O framework web guarda dados em sessão

Algumas vendors gostam de fazer ferramentas que sejam jumento-proof, com o intuito de convencer gerentes de que é possível contratar programadores a preço de banana. Muitos frameworks web já saem com essa mentalidade na sua concepção, e é tão jumento-proof que a ferramenta faz uso constante da HttpSession internamente sem o programador perceber.

Pra não usar sessão nesses casos, só há um jeito: troque de framework web, para um que nunca faça uso implícito de sessão. Porém, se você está no meio de um projeto, ainda é possível criar novas páginas com um novo framework, mas mantendo as antigas, só fazendo a transição quando estas precisarem de alterações. Ah, e se onde você está exigem o uso de uma “arquitetura padrão”? Então troque de emprego, porque ninguém merece, né?

O objeto que eu estou armazenando vai ser usado na próxima tela

São duas situações bastante comuns:

  1. existe uma tela onde aparece uma lista de um domínio qualquer; dado o clique de um elemento, uma nova página com os detalhes aparecerão;
  2. existe uma página com campos “somente-leitura”, onde o clique de um link muda para uma página com campos editáveis.

Nos dois casos, um desenvolvedor comum percebe logo que, como a segunda página irá requisitar os mesmos dados que a primeira, coloca os dados da primeira requisição na sessão para ser consultado depois. Não faça isso! Você pode estar achando que está economizando no banco, mas está negligenciando outros fatores. Exemplos: é mais fácil escalar um banco de dados quando há muita leitura (topologia mestre-escravo, por exemplo), do que escalar sessão de servidor web. E, às vezes, o usuário gostaria de entrar pela segunda página diretamente.

Prefira realizar a consulta de novo quando ocorrer a segunda requisição, e controle o estado pela URL, colocando a chave primária do domínio como parâmetro. Isso te livra de um monte de inconveniências, como no caso de o usuário apertar o botão voltar ou consultar a URL no histórico.
“Ah, mas toda vez que faço uma consulta, um porquinho-da-índia morre.” Então o problema pode ser resolvido pelo primeiro ítem acima: cache.

A lógica de negócio exige várias telas para sua conclusão

Existem casos onde a conclusão de um objetivo depende do envio de vários formulários, mas isso não é tão comum de acontecer. Mesmo assim, muitos consideram que escrever cada formulário no banco não compensa, porque o usuário pode desistir no meio do caminho. A solução mais comum é ficar guardando dados intermediários na sessão até chegar a última tela do processo, quando tudo é persistido.

Bom, pode ser um raro caso onde seja interessante armazenar na sessão. Porém, faça a coisa direito! Não espalhe por todo o código o armazenamento e a obtenção de objetos na Sessão. Se você tiver usando EJB, use um Stateful Session Bean para armazenar todos os objetos obtidos do usuário antes de persistir. Se tiver usando Spring ou outro contêiner de injeção de dependência, use uma classe de escopo de sessão para armazenar todos os objetos. Use o mínimo de classes de infraestrutura para evitar dependências desnecessárias.

Vou implementar um “carrinho de compras”

Todo mundo aprendeu HttpSession usando um exemplo de carrinho de compras. O problema é gente acreditar que, pra esse caso, só existe uma única solução possível, a única que lhe ensinaram, o armazenamento na sessão de usuário! Porém, isso pode não ser verdade num mundo real. Imagine que alguém tenha colocado um produto no carrinho virtual, mas desistido de comprar. Talvez essa informação de compra não-efetuada possa ser interessante para a loja, pois ela pode gerar alguma newsletter. Portanto, manter esses dados na Session está fora de cogitação!

Não quero dizer que um carrinho deve ser feito sempre em banco, mas determinadas regras de negócio podem ser implementados de jeitos diferentes dependendo do contexto. Os exemplos e templates de livros e apostilas só servem pra aprendizagem, não leve-os tão a sério!


E aí? Convencido que dá pra fazer uma aplicação sem HttpSession? Ou vocês acham que existem situações que não falei onde é realmente necessário? Comentem…

§ 7 Responses to “O uso de sessão em aplicações web”

  • alex disse:

    Artigo muito bom!
    Um entrave para não utilizar HttpSession seria do cliente não estar disposto por exemplo a ter um banco de dados mais parrudo…

  • alex disse:

    Artigo muito bom!
    Um entrave para utilizar HttpSession seria do cliente não estar disposto por exemplo a ter um banco de dados mais parrudo…

  • Mateus disse:

    Leonardo,

    Realmente existe um certo abuso sobre o uso de sessões, principalmente dos frameworks jumento-proof (gostei do apelido :) ). Hoje, existem soluções interessantes, além das quais você citou, para os casos do formulários de várias etapas. É possível, por exemplo, usar um escopo de Conversação, que teoricamente deve possuir um tempo de vida menor que o de Sessão, e com controle programável (via API ou declarativo, por exemplo). Nesta linha, existe o JBoss Seam que é um framework que possibilta e encoraja o uso de Conversações.

    Meus 2 centavos na discussão…

    []s

  • Eduardo disse:

    Olá, Leonardo,

    gostei muito dos seus posts, e por isso gostaria de te fazer um convite.

    Caso tenha interesse, é só entrar em contato. :)

    Abraço.

  • pablo disse:

    muito bom o seu post. o uso de sessão e algo que precisamos realmente se preocupar. Mas isso levantou uma dúvida no se diz a respeito do framework wicket (acho que você deve ter conhecimento) onde a grande sacada do framework e programar componentes stateful para um ambiente stateless, onde o controle do estado da aplicação é automático. É nesse caso que tipo de problema você vê? Onde que praticamente tudo que você faz no framework wicket fica armazenado em session. Valeu

  • Leonardo disse:

    O Wicket possui uma espécie de contador, que aparece na URL e que é incrementado toda vez que o usuário anda de página em página. Este contador só é ativado quando um componente statefull é renderizado na tela.
    Pois bem, quando o usuário aperta o botão voltar do browser, a URL exibida terá um contador menor que o atual. Ao clicar em qualquer link ou ativar qualquer formulário, o servidor receberá o contador vindo da URL e dirá: “Hum… estava esperando 5, mas me mandaram 3. Vou lançar um erro pro cliente.”. Esse comportamento serve para evitar a execução de ações fora de estado, mas é um pé-no-saco pra quem está usando o site. Por isso, contar com componentes statefull pode não ser uma boa ideia.
    Mas o Wicket sempre possui componente Stateless para cada componente Statefull. Por exemplo, o BookmarkablePage, o StatelessForm, o StatelessLink. É questão de saber dosar, e utilizar esses componentes na medida do possível.

  • Rogerio Santos disse:

    Uma opção que gosto é o uso de recuros como KeepAlive do richfaces ou saveState do tomahawk, porém vejo que muitas pessoas não gostam dessas opções.
    Estou em um projeto hj em que as pessoas não gostam do saveState por exemplo e preferem usar campos hidden no JSP para transportar dados de uma página para outra.

    Oque vcs acham ?

  • § Leave a Reply

What's this?

You are currently reading O uso de sessão em aplicações web at Objectzilla.

meta