Categoria Rails

Sem reinventar a roda, cache de páginas com EhCache e ServletFilter

Não faz muito tempo, surgiu a necessidade de aumentar o desempenho de uma aplicação JEE, e começamos a ver profile daqui, examina relatórios dali, nisso um amigo de projeto, que a pouco tempo havia se enturmado com Rails, teve uma idéia: "Por que não fazemos cache das páginas mais frequentes, podemos criar um pequeno framework, e fazer como o Rails faz", explicando... em Rails basta colocar no controller as páginas que você deseja que sejam "cacheadas". Ex:

RUBY:
  1. caches_page :noticias

Pronto, a primeira chamada à action "noticias" cria o cache, e será usada pelas chamadas subsequentes. Para expirar o cache basta chamar:

RUBY:
  1. expire_page(:controller => 'public', :action => 'noticias')

Mais detalhes e excelente tutorial no Rails Envy.

Eu gosto muito de criar coisas novas, mas como dito no último post, criar mais um mini-framework para dar manutenção em uma aplicação já não muito pequena... bem, não obrigado. Foi por isso que eu disse: "Cara, dá uma pesquisada, com certeza alguém já fez isso." E pra variar, sim alguém já fez isso.

O excelente e bem conhecido EhCache possui esta funcionalidade e muitas outras.

Este mini tutorial parte do pressuposto que já se tem conhecimento do EhCache e de ServletFilter, para quem não conhece qualquer um dos dois, sem pânico, são muito fáceis de serem utilizados, vale uma pesquisada por tutoriais.

Para facilitar a vida, podem baixar este anexo com a aplicação-exemplo que fiz, basta colocá-lo em seu container web predileto, no meu caso testei no Tomcat, e acessar as URLs de teste:

http://localhost:8080/cache/semcache/teste.jsp

http://localhost:8080/cache/comcache/teste.jsp

O exemplo, mostra a hora atual em milesegundos. A página com cache, após acessada, terá 10 seg de vida.

Para implementar bastou os seguintes passos:

- Baixar e instalar os jars EhCache (ehcache-1.3.0-beta.jar), EhCache Constructors (ehcache-constructs-0.7.3.jar) e Commons-logging (dependência requerida) no diretório lib.

- Incluir no arquivo ehcache.xml as configurações para cache de página, as propriedades falam por si, configurem a gosto:

XML:
  1. <cache name="SimplePageCachingFilter"
  2.     maxElementsInMemory="10000"
  3.     maxElementsOnDisk="1000"
  4.     eternal="false"
  5.     overflowToDisk="true"
  6.     timeToIdleSeconds="10"
  7.     timeToLiveSeconds="10"
  8.     memoryStoreEvictionPolicy="LRU"
  9. >

- Configurar um ServletFilter no web.xml, para a implementação de filtro SimplePageCachingFilter

XML:
  1. <filter>
  2.    <filter-name>SimplePageCachingFilter</filter-name>
  3.    <filter-class>net.sf.ehcache.constructs.web.filter.SimplePageCachingFilter</filter-class>
  4.    <init-param>
  5.        <param-name>suppressStackTraces</param-name>
  6.        <param-value>false</param-value>
  7.        <description>Whether to suppress stack traces in the filter</description>
  8.    </init-param>
  9. </filter>

- Indicar para quais páginas fazer cache a partir do ServletFilter definido acima, dentro do web.xml. No exemplo, tudo que estiver abaixo do diretório "comcache".

