Your SlideShare is downloading. ×
Desarrollo Grails en Español (Spring I/O - 2011)
Upcoming SlideShare
Loading in...5
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

×

Saving this for later?

Get the SlideShare app to save on your phone or tablet. Read anywhere, anytime - even offline.

Text the download link to your phone

Standard text messaging rates apply

Desarrollo Grails en Español (Spring I/O - 2011)

2,960
views

Published on

Presentación en el evento de Spring I/O de 2011 sobre el Observatorio de Grails y el desarrollo de la web cuestamenos.com

Presentación en el evento de Spring I/O de 2011 sobre el Observatorio de Grails y el desarrollo de la web cuestamenos.com

Published in: Technology

0 Comments
6 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
2,960
On Slideshare
0
From Embeds
0
Number of Embeds
1
Actions
Shares
0
Downloads
0
Comments
0
Likes
6
Embeds 0
No embeds

Report content
Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
No notes for slide
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • Tuvimos que tunear el async mail por el tema del MailSender vs JavaMailSender para MIME y algunos problemas con plantillas y el uso del CC y BCC\n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • Comentar tb que otra ventaja de los enums es que pueden asociarse al messages.properties y proporcionar traducción automática\n
  • Comentar tb que otra ventaja de los enums es que pueden asociarse al messages.properties y proporcionar traducción automática\n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • Imaginemos que construimos una aplicación y queremos proporciona búsqueda sobre la misma, y entonces nos damos cuenta de que buscar es complicado. Pero lo que queremos es que nuestro motor de búsqueda sea rápido, sencillo de configurar y completamente libre de esquema. También queremos indexar la información de forma simple con JSON sobre HTTP, queremos que nuestro motor de búsqueda esté siempre disponible, queremos empezar con una máquina y luego escalar a cientos de ellas, queremos búsqueda en tiempo real, y queremos una solución que funcione en la nube.\n\nLos índices se descomponen en shards, donde cada shard puede tener 0 o más réplicas. Cada nodo en el cluster aloja uno o más shards, y actúa como un coordinador que delega operaciones a los shards correctos. El balanceo y el enrutado se gestionan de forma automática y entre bambalinas.\n\nEl estado del cluster (incluyendo el log de transacciones) puede ser regenerado a partir de cada nodo local (por defecto), o a partir de un repositorio compartido (como NFS o Amazon S3). Cuando se utiliza un repositorio compartido, el estado se replica de forma asíncrona.\nIncluso si se utiliza un repositorio compartido, el índice podría mantenerse completamente en memoria y al mismo tiempo hacer una recuperación completa si se produce un apagado del cluster.\n\n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • Transcript

    • 1. Desarrollo Grails en Español Enrique Medina Montenegro @emedinam 1
    • 2. Índice1. Acerca del ponente2. Observatorio de Grails3. cuestamenos.com4. Ruegos y preguntas5. Contacto 2
    • 3. 1. Acerca del ponente•Ingeniero en Informática (Univ. Alicante - 1991/1996)•Fundador del•Socio fundador/desarrollador de•Colaborador de la comunidad “Open Source”•Más de 3 años usando Groovy/Grails•Blogger, liberal, padre, emprendedor 3
    • 4. Índice1. Acerca del ponente2. Observatorio de Grails3. cuestamenos.com4. Ruegos y preguntas5. Contacto 4
    • 5. 2. Observatorio de Grails ✓¿Cómo surge la idea? ‣Asistencia al Spring 2GX Day (18/Feb/2010) ‣Falta de recursos en español ‣Aumento de interés por Grails en comunidad hispana ‣Centralizar información y estructurarla ✓¿Cómo se desarrolla la idea? ‣Equipo de 3 personas heterogéneas ‣Uso de Wordpress (sí, has oido bien, PHP) ‣Multitud de plugins WP (Twitter, Scoring, etc.) ‣Dedicación, esfuerzo e hipoteca de tiempo libre 5
    • 6. 2. Observatorio de Grails ✓ Estructura del Observatorio ‣ Actualidad (noticias, blogs, liberaciones, etc) Inserción manual diaria (excepto fines de semana) 6
    • 7. 2. Observatorio de Grails ✓ Estructura del Observatorio ‣ Artículos (cosecha propia y colaboraciones) Experiencias propias de desarrollo 7
    • 8. 2. Observatorio de Grails ✓ Estructura del Observatorio ‣ Tutoriales (recopilaciones y manuales) Más detalle, más calidad, paso a paso 8
    • 9. 2. Observatorio de Grails ✓ Estructura del Observatorio ‣ Eventos (congresos, conferencias, seminarios, cursos) No te pierdas nada que ocurra cerca de ti 9
    • 10. 2. Observatorio de Grails ✓ Estructura del Observatorio ‣ Otras ayudas Tu puesto de mandos para tecnología Grails 10
    • 11. 2. Observatorio de Grails ✓ Métricas del Observatorio ‣ Más de 1.000 entradas en Actualidad ‣ Más de 150 entradas en Artículos/Tutoriales/Eventos ‣ Más de 150 comentarios de usuarios 11
    • 12. 2. Observatorio de Grails‣ Estadísticas de uso (vista global) 12
    • 13. 2. Observatorio de Grails‣ Gráfico de visitas por ubicación 13
    • 14. 2. Observatorio de Grails‣ Gráfico de visitas por ubicación 13
    • 15. 2. Observatorio de Grails‣ Gráfico de visitas por ubicación 13
    • 16. 2. Observatorio de Grails‣ Visitantes nuevos y recurrentes 14
    • 17. 2. Observatorio de Grails‣ Fidelización de visitas 15
    • 18. 2. Observatorio de Grails‣ Foro de Grails en castellano 16
    • 19. 2. Observatorio de Grails‣ Equipo humano 17
    • 20. 2. Observatorio de Grails ✓ Hoja de ruta ‣ Continuar la labor de divulgación y promoción de Grails ‣ Nuevas ideas de producción propia: ★ ¿Sabías que...? ★ Entre bastidores ★ Podcasts ‣ Colaboraciones de usuarios ‣ Expansión a otros idiomas ‣ Comunidad/Grupo de Usuarios (Meetups) ¡¡¡Te estamos esperando!!! 18
    • 21. Índice1. Acerca del ponente2. Observatorio de Grails3. cuestamenos.com4. Ruegos y preguntas5. Contacto 19
    • 22. 3. cuestamenos.com✓ La idea... ‣ Viajes y más viajes: ¿puedo ahorrar reservando vuelos/coches/hoteles? ‣ Cashback: ¿hay algo de ésto aquí en España? ‣ Espíritu emprendedor: sin financiación (coste 0) ‣ Retos técnicos: ★ Tecnología a usar: seguro que no es JSF ★ APIs heterogéneas (REST, SOAP, HTTP, Offline) ★ Integración OAuth con Facebook, MSN, GMail ★ URLs ‘amigables’ ★ Front-office vs Back-office ★ Motor de búsqueda de tiendas/productos/promociones 20
    • 23. 3. cuestamenos.com✓ El equipo... ‣ Tres desarrolladores (cada uno de su padre y de su madre): ★ 1 PHPero, algo de Java (disp. móviles), algo de .NET ★ 1 Javero, nada de Groovy, nada de Grails ★ 1 Javero, experiencia en Groovy, algo de Grails ‣ Curva de aprendizaje: factor clave de desarrollo ‣ Entorno de desarrollo (herramientas gratuitas): ★ IDE STS (SpringSource) ★ Unfuddle: SVN ★ Comunicación Skype 21
    • 24. 3. cuestamenos.com✓ El proyecto... ‣ Estructura Front-office / Back-office: ★ Aplicación única, no modularizable ★ Front-office: interfaz web cliente con jQuery y GSP ★ Back-office: plataforma Grails + plugins + librerías de terceros ‣ Parte pública / parte privada (administración) ‣ Uso de todos los artefactos disponibles en Grails (+ plugins): ★ Controladores, dominio, servicios, taglibs, pruebas ★ Seguridad por roles: usuario/administrador ★ GORM, scaffolding, i18n, deployment 22
    • 25. 3. cuestamenos.com✓ El proyecto (en imágenes)... 23
    • 26. 3. cuestamenos.com✓ Reto 1. Pero, ¿dónde está mi conexión? ‣ Requisito inicial: ★ Utilizar DBCP como pool de conexiones (OOTB) ‣ Problema surgido: ★ Conexiones perdidas con MySQL cada día ‣ Solución aplicada: ★ Tomcat, tú te encargas (JNDI) 24
    • 27. 3. cuestamenos.com✓ Reto 1. Pero, ¿dónde está mi conexión? grails-app/conf/BootStrap.groovy ‣ Requisito inicial: ★ Utilizar DBCP como pool de conexiones (OOTB) ‣ Problema surgido: ★ Conexiones perdidas con MySQL cada día ‣ Solución aplicada: ★ Tomcat, tú te encargas (JNDI) 24
    • 28. 3. cuestamenos.com✓ Reto 1. Pero, ¿dónde está mi grails-app/conf/DataSource.groovy conexión? ‣ Requisito inicial: ★ Utilizar DBCP como pool de conexiones (OOTB) ‣ Problema surgido: ★ Conexiones perdidas con MySQL cada día ‣ Solución aplicada: ★ Tomcat, tú te encargas (JNDI) 24
    • 29. 3. cuestamenos.com✓ Reto 2. MailService y su dependencia del ‘request’ ‣ Requisito inicial: ★ Gestión de notificaciones de comisiones y boletines de noticias a usuarios ‣ Problema surgido: ★ Error al renderizar plantillas GSP en procesos asíncronos ‣ Solución aplicada: ★ Simular el ‘request’ mediante una dependencia 25
    • 30. 3. cuestamenos.com✓ Reto 2. MailService y su dependencia del ‘request’ grails-app/conf/BuildConfig.groovy ‣ Requisito inicial: ★ Gestión de notificaciones de comisiones y boletines de noticias a usuarios ‣ Problema surgido: ★ Error al renderizar plantillas GSP en procesos asíncronos ‣ Solución aplicada: ★ Simular el ‘request’ mediante una dependencia 25
    • 31. 3. cuestamenos.com✓ Reto 3. Demasiados correos ‣ Requisito inicial: ★ Enviar correo por cada acción del usuario: registro, integración FB, contacto, etc. ‣ Problema surgido: ★ Proceso síncrono. Cola de mensajes inmanejable ‣ Solución aplicada: ★ Uso del plugin AsynchronousMail (tuneado) 26
    • 32. 3. cuestamenos.com✓ Reto 3. Demasiados correos CorreoAsincronoService.groovy ‣ Requisito inicial: ★ Enviar correo por cada acción del usuario: registro, integración FB, contacto, etc. ‣ Problema surgido: ★ Proceso síncrono. Cola de mensajes inmanejable ‣ Solución aplicada: ★ Uso del plugin AsynchronousMail (tuneado) 26
    • 33. 3. cuestamenos.com✓ Reto 4. Aprovéchate de la configuración de Grails ‣ Requisito inicial: ★ Parametrizar múltiples aspectos de la aplicación ‣ Problema surgido: ★ Parémetros dispersos ‣ Solución aplicada: ★ Uso de Config.groovy 27
    • 34. 3. cuestamenos.com grails-app/conf/Config.groovy✓ Reto 4. Aprovéchate de la configuración de Grails ‣ Requisito inicial: ★ Parametrizar múltiples aspectos de la aplicación ‣ Problema surgido: ★ Parémetros dispersos ‣ Solución aplicada: ★ Uso de Config.groovy 27
    • 35. 3. cuestamenos.com grails-app/conf/Config.groovy✓ Reto 4. Aprovéchate de la configuración de Grails ‣ Requisito inicial: ★ Parametrizar múltiples aspectos de la aplicación ‣ Problema surgido: ★ Parémetros dispersos ‣ Solución aplicada: ★ Uso de Config.groovy 27
    • 36. 3. cuestamenos.com✓ Reto 5. Autenticarse con el correo en vez del usuario ‣ Requisito inicial: ★ Utilizar el nombre de usuario para autenticarse en la web ‣ Problema surgido: ★ La gente olvida su usuario, pero nunca su correo email ‣ Solución aplicada: ★ Creación de un proveedor de autenticación basado en email 28
    • 37. EmailAuthenticationProvider.groovy 3. cuestamenos.com✓ Reto 5. Autenticarse con el correo en vez del usuario ‣ Requisito inicial: ★ Utilizar el nombre de usuario para autenticarse en la web ‣ Problema surgido: ★ La gente olvida su usuario, pero nunca su correo email ‣ Solución aplicada: ★ Creación de un proveedor de autenticación basado en email 28
    • 38. EmailAuthenticationProvider.groovy 3. cuestamenos.com✓ Reto 5. Autenticarse con el correo en vez del usuario ‣ Requisito inicial: ★ Utilizar el nombre de usuario para autenticarse en la web ‣ Problema surgido: ★ La gente olvida su usuario, pero nunca su correo email grails-app/conf/spring/resources.groovy ‣ Solución aplicada: ★ Creación de un proveedor de autenticación basado en email 28
    • 39. EmailAuthenticationProvider.groovy 3. cuestamenos.com✓ Reto 5. Autenticarse con el correo en vez del usuario ‣ Requisito inicial: ★ Utilizar el nombre de usuario para autenticarse en la web ‣ Problema surgido: ★ La gente olvida su usuario, pero nunca su correo email grails-app/conf/spring/resources.groovy ‣ Solución aplicada: ★ Creación de un proveedor de autenticación basado en email grails-app/conf/SecurityConfig.groovy 28
    • 40. 3. cuestamenos.com✓ Reto 6. ¿Qué ha pasado? ‣ Requisito inicial: ★ Poder dar soporte ante problemas al usuario ‣ Problema surgido: ★ No podíamos auditar todo el código en todas las clases ‣ Solución aplicada: ★ Capturar excepciones de forma centralizada y auditar 29
    • 41. 3. cuestamenos.com grails-app/conf/spring/resources.groovy✓ Reto 6. ¿Qué ha pasado? ‣ Requisito inicial: ★ Poder dar soporte ante problemas al usuario ‣ Problema surgido: ★ No podíamos auditar todo el código en todas las clases ‣ Solución aplicada: ★ Capturar excepciones de forma centralizada y auditar 29
    • 42. 3. cuestamenos.com grails-app/conf/spring/resources.groovy✓ Reto 6. ¿Qué ha pasado? ‣ Requisito inicial: ★ Poder dar soporte ante problemas al usuario ‣ Problema surgido: ExceptionResolver.groovy ★ No podíamos auditar todo el código en todas las clases ‣ Solución aplicada: ★ Capturar excepciones de forma centralizada y auditar 29
    • 43. 3. cuestamenos.com✓ Reto 7. URLs ‘bonitas’ y ‘marcables’ como favoritas ‣ Requisito inicial: ★ No queremos ver URLs infinitas que no sean legibles ‣ Problema surgido: ★ Hacer una reescritura manual puede ser tedioso ‣ Solución aplicada: ★ Exprimir el URLMappings.groovy 30
    • 44. 3. cuestamenos.com grails-app/conf/URLMappings.groovy✓ Reto 7. URLs ‘bonitas’ y ‘marcables’ como favoritas ‣ Requisito inicial: ★ No queremos ver URLs infinitas que no sean legibles ‣ Problema surgido: ★ Hacer una reescritura manual puede ser tedioso ‣ Solución aplicada: ★ Exprimir el URLMappings.groovy 30
    • 45. 3. cuestamenos.com✓ Reto 8. Darle nombre a los tipos con enumerados ‣ Requisito inicial: ★ Necesitamos definir todo tipo de conceptos: afiliados, auditorías, estados, prioridades, etc ‣ Problema surgido: ★ Declarar los tipos como variables finales estáticas es demasiado engorroso ‣ Solución aplicada: ★ Aprovecharse de los ‘enums’ 31
    • 46. 3. cuestamenos.com TipoEstadoAuditoria.groovy✓ Reto 8. Darle nombre a los tipos con enumerados ‣ Requisito inicial: ★ Necesitamos definir todo tipo de conceptos: afiliados, auditorías, estados, prioridades, etc ‣ Problema surgido: ★ Declarar los tipos como variables finales estáticas es demasiado engorroso ‣ Solución aplicada: ★ Aprovecharse de los ‘enums’ 31
    • 47. 3. cuestamenos.com TipoEstadoAuditoria.groovy✓ Reto 8. Darle nombre a los tipos con enumerados ‣ Requisito inicial: ★ Necesitamos definir todo tipo de conceptos: afiliados, auditorías, estados, prioridades, etc ‣ Problema surgido: TipoMetodoPago.groovy ★ Declarar los tipos como variables finales estáticas es demasiado engorroso ‣ Solución aplicada: ★ Aprovecharse de los ‘enums’ 31
    • 48. 3. cuestamenos.com✓ Reto 9. Mapea, mapea ‣ Requisito inicial: ★ Mapear las clases del dominio y sus asociaciones ‣ Problema surgido: ★ Demasiadas sentencias SQL y problemas de rendimiento ‣ Solución aplicada: ★ Tunear y optimizar los mapeos hasta el más mínimo detalle 32
    • 49. 3. cuestamenos.com Historico.groovy✓ Reto 9. Mapea, mapea ‣ Requisito inicial: ★ Mapear las clases del dominio y sus asociaciones ‣ Problema surgido: ★ Demasiadas sentencias SQL y problemas de rendimiento ‣ Solución aplicada: ★ Tunear y optimizar los mapeos hasta el más mínimo detalle 32
    • 50. 3. cuestamenos.com Historico.groovy✓ Reto 9. Mapea, mapea ‣ Requisito inicial: ★ Mapear las clases del dominio y sus asociaciones ‣ Problema surgido: ★ Demasiadas sentencias SQL y problemas de rendimiento Usuario.groovy ‣ Solución aplicada: ★ Tunear y optimizar los mapeos hasta el más mínimo detalle 32
    • 51. 3. cuestamenos.com✓ Reto 10. Sé DRY, mi amigo ‣ Requisito inicial: ★ Consultar los programas disponibles ordenados por todo tipo de criterios ‣ Problema surgido: ★ Componer un HQL cada vez que se necesitan ‣ Solución aplicada: ★ Definir ‘named queries’ 33
    • 52. 3. cuestamenos.com Historico.groovy✓ Reto 10. Sé DRY, mi amigo ‣ Requisito inicial: ★ Consultar los programas disponibles ordenados por todo tipo de criterios ‣ Problema surgido: ★ Componer un HQL cada vez que se necesitan ‣ Solución aplicada: ★ Definir ‘named queries’ 33
    • 53. 3. cuestamenos.com✓ Reto 11. Disculpe, pero la transaccionalidad es mía ‣ Requisito inicial: ★ Ejecutar acciones de servicio en una transacción atómica ‣ Problema surgido: ★ Por defecto, todos los métodos de un servicio son transacc. ‣ Solución aplicada: ★ Utilizar @Transactional sólo en los métodos que aplica 34
    • 54. 3. cuestamenos.com✓ Reto 11. Disculpe, pero la GestionService.groovy transaccionalidad es mía ‣ Requisito inicial: ★ Ejecutar acciones de servicio en una transacción atómica ‣ Problema surgido: ★ Por defecto, todos los métodos de un servicio son transacc. ‣ Solución aplicada: ★ Utilizar @Transactional sólo en los métodos que aplica 34
    • 55. 3. cuestamenos.com✓ Reto 12. ¿Por qué no habláis de la misma forma? ‣ Requisito inicial: ★ Integrarse de forma automática con las afiliados y sus tiendas ‣ Problema surgido: ★ Cada afiliado ofrece una API de acceso distinto: REST, SOAP, HTTP ‣ Solución aplicada: ★ Usar tecnologías existentes mediante plugin o librerías: HTTPBuilder 35
    • 56. 3. cuestamenos.com✓ Reto 12. ¿Por qué no habláis de la misma forma? ‣ Requisito inicial: ★ Integrarse de forma automática con las afiliados y sus tiendas ‣ Problema surgido: ★ Cada afiliado ofrece una API de acceso distinto: REST, SOAP, HTTP ‣ Solución aplicada: ★ Usar tecnologías existentes mediante plugin o librerías: HTTPBuilder Llamada HTTP 35
    • 57. 3. cuestamenos.com✓ Reto 12. ¿Por qué no habláis de la misma forma? ‣ Requisito inicial: ★ Integrarse de forma automática con las afiliados y sus tiendas ‣ Problema surgido: ★ Cada afiliado ofrece una API de acceso distinto: REST, SOAP, HTTP ‣ Solución aplicada: ★ Usar tecnologías existentes mediante plugin o librerías: HTTPBuilder Llamada REST 35
    • 58. 3. cuestamenos.com✓ Reto 12. ¿Por qué no habláis de la misma forma? ‣ Requisito inicial: ★ Integrarse de forma automática con las afiliados y sus tiendas ‣ Problema surgido: ★ Cada afiliado ofrece una API de acceso distinto: REST, SOAP, HTTP ‣ Solución aplicada: ★ Usar tecnologías existentes mediante plugin o librerías: HTTPBuilder Llamada SOAP 35
    • 59. 3. cuestamenos.com✓ Otros retos ‣ Socializar la aplicación: ★ Integración con API de Facebook ★ MSN, GMail, Paypal ‣ Automatización de procesos: ★ Trabajos Quartz para comprobación de programas, comisiones, pagos, inactividad de cuentas, suscripciones VIP, etc. ‣ Procesos ‘al fondo’: ★ Uso del plugin BackgroundThread ‣ Búsqueda avanzada de programas/productos/promociones: ★ Comenzamos con el plugin Searchable: requiere almacenar los productos en BBDD; resultó ser un cuello de botella enorme ★ Pero además necesitábamos: búsquedas ‘multifacet’, indexador en servidor (distinta JVM), búsqueda avanzada (fuzzy, AND/OR, etc.) ★ Y se hizo la luz: ElasticSearch... 36
    • 60. 3. cuestamenos.com✓ elasticsearch. ‣ Ya sabes, para Buscar: ★ Open Source (Apache 2) ★ Motor distribuido, RESTful, sobre Lucene ‣ Libre de esquema & Orientado a Documento: ★ Modelo NoSQL basado en JSON ‣ Búsqueda: ★ DSL basado en JSON: queries, facets, highlighting, scripting, percolator, geobúsquedas, etc. ★ Multi tenancy: búsqueda por múltiples índices ‣ Distribuido: ★ Índices --> fragmentos (shards) --> réplicas ★ Cluster --> nodos --> 1..n fragmentos ★ Balanceo, enrutado, tolerancia a fallos (Gateway), etc. 37
    • 61. 3. cuestamenos.com✓ Integración en la aplicación ‣ Mediante plugin: ★ Todavía muy virgen; no soporta mucha funcionalidad ‣ Mediante la API de ES: ★ REST API --> Expuesta mediante HTTP, thrift, memcached ★ Java API --> Asíncrona, soporta 100% la REST API ★ Groovy API --> Asíncrona, envoltorio limitado sobre la Java API ‣ Clientes: ★ Node --> Se une al cluster como un nodo más y puede almacenar información o no, incluso configurarse como cluster local. ★ Transport --> No se une al cluster; conexión remota http://www.elasticsearch.org/guide/reference/java-api/client.html 38
    • 62. 3. cuestamenos.com✓ Integración en la aplicación (...continua) ‣ Analizador propio de español 39
    • 63. 3. cuestamenos.com✓ Integración en la aplicación (...continua) ‣ Analizador propio de español SpanishAnalyzer.java 39
    • 64. 3. cuestamenos.com✓ Integración en la aplicación (...continua) ‣ Analizador propio de español SpanishAnalyzer.java elasticsearch/config/elasticsearch.yml 39
    • 65. 3. cuestamenos.com✓ Integración en la aplicación (...continua) ‣ Creación del índice y mapeo del tipo ‘producto’ 40
    • 66. 3. cuestamenos.com✓ Integración en la aplicación (...continua) ‣ Creación del índice y mapeo del tipo ‘producto’ $ curl -XPUT http://localhost:9200/cuestamenos/ -d {     settings : {         index : {             number_of_shards : 3,             number_of_replicas : 2         }     } } 40
    • 67. 3. cuestamenos.com✓ Integración en la aplicación (...continua) ‣ Creación del índice y mapeo del tipo ‘producto’ $ curl -XPUT http://localhost:9200/cuestamenos/producto/mapping -d 40
    • 68. 3. cuestamenos.com✓ Integración en la aplicación (...continua) ‣ Configuración del cliente 41
    • 69. 3. cuestamenos.com✓ Integración en la aplicación (...continua) ‣ Configuración del cliente grails-app/conf/spring/resources.groovy 41
    • 70. 3. cuestamenos.com✓ Integración en la aplicación (...continua) ‣ Configuración del cliente grails-app/conf/spring/resources.groovy TransportClientFactoryBean.groovy 41
    • 71. 3. cuestamenos.com✓ Integración en la aplicación (...continua) ‣ Indexación por lotes (bulk indexing) 42
    • 72. 3. cuestamenos.com✓ Integración en la aplicación (...continua) ‣ Indexación por lotes (bulk indexing) IndexRequestQueue.groovy 42
    • 73. 3. cuestamenos.com✓ Integración en la aplicación (...continua) ‣ Búsqueda avanzada 43
    • 74. 3. cuestamenos.com ✓ Integración en la aplicación (...continua) ‣ Búsqueda avanzada{ "from" : 0, size: 10, "sort" : [ { "_score" : "desc" } ], “query” : { "filtered" : { "query" : { "bool" : { "must" : { "field" : { "_all" : "horror" } }, "must" : { "field" : { “_all" : "noche" } } } }, "filter" : { "bool" : { "must" : { "term" : { "categorias1" : "Ocio y cultura" } }, "must" : { "term" : { "tienda" : "Casa del Libro" } } } } } }, "facets" : { "categorias2" : { "terms" : { "field" : "categorias2", "size" : 10 }, "facet_filter" : { "term" : { "categorias1" : "Ocio y cultura" } } }, "tienda" : { "terms" : { "field" : "tienda", "size" : 10 }, "facet_filter" : { "term" : { "tienda" : "Casa del Libro" } } } }} 43
    • 75. 3. cuestamenos.com ✓ Integración en la aplicación (...continua) ‣ Búsqueda avanzada{ "from" : 0, size: 10, "sort" : [ { "_score" : "desc" } ], “query” : { "filtered" : { "query" : { "bool" : { ElasticSearchUtil.groovy "must" : { "field" : { "_all" : "horror" } }, "must" : { "field" : { “_all" : "noche" } } } }, "filter" : { "bool" : { "must" : { "term" : { "categorias1" : "Ocio y cultura" } }, "must" : { "term" : { "tienda" : "Casa del Libro" } } } } } }, "facets" : { "categorias2" : { "terms" : { "field" : "categorias2", "size" : 10 }, "facet_filter" : { "term" : { "categorias1" : "Ocio y cultura" } } }, "tienda" : { "terms" : { "field" : "tienda", "size" : 10 }, "facet_filter" : { "term" : { "tienda" : "Casa del Libro" } } } }} 43
    • 76. 3. cuestamenos.com ✓ Integración en la aplicación (...continua) ‣ Búsqueda avanzada{ "from" : 0, size: 10, "sort" : [ { "_score" : "desc" } ], “query” : { "filtered" : { "query" : { "bool" : { ElasticSearchUtil.groovy "must" : { "field" : { "_all" : "horror" } }, "must" : { "field" : { “_all" : "noche" } } } }, "filter" : { "bool" : { "must" : { "term" : { "categorias1" : "Ocio y cultura" } }, "must" : { "term" : { "tienda" : "Casa del Libro" } } } } } }, "facets" : { "categorias2" : { "terms" : { "field" : "categorias2", "size" : 10 }, "facet_filter" : { "term" : { "categorias1" : "Ocio y cultura" } } }, "tienda" : { "terms" : { "field" : "tienda", "size" : 10 }, "facet_filter" : { "term" : { "tienda" : "Casa del Libro" } } } }} 43
    • 77. 3. cuestamenos.com ✓ Integración en la aplicación (...continua) ‣ Búsqueda avanzada{ "from" : 0, size: 10, "sort" : [ { "_score" : "desc" } ], “query” : { "filtered" : { "query" : { "bool" : { ElasticSearchUtil.groovy "must" : { "field" : { "_all" : "horror" } }, "must" : { "field" : { “_all" : "noche" } } } }, "filter" : { "bool" : { "must" : { "term" : { "categorias1" : "Ocio y cultura" } }, "must" : { "term" : { "tienda" : "Casa del Libro" } } } } } }, "facets" : { "categorias2" : { "terms" : { "field" : "categorias2", "size" : 10 }, "facet_filter" : { "term" : { "categorias1" : "Ocio y cultura" } } }, "tienda" : { "terms" : { "field" : "tienda", "size" : 10 }, "facet_filter" : { "term" : { "tienda" : "Casa del Libro" } } } }} 43
    • 78. 3. cuestamenos.com ✓ Integración en la aplicación (...continua) ‣ Búsqueda avanzada{ "from" : 0, size: 10, "sort" : [ { "_score" : "desc" } ], ElasticSearchUtil.groovy “query” : { "filtered" : { "query" : { "bool" : { "must" : { "field" : { "_all" : "horror" } }, "must" : { "field" : { “_all" : "noche" } } } }, "filter" : { "bool" : { "must" : { "term" : { "categorias1" : "Ocio y cultura" } }, "must" : { "term" : { "tienda" : "Casa del Libro" } } } } } }, "facets" : { "categorias2" : { "terms" : { "field" : "categorias2", "size" : 10 }, "facet_filter" : { "term" : { "categorias1" : "Ocio y cultura" } } }, "tienda" : { "terms" : { "field" : "tienda", "size" : 10 }, "facet_filter" : { "term" : { "tienda" : "Casa del Libro" } } } }} 43
    • 79. 3. cuestamenos.com✓ Métricas del proyecto... ‣ Equipo: 3 personas a tiempo parcial ‣ Tiempo de desarrollo inicial: 6 meses 44
    • 80. 3. cuestamenos.com✓ Lecciones aprendidas... ‣ Aproximación inicial a la búsqueda: ★ Uso ‘gratuito’ del plugin Searchable ★ No prever funcionalidad futura ‣ Gestión automática de comisiones: ★ Esfuerzo gigante inicial; actualmente se paga solo ‣ Uso ‘indiscriminado’ de plugins: ★ A veces no hay que matar moscas a cañonazos ‣ Sin comunidad, no hay nada que hacer ‣ Seguiremos usando Grails para futuros proyectos (ya en marcha) 45
    • 81. 3. cuestamenos.com✓ Hoja de ruta... ‣ Nueva interfaz completamente rediseñada ★ Más usable, más intuitiva, más sencilla ‣ Gestión avanzada de referidos (apadrinados) ‣ Búsquedas de cupones/promociones ‣ Cliente iPhone con tecnologías HTML5+CSS3 (Phonegap) ‣ Actualización a Grails 2.0 (OSGi) cuando esté disponible 46
    • 82. Índice1. Acerca del ponente2. Observatorio de Grails3. cuestamenos.com4. Ruegos y preguntas5. Contacto 47
    • 83. 5. Contacto E-mail: emedina@cuestamenos.com Twitter: @emedinam @observadegrails @cuestamenos http://observatoriodegrails.com http://forodegrails.com http://cuestamenos.com GRACIAS POR VUESTRA ATENCIÓN 48