Grails. C ada vez mais aplicações corporativas são desenvolvidas ou migradas para a plataforma web. - PDF
Download "Grails. C ada vez mais aplicações corporativas são desenvolvidas ou migradas para a plataforma web."
Raphaella Vilanova Rodrigues
1 a r t i g o Grails Um Caso de Sucesso Agilidade em uma empresa de desenvolvimento para Gestão Hospitalar Desenvolver para a web com agilidade é um grande desafio, até mesmo para empresas já consagradas no mercado de aplicações para esta plataforma. Neste artigo, veremos como a empresa Wareline, que mantinha foco no ambiente desktop, está migrando para o ambiente web utilizando o framework Grails. Também entenderemos, através de um exemplo básico, como o framework funciona. C ada vez mais aplicações corporativas são desenvolvidas ou migradas para a plataforma web. Isso acontece porque a web traz diversos avanços e facilidades no que diz respeito à integração de múltiplos usuários. O conceito de servidores de aplicações permite que usemos alguns padrões para solucionar problemas comuns do modelo client server, como gerenciamento de estado conversacional e sincronismo de informações, de forma praticamente transparente para os desenvolvedores. A única coisa exigida dos desenvolvedores é que conheçam os padrões. Junto com o uso dos objetos 'session', 'request' e 'response', esses padrões formam uma convenção (ver o quadro Convenção sobre Configuração), muito conhecida pelos desenvolvedores web ao redor do mundo. Convention over Configuration Felipe Rodrigues de Almeida Com mais de 7 anos de experiência na área de desenvolvimento de software, trabalhou em projetos para empresas como CPqD, IBM, Telefônica e Embraer, dentre outras. Atualmente é engenheiro de Software na Fratech.net e tem focado seus esforços em duas áreas: Agilidade e Expressividade. Seu dia-a-dia varia entre mentoring técnico para arquiteturas de negócio e coaching de equipes ágeis. Como hobby começou a estudar robótica e eletrônica. Há algum tempo a comunidade internacional de desenvolvimento de software tem ido ao encontro de uma tendência chamada Convention Over Configuration. O objetivo é reduzir drasticamente a quantidade de configuração técnica necessária para se utilizar um framework. Vários frameworks recentes, incluindo algumas das especificações do Java EE 6, incluem essa característica. Alguns de forma mais evidentes que outros. Em uma aplicação web, imagine não precisar mais de um XML para lhe dizer como determinado request deve ser tratado. É possível? Através de convenções simples, como, por exemplo, manter todas as actions no diretório actions elimine a necessidade de configurar qual é o diretório padrão das actions. Qualquer classe inclusa dentro deste diretório será, por convenção, considerada uma action e, portanto, poderá possuir métodos específicos para tratar as requisições. 42
2 O Grails faz uso extensivo de convenções, com o objetivo de simplificar a vida do desenvolvedor. Há, porém, casos em que as conveções não se aplicam. Para esses casos, o Grails (e outros frameworks) oferecem a alternativa de configurar. A diferença é que, neste caso, a configuração é a exceção à regra, o que na prática significa bem menos configurações. Descobrimos então que a plataforma web é a primeira opção quando se fala em desenvolver uma aplicação hoje em dia, porque é mais fácil de se desenvolver com essas convenções todas disponíveis. A sensação é de que a maioria dos problemas foram resolvidos e só nos resta trabalhar com foco nas regras de negócio. Os frameworks mais tradicionais da plataforma Java utilizam-se dessas convenções de forma muito eficaz e já estão consolidados no mercado. Há, porém, alguns problemas quando se fala de frameworks mais tradicionais, principalmente no uso de configurações em excesso. Estes frameworks são muito dependentes de configurações, o que dificulta em muito a vida dos desenvolvedores. É comum que as configurações tenham que ser repetidas para cada ação da aplicação. Isso acontece frequentemente com JSF e Struts, por exemplo. Uma nova geração de frameworks tem surgido para enfrentar este problema. Estes são frameworks que permitem o aproveitamento de convenções ao invés de configurações, mas que quando necessário ainda permite que sejam configurados a um nível bem satisfatório. Para a plataforma Java, um dos principais players deste mercado é o framework Grails. O que é Grails O Grails é um framework full-stack, com conceitos similares aos do Rails, o que o torna uma grande opção para aplicações web 2.0. Ele contém soluções convencionadas para as tarefas mais comuns do desenvolvimento web. Contém mecanismos para persistência de dados, log, injeção de dependências, templates, controle transacional, testes unitários e de integração, webflow, dentre outras coisas. Além disso, é desenvolvido para integração com o mundoj EE, devido à integração nativa que o Groovy tem com a linguagem Java, de forma que as aplicações Grails podem ser executadas em qualquer container de Servlet e JSP, inclusive servidores completos Java EE. Isso possibilita que o desenvolvedor use qualquer uma das bibliotecas disponíveis no ecossistema Java para desenvolver aplicações Grails, além de o tornar uma ótima opção para aplicações corporativas que exigem algo um pouco mais robusto. A grande vantagem do Grails é sua filosofia voltada para o uso de convenções ao invés de configurações (Convention over Configuration), elevando ainda mais as vantagens da plataforma web, no que diz respeito à produtividade e facilidade de desenvolvimento. O Grails começou como um projeto open source de uma empresa chamada G2One, que foi a responsável pela concepção tanto da linguagem Groovy quanto do framework Grails. Após alguns anos adquirindo maturidade e seguidores, a G2One foi comprada pela tão elogiada Spring Source e hoje faz parte do famosíssimo portfólio de projetos open source da Spring Source. A composição do Grails O Grails é um framework MVC que encapsula vários outros frameworks que estão presentes na grande maioria das aplicações web atuais para atender aos requisitos de uma aplicação web completa. Para isso, utiliza o Spring para injeção de dependências, o Log4J para o sistema de logs, o Sitemesh para o sistema de layouts e templates, o Hibernate para persistência e o JUnit para testes, além de ser totalmente baseado no modelo de Servlets e JSPs. Como podemos notar, o Grails é mais uma camada de abstração que ao facilitar o uso de frameworks complexos, nos permite mais tranquilidade para desenvolver nossas aplicações. Apesar de usar os frameworks mais utilizados, a grande diferença consiste exatamente na interface que o Grails disponibiliza para que o desenvolvedor desfrute destes mecanismos. Isso quer dizer que para utilizar o sitemesh, há uma convenção bem mais simples do que se você fosse utilizá-lo diretamente em sua aplicação. O mesmo acontece com o Hibernate, Log4J, Spring e os outros. Plugins Além de sua arquitetura padrão, já presente no download original, há ainda a possibilidade de instalar plugins, que complementam o framework. Dentre os diversos exemplos de plugins, temos o plugin para integração com o JPA, Acegi, JSecurity, o Adobe Flex através do BlazeDS, o Quartz para scheduling etc. Tudo isso pode ser conferido direto no site do framework, Já dá para notar que o Grails é um framework que veio para ficar. A linguagem Groovy Talvez você nunca tenha ouvido falar sobre Groovy, mas, acredite, se você conhece Java está apto a desenvolver em Groovy. Groovy é uma linguagem de tipagem dinâmica que foi criada especificamente para a JVM. Isso quer dizer que, enquanto desenvolvendo em Groovy, você poderá usar código Java normal, porém com certo açúcar sintático. O GDK (Groovy Developer Kit) é uma extensão do JDK, possibilitando assim usar todos os recursos normais do Java. Tudo que podemos fazer em Java, pode ser feito em Groovy. Por exemplo, para criar um ArrayList em Groovy, basta instanciar essa classe. java.util.arraylist mylist = new java.util.arraylist(); Podemos ainda utilizar uma sintaxe um pouco mais groovy: def mylist = new ArrayList() ou def myotherlist = [] O uso de [] nesse caso não cria um array, mas sim uma instância da classe ArrayList. Note que o ; é opcional, assim como o uso de return. Se quiser testar mais a fundo a integração, pegue qualquer programa Java 43
3 que você possua e modifique a extensão do código-fonte de.java para.groovy. Compile utilizando o comando groovyc que possui uma sintaxe muito similar ao javac e execute utilizando o comando groovy com sintaxe idêntica ao comando java. A única diferença é que o jar do groovy deve estar em seu classpath. A maioria dos programas irá funcionar normalmente, como se fosse compilado em Java, com algumas raríssimas exceções. Raras mesmo. public int getmiles(){ println Passei no getmiles() return miles Closures Retirando um exemplo do livro Programming Groovy escrito por Venkat Subrammanian para os famosos Pragmatics Programmers, veremos como a sintaxe do Groovy é um alívio para os programadores java, ao invés de ser um peso. Análise este programa em Java: Há ainda no Groovy uma funcionalidade chamada closure, que nada mais é do que uma instância da classe groovy.lang.closure. Closure cl = { println Eu sou uma closure public class Car { private int miles; private int year; public Car(int theyear) { year = theyear; public int getmiles() { return miles; public void setmiles(int themiles) { miles = themiles; public int getyear(){ return year; public static void main(string[] args) { Car car = new Car(2008); System.out.println( Year: + car.getyear()); System.out.println( Miles: + car.getmiles()); System.out.println( Setting miles ); car.setmiles(25); System.out.println( Miles: + car.getmiles()); Agora veja o mesmo programa, escrito em groovy: No código acima, utilizamos um recurso da sintaxe do groovy para criar uma instância da class Closure. O bloco de código após o sinal de atribuição = na verdade é uma instância da classe Closure. Uma vez que temos essa instância em mãos, podemos utilizá-la como um objeto comum, passando como parâmetro a métodos. Para executar o a closure, fazemos como se chamássemos um método comum. cl() Podemos ainda ter closures que recebem parâmetros. No exemplo a seguir, passaremos um parâmetro indicando o nome de alguém, para que a closure imprima uma saudação. def saudar = { nome -> println Olá, + nome class Car { def miles = 0 final year Car(theYear) { year = theyear def static main(args) { def car = new Car(2008) Repare que indicamos os parâmetro dentro das chaves e, em caso de haver mais de um parâmetro, podemos separá-los por vírgula. Podemos até mesmo indicar o tipo desse parâmetro como na declaração de métodos comuns. Veja como fica a execução dessa closure. saudar( Mundoj ) println Year: ${car.year println Miles: ${car.miles println Setting miles car.miles = 25 println Miles: ${car.miles Para saber mais sobre o Groovy, acesse site da linguagem em groovy.codehaus.org/. Como funciona Veja que a quantidade de código é menor, além de ser mais limpa e fácil de ler. A diferença está na clareza das informações. As classes groovy seguem a convenção JavaBeans automaticamente. Isso quer dizer que o compilador do groovy adiciona os métodos get e set para nós. Quando acessamos um atributo, como no caso de car.miles, na verdade estamos invocando o método getmiles() criado automaticamente pelo compilador. Para testar esse comportamento, basta sobreescrever o método getmiles() conforme o seguinte trecho: Dessa forma, não importa o que você faça, ao chamar car.miles será impresso o texto Passei no getmiles() na saída padrão do sistema. Na prática, o framework funciona de forma muito simples. Devemos criar actions dentro das classes controllers para tratar as requisições dos usuários. Os controllers nada mais são do que classes que agrupam actions. Dessa forma, posso ter um controller count que contém as actions innumbers e inwords. O Grails possui um sistema de roteamento por convenção que fica definido no arquivo grails-app/conf/urlmappings. groovy. O mapeamento de URLs default do Grails irá interpretar as urls conforme mostrado na figura 1. Além dos controllers, podemos utilizar classes de domínio, ou domains. Essas classes representam as entidades de negócio da nossa aplicação. Normalmente esses dados são persistidos em banco de dados e contêm operações 44
4 Herança? Figura 1. Mapeamento de urls do Grails. de negócio. Podem se relacionar e são automaticamente mapeados para persistência através do wrapper do hibernate que já vem com o Grails, chamado GORM. Elas podem se relacionar e também serem utilizadas normalmente, pois são classes simples e normais. Os domain devem ser colocados dentro do diretório grails-app/domains, podendo colocar em pacotes ou não. Neste caso, o uso da herança é interessante devido à forma como o Grails trata esses registros no banco de dados. Não teremos complicações nenhuma com o Hibernate, visto que o mapeamento será feito pelo Grails de forma automática. No banco de dados, o Grails irá criar uma única tabela para essas classes, acrescentando uma coluna com o nome class na tabela, que permitirá a classificação dos registros. Essa coluna reflete o valor do atributo class do objeto tratado, que irá variar entre Pessoa, Paciente e Médico. Optei por este caminho no artigo por motivos didáticos. Há outras opções, como composição através do embedded, por exemplo. Vejamos como desenvolver uma pequena tela de atendimento para este modelo. Como qualquer framework para a web, o Grails também possui views. As views são organizadas dentro do diretório grails-app/views. Normalmente dentro deste diretório, criamos um subdiretório para cada controller e assim separamos as views por controllers. Isso é uma convenção, porém nada nos impede de criar nossa própria organização de diretórios desde que dentro do diretório views. O Grails já vem com um conjunto de tags próprias que permitem realizar várias operações interessantes. Além disso, podemos utilizar o bom e velho JSTL nas views do Grails, além de scriplets com código groovy. Há inclusive mecanismos muito simples para o uso de Ajax nas views do Grails, tanto em termos de tags quanto em termos de modularização das views. As tags podem ser usadas tanto nas views, como também nos controllers, na forma de métodos comuns, permitindo o reuso de lógicas como obtenção de códigos i18n. Além disso, você também pode criar suas próprias taglibs de forma simples e descomplicada. Para finalizar, temos os Services. Services são classes que devem encapsular operações de negócio muito complexas, que precisem de lógicas mais extensas. Dessa forma, podemos separar as regras de negócio das regras de apresentação e, assim, deixar nossas actions e contrllers muito mais limpos. Os services são classes comuns que possuem métodos. Por padrão, são stateless, porém há formas de mudar isso. A exemplo dos outros artefatos, os services são organizados dentro do diretório grails-app/services. Integração pronta O Grails possui um sistema default de injeção de dependências baseado no Spring framework. Esse sistema permite que instâncias sejam injetadas direto em nossos controllers e services sem a necessidade de configurar os spring beans. Isso é possível através de uma simples convenção. Por exemplo, para injetar um service dentro de um controller e fazer uso dele, basta declararmos um atributo simples no controller. Esse atributo dever ser nomeado segundo o nome do service, indicando o tipo do atributo ou não. Em outras palavras, para injetar um service chamado MeuService em um controller, basta declarar o atributo MeuService meuservice no controller. O Grails cuida do resto. Além da injeção de dependências, o Grails trata essas classes de forma especial, acrescentando alguns comportamentos através do sistema de metaprogramação do groovy. No caso dos services, dentre outras coisas, o Grails cuida para que todas as suas operações sejam transacionais por padrão. No caso dos domains, o Grails injeta alguns métodos relacionados à persistência. Métodos como list(), save(), remove(), findallby*(), são alguns exemplos. Criando a aplicação Para criar uma aplicação utilizando o Grails, devemos apenas emitir o comando grails create-app atendimento. Com esse comando, o Grails emitirá uma série de ações, executando alguns scripts para a estruturação da sua aplicação. Ao final, deve haver um diretório com o nome atendimento no diretório onde você emitiu o comando acima. A estrutura de diretórios da aplicação pode ser vista na figura 3. A parte mais interessante e incomum para aqueles que não conhecem o framework está no diretório grails-app, onde podemos notar diretórios com nomes bem sugestivos. Como o Grails é um framework baseado em convenções, convenciona-se que as classes serão categorizadas baseando-se no diretório em que estão. Dessa forma, colocaremos as classes que representam os controllers dentro do diretório controllers, os services no diretório services, as classes de domínio no diretório domain e assim por diante. Domain Vamos começar o desenvolvimento pelo domain. Devemos criar as classes para representar as entidades vistas na figura 2. As classes de Domain no Grails são simplesmente POGOs (Plain Old Groovy Objects) que seguem a convenção de Java Beans. Também podemos utilizar POJOs normais como domains no Grails, devido à integração entre o Groovy e o Java. As Listagens de 1 a 5 mostram como ficam as classes de nosso domínio. 45
5 O case Para exemplificar como o framework pode ser utilizado, nada mais interessante do que apresentarmos um case de sucesso. O case se passa na Wareline, uma empresa de Campinas focada no desenvolvimento de softwares de gestão hospitalar. O sistema atual deles é desenvolvido em visual basic, com módulos web, escritos em Java e PHP. A empresa já mantinha uma relação estreita com o mundo open source, pois há um bom tempo já utiliza o banco de dados PostgreSQL em todos os seus sistemas. Para esse projeto, o objetivo é migrar todo o sistema para a plataforma Web. Participei da definição da arquitetura, do processo de gestão, e agora acompanho a evolução do projeto. Metade da equipe formada possui experiência no desenvolvimento para a web, basicamente com background em servlets e JSPs. A outra metade é formada por desenvolvedores trazidos do Visual Basic para o novo projeto, pois detém grande parte do conhecimento do negócio. O desafio consiste em fazer com que o conhecimento e a produtividade que estes desenvolvedores, vindos do ambiente VB, sejam mantidos para o novo sistema web. Isso exige que a curva de aprendizado e a transição sejam mantidas. Os paradigmas Desktop e Web são bem diferentes e, apesar de passarem por treinamento antes do projeto, as dificuldades que podem surgir são inúmeras. Nesse aspecto, o Grails é favorecido, pois uma vez que o desenvolvedor se acostume com as convenções, basta segui-las. Com o tempo, conforme os desenvolvedores vão ganhando mais experiência, podem começar a customizar as partes necessárias sem perder produtividade ou prejudicar o funcionamento geral do framework. Contar com um ambiente pronto, estável e baseado nas melhores práticas diminui muito os riscos da migração da plataforma desktop para a web, sem trocar todos os desenvolvedores. O Domain Em nosso exemplo, vamos tratar de uma pequena parte do domain desta aplicação: o atendimento de pacientes na recepção do hospital. Obviamente, neste artigo, vou apresentar somente uma pequena e incompleta parte do modelo real da aplicação, devido às limitações de espaço. Na figura 2, vemos uma parte do domínio. Um dos trechos mais simples da aplicação e que já reflete a grande quantidade de relacionamentos entre entidades que há neste projeto. Temos uma entidade Atendimento, que representa cada atendimento feito. Um atendimento sempre deve referenciar um Paciente e um Médico. Além disso, Médico e Paciente são subclasses de Pessoa, que por sua vez contém um Endereço. Pessoa 1 1 Endereço extends extends Paciente 1 N Atendimento N 1 Médico Figura 2. Modelo da aplicação de exemplo. Listagem 1. Classe Atendimento. class Atendimento { static belongsto = [paciente:paciente, medico:medico] Paciente paciente Medico medico String queixa Date data Repare como os relacionamentos são declarados: utiliza-se belongsto para determinar à qual classe aquela pertence. O hasmany para indicar quando uma classe possui um conjunto de objetos de uma outra classe. Isso faz parte de uma série de convenções e configurações possíveis com o mecanismo de persistência do Grails, o GORM (Grails Object Relational Mapper). O GORM possibilita realizar praticamente qualquer coisa que se faz com o Hibernate, já que ele é uma abstração sobre este framework. Agora, seguindo o conceito do MVC, uma vez que já temos as classes de domínio bem definidas, precisamos escrever os Controllers e as Views. Um controller no Grails não passa de uma classe com algumas closures públicas. Essas closures são similares a métodos comuns e serão tratadas como actions para aquele controller. Na Listagem 6 está nosso controller atendimento, com uma action para listar os atendimentos: Listagem 2. Classe Pessoa. class Pessoa implements Serializable { static hasmany = [atendimentos:atendimento] String nome Endereco endereco static constraints = { endereco(nullable:true) Listagem 3. Classe Paciente. class Paciente extends Pessoa { 46
6 Listagem 4. Classe Medico. class Medico extends Pessoa { String especialidade Listagem 5. Classe Endereço. class Endereco { static belongsto = [Pessoa] String logradouro String bairro String cidade String estado Pessoa pessoa Listagem 6. Controller de atendimento. class AtendimentoController { def list = { return [atendimentos: Atendimento.list(params)] Veja como é simples esta action. Tão simples que talvez você se pergunte: De onde veio esse método list() da classe atendimento? A resposta está no GORM. Ele faz uso das capacidades dinâmicas do Groovy para injetar em tempo de execução este e outros métodos em todas as classes de domínio. Veja a referência completa dos métodos do Grails no endereço: Retornamos uma list com os objetos atendimento retornados pela chamada a list(). A ideia simplificada é que uma action retorna uma lista chamada de model, para a view. Quando não especificamos qual o nome da view que a action deve renderizar, o Grails irá, por convenção, buscar uma view que possua o mesmo nome da action. Neste caso, a Listagem 7 apresenta a view para a listagem dos atendimentos. Listagem 7. View de listagem de atendimentos. <div class= body > <h1>atendimento List</h1> <g:if test= ${flash.message > <div class= message >${flash.message </g:if> <div class= list > <table> <tr> <g:sortablecolumn property= id title= Id /> <g:sortablecolumn property= data title= Data /> <th>medico</th> <th>paciente</th> <g:sortablecolumn property= queixa title= Queixa /> </tr> <g:each in= ${atendimentoinstancelist status= i var= atendimentoinstance > <tr class= ${(i % 2) == 0? odd : even > <td> <g:link action= show id= ${atendimentoinstance.id > ${fieldvalue(bean:atendimentoinstance, field: id ) </g:link> </td> <td>${fieldvalue(bean:atendimentoinstance, field: data )</td> <td>${atendimentoinstance.medico.nome</td> <td>${atendimentoinstance.paciente.nome</td> <td>${fieldvalue(bean:atendimentoinstance, field: queixa )</td> </tr> </g:each> </table> <div class= paginatebuttons > <g:paginate total= ${atendimentoinstancetotal /> Este arquivo deve seguir uma convenção de diretórios para que o Grails o encontre. Ele deve ser colocado em grails-app/views/atendimento/list.gsp. Note que dentro do diretório views teremos um subdiretório para cada controller. Nesta view, já identificamos uma série de itens desconhecidos. Trata-se de algumas custom tags do Grails, como a <g:sorteablecolumn>. O Grails possui várias tags que podem ser usadas nas views e algumas até mesmo dentro dos controllers, como é o caso das tags para i18n. Além disso, podemos realizar a interpolação de código Groovy dentro das views, como é o caso do trecho ${fieldvalue(bean:atendimento, field:'id'). A partir daqui, já podemos executar a aplicação e visualizar o que está feito. A figura 4 mostra a listagem com alguns atendimentos já cadastrados e pode ser acessada através da url Agora só precisamos de uma action para inserir um novo atendimento. Para isso, vamos criar uma action em nosso controller de atendimento. Como visto na Listagem 8, adicionamos duas actions ao Atendimento- Controller. A action create irá criar uma nova instância de atendimento e então renderizar, por convenção, a view create, mostrada na Listagem 9. A action save obtém os dados através do mapa params e os grava no banco. Figura 4. Página de listagem dos atendimentos. Listagem 8. Actions para adição de um novo atendimento. def create = { return [ atendimento : new Atendimento()] def save = { def atendimento = new Atendimento(params) if(!atendimento.haserrors() && atendimento.save()) { flash.message = Atendimento ${atendimento.id created redirect(action:list) else { render(view: create,model:[atendimento:atendimento]) 47
7 Vale a pena notar que nós verificamos a existência de erros de casting através da chamada a atendimento.haserrors(). Caso esta chamada retorne false e a chamada ao método atendimento.save() retorne true, então iremos redirecionar para a nossa action list, para listarmos o novo registro. Além disso, adicionamos uma mensagem para ser exibida na página de destino. Caso não consigamos salvar por algum motivo, seja erro de casting ou alguma outra validação, como a ausência do médico ou do paciente, voltaremos à view create, em que a tag <g:haserrors bean="${atendimento"> irá cuidar para que os problemas sejam exibidos para o usuário. A figura 5 mostra como deve ficar o formulário de criação do atendimento que pode ser acessado através da url Listagem 9. View create contendo o formulário para adição de um novo atendimento. <div class= body > <h1>create Atendimento</h1> <g:if test= ${flash.message > <div class= message >${flash.message </g:if> <g:haserrors bean= ${atendimento > <div class= errors > <g:rendererrors bean= ${atendimento as= list /> </g:haserrors> <g:form action= save method= post > <div class= dialog > <div class= value ${haserrors(bean:atendimento,field: data, errors ) > <label for= data >Data:</label><br/> <g:datepicker name= data value= ${atendimento?.data precision= minute ></g:datepicker> <br/> <div class= value ${haserrors(bean:atendimento,field: medico, errors ) > <label for= medico >Medico:</label><br/> <g:select optionkey= id optionvalue= nome from= ${Medico.list() name= medico.id value= ${atendimento?.medico?.id ></g:select> <br/> <div class= value ${haserrors(bean:atendimento,field: paciente, errors ) > <label for= paciente >Paciente:</label><br/> <g:select optionkey= id optionvalue= nome from= ${Paciente.list() name= paciente.id value= ${atendimento?.paciente?.id ></g:select> <br/> <div class= value ${haserrors(bean:atendimento,field: queixa, errors ) > <label for= queixa >Queixa:</label><br/> <input type= text id= queixa name= queixa value= ${fieldvalue(bean:atendimento,field: queixa ) /> <br/> <div class= buttons > <span class= button ><input class= save type= submit value= Create /></span> </g:form> Encapsulando as operações em Services Apesar de esse ser um exemplo simples, o case real não é tão simples assim. A complexidade das operações de negócio pode tornar essas actions muito grandes e difíceis de manter. Os controllers devem ser magros, visto que sua função é apenas chamar as operações de negócio adequadas e redirecionar a requisição para a view adequada. Para resolver isso, podemos utilizar os services do Grails. Com o uso do services, podemos centralizar as operações de negócio em uma classe separada ao controller e, além disso, Listagem 10. Action save refatorada para utilizar um service. def save = { def atendimento = new Atendimento(params) if(!atendimento.haserrors() && atenderservice. else { salvaratendimento(atendimento)) { flash.message = Atendimento ${atendimento.id created redirect(action:list) render(view: create,model:[atendimento:atendimento]) Listagem 11. AtenderService.groovy. public class AtenderService { boolean salvaratendimento(atendimento){ return atendimento.save() utilizar o controle transacional default do Grails. Os services podem ser facilmente utilizados nos controllers através da injeção de dependências por convenção. Após refatorar o código da action save, a action fica como na Listagem 10. Agora precisamos criar o service, conforme a Listagem 11. Os services devem ficar no diretório grails-app/services e por convenção seus nomes devem terminar com a palavra Service. 48
8 Para concluir nosso refactoring, basta adicionarmos um atributo para receber a instância desse service em nosso controller. Adicione AtenderService atenderservice logo após a declaração da classe AtendimentoController e pronto. O Grails irá cuidar de injetar automaticamente, através do spring framework, uma instância deste service em nosso controller. Tudo baseado em convenções. Finalizando a aplicação Para finalizar a aplicação, você pode criar automaticamente as views para os outros Domains utilizando o script generate-all DOMAIN. Assim, executando os seguintes comandos, você terá uma aplicação funcional. grails generate-all Paciente, grails generate-all Endereco, grails generateall Medico. O processo Uma das vantagens que as linguagens dinâmicas trazem para o desenvolvimento do dia-a-dia é exatamente a ideia do design by capability, onde os objetos não são julgados em tempo de compilação, mas em tempo de execução. Não importa o tipo do objeto, só importa o que ele é capaz de fazer. Isso oferece uma flexibilidade que leva a uma quebra de paradigmas. Mas ao mesmo tempo que isso é uma vantagem, essa ferramenta nas mãos de desenvolvedores inexperientes pode resultar em um código difícil de manter. A boa notícia é que com o uso de um processo de desenvolvimento que empregue boas práticas de engenharia, esse problema é minimizado. Por isso, na Wareline, implantamos algumas práticas baseadas nos conceitos de desenvolvimento Ágil. A equipe do projeto utiliza as práticas no dia-a-dia de forma natural e não intrusiva, resultando em mais tranquilidade e transparência para todos. Dentre as práticas, vale destacar as seguintes: que dois desenvolvedores utilizam uma única máquina. Isso resulta em maior foco e atenção, além de ajudar a nivelar o conhecimento da equipe. Os pares variam a cada dia, dando a oportunidade de todos trabalharem com todos, garantindo o alinhamento das ideias e regras de negócio entre a equipe. muito clara para determinar quando certa funcionalidade está pronta. Nesta definição, consta que deve ser desenvolvido testes de unidade para todas as classes e testes de integração para as operações de negócio. Os testes ajudaram em muito a evolução da equipe no sentido de conhecer as falhas e oportunidades ocultas em meio às funcionalidades, tanto em termos de negócio quanto em aspectos técnicos. O processo implantado na wareline segue os princípios definidos no Manifesto Ágil e a empresa tem se adaptado muito bem ao processo. Ao término de cada ciclo a equipe é capaz de mensurar sua produtividade e evolução dentro daquele ciclo, inspecionando e adaptando suas práticas. É um processo de melhoria contínua. Conclusão Com um case como este, temos mais crédito em mostrar algo mais flexível e dinâmico, como a linguagem Groovy, dentro do contexto de negócios e de uma aplicação tão crítica quanto a de gestão hospitalar. Uma empresa com muito tempo de estrada como a Wareline mostra que é possível inovar, quando feita a escolha correta para seu caso. A linguagem Groovy e o framework Grails têm se mostrado cada vez mais capazes de satisfazer as mais diversas necessidades de desenvolvimento, desde aplicações distribuídas com uso de EJBs até aplicações mais simples como um simples site. O framework é modular e baseado em convenções, porém flexível o suficiente para oferecer alternativas às suas convenções, tornando-o uma ótima opção para quem quer permanecer na plataforma Java e ao mesmo tempo evoluir tecnologicamente. Vale lembrar que o Grails não é uma bala de prata e seu foco é basicamente oferecer uma plataforma para o frontend web. Um bom engenheiro de software deve saber distinguir os diversos componentes de sua arquitetura, utilizando a ferramenta correta para aplicar em cada uma das situações. O Grails concorre com vários frameworks muito interessantes focados no desenvolvimento do frontend, como JSF, Play (www.playframework.com. br), Struts, dentre outros. O interessante é saber que cada uma dessas opções tem seu lado forte e suas desvantagens. Recomendo ainda um cuidado especial para não se deixar iludir com a simplicidade do Grails. É preciso manter a mente aberta e buscar melhores formas de se entender o funcionamento interno e os mecanismos por trás da simplicidade. Há de se abrir mão de certo controle sobre o Hibernate e sobre a definição do banco de dados, confiando que o Grails irá cuidar de tudo. Se seu modelo de banco de dados já está definido e é muito complexo para se mapear, vale a pena conferir alternativas aos mecanismos padrão do Grails, utilizar algum plugin ou mesmo buscar outro framework. Neste artigo, mostrei como o Grails funciona, sua arquitetura e ferramentas para desenvolvimento. Vimos que o framework se encaixa com os mais diversos processos, permitindo que trabalhemos o domínio de nossa aplicação da forma que quisermos. Criamos um exemplo simples, mas esclarecedor, Referências - 49