Arquivo da tag: java

Grails & Groovy: primeiras impressões

A maior certeza que você pode ter, se for seguir carreira como programador, é que você vai usar muitos frameworks e linguagens de programação diferentes. Alguns você vai odiar de coração, mas vai ser obrigado a usar. E quando um colega seu citar o nome dessa ferramenta, você provavelmente reagirá como se sua mãe tivesse sido xingada. Mas também haverá os frameworks e linguagens que você vai odiar menos, e que talvez, por comparação com o que você já usou no passado, você chegue até a gostar.

COBOL: não gostei

COBOL: não gostei

Alguns, como eu, nunca ficam muito satisfeitos e sempre estão a procura da solução perfeita. A resposta à pergunta mais levantada por quem precisa parir um projeto: “o que vamos usar?” Esses sujeitos estão sempre experimentando coisas novas, procurando alguma solução que não tenha os problemas que as outras tinham, e quem sabe um dia encontrar o cálice sagrado das soluções de sistemas. E eu TALVEZ tenha encontrado algo bem próximo disso e que por acaso tem o nome de Grails (se você não entendeu está na hora de entrar num curso de inglês – aí CCAA, olha a oportunidade que vocês perderam de fazer merchandising no blog).

Não vou dar o veredito final porque ainda usei muito pouco Grails, em um projeto pequeno, em que um dos maiores objetivos era aprender Grails e Groovy. Mas para vocês terem uma idéia, o projeto envolvia integração com uma interface Flex (o RIA da Adobe) e usava JMS (o padrão de Mensageria Java). E mesmo assim, escrevi muito pouco código, quase nada de configuração e nenhum SQL (sim, o projeto tem banco de dados). Acho que o fato de eu ter tido pouco trabalho fazendo isto já mostra um pouco o porquê de eu ter achado o framework tão bom.

Grails: o logotipo foi o que menos gostei.

Grails: o logotipo foi o que menos gostei.

Outro motivo para não bater o martelo é que ainda não parei para aprender Ruby on Rails. Está na minha lista de “coisas a fazer (ou não)”, mas da forma como é aclamado pelos rubistas, deve realmente ser muito bom. Bom, se bem que “Crepúsculo” é aclamado por muita gente e eu não estou a fim de ver um filme que mistura Malhação com vampiros emos. Mas o fato de Grails ter sido inspirado em Rails não me permite ignorar sua existência.

Minha experiência com o framework foi curta, mas espero poder usar eventualmente para outras coisas. Por enquanto ainda não usaria para um projeto principal, mas para algo menor não teria dúvidas. Seguem abaixo minhas observações sobre Grails:

  • a linguagem Groovy: não gostava muito de linguagens dinâmicas, mas talvez isto tenha sido por conta do período em que usava PHP. Groovy é uma linguagem muito agradável de usar (pelo menos te garanto que é MUITO mais agradável que Java) e que da mesma forma que Perl, te dá diversas formas de se fazer a mesma coisa. E assim como Ruby, te dá a opção de extender a definição de qualquer classe (como adicionar métodos a uma classe da API padrão por exemplo) e de usar closures (que a grosso modo funciona como os ponteiros para métodos e funções existentes em outras linguagens). Me agrada muito a implementação da linguagem, que te poupa de fazer checagens bobas como verificar se o objeto é nulo, ou concatenação de strings, tornando o código mais legível e mais fácil de escrever.
  • plataforma Java: isto é mais vantajoso para quem já trabalha com Java, mas de certa forma é vantajoso para todos pelo tamanho da comunidade Java. O Grails e o Groovy foram contruídos sobre a plataforma Java. Dessa forma, um código escrito em Java é aceito como código em Groovy, o que pode tornar o aprendizado um pouco mais fácil. Um código escrito em Groovy tem total interoperabilidade com código em Java, permitindo que você tenha um projeto com partes escritas em uma linguagem e partes escritas na outra. Tanto que você pode utilizar qualquer coisa que você já podia utilizar em Java (bibliotecas, frameworks, etc). Isso foi aproveitado pelos idealizadores de Grails, pois o framework tem como seus alicerces dois frameworks Java muito populares: Spring e Hibernate.
  • GORM: é o responsável por mapear seus objetos para os registros no banco de dados (daí a sigla ORM – Object-Relational Mapping), e utiliza o Hibernate por baixo do capô. Este é o melhor ORM que já vi, pois de fato torna o trabalho muito mais fácil. Como eu disse, não escrevi uma linha de SQL e também não encostei em nenhum XML de configuração para fazer o GORM funcionar. Utilizar o GORM é basicamente como eu gostaria que fosse utilizar um banco de dados orientado a objetos. Se GORM fosse uma mulher eu casava. Ah, mulher gostosa, claro.
  • plugins: Grails tem uma boa variedade de plugins para extender sua funcionalidade. O que mais me impressionou é a facilidade de se instalar um plugin em um projeto. É tão fácil quanto instalar algo usando apt-get, basta um comando (traduzindo para quem só usa Windows: é fácil pra caralho!). Em um projeto não Grails, normalmente acrescentar uma tecnologia nova, como funcionalidade de web-services ou um motor de busca, sempre gera um certo stress, a ponto de gerentes com mais experiência alocarem um bom tempo na agenda do projeto para a tecnologia ser incorporada sem problemas. Em Grails, você instala o plugin e usa o resto do tempo que seu gerente alocou para ficar pedindo convite para o novo Orkut! SE não fizerem um plugin para isso.
  • ambientes: o framework já vem preparado para rodar sua aplicação nos ambientes de teste, desenvolvimento ou produção, facilitando a configuração para essa divisão por estágios. E não só isso, quando você faz o download do Grails ele já vem com um banco de dados (HSQLDB) e servidor web (Jetty) para que você possa sair escrevendo código sem se preocupar em montar o ambiente na sua máquina.
  • testes: a parte de testes automatizados (tanto unitários quanto funcionais) faz parte do framework, o que faz com que ele reforce o uso dessas boas práticas.

