Jobsket Spring 2GX Madrid

61
Haga clic para modificar el estilo de subtítulo del patrón 2/21/10 Productividad máxima con Grails y Java “Because you're worth much more” way Daniel Latorre – Jordi Monné – Martín Pérez / Jobsket S.L.

description

This is the presentation we gave at Spring 2GX Madrid. It shows how Grails helped us to improve our productivity and why Grails is not that bounded to Groovy and how it can be an outstanding alternative if you are a 100% Java company.

Transcript of Jobsket Spring 2GX Madrid

Page 1: Jobsket Spring 2GX Madrid

Haga clic para modificar el estilo de subtítulo del patrón

2/21/10

Productividad máxima con Grails y Java“Because you're worth much more” way

Daniel Latorre – Jordi Monné – Martín Pérez / Jobsket S.L.

Page 2: Jobsket Spring 2GX Madrid

2/21/10

Sobre Nosotros

● Martin Pérez: Javero desde hace 10 años. Ultimos años como senior architect/contractor en la industria financiera en Irlanda.

● Daniel Latorre: Programador Java, Groovy, Rails, Php. Google Summer of code donde contribuyó a Grails.

● Jordi Monné: Nuestro Spring expert. Javero profesional. ex-JavaConGanas

Page 3: Jobsket Spring 2GX Madrid

2/21/10

Índice

● Acerca de Jobsket

● Jobsket y Grails: Una historia de amor y odio

● Integrando Grails y Java

● Lo que nos gusta más de Grails

Page 4: Jobsket Spring 2GX Madrid

2/21/10

Page 5: Jobsket Spring 2GX Madrid

2/21/10

DEMO

Page 6: Jobsket Spring 2GX Madrid

2/21/10

¿Y todo esto por qué os lo contamos?

● Porque somos sólo tres personas.

● Que hemos hecho una aplicación técnicamente superior a la mayoría de sitios web de empleo.

● Que hemos podido realizar innovaciones que nuestros clientes no se creen cuando las ven.

● Que tenemos un producto sólido que actualizamos frecuentemente en producción, casi cada semana.

● Y porque seguramente Grails tenga algo que ver.

Page 7: Jobsket Spring 2GX Madrid

2/21/10

Arquitectura

IrelandSpain Master

Infojobs

Tecnoempleo

Infoempleo

RedTrabaja

OS Integration

Lucene Index

Lucene Index

Lucene Index

Lucene Index

Customer Website

Customer Website

Customer Website

Control lers

Views C

raw

lers

Stat

s

Spring Framework

GORM Hibernate

Storage Search

Scripts

Page 8: Jobsket Spring 2GX Madrid

2/21/10

Cifras

● Tomcat + Grails 1.0.5

● 3 Instancias de MySQL

● Un índice de Compass

● 10 índices de Lucene

● 1Gb Heap. 1 Major GC cada 24 horas.

● 60.000 lineas de código

● 70% Java

● 20 Crawling threads

● 350 GSPs

Page 9: Jobsket Spring 2GX Madrid

2/21/10

Page 10: Jobsket Spring 2GX Madrid

2/21/10

¿Por qué Grails?

● 2008. Startup. Inseguridad. ¿Funcionará?● Al menos escojamos algo nuevo para aprender

● Pero tiene que ser algo con lo que estemos familiarizados

● Y que más o menos se vea que las cosas van por ahí

● ¿RoR? : No tenemos ni idea de Ruby

● WebFlow: Lo mismo de siempre

● ¿Grails? Venga, probamos.

Page 11: Jobsket Spring 2GX Madrid

2/21/10

Escenario

● Tres personas core Java.

● Legacy de algún otro proyecto en Java.

● Sistemas complejos ya desarrollados en Java.

● Montones de librerías ya existentes en Java que podríamos reutilizar.

● Así que vamos con Grails

Page 12: Jobsket Spring 2GX Madrid

2/21/10

Las cosas no fueron tan bonitas

