Ces dernières semaines, en plus de l’eXpress-Board, je travaille sur un projet avec Play! Framework et Scala. Un nouveau module permet de travailler avec le langage Scala. Mes premiers pas sont hésitants, un peu comme si vous décidiez de vous mettre au roller ou au ski à 35 ans. Cependant on prend rapidement un vrai plaisir à utiliser Scala. Cela demande un temps d’adaptation, et une bonne motivation, mais rien d’insurmontable pour toi. Non franchement, c’est fun. Surtout avec Play! Framework, qui permet de débuter en Scala, mais qui vous permet d’aller rapidement vers une approche très fonctionnelle.
Pour vous illustrer cela, je vais vous montrer plusieurs versions d’un même bloc du projet sur lequel je travaille en ce moment. J’apprends grâce à Sadek Drobi de Zenexity en ce moment. Avec un bon maître Jedi, on arrive à faire du code assez sympa. Vous allez voir cela.
Voici ce que tu dois coder ce matin :
Une page affiche une liste de Website. L’utilisateur authentifié sélectionne un des Website pour créer un dossier pour ce site. Le dossier sera appelé WebsiteCase. Codez l’action qui prend un id de website à charger en argument, qui charge l’utilisateur authentifié, puis ensuite qui créé un nouveau WebsiteCase.
Il y a 3 cas de sortie :
– si l’utilisateur authentifié n’existe plus dans la base, afficher Unauthorized
– si le website sélectionné n’existe pas, afficher Notfound
– sinon, créer un nouveau WebsiteCase
La version Java
Voici la version Java pour commencer :
public static void selectWebsite(Long websiteId) { Website website = Website.findById(websiteId); notFoundIfNull(website); // sortie 1 String uuid = session.get("connected"); Webuser webuser = Webuser.find("uuid", uuid).first(); if (webuser == null) { unauthorized(); // sortie 2 } WebsiteCase websiteCase = new WebsiteCase(website, webuser); websiteCase.save(); render(websiteCase); // sortie 3 }
Première chose à laquelle vous n’êtes peut-être pas habitué avec Play!, c’est son principe de traitement du flux. Dès lors que votre action doit terminer son traitement, vous faîtes appel à une méthode static, qui lève une Exception pour retourner à la vue ce qu’il faut afficher. Donc ici, notFoundIfNull(website) arrêtera le flux d’exécution pour afficher une page 404 Not Found dès lors que website est null. Pour bien comprendre cela, imaginez que le code qui va s’exécuter ressemble à ceci :
public static void selectWebsite(Long websiteId) { Website website = Website.findById(websiteId); if(website==null) { throw new NotFoundException(); } ....
Poursuivons la lecture du code Java avant de passer à la première version Scala.
A la ligne 5 du premier exemple, je récupère dans la session de l’utilisateur la valeur d’un uuid. Lorsque l’utilisateur est authentifié par le controller, celui-ci placera dans mon exemple un cookie « connected » avec un uuid unique. Le cookie est signé. Si vous pensez pouvoir le modifier du côté navigateur, Play! l’invalidera lorsque vous reviendrez sur le serveur. Principe simple qui marche très bien sur de nombreuses applications webs dans le monde.
Mais où est ma session dans Play! Framework ?
Notez qu’il y a bien une session dans Play! Framework. C’est tout simplement le principe des Cookies inventés en 1994 par Lou Montulli. Dire que Play! Framework est un framework sans session est faux. C’est un framework sans état conversationnel du côté serveur. Le framework est dit « sans état conversationnel » car il n’y a rien de stocké en mémoire sur le serveur. L’état est stocké dans un Cookie signé mais non crypté par défaut. La base de données n’est pas non plus un état. Comme le rappelait Benoit Dissert et Arnaud Bailly sur la liste du Paris Scala User Group, Roy Thomas Fiedling l’a très clairement expliqué dans les premiers papiers décrivant l’architecture REST. A la section 5.1.3, il présente la notion de Stateless comme étant une contrainte où chaque requête client doit contenir l’ensemble des informations nécessaires au serveur pour comprendre la requête, et qu’il ne peut utiliser de contextes stockés du côté serveur.
Du respect de cette contrainte, découle alors plusieurs bénéfices clairs : scalabilité, reprise sur incident et simplicité. Le système devient simple car chaque requête est vue comme une exécution du côté serveur. C’est l’un des points forts de Play! Framework. Chaque requête est vue comme une exécution. C’est aussi pour cette raison que vous voyez des méthodes static sur les actions de votre controller. Repensez à ce bon vieux public static void main(String… args).
Scalabilité ensuite. Si chaque requête contient l’ensemble des informations nécessaires à exécuter une action, que le serveur A ou le serveur B vous réponde, n’a pas d’influences sur votre traitement. Attention, un framework sans état conversationnel côté serveur ne veut pas dire que votre application n’a pas d’état. Ce n’est pas la même chose.
Enfin la reprise sur incident : votre traitement est complètement pensé pour que chaque action de votre controleur se suffise à elle-même. Comment sont gérées à votre avis les Transactions avec Play! Framework ? Super simple : par défaut la transaction est créée au début de l’action de votre controleur, et la transaction est commitée à la fin s’il n’y a pas d’erreurs. Vous pouvez piloter ceci plus finement si votre métier l’exige. Mais sur l’eXpress-Board, avec la quantité de code écrite en un an, je n’ai jamais eu de soucis.
Back to the code
Revenons à notre code.
public static void selectWebsite(Long websiteId) { Website website = Website.findById(websiteId); notFoundIfNull(website); // sortie 1 String uuid = session.get("connected"); Webuser webuser = Webuser.find("uuid", uuid).first(); if (webuser == null) { unauthorized(); // sortie 2 } WebsiteCase websiteCase = new WebsiteCase(website, webuser); websiteCase.save(); render(websiteCase); // sortie 3 }
Si le navigateur envoie un Cookie avec un uuid invalide alors à la ligne 8 nous afficherons une page « Unauthorized » afin de bloquer l’accès à la ressource. Ce sera notre cas de sortie 2.
Sinon, je créé un WebsiteCase avec le website sélectionné pour l’utilisateur authentifié, je sauve le tout, et je l’affiche avec l’appel à render.
Si la version Java avec le moteur Groovy est assez procédurale, la version Scala est complètement fonctionnelle.
Voyons cela tout de suite.
Première version
Voici la première version, écrite après quelques heures passées à découvrir Scala. C’est assez simple à lire, et croyez-moi, c’est très proche de ce que vous arrivez à faire en quelques heures. Il n’y a rien de compliqué.
def selectWebsite(id: Long) = { val website = Website.find("id={id}").on("id" -> id).first() website.map { w=> val maybeUser = session("connected").flatMap(Webuser.lookup(_)) maybeUser.map { webuser => val websitecase = WebsiteCase.create(WebsiteCase(w.id(), webuser.id())) html.selectWebsite(websitecase) }.getOrElse { session.remove("connected") Unauthorized } }.getOrElse{ NotFound("Website not found") }
A la ligne 2, je souhaite charger le website associé à l’id passé en paramètre de l’action. Comment gérer le cas où le website sera null ? Dans l’approche Scala, nous allons voir que c’est une notion pensée dès le départ. La fonction « first » retourne un Option[T], plus précisément ici un Option[Website].
Voyez Option[Website] comme une enveloppe, qui peut contenir un Website ou None. Grâce à cette enveloppe, nous allons pouvoir appliquer la fonction map. Un petit tour dans la doc de Scala pour comprendre comment fonctionne map, et nous découvrons que cette fonction est très simple :
def map [B] (f: (A) ⇒ B): Option[B] Returns a Some containing the result of applying f to this Option's value if this Option is nonempty. Otherwise return None.
website.map retourne donc un Some(Website) ou None si website était vide.
Pour traiter notre premier cas de sortie, il suffit alors d’appliquer la fonction getOrElse. Si je n’ai pas trouvé de website pour l’id spécifié, que la fonction first a retourné None, alors la fonction passé en paramètre de getOrElse sera exécutée. NotFound est une fonction de Play! Framework Scala, qui retourne un code d’erreur 404 affiche une page 404 avec votre message.
Intéressons-nous maintenant à ce qui se passe entre les lignes 4 et 11. Je zoome afin de ne garder qu’un bloc de code pour mieux vous l’expliquer :
val maybeUser = session("connected").flatMap(Webuser.lookup(_)) maybeUser.map { webuser => val websitecase = WebsiteCase.create(WebsiteCase(website.id(), webuser.id())) html.selectWebsite(websitecase) }.getOrElse { session.remove("connected") Unauthorized }
Tout d’abord nous allons découvrir une autre fonction de la class Option, à savoir flatMap. C’est une fonction très pratique. Je vous lis d’abord ce que fait la ligne 1 pour bien comprendre :
// session("connected") retourne un Option[String] avec l'uuid de l'utilisateur // ou None s'il n'y a pas de cookie appelé connected val maybeSession:Option[String] = session("connected") // flatMap applique la fonction Webuser.lookup(s) si et seulement maybeSession ne vaut pas None. // Comprenez : fait un lookup si finalement maybeSession n'est pas vide/null, sinon contente-toi de retourner None val maybeUser:Option[Webuser] = maybeSession.flatMap( s => Webuser.lookup(s))
On simplifie tout cela sur une seule ligne, ce que j’ai fait à la ligne 4 de mon premier exemple Scala.
Est-ce que vous commencez à voir l’enchainement de fonctions ?
Le premier principe pour bien comprendre ce code, c’est d’imaginer que votre code va aller aussi loin que possible, tout en gérant proprement les cas exceptionnels.
On termine avec un appel à map sur notre maybeUser :
maybeUser.map { webuser => val websitecase = WebsiteCase.create(WebsiteCase(website.id(), webuser.id())) html.selectWebsite(websitecase) }
Si notre Option[Webuser] maybeUser ne vaut pas None, alors la fonction comprise entre les 2 accolades est exécutée. Ici j’utilise Magic, une partie du framework Anorm de Play! Scala, pour créer mon WebsiteCase. Notez que nous avons là aussi l’approche Domain Driven Design, portée par Play! Framework. Les entités ne sont pas anémiques, mais capables d’effectuer des traitements. Dans la version Scala de Play! il n’y a pas d’ORM. C’est bien plus simple. On en reparlera une autre fois, car là je vous sens un peu groogy.
html.selectWebsite(websitecase)
permet d’exécuter le template et de générer le contenu HTML qui sera finalement retourné par ma fonction selectWebsite. Vous voyez, je ne parle pas de méthode ou d’action. Il faut vraiment comprendre que selectWebsite est une fonction, qui va générer du HTML à partir d’un contexte donné. Ici ma fonction prend 2 arguments : l’id du website et l’uuid de l’utilisateur connecté. Cela devient simple lorsque l’on visualise une boîte qui prend 2 cacahuètes, et qui vous retourne une 3ème cacahuète en sortie… Bon bref, on a la culture qu’on peut mon bon monsieur, mais vous m’avez compris.
Terminons maintenant par la version avancée du même traitement.
Après quelques heures avec Scala
Sadek Drobi m’a montré comment il était possible d’aller encore plus loin. Ne débattez pas sur l’intérêt de le faire ou non. Imaginez que vous êtes hyper calé en Scala dans quelques mois, et dîtes-vous que ce que vous allez voir est normal. Evidemment, là avec un oeil Javaiste, je vous préviens, ça va piquer un peu. Mais allez, vous êtes des grands gars, vous allez voir, c’est simple.
Je vous montre le code tout d’abord :
def selectWebsite(id: Long) = { val website = Website.find("id={id}").on("id" -> id).first() website.toRight(NotFound) .right .flatMap { ws => val maybeUser = session("connected").flatMap(Webuser.lookup(_)) maybeUser.map( webuser => WebsiteCase.create(WebsiteCase(ws.id(), webuser.id())) ) .toRight { session.remove("connected") Unauthorized } } .fold(identity, html.selectWebsite.apply) }
Ici nous allons utiliser Either. Cette classe est souvent utilisée comme alternative à Option pour traiter les cas d’erreurs simplement. Either est un tuple, où par convention vous allez placer vos cas d’erreur dans l’ensemble de gauche, et ce que vous souhaitez conserver dans l’ensemble de droite. Notez que je n’ai pas le vocabulaire pour l’expliquer simplement. Il faut avoir un certain bagage fonctionnel pour bien comprendre. Mais vraiment, c’est simple.
Prenons le code pas à pas, je vais vous montrer à chaque fois les types intermédiaires pour mieux comprendre.
website.toRight(NotFound) retourne un Product with Either(NotFound,Website)
. Product est un tuple, un ensemble de 2 valeurs. Nous examinons website, un Option[Website]. Si celui-ci vaut None, alors nous garderons NotFound. Sinon, nous garderons Website.
En fait, si je retire la partie de chargement du Webuser et de la création du WebsiteCase, je peux écrire ce code :
website.toRight(NotFound).fold(identity,html.selectWebsite.apply)
La fonction « fold » de Either est très simple : si je trouve quelque chose à gauche, j’évalue ce bloc. Si j’ai trouvé quelque chose à droite, j’evalue ce bloc. Si vous préférez, c’est comme un bloc if/then/else.
Ensuite identity
me permet de dire : je veux exécuter NotFound
.
Enfin html.selectWebsite.apply
permet d’exécuter mon template en passant l’élément de droite, ici un Website pour mon exemple.
Vous voyez comment en une ligne, je traite le cas où website n’existerait pas.
Pour mieux comprendre, voici comment implémenter simplement « charge le website spécifié par l’id, retourne NotFound s’il n’existe pas, sinon exécute le template showWebsite »
def showWebsite(id:Long)={ val website=Website.find("id={id}").on("id"->id).first() website.toRight(NotFound).fold(identity,html.showWebsite.apply) }
Explique moi la suite…
A cette heure avancée de la nuit, je sens bien que j’ai perdu une bonne partie de mon lectorat. Mais même pas peur, je continue.
website.toRight(NotFound).right.flatMap { ws => val maybeUser = session("connected").flatMap(Webuser.lookup(_)) //... }.fold(identity, html.selectWebsite.apply)
website.toRight(NotFound).right
retourne un EitherRightProjection[NotFound,Website]. La fonction right permet de dire : ok, je m’intéresse maintenant à la partie droite de mon ensemble Either.
La fonction flatMap ensuite nous permet de nous intéresser uniquement à Website. Cette fois-ci, nous ne parlons plus d’Option. Si j’arrive à cette fonction, c’est bien parce que j’ai chargé correctement un Website.
Je charge ensuite mon Webuser, vous connaissez déjà ce code.
Attention les yeux. Si Webuser est null, il faut que j’appelle Unauthorized
. Sinon, on continue notre traitement. Je vais profiter de mon Either pour en créer un nouveau. Oui monsieur. Un Either de [Unauthorized,WebsiteCase].
Allons-y. Premier temps : créer un websitecase si maybeUser contient bien un webuser et pas None. Sinon, je retournerai None
maybeUser.map( webuser => WebsiteCase.create(WebsiteCase(ws.id(), webuser.id())) )
Deuxième temps : si j’ai un None, j’aimerai le stocker à gauche. Si j’ai un websitecase, je veux le garder. Pour cela, j’utilise à nouveau toRight qui va me créer un Either. La lecture du toRight ici est un peu compliquée. Si mon Option[WebsiteCase] vaut None, alors le bloc entre accolade sera placé à gauche. Sinon, ce sera le websitecase.
maybeUser.map( webuser => WebsiteCase.create(WebsiteCase(ws.id(), webuser.id())) ) .toRight{ session.remove("connected") Unauthorized }
Je me retrouve au final avec un Either[Unauthorized,WebsiteCase]. Voyez à nouveau ceci comme un petit panier. Vous ouvrez le panier. Si l’authentification n’a pas marché, vous trouverez une fonction Unauthorized. Sinon vous trouverez un WebsiteCase.
Pour terminer, j’ai pour l’instant un Either[Result, WebsiteCase]
Sympa. Mais j’en fait quoi ?
Je termine en utilisant la fonction fold
qui est vraiment pratique.
Voici les 3 cas que je vais rencontrer :
// cas 1 val result1:Either[NotFound,None] = ... // cas 2 val result2:Either[Unauthorized,None] = ... // cas 3 val result3:Either[None,WebsiteCase]] = ...
Voici le code final :
def selectWebsite(id: Long) = { val website = Website.find("id={id}").on("id" -> id).first() website.toRight(NotFound).right.flatMap { ws => val maybeUser = session("connected").flatMap(Webuser.lookup(_)) maybeUser.map( webuser => WebsiteCase.create(WebsiteCase(ws.id(), webuser.id())) ) .toRight{ // left session.remove("connected") Unauthorized } }.fold(identity, html.selectWebsite.apply) }
result1 est un Left, donc fold va s’appliquer sur le premier élément. Vous voyez que result1 a une fonction à gauche (NotFound) et un None à droite. Donc la fonction NotFound sera évaluée. J’utilise identity pour simplement dire : évalue la fonction.
Pour result2, c’est un Right. fold est une fonction récursive comme flatMap. La deuxième évaluation retournera la fonction Unauthorized. Je l’évalue comme un Left avec identity, et c’est terminé.
Pour result3, c’est un Right, puis un autre Right.
Donc cette fois-ci, fold va évaluer mon template avec html.selectWebsite.apply(websitecase)
Conclusion
Je sais, je vous sens tout bizarre.
Les Javaistes vont dire que c’est compliqué, que franchement le code du début, et bien il est très bien pour les 10 années qui viennent. Que même la version en Cobol serait moins verbeuse, et que ça roxe.
Je réponds : oui je suis d’accord pour cet exemple précis, là, dont nous venons de discuter. Après votre grand esprit d’abstraction comprend qu’il s’agit d’un exemple, votre frange de patriotisme Java comprend que nous venons de voir un exemple forcément un peu caricatural. Bref je vous dis : oui.
Attendez que j’aille chercher un bout de code avec 1 DAO, 1 Service et 1 ServiceImpl et vous ne ferez plus les fiers.
– En scala on a un Problem
– En Java on a un Problem
et un ProblemImpl
.
Les Scalaistes vont aussi commenter ce billet. On va rien comprendre aux commentaires. Ils vont encore passer pour d’obscurs fanatiques fétichistes du code. C’est tout à fait normal, nous sommes encore dans l’ère universitaire du langage. Moi je m’intéresse à ce qu’il deviendra dans l’industrie au travers de Play! Framework. Et en plus je vous réponds : je débute en Scala. Donc je corrigerai les grosses bourdes si nécessaire pour que l’article soit clean. Contactez-moi par mail si vous voulez.
Perso, je dois être un extra-terrestre, mais moi cela m’intéresse. Je ne dis pas que je vais vous balancer du toRight
à tout va. Cependant, en allant jusqu’au bout de l’approche Scala, cela permet de voir une autre façon d’appréhender un problème. Je trouve assez élégant l’idée de dire : je vais aussi loin que je peux, j’enchaine un paquet de fonctions, et je gère l’exceptionnel normalement.
En tous les cas moi je m’éclate bien.
Pour tester :
Play! Scala Framework
Test plugin syntax highlighter
$input = array("Neo", "Morpheus", "Trinity", "Cypher", "Tank"); $rand_keys = array_rand($input, 2); echo $input[$rand_keys[0]] . "\n";
> Moi je m’intéresse à ce qu’il deviendra dans l’industrie
Pour information, Scala commence à entrer dans l’industrie. Chez mon client actuel par exemple, nous avons démarrer une application en Scala avec 4 développeurs « Java ». 2 purs Javaistes, un rubyiste et un Javaiste qui avait des notions de Scala.
Et bien cela se passe très bien et le projet avance plus vite que prévu. En revanche nous n’utilisons pas Play! car il ne s’agit d’une application web 🙂
C’est marrant j’ai commencé a jouer avec play!scala hier m, je suis javaiste et je trouve ça intéressant aussi
la partie
[quote]
La fonction « fold » de Either est très simple : si je trouve quelque chose à gauche, j’évalue ce bloc. Si j’ai trouvé quelque chose à droite, j’evalue ce bloc. Si vous préférez, c’est comme un blog if/then/else.
[quote]
est pas super claire.
J’avais regardé ioke a un moment et la doc de ces fonctions était très claire je vous la recommande même si le langage n’a pas d’avenir
http://ioke.org/dok/release/kinds/Mixins/Enumerable.html
chacune des fonctions « magique » des langages fonctionnels y est expliquée sous la forme d’assertions BDD et des exemples associés …
Bof, disons que c’est compliqué, que franchement le code du début, et bien il est très bien pour les 10 années qui viennent. Que même la version en Cobol serait moins verbeuse, et que ça roxe.
😛
Scala sera fin près pour l’industrie lorsque les plugins d’affichage de code sauront l’afficher de manière lisible 😛
J’aime bien.
C’est sur que je sort d’un article de SF 🙂
j’ai encore des séquelles aux yeux! Ah non ca c’est parce que j’ai vraiment pas assez dormi lol.
Perso le fold c’est encore magique pour moi. Genre comment il fait pour dire; »j’évalue à gauche » ou « j’évalue à droite »? Cest avec les None?
ps: le captcha est vraiment fun. tu as des stock options chez ikea?
Merci pour ce retour.
C’est vrai que flatMap, either, foldLeft, Right etc.. ça pique au début mais on s’y fait quand même. L’expressivité de Scala est tel que parfois j’ai l’impression qu’on peut tout écrire de mille et une façons.
@Piwai, tu parles juste de coloration syntaxique, ou de plus. Parce que je connais pas mal de gens qui codent en scala, pour l’industrie justement et ils utilisent soit vi, TExtmate ( ce que je ne pourrais pas faire) ou encore IntelliJ qui avec les thèmes adéquats te donnent un rend pas si mal. Mais je pense (vu que tu déconnes) )que t’as pas besoin de shiny little colors pour évaluer ou non les mérites d’un langage. 🙂
« L’expressivité de Scala est tel que parfois j’ai l’impression qu’on peut tout écrire de mille et une façons. »
Et ça va finir comme Javascript avec Scala : the good parts 😉
D’ailleurs je serais curieux de savoir si Javascript n’est pas encore plus flexible et « puissant » que Scala 🙂
@Piwai @samklr On code avec IntelliJ et le plugin Scala et ça fonctionne très bien 🙂
Après la lisibilité du code c’est comme en Java, c’est le rôle du développeur : soit tu codes crade, soit tu es conscient que la lisibilité importe plus que la concision 🙂
@David CHAU
Concernant le fold (et map, flatMap etc.) c’est tres simple en fait (rien de magique =)).
Tu peux voir ça comme cela: Either est une classe abstraite, avec 2 implémentations (et seulement 2) possibles (elle est « sealed »)
Ces 2 implémentations sont Left et Right, chacune override la méthode fold.
Le fold le la Class Left travaille le 1er paramètre (celui de gauche :)), le fold de la Class Right travaille sur le 2eme paramètre (celui de droite)
Voila c’est tout ^^
PS: en réalité ce n’est pas implémenté de cette manière, le code est mutualisé entre les 2 classes, mais le principe est la.
Deux autres implémentations du Either/Or…
Toutes les deux sont aussi importantes
Elliot Smith
http://fr.wikipedia.org/wiki/Either/Or
Et Soeren Kierkegaard
et http://fr.wikipedia.org/wiki/Ou_bien…_ou_bien
@David CHAU
Voici un exemple pour comprendre un peu les map et les fold(Left/right)
Scroll down a little.
http://stackoverflow.com/questions/2293592/functional-programming-scala-map-and-fold-left
On peut aussi souligner que le contrat qui t’est imposé n’aide pas à
la simplicité pour du fonctionnel : si tu ne devais pas lever les
exceptions NotFound et Unauthorized, ça ressemblerait à qqc comme ça :
T’es d’accord avec ça ?
Le framework web fonctionnel de Scala, Lift, t’inciterait (sans doute,
je débute aussi…) à faire qqc comme ça pour supporter ton contrat
complètement :
Le type Box est similaire à Option, mais il gère justement les
situations d’échec via le sous-type Failure. (@see
http://www.assembla.com/spaces/liftweb/wiki/Box)
Scala, ça reste quand même un langage d’un grand pragmatisme qui n’a
pas peur du compromis pour prendre le meilleur de chaque monde (OO,
FP). Si bien que quand je trouve mon code trop compliqué, je vois
souvent ça comme un signe qu’il faut changer de paradigme (OO, FP ou
même procédural, soyons « open »). En revanche, plus le temps passe,
plus je suis prêt à sacrifier de la simplicité pour de la concision.
Et puis, les map, flatMap, fold, à la fin c’est plus que des blondes,
des brunes et …tiens, là une rousse 😉
OCAML et HASKELL c pas mal aussi pour les « Fonctionnelleux »
Comme Jean-Baptiste, pas d’accord avec ca : « C’est tout à fait normal, nous sommes encore dans l’ère universitaire du langage ».
Meme si c’est la plupart du temps pour des applis secondaires, Scala commence a avoir de serieuses references.
Et je vois Scala passer de plus en plus souvent dans les offres d’emploi ici dans la SF Bay Area.
Et quand on code en Scala pendant 6 mois et que l’on doit se remettre à Java, cela fait tout drôle…
C’est un peu comme repasser de git à CVS 😉
Ou alors de Gmail à IMP.
Ou alors de Chrome à Mosaic.
Ou alors de QuakeLive à Wolfenstein.
…
Sinon pour ceux qui sont sur l’ile de france, il y a le Paris Scala User Group.
https://groups.google.com/forum/#!forum/paris-scala-user-group
Désolé pour la pub 😉
Excellent post, merci Nicolas pour ce retour détaillé.
Pour ma part, j’utilise Scala depuis 1 an maintenant, et j’ai trois projets play + scala en ligne, et un autre qui passera en prod à la fin de la semaine.
Hé bien jusqu’ici rien a redire:
tout est fluide, la puissance et la concision de Scala au rendez-vous avec la souplesse de Play!.
En gros, en codant en Scala + Play!:
– je vais vraiment beaucoup plus vite, chose que je vais essayer de quantifier précisément avec mes outils de time-tracking,
– j’accepte à nouveau la prise en charge projets web, chose que je m’étais juré de ne plus JAMAIS faire,
– j’ai l’impression d’avoir des super-pouvoirs 🙂
On est bien dans l’ere startup du langage 😉
http://mashable.com/2011/07/14/foursquare-engineering
Je sais pas si c’est le fait que j’approche les 30 ans mais je n’arrive pas à prendre plus de 20min pour regarder de plus prêt Scala… A chaque fois je me dis : « Pourquoi faire simple quand on peut faire compliqué ». Mais bon je suis certain que je vais m’y mettre pour me faire ma propre idée au vu de toutes les éloges qu’on entend sur ce language.
Ma plus grande peur aujourd’hui réside sur la capacité à maintenir le code par une équipe qui évolue dans le temps (plusieurs niveau de développeurs java/scala). Aller je me prends du temps pour lire l’article 🙂
Surement un excellent article et surement un excellent langage. Mais j’avoue que pour moi qui n’en ai jamais fait, ça fait peur….
Ça fait quelques temps qu’à force de vous lire vanter ce langage je me dis qu’il faudrait que je m’y mette, mais pour le moment j’ai du mal à m’investir étant donné la vitesse de dev offerte par play java. J’imagine mal que ça puisse aller plus vite ou etre plus clair. Et puis je n’ai peut être pas le niveau d’abstraction qu’il faudrait. Ce serait peut être intéressant de comparer les ticket d’entrée nécessaires pour java et scala.
Mais bon, les vacances approches. Je vais peut être quand meme me laisser tenter par un bouquin sur le sujet à emmener à la plage… 🙂
Je pense que l’exemple choisi n’est pas bon. La programmation objet et procédurale sont très bien pour résoudre la plupart des problèmes. Mais là où je vois un avantage réelle à utiliser scala, c’est dans la résolution de problème récursif et d’aggrégation. Il ne faut pas se tromper d’outil. SQL pour les requêtes, l’objet pour le modèle. Si on retourne sur l’idée d’un seul language pour tout faire, c’est perdu d’avance. On peut très bien mélanger des classes Java, Groovy et Scala. Selon les besoins. Si déjà je lisais du code OO en java sur mes projets ça serait bien, au lieu de voir du procédural…
Challenge de l’été: apprendre le Scala et comprendre complètement les exemples en revenant 🙂
ça devient lassant de lire que scala serait encore dans une sorte d’ère universitaire. Je crois que le langage est bien passé dans une étape plus industrielle, n’en déplaise aux détracteurs. Le guardian ,twitter, foursquare, Barclays, UBS, Goldman Sachs, AIG, les boites de paris en ligne (notamme avec Akka) … et j’en passe des grosse boutiques qui ont du scala en production parce qu’ils veulent lévereger le côté fonctionnel, avec leurs armées de devs java. Faire du fonctionnel en ayant fait du java est bien plsu, que de passer à Haskell ou F#, ou encore Clojure. Maintenant Scala n’est pas parfait. Mais il a des utilisations avérées.