Se você se interessou em aprender mais, a InfoQ tem um livro gratuito (gratuito de verdade) chamado Getting Started with Grails. Para mais conteúdo, eu recomendo um livro não-gratuito chamado Beginning Groovy and Grails: From Novice to Professional. E para trocar experiências, já existe um fórum de Grails e Groovy brasileiro: o Grails Brasil.

Anúncios

Clusters de aplicações Java

Ao criar sistemas utilizados por milhares (ou milhões) de usuários diariamente, o arquiteto da solução precisa sempre se fazer algumas perguntas (ou pelo menos deveria):

Minha solução é capaz de suportar o número esperado de usuários?

O que fazer se o sistema não der conta da demanda de usuários?

E se um servidor sair do ar enquanto usuários estão acessando o sistema?

Não pensar nestas questões pode custar muito caro quando o sistema entra em produção. Se o sistema não aguentar a demanda de usuários e a equipe responsável não pensou em alguma forma para aumentar a capacidade do sistema de forma rápida, só resta colocar uma plaquinha “Em manutenção” e aguentar os esporros do chefe. Se o servidor tem algum problema e sai do ar enquanto estava em produção, isso pode gerar desde um aborrecimento com os clientes até perda de dados importantes. De qualquer forma, isso se traduz em prejuízos.

O quanto os seus servidores aguentam?

O quanto os seus servidores aguentam?

Já houve um tempo em que os sistemas rodavam apenas em um servidor, e para aumentar sua capacidade bastava adicionar mais memória RAM, ou colocar uma CPU mais turbinada. Mas hoje a ordem de grandeza para quantidade de usuários que podem acessar um sistema Web, por exemplo, é muito maior. E difícil de prever com exatidão. Desse jeito você tem como alternativas:

  • comprar um mega servidor caríssimo, que pode receber grandes quantidades de RAM e CPU. Não é a solução ideal porque servidores caríssimos são… bem, caríssimos. Ou seja, você pode acabar gastando muito mais do que precisaria de verdade. Ou mesmo comprando um, ele pode não dar conta do recado, porque mesmo mega servidores caríssimos tem limite máximo de memória e CPU. Mas a maior desvantagem é que se você tem apenas um servidor, e ele quebra, pode começar a enviar currículos, porque você está ferrado.
  • colocar seu sistema para rodar em cluster. Em um cluster você pode rodar seu sistema em vários servidores, pode dividir a carga entre esses servidores. Se a carga aumenta acima do esperado, não é coisa do outro mundo adicionar outro servidor para aumentar a capacidade do cluster. Se um servidor cai, você tem vários outros para continuar atendendo os usuários. O maior problema dessa brincadeira é que a complexidade para montar, configurar e manter essa arquitetura é bem maior.

A discussão a seguir se aplica a clusters de aplicações Java, mas clusters em outros ambientes não são tão diferentes. A limitação da discussão a Java se deve apenas ao fato de que quero falar um pouco sobre uma solução que encontrei para este ambiente. Se conhecerem soluções boas para outros ambientes, por favor, comentem neste post.