● Grails todavía en betas

● Tentados a echar marcha atrás

● Muy buggy hasta la versión 1.0.3

● Muchos plugins que no funcionaban

● Soporte en IDEs inexistente no sólo en cuanto a sintaxis sino usabilidad (crash cada 30mins)

Page 13: Jobsket Spring 2GX Madrid

2/21/10

Las cosas no fueron tan bonitas

● Quartz Plugin. Problemas con la sincronización de sesiones.

● GORM y Grails están pensados para utilizar una única conexión de BD.● Servicios que acceden a diferentes BDs = problema

● Algún plugin pero no funcionaba bien

Page 14: Jobsket Spring 2GX Madrid

2/21/10

Pero por otra parte

● Plataforma enormemente sencilla e intuitiva.

● La integración con Spring estaba muy bien.

● Adicción a:● La plataforma de testing

● La partición en environments

● La cantidad de plugins. Algunos funcionaban bastante bien :) (ahora son mucho más estables)

● La comunidad

Page 15: Jobsket Spring 2GX Madrid

2/21/10

¿Comunidad?

Page 16: Jobsket Spring 2GX Madrid

2/21/10

Así que seguimos con Grails

● Pero. Casi todo nuestro código está en Java

● Sólo utilizamos Groovy en:● Controllers

● TagLibs

● Tests

● Filters

● Maximizar la productividad: Nuestro conocimiento en Java + Plataforma Grails

Page 17: Jobsket Spring 2GX Madrid

2/21/10

Grails y Java

● Groovy no es excusa para no usar Grails.

● No es que no nos guste Groovy, pero:● Es difícil encontrar perfiles en Groovy.

● Las empresas tienen mucho talento en Java.

● Hay muchas librerías ya en Java.

● El soporte de herramientas es muy malo.

● Sin embargo hemos encontrado que Groovy es muy bueno para algunas cosas.

Page 18: Jobsket Spring 2GX Madrid

2/21/10

¿Me interesa para mi empresa?

● Muy productivo

● Reaprovechamiento de nuestro legacy Java

● Fácil partición de equipos:● Los que le gusta lo dinámico

● Las viejas glorias de Java

● El núcleo en Java y la parte dinámica en Groovy. A nosotros nos ha funcionado bien.

Page 19: Jobsket Spring 2GX Madrid

2/21/10

Page 20: Jobsket Spring 2GX Madrid

2/21/10

Integración de Grails y Java

● Integramos Grails con● Hibernate, Spring, Lucene, Compass, Maven, Hudson, ...

● No utilizar Groovy en los servicios no implica perder productividad

● La clave, la plataforma Grails

Page 21: Jobsket Spring 2GX Madrid

2/21/10

Integración de Grails y Java

● Integración con Spring● Capa de servicio completamente en Java

● Configuración típica en resources.xml

● Perdemos la posibilidad de enlazar dependencias en runtime

● Sencilla y transparente

● Exactamente igual que cualquier otro proyecto no Grails

Page 22: Jobsket Spring 2GX Madrid

2/21/10

Integración de Grails y Java

● Integración con Spring● grails-app/conf/spring/resources.xml

<beans xmlns....>

<import resources=”crawlers.xml”/>

<bean id="jobOffersService" class="com.jobsket.services.JobOfferService">

<property name="configuration" ref="freemarkerMailConfiguration" />

<!-- otras dependencias -->

</bean>

</beans>

Page 23: Jobsket Spring 2GX Madrid

2/21/10

Integración de Grails y Java

● Integración con Spring● grails-app/controllers/JobOffersController.groovy

class JobOffersController = {

def jobOffersService

def index = {

def jobs = jobOffersService.lastJobOffers();

jobs.sort{it.date}

[jobs:jobs]

}

}

ID del bean de Spring

Page 24: Jobsket Spring 2GX Madrid

2/21/10

Integración de Grails y Java

● Integración con Spring● grails-app/controllers/JobOffersController.groovy

