2. Le programme
L’histoirede Play!
Développer avec Play!
Test, déploiement, exploitation
L’écosystème autour de Play!
Le futur
Alors, Play ou pas Play?
3. A propos…
Sylvain Wallez
Architecteexpert freelance, web & Java
2008-2010 : CTO de Goojet/Scoop.it
2006-2008 : Backend architect Joost
2000-2008 : cofondateur & CTO
Anyware Technologies
2003 : premier VP français de la fondation
Apache
Membre du Tetalab, hacking Kinect & Arduino
sylvain@bluxte.net
http://bluxte.net
Twitter: @bluxte
5. L’histoire de Play
Framework web
Orienté REST (urls matter !)
Framework full stack
http, persistance, build, test, déploiement
Haute productivité
TrèsDRY
Save / reload, recompilation à la volée
Très inspiré de Rails et Django ! J2EE
6. L’histoire de Play
Créé par Guillaume Bort (cocorico !) de Zenexity
Open source en 2008
Licence Apache
Actuellement : version 1.2.3 (Java + Scala)
Bientôt : version 2.0 (Scala + Java)
7. L’histoire de Play
Les frameworks web Java sont créés par des devs
Java, et pas des développeurs web
Java a une culture de la complexité, préférant
l’empilement des abstractions à la résolution
effective des problèmes
Mais l’écosystème Java est incroyablement riche
11. Le contrôleur
package controllers;
import play.data.validation.Required; Méthode
import play.mvc.Controller;
statique
Appel du public class Application extends Controller {
template public static void index() {
render();
}
public static void hello(@Required String who) {
Binding et
if (validation.hasErrors()) { validation
Template render("@index");
} else {
nommé render(who);
}
}
}
Modèle
pour la vue
16. Architecture de Play
Modèle MVC classique…
HTTP
Routes DB
server
Views Controllers Models
… mais une implémentation iconoclaste !
17. Architecture : le serveur
Serveur HTTP : ce n’est pas du Servlet !
Serveur NIO très léger et rapide (Netty)
Pas de session (stateless, scalabilité horizontale)
Besoin stateful ? API cache avec EHCache &
Memcache fournie
HTTP
Routes DB
server
Views Controllers Models
18. Architecture : routage des URLs
Routes : dispatching des requêtes sur les contrôleurs
Tout le REST est là
Méthode Contrôleur
HTTP # Home page
GET / Application.index
# Ignore favicon requests
GET /favicon.ico 404
# Map static resources from the /app/public folder to the /public path
GET /public/ staticDir:public
# Catch all
* /{controller}/{action} {controller}.{action}
HTTP
Routes DB
server
Pattern
Views Controllers Models
19. Architecture : routage des URLs
GET / Application.index
GET /public/ staticDir:public
« mount » GET /imgcache/ staticDir:imgcache
d’un module
* /admin module:crud
GET /villes/{name} Villes.showByName
URLs
GET /boutiques/{name} Boutiques.showByName « SEO friendly »
GET /categories/{name} Categories.showByName
GET /villes/{id1}/categorie/{id2} Villes.categorie
GET /{controller}/{name},{id} {controller}.show2
POST /{action} Application.{action}_post
GET /{action} Application.{action}
GET /{controller}/ {controller}.index
POST /{controller}/ {controller}.index_post
POST /{controller}/-{id1}/{action}/-{id2} {controller}.{action}_post
GET /{controller}/-{id1}/{action}/-{id2} {controller}.{action}
Patterns
génériques
GET /{controller}/-{id} {controller}.show
POST /{controller}/-{id}/{action} {controller}.{action}_post
GET /{controller}/-{id}/{action} {controller}.{action}
POST /{controller}/{action} {controller}.{action}_post
GET /{controller}/{action} {controller}.{action}
20. Architecture : contrôleurs
Contrôleurs : méthodes statiques
Un contrôleur est sans état
Binding et validation automatique des paramètres
request/response ? Pas besoin 90% du temps !
HTTP
Routes DB
server
Views Controllers Models
21. Architecture : contrôleur
Paramètres de la vue : bytecode analysis pour
extraire les variables locales
Finis les model.addAttribute("user", user) !
public static void hello(@Required String who) {
if (validation.hasErrors()) {
render("@index");
} else {
render(who);
}
}
22. Architecture : modèles
Modèles
Attributs publics
Ecriture
simplifiée : user.getName() user.name !
Bytecode processing : génération des getter/setter
DAO : méthodes statiques
Fin du « anemic domain model »
HTTP
Routes DB
server
Views Controllers Models
23. Architecture : modèles
package models;
import ...
Entité JPA
@Entity
public class UserGroup extends Model {
@Required
public String name;
@Required
public String accessCode;
@ManyToOne
get/set public User coach;
générés public long getSize() {
return find("select count(u) from User u where u.group = ?", this).first();
}
// DAO methods
public static UserGroup findByAccessCode(String code) {
return find("accessCode", code).first();
}
DAO
public static List<UserGroup> findByCoach(User user) {
return find("select g from UserGroup g where g.isActivated = true" +
" and g.coach = ?", user).fetch();
}
}
24. Architecture : vues
Vues : templates Groovy
Héritage de templates
Nombreux tags : structures de contrôle, forms, erreurs
de validation, tables, etc.
Un tag est un mini template
Escaping HTML par défaut !
Autres moteurs via des modules
Scalate, Japid, Cambridge…
HTTP
Routes DB
server
Views Controllers Models
25. Architecture : vues
<p>
#{if product.ratingCount != 0}
<div class="rateit" data-rateit-value="${product.rating}"></div>
<a href="#">Notez ce produit</a>
#{/if}
#{else}
<div class="rateit"></div>
<a href="#">Soyez le premier à noter ce produit.</a>
#{/else}
</p>
Iteration
#{list results, as: 'product'}
<p class="clear">
<img src="${product.thumbnailUrl}" style="float: left"/>
${product.link}<br/>
Boutique ${product.shop.link} à ${product.shop.city.link}.
</p>
#{/list}
<div class="${page.cssClass}">
<h1>${page.title}</h1>
${page.text.textile()}
</div>
Fonctions
d’extension
27. Les tests
Junit, Corbertura et Selenium intégrés
Avec des « helpers » spécialisés
public class ApplicationTest extends FunctionalTest {
@Test
public void testThatIndexPageWorks() {
Response response = GET("/");
assertIsOk(response);
assertContentType("text/html", response);
assertCharset(play.Play.defaultWebEncoding, response);
}
}
#{selenium}
// Open the home page, and check that no error occured
open('/')
assertNotTitle('Application error')
#{/selenium}
31. Déploiement
The Play! Way
Pull du code (taggué) et « play start »
Tout est précompilé au démarrage
The J2EE way
« play war » crée un war
Permet de s’intégrer dans un environnement J2EE
32. Configuration
Fichier de properties centralisé
# i18n
# ~~~~~
# Define locales used by your application.
# You can then place localized messages in conf/messages.{locale} files
# Date format
# ~~~~~
# date.format.fr=dd/MM/yyyy
# Server configuration
# ~~~~~
# If you need to change the HTTP port, uncomment this (default is set to 9000)
# http.port=9000
#
# By default the server listen for HTTP on the wilcard address.
# You can restrict this.
# http.address=127.0.0.1
# Session configuration
# ~~~~~~~~~~~~~~~~~~~~~~
# By default, session will be written to the transient PLAY_SESSION cookie.
# The cookies are not secured by default, only set it to true
# if you're serving your pages through https.
# application.session.cookie=PLAY
# application.session.maxAge=1h
# application.session.secure=false
# JVM configuration
# ~~~~~
# Define which port is used by JPDA when application is in debug mode (default is
set to 8000)
# jpda.port=8000
#
33. Configuration
Modes dev/integration/prod, etc
# JPA Configuration (Hibernate)
# ~~~~~
#
# Specify the custom JPA dialect to use here (default to guess):
# jpa.dialect=org.hibernate.dialect.PostgreSQLDialect
#
# Specify the ddl generation pattern to use. Set to none to disable it
Config # (default to update in DEV mode, and none in PROD mode):
# jpa.ddl=update
de tests
%test.application.mode=dev
%test.db.url=jdbc:h2:mem:play;MODE=MYSQL;LOCK_MODE=0
%test.jpa.ddl=create
%test.mail.smtp=mock
Config %integration.db=mysql://root@localhost/helloworld
%integration.jpa.ddl=none
d’intégration
35. Monitoring
Disponible en texte et en JSON
Intégration très simple avec munin, collectd, etc.
Librairie JaMon pour du monitoring applicatif facile
Monitor monitor = MonitorFactory.start("SuperAlgorithm.findTheAnswer");
// Do complicated stuff
// (should be 42 anyway...)
monitor.stop();
Monitors:
~~~~~~~~
SuperAlgorithm.findTheAnswer, ms. -> 1 hits; 1038,0 avg; 1038,0 min; 1038,0 max;
37. L’écosystème
Des modules à foison
Systèmede plugins qui apportent composants, tags,
templates, moteurs de persistance, générateurs de
PDF/Excel, interfaces mobiles, etc…
Play a son repository de modules
Gestion des dépendances avec Ivy
Intégration avec tout repository Maven
40. Le futur de Play
Play 2.0 beta sorti hier (16 nov)
Moteur en Scala / Akka
API Java pour « masquer » Scala
Templates Scala avec typage fort
Performances extrèmes
41. Le futur de Play
TypeSafe s’engage sur Play 2.0
La société du créateur de Scala
Play pourrait bien être la « killer app » qui fait
décoller Scala
L’API Java permet une évolution en douceur vers Scala
42. Le futur de Play
Play 1.x is dead ?
Non, beaucoup de projets existants
Mais entrée en mode maintenance
Play 2.0 est compatible avec Play 1.x ?
Lesprincipes sont les mêmes, mais les APIs changent
Adaptation importante nécessaire
44. The good
Oubliez J2EE, (re)découvrez la simplicité
Fin des getters et setters !
Beaucoup moins de code
Reload / recompil automatique
Des messages d’erreurs parlants
Développement high-speed et « in the flow »
45. The bad
Byte code processing
Le debugger n’aime pas (re-attach à chaque recompil)
Mais on en a aussi moins besoin !
Méthodes statiques
Empêche l’héritage sur les contrôleurs
Des « contournements » existent dans la lib Play
Bonne doc, mais code source peu commenté
47. The ugly
Ah si…
le temps nécessaire pour
convaincre votre DSI
(mais chuuut… « play war » et hop !)
48. Quand choisir Play ?
Une application web
Adhérence sur la couche métier acceptable
Ou se passer de l’intégration Play dans le modèle
Avec des développeurs calés en HTML,
mais pas forcément experts en Java
Quand vous êtes pressé
Projet court/moyen terme avec Play 1.x