Clusters para Java

Todos os servidores de aplicação J2EE do mercado possuem uma implementação de cluster. O grande problema é que não existe um padrão para isso, então cada um implementa de uma forma. Isso é chato para os desenvolvedores que precisam absorver muito conhecimento complicado para configurar um servidor com que não estão acostumados a lidar. É mais caro, porque a empresa precisa investir muito mais para que os arquitetos de soluções conheçam bem como funcionam as soluções de cluster de cada fornecedor com quem trabalham. Para um panorama sobre clusters de aplicações J2EE, dê uma olhada neste artigo do TheServerSide.

Além de serem complicados, eles não são nem um pouco “Plug ´n Play”. Se você não desenhou seu sistema para funcionar na arquitetura de cluster proposta pelo seu fornecedor, provavelmente terá que redesenhar muita coisa. Imagine, por exemplo, aquela sua classe Singleton, que coordena várias operações. Ela não vai mais ser Singleton com o cluster, porque você acaba com uma instância em cada servidor, o que significa que você vai ter que bolar uma forma desses objetos funcionarem da mesma forma que o seu Singleton fazia. Ter que rearquitetar partes grandes de um sistema é uma tarefa trabalhosa e bastante arriscada. Se você está nesta situação, meus pêsames.

Essas arquiteturas de cluster também acrescentam muito overhead na performance do sistema como um todo. A comunicação que eles precisam fazer entre si e com bancos de dados, só para manter o conjunto consistente, pode tornar as respostas do sistema muito mais demoradas. Você sempre vai ter algum overhead quando utiliza um cluster, mas dependendo da arquitetura, o remédio pode sair pior que a doença.

Outro ponto de overhead de performance é o banco de dados. Quando o banco de dados começa a ser utilizado para persistir os dados de um servidor de aplicação apenas para que os outros servidores tenham acesso a esses dados (que neste caso seria mais para manter a consistência do cluster), o cluster começa a abusar demais do banco de dados. O banco de dados deveria servir para armazenar os dados da aplicação, e não passar a maior parte do tempo cuidando do estado do cluster. Armazenar esse tipo de informação em um banco de dados relacional é como tentar almoçar utilizando uma metralhadora AR-15 no lugar de garfo. É uma ferramenta com muito mais recurso do que o necessário para a tarefa, o que acaba acrescentando muito mais overhead. Mas é uma das soluções preferidas, por pura falta de solução mais segura, rápida  e mais simples (ou desconhecimento de uma solução assim).

Seus problemas acabaram… acho

A melhor solução que encontrei até agora foi o Terracotta. Terracotta é um software open-source e gratuito para facilitar o trabalho de tornar uma aplicação Java mais escalável. É o tipo de coisa que eu não entendo como pode ser de graça (bom, eu entendo, eles vendem serviços em cima disso, mas preciso dizer que não entendo para que vocês tenham uma noção do quanto eu acho esse negócio FODA). Definitivamente é uma solução que eu indicaria para quem precisa de mais escalabilidade com menos custo (e alguém quer menos escalabilidade com mais custo?). E não é um projeto open-source de garagem, é uma empresa financiada, com alguns clientes na lista da Fortune 500. Entre seus clientes estão a JPMorgan, a Adobe, a BBC e a Hitachi.

Console de administração

Console de administração

O Terracotta pode ser visto mais simplesmente como uma solução para compartilhar objetos entre servidores. Cada nó de aplicação em um cluster Terracotta pode acessar todos os objetos que estão no pool de objetos do cluster. Quando um objeto é criado em um servidor, e está configurado para ser compartilhado no cluster, os outros servidores podem enxergá-lo e acessá-lo, como se estivesse na memória local. É como se cada servidor estivesse fornecendo mais memória ao cluster, uma arquitetura conceitual muito mais simples do que os quebra cabeças complicados que chamamos de cluster de aplicações.

Se você só tirava notas de C para cima no colégio, deve estar pensando “mas se todos os servidores tem acesso a todos os objetos compartilhados, essa arquitetura não é escalável nem aqui, nem na China! Para cada servidor acrescentado eu ia precisar de muito mais memória em cada nó do cluster!“. Calma, que os arquitetos do Terracotta pensaram nisso. Cada nó pode acessar todos os objetos do cluster, mas ele só carrega esses objetos na memória quando necessário (o que é milhares de vezes mais rápido do que pegar essas informações em um banco de dados). Assim cada servidor acaba utilizando apenas a memória para os objetos que realmente está utilizando.