class JobOffersController = {

def jobOffersService

def index = {

def jobs = jobOffersService.lastJobOffers();

jobs.sort{it.date}

[jobs:jobs]

}

}

Método del servicio inyectado

Page 25: Jobsket Spring 2GX Madrid

2/21/10

Integración de Grails y Java

● Integración con Spring● grails-app/controllers/JobOffersController.groovy

class JobOffersController = {

def jobOffersService

def index = {

def jobs = jobOffersService.lastJobOffers();

jobs.sort{it.date}

[jobs:jobs]

}

}

Groovy :)

Page 26: Jobsket Spring 2GX Madrid

2/21/10

Integración de Grails y Java●

● Integración con Hibernate● Modelo mixto

● GORM en algunos casos

● Hibernate con HibernateDaoSupport en otros

● Se mezclan perfectamente

● Necesitabamos múltiples DataSources

● El plugin no nos funcionaba demasiado bien

Page 27: Jobsket Spring 2GX Madrid

2/21/10

Integración de Grails y Java●

● Integración con Hibernate● Configuración para GORM

dataSource {

pooled = true

driverClassName = "com.mysql.jdbc.Driver"

username = "tu_usuario"

password = "tu_password"

}

Page 28: Jobsket Spring 2GX Madrid

2/21/10

Integración de Grails y Java●

● Integración con Hibernate● Configuración no GORM

<bean id="masterDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"

depends-on="mysqlJDBCDriver"

destroy-method="close">

<property name="jdbcUrl" value="jdbc:mysql://${master.db.server}:3306/jobsket_master"/>

<property name="user" value="tu_usuario"/>

<property name="password" value="tu_password"/>

</bean>

Page 29: Jobsket Spring 2GX Madrid

2/21/10

Integración de Grails y Java●

● Integración con Hibernate● Mappings en *.hbm.xml sea para GORM o sin GORM

<hibernate-mapping package="com.jobsket.core.model">

<class name="Role" table="roles">

<id name="id" type="integer">

<column name="id" />

<generator class="identity" />

</id>

<property name="name" type="string" not-null="true" length="64" />

...

</class>

Page 30: Jobsket Spring 2GX Madrid

2/21/10

Integración de Grails y Java●

● Integración Spring-Groovy● Reutilización de variables *.groovy en la configuración Spring

● Configuración dinámica

● Setear variables en función del environment

● Condicionales

Page 31: Jobsket Spring 2GX Madrid

2/21/10

Integración de Grails y Java●

● Integración Spring-Groovy● Fichero Spring XML

<bean id="masterDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"

depends-on="mysqlJDBCDriver"

destroy-method="close">

<property name="jdbcUrl" value="jdbc:mysql://${master.db.server}:3306/jobsket_master"/>

<property name="user" value="tu_usuario"/>

<property name="password" value="tu_password"/>

</bean>

Page 32: Jobsket Spring 2GX Madrid

2/21/10

Integración de Grails y Java●

● Integración Spring-Groovy● grails-app/conf/Config.groovy

development {

master.db.server=”localhost"

}

production {

locale = System.getProperty("jobsket.locale")

If (locale.equals("es")) { crawlers.ip=crawlers_es } else { crawlers.ip=crawlers_ie }

master.db.server=db_production

}

(1)

(1)

(2)

1 = variable según environment2 = variable según condición

Page 33: Jobsket Spring 2GX Madrid

2/21/10

Integración de Grails y Java

● Integración con Spring Web Flow● Ideal para crear flujos entre páginas

● Reserva billete de avión, formulario de pago, ...

● Plugin Grails WebFlow

● Facilidad de uso con su DSL

● Añadir o quitar flujos sin reiniciar, genial

Page 34: Jobsket Spring 2GX Madrid

2/21/10

Integración de Grails y Java

Page 35: Jobsket Spring 2GX Madrid

2/21/10

Integración de Grails y Java

Page 36: Jobsket Spring 2GX Madrid

