Post on 13-May-2015
Un poco más allá con Grails
Daniel Latorre
dani@primerviernes.com11/03/2011 – Madrid on Rails
PrimerVienes
¿Quién?
Cofundador de Jobsket.com
Desarrollador independiente
Principalmente Grails/Groovy/Java
Google Summer of Code 2008 y contribuidor Open Source
Web: http://www.danilat.com/
CV: http://www.jobsket.es/cv/dani
Twitter: @dani_latorre
¿Qué es Grails?
Framework web para la plataforma Java “full stack”. Escrito en Groovy y Java utilizando como base varias herramientas
maduras(Spring, Hibernate, Tomcat...).
CoC & DRY.
Fuertemente inspirado en Ruby on Rails.
Principales características de Groovy
Menos ceremonioso y más expresivo que Java
Todo es un objeto (no hay tipos primitivos)
Compilado o script
Imports por defecto (java.util.*, java.io.*, java.net.*, java.math.BigDecimal, java.math.BigInteger, groovy.util.*)
Compilación cruzada (Joint compilation)
El GDK extiende a la JDK
Expandos y MOP (añade y modifica atributos y métodos en tiempo de ejecución)
Artefactos de Grails
Clases de Dominio (GORM)
Servicios
Controladores
Vistas + layouts
Librerías de tags
Filtros
Codecs
Soporte I18N
Un properties por Locale.
Cambio de idioma con /book/list?lang=en.
<g:message code="my.localized.content" args="${['Juan']}"/>
message(code:"my.localized.content", args:['Juan'])
Podemos inyectar messageSoruce de Spring en cualquier parte.
Usando Spring podemos incluso modificar el origen de datos del messageSoruce.
Externalizar configuraciones
Base de datos por JDNI. En el DataSoruce.groovy:
dataSource {
jndiName = "java:comp/env/myDS"
}
Configuración del Config.groovy:
grails.config.locations = [ "classpath:${appName}-config.groovy","file:${userHome}/.grails/${appName}-config.groovy"]
Plugins Autentificación
Spring Security, casi indiscutible. También con soporte OpenID, LDAP, CAS
Facebook Connect
OAuth
Solución Do It Yourself
Plugin REST Client
Para consumir servicios REST externos. Ejemplo:
Envío de emails
Mail Plugin, para envíos por SMTP
Postmark Plugin, servicio que asegura la recepción.
Existen varios plugins con más funcionalidades
Lazy/eager loading
Por defecto los objetos relacionados se cargan de forma perezosa.
Podemos necesitar una session diferente al OpenSessionInView de Grails/Spring
static mapping = {
books lazy: false
}
NO evitamos el problema de N + 1 queries.
Evitando el problema N+1
La solución: fetch.
A nivel de relaciones GORM:
static mapping = {
books fetch: 'join'
}
En las consultas:
Author.findAllByNameLike("John%", [fetch: [location: 'join'] ])
Caché de primer nivel de Hibernate
Caché de primer nivel para ahorrar tráfico en red y aumentar la velocidad.
Sin flush:true en save o delete, no se persisten los cambios hasta que hibernate ejecute el próximo select.
Caché de segundo nivel de Hibernate
Se cachea cada insancia de la clase de Dominio:
static mapping = { cache 'read-only' // cache true}
read-only: Si los datos son sólo lectura.non-strict-read-write: Para pocas actualizaciones, no asegura si varias transacciones modifican la misma instancia.read-write: Actualizaciones frecuentes. Al modificar se actualiza en cache, no soporta transacciones y pueden surgir inconsistencias.transactional: Necesita un proveedor que lo soporte(JBoss TreeCache)
Caché de consultas de Hibernate
Es posible cachear queries indicándolo al ejecutar. Habitual para consultas que se repitan de forma
constante
def person = Person.findByFirstName("Fred", [cache:true])
¿Opciones para una política de caché propia?
EhCahe
OSCahe
Memcache
JBoss Cache
Terracota
¿Bases de datos NoSQL?: Redis, Mongo...
Caché de métodos de un Service con SpringCache
Puede interesar cachear las llamadas al método de algún Service.
@Cacheable("pirateCache")
def getPirates() {...}
@CacheFlush("pirateCache")
void registerNewPirate(Pirate pirate) {...}
Caché de HTML con SpringCache
Cachear porciones de HTML es una práctica habitual. Para hacerlo se combina SpringCache y el tag include en
las vistas.
@Cacheable("albumControllerCache")
def list = {...}
@CacheFlush("albumControllerCache")
def save = {...}
Caché HTTPPodemos cachear a nivel de navegador jugando con las
cabeceras HTTP. Ahorrando tráfico y CPU.
Con el plugin Caching Headers, antes de los renders de los actions a cachear:
cache shared:true, validFor: 3600 // 1hr on content
cache shared: true, validUntil: new Date()+1
lastModified book.dateUpdate
Hay disponible también un DSL con withCacheHeaders, para permitir más flexibilidad.
Caché de estáticos
Resources plugin: comprime .js/.css
Cache-resources plugin: añade manejo de cacheo de estáticos al navegador.
Sistemas de mensajería
Hay que tratar quitar lo máximo de la request para mejorar la velocidad, la UX y facilitar la escalabilidad.
JMS Plugin. Java Message Service
Rabbit MQ Plugin. Advanced Message Queuing Protocol
Jabber Plugin.
Solución Do It Yourself(Con quartz o java.util.concurrent)
Optimizando para móvilesEs posible detectar si el navegador es un teléfono en el
request.getHeader('user-agent'). Para ahorrar ese trabajo manual, SpringMobile.
def list = {
withMobileDevice {def device ->
if(device.id.contains("iphone"){
render(view: "iphoneList", model: [list: listInstance])
}
render(view: "mobileList", model: [list: listInstance])
}
render(view: "list", model: [list: listInstance])
}
Optimizando para móviles II
En la parte de front, hay que optimizar también el html, tamaño de ficheros estáticos, imágenes, etc.
Para smartphones, HTML5: Soporte de geolocalización, Web Database...
Librerías Javascript que pueden ayudar: Sencha Touch o jQuery Mobile.
Algunos enlaces de interés
Postmark, servicio de mailing: http://postmarkapp.com/
Reading i18n messages from the database with Grails: http://1vm.es/000K
SpringSecurity with SpringCache: Caching content per user: http://1vm.es/000L
Localizable plugin: https://github.com/danilat/localizable