Quem tirava C+ na maioria das matérias deve perguntar “mas qual a diferença, em termos de performance, entre essa forma de sincronização para os clusters tradicionais?“. Em comparação a arquiteturas que fazem persistência dessas informações em banco de dados, não há nem o que discutir. Como o Terracotta armazena as informações em memória, ele responde muito mais rápido do que um banco de dados pensando em fazer a query. Além disso, quando dados de um objeto são atualizados em um servidor, apenas os campos que foram alterados são propagados para o cluster. Em clusters tradicionais, objetos inteiros são trafegados, mesmo que só 1% deles tenham sido alterados.

Os alunos nota B sempre me perguntam “E isso é seguro?“. O framework reforça que os acessos aos dados compartilhados tenham algum controle para sincronizar o acesso, garantindo consistência entre os nós. Um servidor pode tentar acessar um objeto, mas enquanto outro servidor estiver alterando esse objeto, o primeiro servidor deve esperar sua vez. Além da redundância de dados que existe entre os nós do cluster, em um sistema com Terracotta você deverá ter um ou mais servidores Terracotta, que fazem a sincronização da memória dos servidores de aplicação. Além disso, o servidor Terracotta armazena em disco as informações do cluster, de forma mais eficiente quen um banco de dados, mas tão seguro quanto. É possível ainda configurar facilmente vários servidores Terracotta em um mesmo cluster, assim, se um servidor desses sai do ar, o cluster continua operando normalmente.

Tudo parece resolvido, mas os alunos nota A com certeza não vão sossegar se eu não responder “Quanto trabalho vou ter usando isso?“. Perceba que é a pergunta mais esperta de todas. Esse, acho que é o ponto mais positivo da solução. Dependendo do que você usa em sua aplicação, é possível que não precise mexer em nenhuma linha de seu código para fazê-lo funcionar em cluster com Terracotta. Basta a configuração. Nem mesmo a sincronização de acesso aos dados vai exigir uma alteração de código, pois além de reconhecer a sintaxe de sincronização de threads do Java, os acessos podem ser configurados no arquivo de configuração do Terracotta. Nem mesmo as classes precisam ser serializáveis para participar do cluster (exigência normal em outras soluções). E existem diversos pacotes de integração para frameworks existentes (como Hibernate, Struts, Spring, etc.).

Nem tudo são flores

Umas dicas para enfrentar o caminho das pedras:

  • O processo para instrumentalizar as classes para o cluster pode ser meio doloroso. O ideal é colocar como classe instrumentalizada, no arquivo de configuração, apenas as classes que devem ser utilizadas pelo cluster. Se você não conhece muito bem sua aplicação, o processo consiste em rodar sua aplicação com o Terracotta, até que ocorra um erro dizendo que você deveria colocar a classe X na sua configuração. Se você tiver um sistema muito grande, esse processo manual pode tornar inviável ficar escolhendo as classes certas (você pode mandar instrumentalizar tudo de uma vez). E é bom que você tenha bons testes funcionais do seu sistema, que exercitem todo seu código, porque você não quer descobrir que deixou de instrumentalizar alguma classe depois que o sistema estiver em produção.
  • Se não existir o pacote de integração para algum framework que seu sistema utiliza, e esse framework precise de acesso ao cluster, você pode ter um trabalho extra para fazê-lo funcionar com o Terracotta. O que exige que você tenha um conhecimento um pouco maior sobre esse framework (o que normalmente não é o caso).

Ainda fiz poucos testes com o Terracotta. Até onde vi, me agradou bastante. Não chega ainda a ser uma solução perfeita, mas está em um bom caminho. Ainda preciso fazer um teste de carga, para sentir a performance. Vou continuar acompanhando o progresso da ferramenta. E acho que para quem está precisando de uma solução para aumentar a escalabilidade, disponibilidade e performance de um sistema, vale a pena dar uma olhada no Terracotta. Quem sabe você nem precise mais usar aquelas licenças de Oracle RAC que você precisou se prostituir para conseguir.

Gostaria muito de ver soluções parecidas para .Net ou outros ambientes. Agora com a computação em nuvem na moda, algo muito desejável é simplificar um pouco a loucura que é um sistema distribuído.

Atualização: Postei uma pergunta no fórum do Terracotta e em 2 horas tive respostas de 2 engenheiros! Um deles me respondeu em menos de 30 minutos. Acho que nem com suporte técnico via telefone fui atendido tão rápido.