Vous êtes sur la page 1sur 8

artigo

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 à inte-
graçã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


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 quan-
Felipe Rodrigues de Almeida tidade de configuração técnica necessária para se utilizar um framework. Vários frameworks recentes,
(felipe@fratech.net): Com mais de 7 anos de incluindo algumas das especificações do Java EE 6, incluem essa característica. Alguns de forma mais
experiência na área de desenvolvimento de evidentes que outros.
software, trabalhou em projetos para empresas
como CPqD, IBM, Telefônica e Embraer, dentre
outras. Atualmente é engenheiro de Software na Em uma aplicação web, imagine não precisar mais de um XML para lhe dizer como determinado request
Fratech.net e tem focado seus esforços em duas deve ser tratado. É possível?
áreas: Agilidade e Expressividade. Seu dia-a-dia
varia entre mentoring técnico para arquiteturas
de negócio e coaching de equipes ágeis. Como
Através de convenções simples, como, por exemplo, manter todas as actions no diretório “actions” elimine
hobby começou a estudar robótica e eletrônica. 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 www.mundoj.com.br
"SUJHPt(SBJMTo6N$BTPEF4VDFTTP

O Grails faz uso extensivo de convenções, com o objetivo de simplificar a aos requisitos de uma aplicação web completa. Para isso, utiliza o Spring
vida do desenvolvedor. Há, porém, casos em que as conveções não se apli- para injeção de dependências, o Log4J para o sistema de logs, o Sitemesh
cam. Para esses casos, o Grails (e outros frameworks) oferecem a alternativa para o sistema de layouts e templates, o Hibernate para persistência e o
de configurar. A diferença é que, neste caso, a configuração é a exceção à JUnit para testes, além de ser totalmente baseado no modelo de Servlets e
regra, o que na prática significa bem menos configurações. JSPs. Como podemos notar, o Grails é mais uma camada de abstração que
ao facilitar o uso de frameworks complexos, nos permite mais tranquilida-
Descobrimos então que a plataforma web é a primeira opção quando se de para desenvolver nossas aplicações.
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 Apesar de usar os frameworks mais utilizados, a grande diferença consiste
a maioria dos problemas foram resolvidos e só nos resta trabalhar com foco exatamente na interface que o Grails disponibiliza para que o desenvol-
nas regras de negócio. Os frameworks mais tradicionais da plataforma Java vedor desfrute destes mecanismos. Isso quer dizer que para utilizar o site-
utilizam-se dessas convenções de forma muito eficaz e já estão consolida- mesh, há uma convenção bem mais simples do que se você fosse utilizá-lo
dos no mercado. diretamente em sua aplicação. O mesmo acontece com o Hibernate, Log4J,
Spring e os outros.
Há, porém, alguns problemas quando se fala de frameworks mais tra-
dicionais, principalmente no uso de configurações em excesso. Estes
frameworks são muito dependentes de configurações, o que dificulta em Plugins
muito a vida dos desenvolvedores. É comum que as configurações tenham
que ser repetidas para cada ação da aplicação. Isso acontece frequente- Além de sua arquitetura padrão, já presente no download
mente com JSF e Struts, por exemplo. original, há ainda a possibilidade de instalar plugins, que
complementam o framework. Dentre os diversos exemplos
Uma nova geração de frameworks tem surgido para enfrentar este proble- de plugins, temos o plugin para integração com o JPA, Acegi,
ma. Estes são frameworks que permitem o aproveitamento de convenções JSecurity, o Adobe Flex através do BlazeDS, o Quartz para
ao invés de configurações, mas que quando necessário ainda permite que scheduling etc.
sejam configurados a um nível bem satisfatório. Para a plataforma Java, um
dos principais players deste mercado é o framework Grails. Tudo isso pode ser conferido direto no site do framework,
www.grails.org. Já dá para notar que o Grails é um framework
O que é Grails que veio para ficar.

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 A linguagem Groovy
convencionadas para as tarefas mais comuns do desenvolvimento web. Con-
tém mecanismos para persistência de dados, log, injeção de dependências, Talvez você nunca tenha ouvido falar sobre Groovy, mas, acredite, se você
templates, controle transacional, testes unitários e de integração, webflow, conhece Java está apto a desenvolver em Groovy.
dentre outras coisas.
Groovy é uma linguagem de tipagem dinâmica que foi criada especifi-
Além disso, é desenvolvido para integração com o mundoj EE, devido à camente para a JVM. Isso quer dizer que, enquanto desenvolvendo em
integração nativa que o Groovy tem com a linguagem Java, de forma que Groovy, você poderá usar código Java normal, porém com certo açúcar
as aplicações Grails podem ser executadas em qualquer container de Servlet sintático. O GDK (Groovy Developer Kit) é uma extensão do JDK, possibi-
e JSP, inclusive servidores completos Java EE. Isso possibilita que o desen- litando assim usar todos os recursos normais do Java. Tudo que podemos
volvedor use qualquer uma das bibliotecas disponíveis no ecossistema Java fazer em Java, pode ser feito em Groovy. Por exemplo, para criar um
para desenvolver aplicações Grails, além de o tornar uma ótima opção para ArrayList em Groovy, basta instanciar essa classe.
aplicações corporativas que exigem algo um pouco mais robusto.