2/21/10

Integración de Grails y Java

● Integración con Spring Web Flowdef registerFlow = {

recruiterDetails {

on("next") { ... }.to "payment"

on("cancel").to "cancel"

}

payment {

on("nextCreditcardTab") { ... }.to "confirm"

on("nextBankTransferTab") { ... }.to "confirm"

}

Page 37: Jobsket Spring 2GX Madrid

2/21/10

Integración de Grails y Java

● Integración con Spring Web Flowdef registerFlow = {

recruiterDetails {

on("next") { ... }.to "payment"

on("cancel").to "cancel"

}

payment {

on("nextCreditcardTab") { ... }.to "confirm"

on("nextBankTransferTab") { ... }.to "confirm"

}

click en next

Page 38: Jobsket Spring 2GX Madrid

2/21/10

Integración de Grails y Java

● Integración con Compass● Proyecto para integrar búsquedas full-text

● Plug-in Searchable● No lo utilizamos

● Nuestras clases de modelo són Java

● Integración como en cualquier otro proyecto Java

Page 39: Jobsket Spring 2GX Madrid

2/21/10

Integración de Grails y Java

● Integración con Compass● @Searchable en las entidades a indexar/buscar

● Configuración en grails-app/conf/compass/compass.cfg.xml

● CompassService.java CompassConfiguration configuration = new CompassAnnotationsConfiguration(). configure("/compass/compass.cfg.xml")

compass = configuration.buildCompass();

Page 40: Jobsket Spring 2GX Madrid

2/21/10

Integración de Grails y Java

● Integración con Hudson● Servidor de Integración Continua

● Hudson con plugin de Grails

● Hudson sin plugin de Grails● Nuestra elección (ninguna razón especial)

● Muy fácil de configurar para trabajar con Grails

Page 41: Jobsket Spring 2GX Madrid

2/21/10

Integración de Grails y Java

Page 42: Jobsket Spring 2GX Madrid

2/21/10

Integración de Grails y Java

Page 43: Jobsket Spring 2GX Madrid

2/21/10

Integración de Grails y Java

● Integración con Maven● Herramienta para gestionar y construir proyectos Java

● Utilizamos el plugin para Maven

● Se combina bien con los goals por defecto

● mvn clean, mvn compile● Añade nuevos goals

● mvn grails:run-app, grails:list-plugins

Page 44: Jobsket Spring 2GX Madrid

2/21/10

Integración de Grails y Java

● Integración con Maven● Administración de dependencias con pom.xml

<dependencies>

<dependency>

<groupId>org.grails</groupId>

<artifactId>grails-crud</artifactId>

<version>1.1</version>

</dependency>

</dependencies>

Page 45: Jobsket Spring 2GX Madrid

2/21/10

Page 46: Jobsket Spring 2GX Madrid

2/21/10

Lo que más nos gusta

● Plugins

● Taglibs

● Testing

● El dinamismo de Groovy

Page 47: Jobsket Spring 2GX Madrid

2/21/10

Plugins

● Image tools

● Avatar

● Twitter

● Webtest

● JSecurity

● Grails UI (basado en Yahoo UI)

Page 48: Jobsket Spring 2GX Madrid

2/21/10

Componentes de Grails UI

Page 49: Jobsket Spring 2GX Madrid

2/21/10

Grails UI

● Pros:

● Componentes precocinados sencillos de utilizar.

● Aspecto adaptable(vía css)

● Se cargan sólo las dependencias js necesarias

● Contras:● Genera código js junto al html

● Dificultad para añadir/adaptar algunos comportamientos a los componentes.

Page 50: Jobsket Spring 2GX Madrid

2/21/10

Taglibs

● Reutilizar lógica de presentación● Mucho más simple que con JSP(closure en una clase

groovy)

● Repetimos menos código en los controllers y es más potente que templates GSP

● Posibilidad de hacer tests

● Es posible reutilizarlos desde controllers y otros tags

Page 51: Jobsket Spring 2GX Madrid

2/21/10

Testing

● Uno de los puntos fuertes de Grails.

● Cubre todos los tipos de tests:● Unitarios

● Integración

● Funcionales(vía plugins)

● Plugins para testing(Spock, dbUnit, Code Coverage, Easyb, Webtest...)

Page 52: Jobsket Spring 2GX Madrid

2/21/10

Tests de integración

● Hacer tests de integración es complejo. ● Hay que preparar los sistemas, las bases de datos, los

ficheros.

● Hay que gestionar la inicialización de recursos. Inicializar Spring, Hibernate, preparar y rellenar las bases de datos...

● Mucha gente termina haciendo su framework.

Page 53: Jobsket Spring 2GX Madrid

2/21/10

Test de un Service

class CvServiceTests extends GroovyTestCase { def cvService void testFindById() { def cv = new CV(id:1,name:"Dani") cvService.save(cv) cv = cvService.findById(1)

assertNotNull cv assertEquals "Dani", cv.name } }

Accesos reales a BD

Beans inyectados desde Spring

Page 54: Jobsket Spring 2GX Madrid

2/21/10

Tests para los Controllers

● Es posible hacer tanto tests unitarios como de integración.

● Ejecutar acciones y comprobar el estado del controlador.

● Utiliza Spring Mock (MockHttpServletRequest, MockHttpServletResponse y MockHttpSession).

Page 55: Jobsket Spring 2GX Madrid

2/21/10

Test de un Controller

class JobOfferControllerTests extends GroovyTestCase { def jobOffersService void testCreateJobOffer() { def controller = new JobOffersController() controller.jobOffersService = jobOffersService controller.params.title = "Groovy Developer" controller.params.city = "Madrid" controller.save() assertEquals "/joboffer/index", controller.response.redirectedUrl

def jobOffers = jobOffersService.findAllJobOffers() assertEquals 1, jobOffers.size() assertEquals "Madrid", jobOffers[0].city } }

Beans inyectados desde Spring

Ejecuta la action

Comprueba la BD

Page 56: Jobsket Spring 2GX Madrid

2/21/10

Test Funcionales (Webtest)

class AuthWebtest extends grails.util.WebTest { def testLogin(){ invoke '/login' verifyText 'Entra en Jobsket' setInputField(name:'login',value:"dani") setInputField(name:'password',value:"dani") clickButton 'Entra' verifyText 'Publica tu CV' }}

● Alternativas: Functional Testing, Selenium, Webdriver...

Page 57: Jobsket Spring 2GX Madrid

2/21/10

Groovy: Añadir métodos

● Código más limpio

StringBuilder.metaClass.appendNotNull = { str -> if(str){ append(str) }}...def sb = new StringBuilder()sb.appendNotNull(unaCadena)sb.appendNotNull(otraCadena)...if(unaCadena){ sb.append(unaCadena)}if(otraCadena){ sb.append(otraCadena)}

Page 58: Jobsket Spring 2GX Madrid

2/21/10

Groovy: Modificar métodos

● Sin necesidad de extender una clase para un mock puntual

cvService.metaClass.getOriginalInputStream = { int id-> return new MockMultipartFile("test.pdf", new byte[0]) .getInputStream() }

Page 59: Jobsket Spring 2GX Madrid

2/21/10

Groovy: Closures

● Modificar un tag estándar de Grails

def applicationTaglib = ctx.getBean("org.codehaus.groovy.grails.plugins.web.taglib.ApplicationTagLib")

def createLinkJobsket = { attrs, body-> ...}createLinkJobsket.delegate = applicationTaglibcreateLinkJobsket.resolveStrategy = Closure.DELEGATE_FIRSTapplicationTaglib.createLink = createLinkJobsket

Page 60: Jobsket Spring 2GX Madrid

2/21/10

GRACIAS

Page 61: Jobsket Spring 2GX Madrid

2/21/10

QA