Há alguns meses, alguém levantou a possibilidade de melhorar o gerenciamento das visitas a clientes na empresa em que trabalho, utilizando um sistema específico.
Consultaram-me sobre a possibilidade de utilizar um sistema opensource, entretanto não encontrei nada nessa linha. Como estava estudando algumas novidades e queria desenvolver algum sistema com elas, no caso o play! framework, vi que a oportunidade era perfeita, pois tratava-se de um sistema de uso interno e de baixíssimo risco, então respondi que em pouco tempo poderia criar um protótipo.
Utilizei o Twitter Bootstrap (que também estava aprendendo) na camada de apresentação e o Hibernate para persistência (depois de desistir do Ebeans, padrão do framework).
O desenvolvimento do protótipo totalmente funcional ocorreu em uma semana. Trata-se de um sistema pequeno, porém como estava usando o play! e o bootstrap pela primeira vez, acredito que foi bem rápido.
Depois das rotineiras mudanças de requisitos e solicitações de melhorias após a apresentação para os usuários, mais dois ou três dias e estava tudo pronto.
O que tem de mais esse tal de play!?
- Instantâneo: Todas as alterações em telas ou no código java são recompiladas e executadas sem reiniciar o servidor, só é necessário um “refresh”;
- Depuração: é possível conectar o debugger do Eclipse com a aplicação executando em modo de desenvolvimento, mas nem é tão necessário, pois quando há algum erro no Java ou na tela, a mensagem do framework é tão amigável que mostra, além da pilha, o próprio código fonte e qual o comando ou erro de sintaxe que causou a falha;
- Sessão: não existe uma session, os únicos valores que são armazenados entre as requisições ficam em cookies criptografados. Isso faz com que a aplicação seja altamente escalável com múltiplas instâncias, embora seja confuso para quem está acostumado com as tecnologias JEE padrão;
- Threads: não há criação de threads por requisição como nos Servlets, os métodos dos controladores são static e processamentos “demorados” devem ser assíncronos;
- Totalmente REST: todas as entradas de url são configuradas no arquivo “routes”, como no rails;
GET /sobre controllers.App.sobre()
- CoC (Convensão sobre Configuração / Convention over Configuration): a ideia é não reinventar a roda, basta executar um comando “play new [nome sistema]” e sair programando, obviamente se você seguir o padrão adotado pelo framework. Já se quiser fazer diferente aí vai ter tanto ou mais trabalho do que num framework tradicional;
- Builders para as views: as telas, por exemplo, possuem parâmetros e você “invoca” uma tela a partir do código chamando um método de uma classe gerada dinamicamente que recebe os devidos parâmetros, então se você mudar uma tela para receber algo novo, não tem como esquecer de atualizar o código, já que isso vai gerar erros de compilação;
- Servidor de aplicação: esqueça Tomcat, Glassfish, Weblogic ou Websphere, ele já vem com um servidor leve embutido, o comando “run” inicia a aplicação em modo desenvolvimento e o comando “start” em modo de produção;
- Ciclo de vida: o framework gerencia o ciclo de vida através de uma ferramenta de build chamada SBT (uma espécie de ANT), gerencia as dependências através do IVY e também é compatível com Maven;
- Integração com Eclipse: o comando “eclipsify” gera os arquivos necessários para importar o projeto no Eclipse, quando incluir uma nova dependências, basta executar o comando novamente para atualizar o classpath e demais configurações;
- Banco de dados: integração nativa com JPA, inclusive gerenciando as evoluções da estrutura do banco e gerando a DDL necessária a partir das classes
- Telas: templates feitos numa mistura de HTML com a liguagem Scala. É simples e rápido para implementar, porém lento demais para compilar.
<select id="cliente" name="cliente"> @for(opcao <- options(Cliente.options)) { <option value="@opcao._1" @if(opcao._1 == filtro.cliente) { selected }>@opcao._2</option> } </select>
Pontos negativos
No Eclipse, várias vezes as classes geradas pelos builders não são reconhecidas mesmo dando refresh no projeto e erros em views, por exemplo, são listados mesmo que já estejam corrigidos. Às vezes, só fechando e reabrindo o projeto (usando “Close Project”). Isso não afeta a execução mas fica “feio” ver o projeto com erros que não existem.
A versão 2.x mudou muito em relação à primeira e a maioria dos tópicos encontrados fala da versão 1. Além diso, ela não é uma simples evolução da primeira, mas uma reformulação total, tornando a migração muito difícil. Por exemplo, alguns recursos, tal como a geração de WAR para deploy num container, foram removidos e atualmente só é possível executar a aplicação no servidor embutido.
Apesar do framework suportar Java ou Scala como linguagem de programação, os templates da versão 2 são feitos em Scala por padrão, portanto é necessário aprender um pouco da sintaxe e a curva de aprendizagem aumenta. A linguagem Scala executa na JVM e é eficiente, mas a compilação pode ser bem mais demorada que uma classe comum.
O gerenciamento automático da evolução da DDL pode ser confuso à primeira vista e causar alguns efeitos colaterais se mal utilizada.
Update: Como comentei num post mais recente, uma biblioteca foi removida do repositório, tornando impossível compilar uma versão do sistema com o play 2.0 e obrigando os desenvolvedores a migrar para a versão 2.1.
Resumo
No geral as implementações dos diversos aspectos do play! framework usam outras ferramentas já bem conhecidos, tal como o Hibernate, a linguagem Scala, o gerenciador de dependências IVY, etc. O uso dessas e outras tecnologias já consagradas é uma ótima base para se desenvolver, aumentando a confiança nos resultados.
Desde que seguidos os padrões do framework e depois que se pega o jeito dele, fica muito fácil sair implementando novos requisitos. O maior problema no começo é se despender do conceito de JSP/Sevlet que está tão arraigado no mundo Java.
Enfim, o play! framework é muito bom para projetos pequenos e rápidos. Para algo maior, com uma vida útil mais longa, maior risco ou com uma equipe que não conheça a tecnologia, não recomendaria no momento, por dois motivos: a documentação não é muito completa e os desenvolvedores não tem um compromisso em manter compatibilidade, corrigir bugs críticos ou implementar funcionalidades que eles não considerem importantes.
Por outro lado, com o estudo de frameworks como este, é possível extrair algumas boas práticas e conceitos importantes, aplicando de outras maneiras mesmo em tecnologias mais tradicionais.