A grande vantagem do Grails é sua filosofia voltada para o uso de convenções java.util.ArrayList myList = new java.util.ArrayList();
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. Podemos ainda utilizar uma sintaxe um pouco mais groovy:

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 def myList = new ArrayList()
quanto do framework Grails. Após alguns anos adquirindo maturidade e ou
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. def myOtherList = []

A composição do Grails
O uso de [] nesse caso não cria um array, mas sim uma instância da classe Ar-
O Grails é um framework MVC que encapsula vários outros frameworks que rayList. Note que o ; é opcional, assim como o uso de return.
estão presentes na grande maioria das aplicações web atuais para atender
Se quiser testar mais a fundo a integração, pegue qualquer programa Java

43
"SUJHPt(SBJMTo6N$BTPEF4VDFTTP

que você possua e modifique a extensão do código-fonte de .java para .groovy.


public int getMiles(){
Compile utilizando o comando groovyc que possui uma sintaxe muito similar ao println “Passei no getMiles()”
javac e execute utilizando o comando groovy com sintaxe idêntica ao comando return miles
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 Closures
em Java, com algumas raríssimas exceções. Raras mesmo.

Retirando um exemplo do livro Programming Groovy escrito por Venkat Subram- Há ainda no Groovy uma funcionalidade chamada closure, que nada
manian para os famosos Pragmatics Programmers, veremos como a sintaxe do mais é do que uma instância da classe groovy.lang.Closure.
Groovy é um alívio para os programadores java, ao invés de ser um peso. Análise
este programa em Java: Closure cl = { println “Eu sou uma closure” }

public class Car {


private int miles; No código acima, utilizamos um recurso da sintaxe do groovy para
private int year; criar uma instância da class Closure. O bloco de código após o sinal de
public Car(int theYear) { year = theYear; }
atribuição “= “ na verdade é uma instância da classe Closure. Uma vez
public int getMiles() { return miles; } que temos essa instância em mãos, podemos utilizá-la como um objeto
public void setMiles(int theMiles) { miles = theMiles; } comum, passando como parâmetro a métodos. Para executar o a closure,
fazemos como se chamássemos um método comum.
public int getYear(){ return year; }

public static void main(String[] args) {


Car car = new Car(2008); cl()

System.out.println(“Year: “ + car.getYear());
System.out.println(“Miles: “ + car.getMiles());
System.out.println(“Setting miles”); Podemos ainda ter closures que recebem parâmetros. No exemplo a se-
car.setMiles(25); guir, passaremos um parâmetro indicando o nome de alguém, para que
System.out.println(“Miles: “ + car.getMiles()); a closure imprima uma saudação.
}
}
def saudar = { nome -> println “Olá, ” + nome }
Agora veja o mesmo programa, escrito em groovy:

class Car { Repare que indicamos os parâmetro dentro das chaves e, em caso de ha-
def miles = 0 ver mais de um parâmetro, podemos separá-los por vírgula. Podemos até
final year mesmo indicar o tipo desse parâmetro como na declaração de métodos
comuns. Veja como fica a execução dessa closure.
Car(theYear) { year = theYear }

def static main(args) { saudar(“Mundoj”)


def car = new Car(2008)

println “Year: ${car.year}”


println “Miles: ${car.miles}” Para saber mais sobre o Groovy, acesse site da linguagem em http://
println ‘Setting miles’ groovy.codehaus.org/.
car.miles = 25
println “Miles: ${car.miles}”
}
} Como funciona
Na prática, o framework funciona de forma muito simples. Devemos
Veja que a quantidade de código é menor, além de ser mais limpa e fácil criar actions dentro das classes controllers para tratar as requisições dos
de ler. A diferença está na clareza das informações. As classes groovy usuários. Os controllers nada mais são do que classes que agrupam ac-
seguem a convenção JavaBeans automaticamente. Isso quer dizer que o tions. Dessa forma, posso ter um controller count que contém as actions
compilador do groovy adiciona os métodos get e set para nós. Quando inNumbers e inWords. O Grails possui um sistema de roteamento por
acessamos um atributo, como no caso de car.miles, na verdade estamos convenção que fica definido no arquivo grails-app/conf/UrlMappings.
invocando o método getMiles() criado automaticamente pelo compi- groovy. O mapeamento de URLs default do Grails irá interpretar as urls
lador. Para testar esse comportamento, basta sobreescrever o método conforme mostrado na figura 1.
getMiles() conforme o seguinte trecho:
Além dos controllers, podemos utilizar classes de domínio, ou domains. Essas
Dessa forma, não importa o que você faça, ao chamar car.miles será im- classes representam as entidades de negócio da nossa aplicação. Normal-
presso o texto “Passei no getMiles()” na saída padrão do sistema. mente esses dados são persistidos em banco de dados e contêm operações

44 www.mundoj.com.br
"SUJHPt(SBJMTo6N$BTPEF4VDFTTP

Herança?
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 clas-
Figura 1. Mapeamento de urls do Grails. sificação dos registros. Essa coluna reflete o valor do atributo class do objeto
tratado, que irá variar entre Pessoa, Paciente e Médico.
de negócio. Podem se relacionar e são automaticamente mapeados para per-
sistência através do wrapper do hibernate que já vem com o Grails, chamado Optei por este caminho no artigo por motivos didáticos. Há outras opções,
GORM. Elas podem se relacionar e também serem utilizadas normalmente, como composição através do embedded, por exemplo.
pois são classes simples e normais. Os domain devem ser colocados dentro Vejamos como desenvolver uma pequena tela de atendimento para este
do diretório grails-app/domains, podendo colocar em pacotes ou não. 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 uti-
lizar “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.
'JHVSB&TUSVUVSBEFVNBBQMJDBÎÍP(SBJMT

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 ex- Criando a aplicação
tensas. Dessa forma, podemos separar as regras de negócio das regras de
apresentação e, assim, deixar nossas actions e contrllers muito mais limpos. Para criar uma aplicação utilizando o Grails, devemos apenas emitir o
Os services são classes comuns que possuem métodos. Por padrão, são sta- comando grails create-app atendimento. Com esse comando, o Grails
teless, porém há formas de mudar isso. A exemplo dos outros artefatos, os emitirá uma série de ações, executando alguns scripts para a estrutura-
services são organizados dentro do diretório grails-app/services. ção da sua aplicação. Ao final, deve haver um diretório com o nome aten-
dimento no diretório onde você emitiu o comando acima. A estrutura de
Integração pronta diretórios da aplicação pode ser vista na figura 3.

A parte mais interessante e incomum para aqueles que não conhecem o


O Grails possui um sistema default de injeção de dependências baseado no
framework está no diretório grails-app, onde podemos notar diretórios com
Spring framework. Esse sistema permite que instâncias sejam injetadas direto
nomes bem sugestivos. Como o Grails é um framework baseado em conven-
em nossos controllers e services sem a necessidade de configurar os spring ções, convenciona-se que as classes serão categorizadas baseando-se no di-
beans. Isso é possível através de uma simples convenção. Por exemplo, para retório em que estão. Dessa forma, colocaremos as classes que representam
injetar um service dentro de um controller e fazer uso dele, basta declararmos os controllers dentro do diretório controllers, os services no diretório services,
um atributo simples no controller. Esse atributo dever ser nomeado segundo as classes de domínio no diretório domain e assim por diante.
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. Domain
Além da injeção de dependências, o Grails trata essas classes de forma especial, Vamos começar o desenvolvimento pelo domain. Devemos criar as classes
acrescentando alguns comportamentos através do sistema de metaprogra- para representar as entidades vistas na figura 2. As classes de Domain no
mação do groovy. No caso dos services, dentre outras coisas, o Grails cuida Grails são simplesmente POGOs (Plain Old Groovy Objects) que seguem a
para que todas as suas operações sejam transacionais por padrão. No caso dos convenção de Java Beans. Também podemos utilizar POJOs normais como
domains, o Grails injeta alguns métodos relacionados à persistência. Métodos domains no Grails, devido à integração entre o Groovy e o Java. As Lista-
como list(), save(), remove(), findAllBy*(), são alguns exemplos. gens de 1 a 5 mostram como ficam as classes de nosso domínio.

45
"SUJHPt(SBJMTo6N$BTPEF4VDFTTP

O case
Para exemplificar como o framework pode ser utilizado, nada mais interessante O desafio consiste em fazer com que o conhecimento e a produtividade que es-
do que apresentarmos um case de sucesso. tes desenvolvedores, vindos do ambiente VB, sejam mantidos para o novo sis-
tema web. Isso exige que a curva de aprendizado e a transição sejam mantidas.
O case se passa na Wareline, uma empresa de Campinas focada no desenvolvi-
mento de softwares de gestão hospitalar. O sistema atual deles é desenvolvido Os paradigmas Desktop e Web são bem diferentes e, apesar de passarem por
em visual basic, com módulos web, escritos em Java e PHP. A empresa já manti- treinamento antes do projeto, as dificuldades que podem surgir são inúmeras.
nha 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. 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 de-
Para esse projeto, o objetivo é migrar todo o sistema para a plataforma Web. senvolvedores vão ganhando mais experiência, podem começar a customizar
Participei da definição da arquitetura, do processo de gestão, e agora acompa-
as partes necessárias sem perder produtividade ou prejudicar o funcionamento
nho a evolução do projeto.
geral do framework.
Metade da equipe formada possui experiência no desenvolvimento para a
web, basicamente com background em servlets e JSPs. A outra metade é for- Contar com um ambiente pronto, estável e baseado nas melhores práticas
mada por desenvolvedores trazidos do Visual Basic para o novo projeto, pois diminui muito os riscos da migração da plataforma desktop para a web, sem
detém grande parte do conhecimento do negócio. trocar todos os desenvolvedores.

O Domain
s Paciente
tend
Em nosso exemplo, vamos tratar de uma pequena parte do domain desta ex 1
aplicação: o atendimento de pacientes na recepção do hospital. Obviamente,
neste artigo, vou apresentar somente uma pequena e incompleta parte do Pessoa N
modelo real da aplicação, devido às limitações de espaço. 1
ex
ten Atendimento
Na figura 2, vemos uma parte do domínio. Um dos trechos mais simples da ds
N
aplicação e que já reflete a grande quantidade de relacionamentos entre 1
entidades que há neste projeto. Temos uma entidade Atendimento, que repre- 1
senta cada atendimento feito. Um atendimento sempre deve referenciar um Endereço
Paciente e um Médico. Além disso, Médico e Paciente são subclasses de Pessoa, Médico
que por sua vez contém um Endereço.
Figura 2. Modelo da aplicação de exemplo.

Listagem 1. Classe Atendimento.


para aquele controller. Na Listagem 6 está nosso controller atendimento, com
uma action para listar os atendimentos:
class Atendimento {
static belongsTo = [paciente:Paciente, medico:Medico]
Listagem 2. Classe Pessoa.
Paciente paciente
Medico medico class Pessoa implements Serializable {
String queixa
Date data static hasMany = [atendimentos:Atendimento]
} String nome
Endereco endereco

Repare como os relacionamentos são declarados: utiliza-se belongsTo para static constraints = {
endereco(nullable:true)
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á Listagem 3. Classe Paciente.
que ele é uma abstração sobre este framework.
class Paciente extends Pessoa {
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

46 www.mundoj.com.br
"SUJHPt(SBJMTo6N$BTPEF4VDFTTP

Listagem 4. Classe Medico. Listagem 7. View de listagem de atendimentos.

class Medico extends Pessoa { <div class=”body”>


String especialidade <h1>Atendimento List</h1>
} <g:if test=”${flash.message}”>
<div class=”message”>${flash.message}</div>
</g:if>
<div class=”list”>
Listagem 5. Classe Endereço.
<table>
<tr>
class Endereco { <g:sortableColumn property=”id” title=”Id” />
<g:sortableColumn property=”data” title=”Data” />
static belongsTo = [Pessoa] <th>Medico</th>
<th>Paciente</th>
String logradouro <g:sortableColumn property=”queixa” title=”Queixa” />
String bairro </tr>
String cidade <g:each in=”${atendimentoInstanceList}” status=”i”
String estado
Pessoa pessoa var=”atendimentoInstance”>
} <tr class=”${(i % 2) == 0 ? ‘odd’ : ‘even’}”>
<td>
<g:link action=”show” id=”${atendimentoInstance.id}”>
${fieldValue(bean:atendimentoInstance, field:’id’)}
Listagem 6. Controller de atendimento.
</g:link>
</td>
class AtendimentoController { <td>${fieldValue(bean:atendimentoInstance,
def list = { field:’data’)}</td>
return [atendimentos: Atendimento.list(params)] <td>${atendimentoInstance.medico.nome}</td>
} <td>${atendimentoInstance.paciente.nome}</td>
} <td>${fieldValue(bean:atendimentoInstance,
field:’queixa’)}</td>
Veja como é simples esta action. Tão simples que talvez você se pergunte: De </tr>
</g:each>
onde veio esse método list() da classe atendimento? A resposta está no GORM. </table>
Ele faz uso das capacidades dinâmicas do Groovy para injetar em tempo de </div>
execução este e outros métodos em todas as classes de domínio. Veja a referên- <div class=”paginateButtons”>
<g:paginate total=”${atendimentoInstanceTotal}” />
cia completa dos métodos do Grails no endereço: http://grails.org/doc/1.1.x </div>
</div> 
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 ac-
tion 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.

Este arquivo deve seguir uma convenção de diretórios para que o Grails o en-
contre. 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 Figura 4. Página de listagem dos atendimentos.
a interpolação de código Groovy dentro das views, como é o caso do trecho
${fieldValue(bean:atendimento, field:'id')}. Listagem 8. Actions para adição de um novo atendimento.

A partir daqui, já podemos executar a aplicação e visualizar o que está feito. A def create = {
figura 4 mostra a listagem com alguns atendimentos já cadastrados e pode ser return [‘atendimento’: new Atendimento()]
acessada através da url http://localhost:8080/atendimento/atendimento/list. }

def save = {
Agora só precisamos de uma action para inserir um novo atendimento. def atendimento = new Atendimento(params)
Para isso, vamos criar uma action em nosso controller de atendimento. if(!atendimento.hasErrors() && atendimento.save()) {
flash.message = “Atendimento ${atendimento.id} created”
Como visto na Listagem 8, adicionamos duas actions ao Atendimento- redirect(action:list)
Controller. A action create irá criar uma nova instância de atendimento e } else {
então renderizar, por convenção, a view create, mostrada na Listagem 9. render(view:’create’,model:[atendimento:atendimento])
}
A action save obtém os dados através do mapa params e os grava no banco. }

47
"SUJHPt(SBJMTo6N$BTPEF4VDFTTP

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 redirecio-
nar para a nossa action list, para listarmos o novo registro. Além disso, adiciona-
mos 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
http://localhost:8080/atendimento/atendimento/create.

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}</div>
</g:if>
<g:hasErrors bean=”${atendimento}”>
<div class=”errors”> 'JHVSB'PSNVMÈSJPQBSBDSJBÎÍPEFVNBUFOEJNFOUP
<g:renderErrors bean=”${atendimento}” as=”list” />
</div>
</g:hasErrors> utilizar o controle transacional default do Grails. Os services podem ser
<g:form action=”save” method=”post” > facilmente utilizados nos controllers através da injeção de dependências
<div class=”dialog”> por convenção.
<div class=
”value ${hasErrors(bean:atendimento,field:’data’,’errors’)}”>
<label for=”data”>Data:</label><br/> Após refatorar o código da action save, a action fica como na Listagem 10.
<g:datePicker name=”data” value= ”${atendimento?.data}”
precision=”minute” ></g:datePicker>
</div><br/> Listagem 10. Action save refatorada para utilizar um service.
<div class=
”value ${hasErrors(bean:atendimento,field:’medico’,’errors’)}”>
<label for=”medico”>Medico:</label><br/> def save = {
<g:select optionKey=”id” optionValue=”nome”
from=”${Medico.list()}” name=”medico.id”
value=”${atendimento?.medico?.id}” ></g:select> def atendimento = new Atendimento(params)
</div><br/>
<div class= if(!atendimento.hasErrors() && atenderService.
”value ${hasErrors(bean:atendimento,field:’paciente’,’errors’)}”>
<label for=”paciente”>Paciente:</label><br/>
<g:select optionKey=”id” optionValue=”nome” salvarAtendimento(atendimento)) {
from=”${Paciente.list()}” name=”paciente.id”
value=”${atendimento?.paciente?.id}” ></g:select> flash.message = “Atendimento ${atendimento.id} created”
</div><br/>
<div class=
”value ${hasErrors(bean:atendimento,field:’queixa’,’errors’)}”> redirect(action:list)
<label for=”queixa”>Queixa:</label><br/>
<input type=”text” id=”queixa” name=”queixa” } else {
value=”${fieldValue(bean:atendimento,field:’queixa’)}”/>
</div><br/>
</div> render(view:’create’,model:[atendimento:atendimento])
<div class=”buttons”>
<span class=”button”><input class=”save” type=”submit” }
value=”Create” /></span>
</div>
</g:form> }
</div>
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
Encapsulando as operações em Services devem terminar com a palavra Service.
Apesar de esse ser um exemplo simples, o case real não é tão simples as-
sim. A complexidade das operações de negócio pode tornar essas actions Listagem 11. AtenderService.groovy.
muito grandes e difíceis de manter. Os controllers devem ser magros, visto
public class AtenderService {
que sua função é apenas chamar as operações de negócio adequadas e re-
boolean salvarAtendimento(atendimento){
direcionar a requisição para a view adequada. Para resolver isso, podemos return atendimento.save()
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, }

48 www.mundoj.com.br
"SUJHPt(SBJMTo6N$BTPEF4VDFTTP

Para concluir nosso refactoring, basta adicionarmos um atributo para Conclusão


receber a instância desse service em nosso controller. Adicione Aten-
derService atenderService logo após a declaração da classe Atendimen- Com um case como este, temos mais crédito em mostrar algo mais flexível
toController e pronto. O Grails irá cuidar de injetar automaticamente, e dinâmico, como a linguagem Groovy, dentro do contexto de negócios e
através do spring framework, uma instância deste service em nosso de uma aplicação tão crítica quanto a de gestão hospitalar. Uma empresa
controller. Tudo baseado em convenções. com muito tempo de estrada como a Wareline mostra que é possível inovar,
quando feita a escolha correta para seu caso.
Finalizando a aplicação
A linguagem Groovy e o framework Grails têm se mostrado cada vez mais
Para finalizar a aplicação, você pode criar automaticamente as views capazes de satisfazer as mais diversas necessidades de desenvolvimento,
para os outros Domains utilizando o script generate-all DOMAIN. Assim, desde aplicações distribuídas com uso de EJBs até aplicações mais simples
executando os seguintes comandos, você terá uma aplicação funcional. como um simples site. O framework é modular e baseado em convenções,
grails generate-all Paciente, grails generate-all Endereco, grails generate- porém flexível o suficiente para oferecer alternativas às suas convenções,
all Medico. tornando-o uma ótima opção para quem quer permanecer na plataforma
Java e ao mesmo tempo evoluir tecnologicamente.
O processo 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
Uma das vantagens que as linguagens dinâmicas trazem para o desen-
software deve saber distinguir os diversos componentes de sua arquitetura,
volvimento do dia-a-dia é exatamente a ideia do design by capability,
utilizando a ferramenta correta para aplicar em cada uma das situações.
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 O Grails concorre com vários frameworks muito interessantes focados no
é capaz de fazer. Isso oferece uma flexibilidade que leva a uma quebra desenvolvimento do frontend, como JSF, Play (www.playframework.com.
de paradigmas. Mas ao mesmo tempo que isso é uma vantagem, essa br), Struts, dentre outros. O interessante é saber que cada uma dessas opções
ferramenta nas mãos de desenvolvedores inexperientes pode resultar tem seu lado forte e suas desvantagens.
em um código difícil de manter.
Recomendo ainda um cuidado especial para não se deixar iludir com a
A boa notícia é que com o uso de um processo de desenvolvimento que simplicidade do Grails. É preciso manter a mente aberta e buscar melhores
empregue boas práticas de engenharia, esse problema é minimizado. formas de se entender o funcionamento interno e os mecanismos por trás da
Por isso, na Wareline, implantamos algumas práticas baseadas nos con- simplicidade. Há de se abrir mão de certo controle sobre o Hibernate e sobre
ceitos de desenvolvimento Ágil. A equipe do projeto utiliza as práticas no a definição do banco de dados, confiando que o Grails irá cuidar de tudo. Se
dia-a-dia de forma natural e não intrusiva, resultando em mais tranquili- seu modelo de banco de dados já está definido e é muito complexo para se
dade e transparência para todos. mapear, vale a pena conferir alternativas aos mecanismos padrão do Grails,
utilizar algum plugin ou mesmo buscar outro framework.
Dentre as práticas, vale destacar as seguintes:
t 1BJS1SPHSBNNJOHPTEFTFOWPMWFEPSFTTFOUBNFNQBSFT EFGPSNB Neste artigo, mostrei como o Grails funciona, sua arquitetura e ferramentas
que dois desenvolvedores utilizam uma única máquina. Isso resulta para desenvolvimento. Vimos que o framework se encaixa com os mais di-
em maior foco e atenção, além de ajudar a nivelar o conhecimento versos processos, permitindo que trabalhemos o domínio de nossa aplicação
da equipe. Os pares variam a cada dia, dando a oportunidade de da forma que quisermos. Criamos um exemplo simples, mas esclarecedor,
todos trabalharem com todos, garantindo o alinhamento das ideias EFJYBOEPOPBSRVFIÈNVJUPNBJTEP(SBJMTQBSBTFFTUVEBSt
e regras de negócio entre a equipe.
t 5FTU#FIBWJPS%SJWFO%FWFMPQNFOUBFRVJQFTFHVFVNBEFmOJÎÍP
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 Referências


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 t HSBJMTPSH
t HSPPWZDPEFIBVTPSH
evolução dentro daquele ciclo, inspecionando e adaptando suas práticas. t <4VC>7FOLBU4VCSBNNBOJBO1SPHSBNNJOH(SPPWZ5IF1SBHNBUJD1SPHSBNNFST 
É um processo de melhoria contínua. --$ 3BMFJHI /$BOE%BMMBT 59 
t %ZOBNJD 5ZQJOH o $BQBCJMJUZ WT $POUSBDU o IUUQXXXGSBUFDIOFUDPNVOJEBEFFYJ-
CJS

49

Vous aimerez peut-être aussi