20. “
There are known knowns; there are things we know that we know.
There are known unknowns; that is to say, there are things that we now know we don't know.
But there are also unknown unknowns – there are things we do not know we don't know.
”
—United States Secretary of Defense, Donald Rumsfeld
samedi 26 octobre 13
31. Equipe
Ze Boss
Java
HTML CSS Scala
Play2 Scala
5
3,75
2,5
1,25
0
samedi 26 octobre 13
Mai 2012
Ete 2012
Sept 2012 Oct 2012 Nov 2012
Jan 2013
Oct 2013
40. Les choses que je ne savais pas
• Faut être gonflé
• Communauté
• Parallélisme,
Reactivité
• Play2/Scala/Redis en
PROD ???
• SEO
samedi 26 octobre 13
• JSON+Redis
• Typesafe / refactoring
50. /**
* Server sent event streaming controller.
* Date: 06/08/12
* Time: 12:16
*/
object Streaming extends Controller {
// Streaming using server sent event
def stream(requestId: String) = Action {
// Define an implicit EventNameExtractor wich extract the "event" name from the Json event so that the EventSource() sets
the event in the message
implicit val eventNameExtractor: EventNameExtractor[JsValue]=EventNameExtractor[JsValue](eventName = (zepEvent)=>zepEvent.
("event").asOpt[String])
// Streams.events is a composition of HotelPrice and AirfarePrice.
Ok.feed(Streams.events(requestId) &> EventSource()).as("text/event-stream")
}
implicit val eventNameExtractor: EventNameExtractor[JsValue] =
EventNameExtractor[JsValue](eventName = (zepEvent)=>zepEvent.
("event").asOpt[String])
samedi 26 octobre 13
77. Cas d’usage
Donne moi le label qui correspond à originId
=380
ZapTravel
samedi 26 octobre 13
78. Cas d’usage
Donne moi le label qui correspond à originId
=380
def getSlug(originId: Long): Option[String] = Redis.pool.withClient
{
client =>
Option(client.hget("Url:From:Rev", originId.toString))
}
ZapTravel
samedi 26 octobre 13
79. Cas d’usage
Donne moi le label qui correspond à originId
=380
def getSlug(originId: Long): Option[String] = Redis.pool.withClient
{
client =>
Option(client.hget("Url:From:Rev", originId.toString))
}
ZapTravel
samedi 26 octobre 13
80. Cas d’usage
Donne moi le label qui correspond à originId
=380
def getSlug(originId: Long): Option[String] = Redis.pool.withClient
{
client =>
Option(client.hget("Url:From:Rev", originId.toString))
}
Driver Sedis https://github.com/pk11/sedis
samedi 26 octobre 13
ZapTravel
87. La Tour Eiffel
1. Charger du JSON à partir de Redis
2. Interpréter et retourner un objet
PointOfInterest
ZapTravel
samedi 26 octobre 13
88. HGET Pois:PoisHash 52511
{"name":"Eiffel
Tower","address":"","latitude":"48.8582493546","longitude":"2.2945117950","website":"www.toureiffel.fr","rank":3,"photo":{"r":"eiffel-tower-paris-france","k":"6b56","e":"jpg","w":2406,"h":
1600,"a":"Mirari Erdoiza","l":"http://www.fotopedia.com/items/anboto-RiKxAA3gE6I"},"sentences":
{"gbs":[{"d":"The Eiffel Tower is one of the most famous monuments in the world (324 metres, 10,100
tonnes).","a":"Paris","l":"http://www.paris.com/paris_landmarks/monuments/
eiffel_tower_paris"},{"d":"This is without doubt one of the most recognizable structures in the
world.","a":"Frommers","l":"http://www.frommers.com/destinations/paris/A25288.html"},{"d":"If
the Statue of Liberty is emblematic of New York, Big Ben is London, and the Kremlin is Moscow, then the
Eiffel Tower is the symbol of Paris.","a":"Fodors","l":"http://www.fodors.com/world/europe/
france/paris/review-97417.html"},{"d":"When it was built for the 1889 Exposition Universelle (World
Fair), marking the centenary of the Revolution, the Tour Eiffel faced massive opposition from Paris'
artistic and literary elite.","a":"Lonely Planet","l":"http://www.lonelyplanet.com/france/paris
/sights/famous-landmark/eiffel-tower"}],"tips":[{"d":"It's pretty
high!.","a":"annawelford","l":"http://www.lonelyplanet.com/france/paris/sights/famouslandmark/eiffel-tower","s":"Lonely Planet"},{"d":"Bigger than you think.","a":"anomolly","l":"http:/
/www.lonelyplanet.com/france/paris/sights/famous-landmark/eiffel-tower","s":"Lonely
Planet"},{"d":"Overcrowded.","a":"anshjain","l":"http://www.lonelyplanet.com/france/paris/
sights/famous-landmark/eiffel-tower","s":"Lonely Planet"},{"d":"The restaurant on the first floor is
an amazing experience!.","a":"ansofie","l":"http://www.lonelyplanet.com/france/paris/sights
/famous-landmark/eiffel-tower","s":"Lonely Planet"}]},"tags":["Landmark","Memorials/
Monuments","Sights","Famous landmark"]}
samedi 26 octobre 13
89. Play 2.1
• Définir une case class POI
• Définir un implicit Json.format[POI]
• C’est tout... ou presque
samedi 26 octobre 13
90. Play 2.0
case class POI(name: String,
address: String,
latitude: String,
longitude: String,
website: Option[String],
photo: Option[SightPhoto] = None,
sentences: Sentences,
tags: Option[List[String]])
POI = Point of Interest = notre Tour Eiffel
samedi 26 octobre 13
97. Aller sur Redis
def allOrigins: List[Origin] =
Redis.pool.withClient {
client =>
// ...
// ...
}
Modèle
samedi 26 octobre 13
98. Préparer une liste
def allUrlOrigins: Seq[(String, String)] =
{
Origin.allOrigins.map{
origin =>
(origin.slug, origin.label)
}.sortBy(_._2)
}
Contrôleur
samedi 26 octobre 13
99. Envoyer la liste au
template
Code dans la page HTML
<label for="location">Your travel origin is :</label>
@select( userForm("originCity"),
FolioCriteria.allUrlOrigins ,
'_label -> "Travel from origin",
'_showConstraints -> false
)
Vue
samedi 26 octobre 13
109. Indexation et
référencement
• URLs propres et pondérées
• Mots clés
• Liens et Sitemap
• Microformat (Hotel, Avion, Lieux)
• Contenu non répété
samedi 26 octobre 13
113. Play2
• La séparation entre la partie routage et
la partie contrôleur permet de créer des
URLs «propres»
samedi 26 octobre 13
114. Sitemap
• Déclarer la table des matières de son
site
• Optimise le référencement
• Permet de mettre en cache les pages
curl http://www.zaptravel.com/sitemap.xml
samedi 26 octobre 13
125. Eviter de recharger la
même page,
utilisez code 304 NotModified
Note: @rosstuck a fait une session sur HTTP à Confoo mercredi dernier
samedi 26 octobre 13
127. Exemple sur /from-paris/quality
Navigateur
Play2
OK
HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
ETag: 11299930771
Cache-Control: max-age=600, s-maxage=600, must-revalidate
Content-Length: 103586
...
...
ce n’est pas une erreur
samedi 26 octobre 13
129. Optimisation 1
• Evitez de faire travailler votre serveur
pour rien
• Déterminez des ETags «métiers»
• Attention à la gestion du cache et des
serveurs mandataires.
samedi 26 octobre 13
132. 2 types de cache
Cache technique type
Varnish
- Process à part
- Cache HTTP
samedi 26 octobre 13
Cache de Play2 ou Redis
- Code applicatif
- utilise la mémoire
de Play2 ou Redis
133. 2 types de cache
Cache technique type
Varnish
• Facile à installer
• Evite de solliciter
Play2
• Scalable
• Configurable
samedi 26 octobre 13
134. 2 types de cache
Cache applicatif Play2/
Redis
• Prend en compte le
métier
• Permet de garder les
pages «authentifiées»
• Pas aussi performant
que la solution
Varnish
samedi 26 octobre 13
135. Sur Zaptravel
• Page d’accueil
optimisé avec Cache
de Play2
• Page Folio, section
top Deal avec cache
Play2
• Page Deal, cache
avec Redis
samedi 26 octobre 13