XML:
  1. <filter-mapping>
  2.    <filter-name>SimplePageCachingFilter</filter-name>
  3.    <url-pattern>/comcache/*</url-pattern>
  4. </filter-mapping>

Pronto, é somente isso, a página será devidamente cacheada, seguindo as configurações do ehcache.xml.

Caso queira fazer cache de apenas uma parte da página, no caso de quem utiliza jsp:include, basta utilizar a outra implementação PageFragmentCachingFilter

Essa pequena implementação já garantiu um bom desempenho em várias páginas e sem reinventar a roda criando um mini-framework para esta função.

Se alguém souber de outro meio para fazer cache de página em Java, por favor esteja a vontade para comentar, gostaria muito de conhecer outras implementações.

Comments

Getting Real, o princípio K.I.S.S. aplicado em metodologia

Faz pouco mais de 4 meses que comecei a utilizar Rails em alguns projetos, mas Java ainda é minha linguagem do coração, e algo que me surpreendeu muito foi a filosofia por trás do Rails, ele não é um framework matador de horda de dragões, e não é pra ser mesmo, seu próprio criador David Heinemeier Hansson não tem a intenção de adicionar um milhão de funcionalidades, e tem motivo pra isso, trabalha na 37signals, prercursora da metodologia Getting Real, uma verdadeira aula de como evitar a burocracia e extrair muita produtividade, considero o livro radical em alguns pontos, mas isso é questão de opinião, e é claro adequação à realidade do seu projeto.

E aqui cabe a pergunta, você não está fazendo coisas demais no seu projeto ?

Os frameworks hoje em dia parecem querer abraçar o mundo, querem estar em todos os tipos de projetos, seus criadores prometem funcionalidades novas e/ou extravagantes a cada dia, e nessa vontade de fazê-lo crescer, vai tornando-o apenas cada vez mais "gordo", de difícil manutenção, e com isso nenhum projeto é ajudado. Sem contar a ausência de testes em muitos deles. Não quero dizer que Rails é o melhor de todos, estou citando apenas a filosofia por trás dele, há outros frameworks ótimos no mercado, tudo depende de pensar no que essencialmente o projeto precisa e com isso encontrar o framework correto.

Uma resposta para a enorme "gordura" de alguns frameworks é sempre: "Seu projeto tende a crescer, você vai precisar dos demais recursos oferecidos". Sinceramente não gostaria de precisar usar tudo, não quero complexidade demais no projeto só para ganhar mais manutenção. Gosto da filosofia K.I.S.S. (Keep It Simple Stupid). O que o meu cliente vai ganhar com esta funcionalidade X ? Ela é realmente é necessária ? Quanto mais simples, menos manutenção, mais tempo você tem para funcionalidades novas e simples.

Vocês podem pensar que isso é preguiça mas não é, recentemente houve um caso interessante, eu precisava adicionar um editor de texto na aplicação, escolhi o excelente FckEditor, ele possui ótimas funcionalidades para um editor de texto em browser, a primeira coisa que fiz foi reduzir a quantidade de botões. Apresentei ao cliente, ele usou um pouco e disse "acho que o pessoal vai estranhar um pouco a princípio, tem como melhorar o layout ?", mas o problema não era layout, observando como ele usou a ferramenta reduzi novamente a quantidade de botões para ter apenas o que ele realmente precisava e apresentei novamente. O resultado: "Puxa o layout melhorou mesmo, mais intuitivo", ele nem reparou que a quantidade de botões foi diminuída, eu apenas apresentei o que ele precisava, e nem uma linha a mais. Se o seu cliente precisa de uma funcionalidade supérflua, que ele pediu por impulso, convença-o do contrário, ou ambos sofrerão com uma funcionalidade que talvez nem seja usada, está lá apenas para formentar a entropia.

É como o novato que lê um livro sobre padrões de projeto e acha que deve usar todos de uma vez, é necessário pensar no básico. Keep It Simple!

Comments (1)

Como a filosofia de convenção ao invés de configuração do Rails enganou um novato

Há cerca de 3 meses resolvi me aventurar no mundo da linguagem Ruby, embora estivesse curioso há um bom tempo, foi mais por necessidade do que curiosidade, e como não poderia deixar de ser, utilizando o framework Rails. Só tenho a dizer o quanto a dupla Ruby+Rails me surpreende a cada dia, mas não é por isso que deixarei de utilizar Java, prefiro trabalhar com ambas as linguagens, escolhendo a que melhor convier ao projeto, prazo, custo e hospedagem, mas esta história fica pra outro post.

Como todo novato, apanhei feio no início, e é claro ainda estou tropeçando, mas o que mais me fez rir foi não ficar atento a filosofia do Rails de "convenção ao invés de configuração", ou seja, seguir padrões de nomes de métodos, classes, estrutura de diretórios, etc. Há um "jeito" certo de se estruturar o código seguindo esta filosofia, e quando você sai dela é que sua dor de cabeça começa, é normal encontrar pessoas zangadas com erros estranhos que só acontecem por não ter seguido as regras. As pessoas ficam bravas pois estão acostumados a seguir um modo rotineiro de estruturação. Bem estas pessoas que se adaptem às coisas novas. Pessoalmente se um framework segue "convenção ao invés de configuração" já consegue me atrair logo de cara pois eu entendo isso como "me faça ter menos trabalho pra utilizar você".

O meu erro foi ter "apenas" criado no modelo uma coluna com nome "type". O que eu não sabia, é que para o Rails, uma coluna "type", é reservada automaticamente para salvar o class-name do objeto na tabela, para caso você necessitar de um modelo de herança simples. Vamos supor um objeto Cachorro e outro Gato, ambas descendem do objeto Animal, mas há uma única tabela (Animal) para salvar Cachorro e Gato, a coluna "type" seria automaticamente preenchida com o class-name correspondente do objeto, para que ao consultar o registro, o Rails saiba que objeto deve criar. Óbvio que esta não era minha intenção, após ver sucessivas vezes o erro ":in `instance_eval': compile error" e consultar a documentação, descobri o motivo.

Não posso culpar o Rails, é um padrão dele, assim como outros nomes também são reservados como created_at e id, são os chamados MagicFieldNames. Resumindo: ao trabalhar com "convenção ao invés de configuração" lembrem-se sempre de olhar quais convenções são estas, vai te prevenir muitos erros e com certeza vai aumentar em muito sua produtividade, afinal o padrão está lá pra ser seguido.

Ah sim, caso você realmente precise de uma coluna chamada type para outros fins, basta sobrescrever o seguinte método no modelo:

def self.inheritance_column
"<nome da coluna a ser utilizada ao invés de type>"
end

Pronto, agora o Rails utilizará esta coluna para salvar o class-name e a type fica livre para fazer o que melhor convier, embora eu não recomende fazer isso.

Comments