Scala IO 2013 => Patterns de développement pour une application web réactive et concurrente

Présentateurs
Fabrice Croiseaux, CEO chez InTech Luxembourg. Il anime régulièrement des podcasts NipDev.
- Twitter : @fXzo
- LinkedIn : http://www.linkedin.com/in/fcroiseaux
- Github : fcroiseaux
-
Sa bio sur Scala IO
Antoine Detante, Ingénieur chez InTech Luxembourg.
- Twitter : @antoined
- LinkedIn : http://www.linkedin.com/in/fcroiseaux
- Github : adetante
- Sa bio sur Scala IO
=> La description de la session ScalaIO
Le Talk !
Antoine et Fabrice sont arrivés 2nd au concours Typesafe’s Developer Contest qui a eu lieu en début d’année.
Ils ont concouru avec une application Car Race Dashboard construite avec Play! Framework qui offre en temps réel la visualisation d’un dashboard de course de voitures.
Ce talk a été l’occasion pour eux de présenter leur travail.
Une application construite avec 3 composants principaux
-
Race Simulation => un moteur qui simule le déplacement de voitures
-
Race Dashboard => Stockage des positions dans une base Mongo DB + calcul des statistiques en asynchrone + notification des résultats
-
Web Client => un client web qui affiche en temps réel l’évolution de la course
Race Simulation
Du KML en guise de circuit
Pour simuler le déplacement d’une voiture, il faut déterminer une liste de coordonnées possibles. Cette liste de coordonnées est commune à toutes les voitures lors d’une course. Elle dépend évidemment du circuit sélectionné pour la course.
La liste des points est obtenue à partir d’un fichier KML pour un circuit. A titre d’exemple, vous pouvez consulter celui du Mans ici. Ce fichier XML sera parsé pour récupérer la liste des coordonnées possibles pour une course donnée.
Curieux de voir à quoi ressemble le code Scala qui a en entrée une URL de fichier KML et en sortie une liste de points ?
``` scala TrackParser https://github.com/intechgrp/CarRaceDashboard/blob/master/app/simulation/TrackParser.scala def readTrack(url: String): List[TrackPoint] = readTrack(XML.load(url))
def readTrack(data: Elem): List[TrackPoint] = { val positions = (for { pos <- (data \ “coordinates”).text.split(“\n”) if (pos.trim.length > 0) } yield pos.trim).toList.map { pos => val coordinates = pos.split(“,”) Position(coordinates(1).toDouble, coordinates(0).toDouble) } positions.zipWithIndex.map(v => TrackPoint(v._2, v._1)) } ```
Des acteurs, des acteurs, des acteurs
-
Race Actor => Acteur qui représente la course et qui permet de lancer toutes les voitures via un événement start. Il va aussi se charger de communiquer l’évolution des voitures au composant Race Dashboard.
-
Car Actor => Acteur qui simule le déplacement d’une voiture. Une fois l’événement start reçu du Race Actor, il va déplacer à intervalle régulier une voiture suivant la liste des points ordonnés du circuit.
Race Dashboard
Storage Actor
Cet acteur va sauvegarder les vitesses, positions et les distances successives dans la base Mongo DB. Le driver Reactive Mongo y est utilisé.
Stats Actor
Stats Actor calcule à partir des données stockées :
- La vitesse moyenne
- La vitesse maximale
- Le classement général
RTEventListener
Un acteur RTEventListener est instancié pour chaque client Web. Il écoute les messages du composant des acteurs Storage Actor et Stats Actor puis notifie via SSE le client web.
Web Client
Le client Web est construit avec :
- Coffescript qui s’intègre naturellement avec Play! Framework
- backbone.js pour une structure MVC
- Twitter Bootstrap pour la présentation générale de l’application
- Kineticjs pour le dessin du circuit et le déplacement des voitures
A quoi ressemble l’application ?
Les slides de la présentation
Ce que j’en ai pensé
Ce talk montre un exemple d’architecture se reposant complètement sur le modèle d’acteur. Ce style d’architecture permet une organisation séparant clairement les responsabilités entre les acteurs et une communication asynchrone entre les différents composants.
Je me suis poser la question de l’intérêt de l’instanciation d’un acteur RTEventListener par client Web. Je pensais trouver 1 acteur unique pour communiquer via SSE avec tous les clients. Je comprends qu’en utilisant 1 acteur par client Web, on se donne l’opportunité de notifier de façon concurrente les clients.
Asynchronisme + séparation des responsabilités + concurrence constituent-ils les fondations d’une application web réactive ?
Vous souhaitez en savoir plus sur ce style d’architecture ? Consulter le code sur Github et surtout inscrivez-vous au cours gratuit Principles of Reactive Programming de Coursera.