Le Paris Scala User Group, présidé organisé par Alexis Agahi, organisait une présentation de Play! Scala lundi dernier. Guillaume Bort, fondateur de Play! Framework et Sadek Drobi, l’un des développeurs du module Scala, nous ont fait une présentation d’1h30, avec live-coding.
Play Scala en quelques mots, c’est la philosophie de Play! Framework, pour le monde du web en Scala. Il s’agit avant tout d’un framework « fullstack« . L’outil compile, fait tourner les tests et déploie votre code, jusqu’à la mise en production. Il n’est pas nécessaire d’utiliser un serveur d’application, puisque l’outil embarque JBoss Netty. Le noyau Netty est un coeur applicatif orienté réseau écrit en Java, basé sur Java NIO, destiné à faciliter l’écriture d’un serveur. Vous pouvez écrire un serveur Web, un serveur FTP ou autre.
Le Challenge USI 2011
Chose intéressante, des finalistes du challenge USI 2011 utilisent Netty. L’équipe du Scala User Group n’a pas passé la dernière phase de qualification. Alexis explique que leur solution, codée en 20 à 30 jours/homme environ, tenait environ 12000 joueurs sur les 5 machines de l’environnement de qualification. Cependant, un test en local, sur une seule VM, a montré que l’application passait les 30 000 joueurs. Ce qui a éliminé l’équipe, c’est l’allongement du temps de réponse. L’application tenait sur une fourchette située entre 20 et 30 000 utilisateurs, mais avec un temps de réponse supérieur aux 350 ms demandés. Enfin, l’équipe du Paris Scala User Group a placé le code source de son application sur Github.
Alexis a aussi expliqué que les cycles d’édition-compilation-test étaient plus lents en Scala, malgré la compilation incrémentale. La programmation en mode cluster avec Akka 1.0 est encore un peu jeune, et la reprise sur incident ne marchait pas. Bref il faudrait revoir cela, Akka étant en version 1.2 maintenant. Enfin Alexis explique aussi que les tests de la partie Actor étaient difficiles à réaliser.
Play! Scala
Revenons à nos moutons. Guillaume débute sa présentation en expliquant d’où vient l’idée de Play! Scala. Tout d’abord, c’est l’envie d’apporter un socle Agile avec un langage typé sur la JVM, avec la puissance de Scala. Complémentaire à Java, Guillaume voit dans Scala des possibilités plus puissantes, avec cependant la volonté d’éviter la complexité. Les premiers essais du module Scala, il y a plus d’un an, n’étaient pas concluants. Certes, cela fonctionnait. Mais il n’y avait pas d’intérêt par rapport à la version Java.
Sadek Drobi, bien connu dans la communauté des langages fonctionnels, a rejoint Zenexity il y a quelques mois. Il a travaillé sur cette version avec Guillaume, pour extraire et apporter de nouvelles idées, plus dans le courant Scala.
Au final, dans la version 0.9.1 beta, nous retrouvons ce qui fait déjà le bonheur des gens comme moi, qui travaillent avec la version Java :
– compilation incrémentale avec SBT (simple build tool) v0.9
– coeur MVC avec la même approche que Play! Framework ou Ruby On Rails
– moteur de template avec une vision fonctionnelle
– un moteur de parser pour les requêtes SQL appelé Anorm
Au final, environ 1 an de travail. Si vous voulez voir un site qui tourne avec Play! Scala, regardez tout simplement le site de Typesafe..
Hello World !
Pour expliquer Play! Scala, Guillaume débute l’écriture d’une application. Chaque template est converti en une fonction, qui prend un ensemble d’argument et qui retourne un ensemble de résultat. « L’approche Java est impérative, chaque action se termine par un appel à render La version Scala est plus simple, elle se termine par ce que l’on souhaite retourner« .
Pour comprendre l’idée de ce moteur, imaginez que Play! Scala est une boite noire, sans état, qui applique un ensemble de fonction à vos arguments HTTP. La combinaison des templates est vraiment simple, elle ouvre la voix à une alternative pour le développement des applications webs. Bien entendu, ce n’est pas spécifique à Play! Scala.
Voyons un simple hello world pour comprendre comment cela fonctionne.
package controllers import play._ import play.mvc._ object Application extends Controller { import views.Application._ def index = { <H1>"hello world !"</H1> }
Bien entendu, pour construire une application web, votre code HTML ne sera pas placé dans votre code Scala. Prenons ce bloc HTML, et écrivons notre premier template, un simple fichier « app/views/Application/index.scala.html ». Modifions ensuite notre controller pour appeler notre template :
package controllers import play._ import play.mvc._ object Application extends Controller { import views.Application._ def index = { html.index() }
Je recharge ma page sans arrêter mon serveur, l’ensemble est recompilé, et c’est tout.
Je travaille avec Alexis sur un projet en ce moment avec Play! Scala. Mon expérience pour l’instant est la suivante : j’ai noté que ce cycle est plus lent que la version Java. Là où la version Java, avec le compilateur Eclipse IDT est plutôt ultra-performante, je trouve que la version Play! Scala est pour l’instant un peu plus poussive. Guillaume l’a confirmé lors de la session des questions/réponses.
Les templates sont typés, chaque paramètre est déclaré, ce qui permet contrairement à la version Java+Groovy, de vérifier à la compilation que vos paramètres sont correctes. De ce côté là, c’est un gros plus, malgré le fait que le cycle édition/rechargement/affichage est plus lent que la version Java.
A l’exécution par contre, je trouve que la version Scala est bien plus rapide, même en mode production. La version Java de Play! se base sur un moteur écrit en Groovy. Ce moteur de template s’est fait tailler un short par Node.js dans un article récent de Subbu Allamaraju, mais la version Scala par contre est plus performante. Je n’ai pas retrouvé un bench comparant Play! Scala et Play! Framework, mais les chiffres montraient que les temps étaient meilleurs.
Guillaume a ensuite écrit un exemple utilisant la base de démonstration de MySQL. Voyons si vous relisez le code de cet exemple, dites-moi ce que vous en pensez :
package controllers import play._ import play.mvc._ import play.db.anorm._ object Application extends Controller { import views.Application._ def index = { html.index() } val query = SQL(""" Select * from Country left join City on Country.Code = City.CountryCode where Country.name = {name} """) def search = { val country = Option(param.get("country")) country.map { country => query.on("name" -> country).as( str("Country.Name"), int("City.population") ˜< str("City.Name") ) ^^ { case name~Cities => Country(name, cities) } } getOrElse { NotFound } } } case class Country(name:String, cities:Seq[(Int~String)])
Voilà, je vous laisse méditer sur ce code, je vous donnerai une explication détaillée ligne par ligne demain.
Nan je rigole.
Ligne 16 : Guillaume définit une requête. Voyez cela comme une NamedQuery ou un template JDBC. Nous recherchons la liste des villes et la population de chaque ville pour un pays donné. Il utilise la base de données World de MySQL pour son test.
ligne 22 : déclaration d’une action « search ». Cette action est appelée à partir d’un formulaire HTML simple. Guillaume montre aussi l’utilisation du fichier « routes » pour avoir des URLs propres. Comme l’avait expliqué Alexandre Bertails, en Scala les fonctions sont des objets, que vous pouvez utiliser.
ligne 23: intéressant. Cette ligne se lit : « récupère un paramètre HTTP country. Ce paramètre peut être présent ou pas. Dans cet article de l’an dernier, j’explique le type Option plus en détails.
ligne 25 : nous utilisons une « for comprehension » (voir les specs Scala section 6.19) afin d’exécuter le bloc compris entre l’accolade de la ligne 25 et celle de la ligne 32. Si le paramètre country a été renseigné, alors l’expression sera exécutée. Sinon, nous retournerons une page « 404 Not Found ». Notez la fonction « Not Found » déclarée dans ScalaController, qui permet de renvoyer une erreur HTTP 404. Le chainage des Options values est très pratique, sans avoir besoin de vérifier la présence ou non d’une valeur (voir aussi la doc ici).
Je pense que le code doit même pouvoir s’écrire de cette façon :
def search = { val country = Option(param.get("country")) val upper = country map { query.on("name"->_) .as(str("Country.Name"),int("City.Population") ~< str("City.Name") ) ^^ { case name ~ Cities => Country(name, cities)} } val result=upper.getOrElse { NotFound} } case class Country(name:String, cities:Seq[(Int~String)])
Conclusion de la soirée
La soirée s’est terminée par une discussion et un buffet sympa. Les avis entendus divergent. La majorité a trouvé cela plutôt impressionnant et simple. Ceux qui ne connaissent pas la version Java, n’étaient pas plus emballés que cela. Il faut dire que l’on a pas vu d’autres fonctions comme l’envoi de mail, le support du long-polling, des Web Sockets, la sécurité et le nouveau type Functional.WS… Bref il en reste encore à découvrir.
L’approche « back to SQL » peut surprendre, alors que nous vivons dans un univers « ORM-isé » depuis quelques années maintenant. A titre personnel, cela me rappelle mes développements webs en Perl et Python entre 97 et 2000. J’ai regretté que Guillaume ne présente pas plus la partie « Magic[T] » d’Anorm, qui permet d’utiliser des parsers prédéfinis sur des objects. J’écrirai un article sur ce sujet afin de vous montrer comment cela fonctionne.
Mon avis sur la question, car je bosse avec Play! Scala depuis début juin, c’est que c’est intéressant. Le code est plus clair, l’aspect fonctionnel donne une nouvelle vision à l’écriture d’une application Web. Côté performance lors de la phase de développement, je trouve que c’est un peu poussif. Je suis moins productif pour l’instant. Côté écriture de code, j’adore. Cela fait du bien de trouver une nouvelle approche pour résoudre un problème.
Si vous voulez tester Play! Scala, rendez-vous sur le site dédié : http://scala.playframework.org/
0 no like
J’ai également testé play + scala.
J’ai trouvé plutôt sympa d’utiliser des requêtes SQL dans le modèle, mais si la partie magic me parait un peu trop magique, et il y a pas mal de notions que j’ai n’ai pas bien compris (flatten, ^^…)
Côté controller par contre, ça à l’air moins mature pour le moment, impossible de mapper autre chose que des primitifs
ex :
public static void addComment(@Valid comment : Comment)
D’après les exemples que j’ai pu voir, il faut récupérer les paramètres un à un dans les paramètre http, un peu lourd.
Côté compil, c’est clair que c’est poussif, a chaque modification de code sur un pc (core i7 quad core à 2 GHZ) le processus edition + sauvegarde + compilation prend plus de 2 secondes.
Pour ma part, je pense que je vais le laisser de côté et attendre que le projet murisse un peu.
Pour des benchmark, j’étais tombé sur cet article le mois dernier : http://www.jtict.com/blog/rails-wicket-grails-play-lift-jsp/
dans le bloc search réécrit ( avec le upper )
le bloc ne renvoie rien.
je pense qu’il faut écrire
… fin je pense..
[[
Mon expérience pour l’instant est la suivante : j’ai noté que ce cycle est plus lent que la version Java. Là où la version Java, avec le compilateur Eclipse IDT est plutôt ultra-performante, je trouve que la version Play! Scala est pour l’instant un peu plus poussive. Guillaume l’a confirmé lors de la session des questions/réponses.
]]
Forcément, si tu n’as pas accès à la configuration sbt, tu ne pourras pas customiser ton build. Perso, j’ai un build sbt avec plus de 10 sous-modules. Avoir la possibilité d’exprimer les dépendances permet d’avoir des gains de performances très importants.
D’ailleurs, ce qui avait démarré pour moi juste comme une « bonne pratique sbt » s’est en fait révélé super intéressant sur le long-terme, car le découpage modulaire m’a demandé une réflexion sur l’objectif de chaque module, et j’ai eu un gain très important en terme de maintenance. (le genre de trucs que Maven rendait très difficile à faire en pratique…)
Enfin, la toute dernière version de sbt (0.10) booste vraiment les performances de compilation. Je ne serais pas étonné que Play! utilise encore la série 0.7.x.
Juste une petite précision, je ne préside pas le PSUG, personne ne préside le PSUG, c’est une non-organisation 😉
Sinon super article ! et oui je trouve aussi que Play est un peu lent pour la compilation 😉 et je préférerais compiler dans mon IDE en incremental au fil de l’eau (faut surement configurer des choses, j’avoue ne pas avoir de près).
Mais de toute façon Scala en général est lent pour la compilation et c’est normal vu le boulot que produit le compilo. J’avais lu qu’ils (l’équipe Scala) envisageaient d’optimiser un peu le code, mais il ne fallait pas s’attendre à gagner plus de 2x la vitesse actuelle (ce qui est déjà pas si mal).
@Alexandre : Play! Scala utilise SBT 0.10