Archives du blog

JHipster – boost your Spring and AngularJS app

Mon blog s’appelant Hype Driven Development, ça me semblait difficile
de ne pas faire un article sur JHipster, le générateur d’application full stack pour
les hipsters du Java (avouez, c’est difficile de résister).

Un générateur? Oui, un générateur Yeoman. Vous avez peut être entendu parler
de cet outil, fort pratique pour générer des squelettes de projets,
par exemple pour commencer votre prochain projet Angular (c’est d’ailleur le générateur le plus connu).
Yeoman fournit le moteur de base, et vous pouvez installer les générateurs qui vous intéressent.
Il y en a plein et JHipster commence à être fort populaire.

JHipster est un générateur d’application Spring/AngularJS, et donne un projet tout bien
configuré et prêt à démarrer en moins de 10 minutes,
qui se répartissent entre taper 2 commandes et répondre à quelques questions (2 minutes),
regarder NPM télécharger la partie paire de l’internet (3 minutes) et Maven télécharger la partie impaire (5 minutes).
Oui c’était jour de circulation alternée.
Les seuls pré-requis sont donc NodeJS et NPM, un JDK 1.7 et Maven 3.

Stack serveur

Alors qu’est-ce que ça nous a installé ?
Côté serveur, cela s’appuie sur Spring Boot, un projet assez récent
qui permet de créer rapidement une application fonctionnelle avec Spring 4.
C’est clairement un projet que les équipes Spring veulent mettre en avant, pour montrer
que la création d’une application Spring peut être très simple. Spring Boot va créer une application toute prête
(une CLI est disponible, ou un plugin pour votre outil de build préféré), un pom.xml configuré, un serveur Tomcat ou Jetty embarqué,
pas de XML ou de code généré. Vous avez une classe de démarrage de votre application
avec quelques annotations dessus, et ça roule. Spring Boot ramène des copains à la fête :
- Spring MVC pour les controllers REST.
- Jackson pour la sérialisation JSON.
- Spring JPA et Hibernate pour la partie accès aux données.
- HikariCP pour le pool de connexion JDBC.
- Spring Security pour la gestion des utilisateurs et de l’authentification.
- Joda Time pour la gestion des dates (ca devrait être inutile en Java 8).
- Metrics un framework de monitoring, développé par Yammer.
- Thymeleaf si vous voulez faire des templates côté serveur.
- les drivers de la base de données choisie (H2, PG ou MySQL).
- Liquibase pour gérer les changements de schéma (très pratique comme outil).
- JavaMail pour les… mails.
- EhCache ou Hazelcast selon le cache choisi.
- Logback pour la gestion des logs.
- JUnit, Mockito et
Awaitility pour les tests.

Pas mal de code est déjà généré également, notamment pour la partie sécurité,
avec une classe utilisateur, une pour les rôles, une autre pour les audits…
Et bien sûr les repositories, services et controllers associés.
Un service d’authentification est déjà prévu avec une configuration très solide.
L’organisation des sources est claire et très classique, on s’y retrouve facilement.
Les ressources contiennent le nécessaire pour la configuration Liquibase, les fichiers
YAML de paramétrage de Spring selon le profil (deux profils, prod et dev sont fournis).
C’est dans ces fichiers que vous pourriez configurer votre BDD ou votre serveur mail par exemple.
On trouve également les fichiers de messages pour l’i18n, dans plusieurs langues.
Enfin, figurent aussi les fichiers de config du cache et du logger.

Dans les tests, on trouve des exemples de tests unitaires et de tests de controllers REST.

Stack client

Passons côté client. On a bien sûr du AngularJS (what else?).
Grunt est l’outil de build choisi (pas encore de Gulp? c’est pourtant plus hype…), il est déjà bien configuré
pour surveiller les fichiers et les recharger à chaud au moindre changement sauvegardé, passer JsHint pour vérifier,
tout minifier et concaténer. Bower est là pour la gestion de dépendances, rien d’exotique dans ce qui est récupéré :
Angular et ses différents modules indispensables (routes, cookies, translate…). On retrouve bien sûr Twitter Boostrap
pour faire joli et responsive. Les tests unitaires (avec quelques exemples fournis) sont lancés grâce à Karma,
pas de tests end-to-end en revanche.

Le fichier `index.html` est basé sur HTML5 Boilerplate, les fichiers CSS et i18n sont là.
Les scripts JS sont regroupés par type (`controllers.js`, `services.js` …).
Les déclarations d’injection Angular sont faites en mode tableau de chaîne de caractères pour éviter les problèmes de minification.
C’est un bon point, le générateur Yeoman pour Angular propose d’utiliser le plugin ngmin, mais celui-ci a quelques limites.
La sécurité est aussi gérée côté client. Enfin un certain nombre de vues sont disponibles d’origine pour le login et des vues
d’administration : gestion des logs, des perfs.

Run

Lançons tout ça!
Le projet démarre sur le port 8080 avec un simple `mvn spring-boot:run`, sur un écran d’accueil. On peut se connecter en tant qu’admin
et voir des écrans de gestion de profil (mot de passe, settings, sessions), l’écran d’audit (avec la liste des événements), l’écran de configuration des (977!!) loggers par défaut,
dont on peut changer le niveau à chaud, et enfin l’écran exposé par Metrics, avec les différentes… métriques donc!
On peut y voir des ‘Health checks’ (est-ce que la base de données est up? le serveur de mail?), les stats de la JVM
(mémoire, threads, GC), les requêtes HTTP, les statistiques des différents services (nombres d’appel, temps moyen, min, max et différents percentiles)
et enfin les statistiques du cache. J’aime beaucoup cette intégration d’un outil de monitoring simple, c’est certainement
quelque chose que j’utiliserai sur mes projets.
Il est possible de changer dynamiquement le langage de l’application (merci angular-translate).

Développement

JHipster permet aussi de générer des entités pour nous,
depuis la base de données jusqu’à la vue Angular, en passant par le repository et le controller Spring,
la route, le service et le controller Angular. C’est un peu anecdotique (la génération de code, à force…), mais ça marche, et ça
donne un CRUD tout à fait utilisable pour des écrans d’admin. Le service Spring doit lui être généré à part, pour
ne pas encourager la production de code inutile (ce qui est un peu paradoxal pour un générateur de code, vous en conviendrez, mais
je suis sensible au geste).

Ce qui est plus impressionnant, c’est que le projet utilise Spring Loaded, que j’ai découvert très récemment
(merci Brian de l’équipe Spring au détour d’un café à la Cordée!), et que cet agent permet le rechargement de code à chaud, même
lors d’un ajout de bean Spring! Couplez ça à Grunt et son LiveReload, et chaque modification est prise en compte
instantanément. Très très cool! Je pense que Spring Loaded va se retrouver sur les projets Ninja Squad d’ici peu.

Il faut quand même reconnaître qu’entrer la commande

yo jhipster:entity campaign

Puis se rendre directement dans son navigateur à l’url ‘/campaign’ et avoir le CRUD fonctionnel devant les yeux
en moins d’une seconde alors que cela a créé des tables en base, des beans Springs, du JS, qu’on a rien relancé,
c’est quand même pas mal la classe internationale.

TL, DR;

La stack complète est au final extrêmement proche de celle que nous utilisons
sur certains projets chez Ninja Squad : Spring MVC, Spring JPA, Spring Data,
HikariCP, Liquibase, Bower, Grunt, NPM, AngularJS, à l’exception donc
de Spring Boot, Spring Loaded, Metrics, Spring Security et nous préférons LESS à Compass et FestAssert pour les tests.
Puis on fait du Gradle, parce que certains n’aiment pas Maven (je ne donnerai pas de noms).

Mais je crois que Spring Loaded et Metrics vont bientôt rejoindre mes outils favoris.

JHipster propose aussi de faire des WebSockets avec Atmosphere ou
de gérer le clustering des sessions HTTP avec Hazelcast.

Bref, plein de bonnes idées, même si vous connaissez bien toutes les technos, et de bonnes pistes de configuration
si vous les découvrez.

Si vous ne saviez pas comment démarrer votre prochain projet Web Java, vous savez maintenant par quoi commencer!
En plus JHipster propose un container Docker pour tester. Si ça c’est pas le top
de la hype 2014, je sais plus quoi faire…

Angular, Express et Socket.io

Vous savez, si vous lisez le blog de Ninja Squad régulièrement, que nous donnons des cours dans différents établissements, de la fac aux écoles d’ingé, en passant par l’IUT. Avec cette nouvelle année scolaire, nous voici repartis!

Je donne depuis quelques années un cours sur les web services à l’INSA, à l’invitation du Docteur Ponge : c’est l’occasion de parler SOAP (beurk), REST (yay!) et Websocket (re-yay!).

Cette année, je veux faire une démo des websockets pour que cela soit un peu moins mystérieux. Faire un peu de code live est toujours un exercice périlleux, mais c’est un bon moyen pour échanger avec les étudiants et leur présenter un certain nombre de technologies, qu’ils connaissent parfois de nom ou pas du tout.

Les websockets sont l’occasion idéale de faire une application web basique, mais permettant d’introduire quelques concepts du Web parfois mal connus (HTML, CSS, Javascript) et un peu de code plus innovant (Node.js, Express, Socket.io, AngularJS, Bootstrap), de discuter sur l’histoire du Web, le fonctionnement des navigateurs (Chrome, Firefox, V8…) et quelques outils pratiques (npm, Git). Bref, d’apporter un peu de culture générale de notre métier, chose que j’appréciais beaucoup lors des interventions de professionnels lorsque j’étais étudiant.

Après cette remise en contexte, passons aux choses sérieuses!

Il me fallait donc un exemple d’application, qui me prenne une trentaine de minutes à réaliser au maximum. J’ai choisi de faire simple : une application de vote qui permet de choisir votre framework Javascript préféré, et de voir les résultats en temps réel. Nous allons voir les différentes étapes pour y parvenir.

Vous trouverez le nécessaire pour utiliser l’application sur le repo Github de Ninja Squad.

Express/Angular

La première branche Git, nommée `express` met en place une application Node.js/Express minimale.

    var express = require('express')
      , app = express()
      , server = require('http').createServer(app);
    
    app.use(express.static(__dirname + '/'));
    
    server.listen(9003);

L’application Node.js va servir les ressources statiques sur le port 9003. On peut alors ajouter le fichier HTML de notre application, qui contient basiquement :

    <div class="row">
      <div class="col-xs-4 vote"> {{ vote.choice }} </div>
      <div class="col-xs-4 vote"> {{ vote.votes }} </div> 
      <div class="btn btn-primary col-xs-4">+1</div>
    </div>

Pour chaque vote de la collection `votes`, le choix (VanillaJS, AngularJS, BackboneJS ou EmberJS), le nombre de vote pour ce choix et un bouton pour ajouter un vote seront affichés. Cela est réalisé en utilisant la directive `ng-repeat` d’Angular.

Le bouton de vote comporte l’attribut `ng-click` qui permet de lui lier une fonction à exécuter. Cette fonction `voteFor` est définie dans le controller :

	function VoteCtrl($scope){
      $scope.votes = [ { choice: 1, label: 'VanillaJS', votes: 0 }, { choice: 2, label: 'AngularJS', votes: 0 }, { choice: 3, label: 'BackboneJS', votes: 0 }, { choice: 4, label: 'EmberJS', votes: 0 }];

      $scope.voteFor = function(choice){ $scope.votes[choice-1].votes++; }
    }

Le controller Angular initialise les votes et définit la fonction de vote, qui ajoute simplement 1 aux votes du choix cliqué.

Etape 1 terminée! Passons maintenant à l’intégration de Socket.io.

Socket.io

Socket.io est l’une des librairies les plus utilisées pour les websockets dans Node (même si elle est maintenant concurrencée par d’autres comme SockJS). Elle a l’avantage de gérer le fallback si les websockets ne sont pas disponibles, et d’être très simple à utiliser à la fois côté client et côté serveur.

La branche `websocket` contient le code correspondant. Outre l’installation de socket.io (`npm install` is your best friend), il nous faut modifier un peu le serveur :

    io.sockets.on('connection', function (socket) {
      socket.emit('votes', { votes: votes });
      socket.on('vote', function(msg){
      	votes[msg.vote-1].votes++;
      	io.sockets.emit('votes', { votes: votes });
      })
    });

L’implémentation est naïve mais suffit à la démonstration : à la connexion d’un nouveau client (`socket.on(‘connection’, …)`), on envoie les votes dans l’état du moment (`socket.emit`). Puis, lorsque l’on recevra un vote (`socket.on(‘vote’, …)`), on incrémente les votes du choix correspondant et on informe tous les participants avec les nouvelles valeurs (`io.sockets.emit`).

Reste à mettre à jour le client pour communiquer avec les sockets :

    var socket = io.connect('http://localhost:9003');

    $scope.voteFor = function(choice){
      socket.emit('vote', {vote : choice })
    }

    socket.on('votes', function(msg){
      $scope.votes = msg.votes;
      $scope.$apply();
    });

On commence par se connecter aux websockets (`io.connect`). La fonction `voteFor` est modifiée pour maintenant envoyer un évenement de vote au serveur (`socket.emit`). Enfin, à chaque fois que les votes sont reçus, les votes du `$scope` Angular sont mis à jour. Petite subtilité : comme cette mise à jour intervient en dehors de la boucle d’exécution d’Angular, il nous faut appeler la fonction `$apply()` pour que le framework prenne les nouvelles valeurs en compte et rafraîchisse les vues.

Nous sommes prêts : si vous ouvrez cette application dans deux onglets, vous pourrez la voir se mettre à jour en temps réel!

A noter que le brillant Brian Ford de l’équipe Angular propose un service Angular pour Socket.io, afin de simplifier son utilisation et notamment les appels à `$apply()`.

Vous pouvez voir une démo en ligne, déployé sur Heroku (le code nécessaire pour cette partie est également sur le repo Github).

Espérons que ce petit essai vous plaise et plaise à nos étudiants!

Forms in AngularJS

Si vous lisez ceci, vous savez probablement créer un formulaire en HTML. Toute application web en contient son lot. Un formulaire contient un ensemble de champs, chaque champ étant une manière pour l’utilisateur de saisir des informations. Ces champs groupés ensemble dans un formulaire ont un sens, que ce soit une page d’enregistrement pour vos utilisateurs, ou une formulaire de login.

Les formulaires en Angular étendent les formulaires HTML en leur ajoutant un certain nombre d’états et en donnant aux développeurs de nouvelles façon d’agir.

Les formulaires, comme beaucoup de composants en Angular, sont des directives. Chaque fois que vous utilisez un formulaire en Angular, la directive ‘form’ va instancier un controller nommé ‘FormController’. Il est possible d’accéder au controller dans votre code en utilisant comme nom l’attribut ‘name’ de votre formulaire.

Ce controller expose un ensemble de méthode et de propriétés :
- ‘$pristine’ : permet de savoir si l’utilisateur a déjà touché au formulaire. On pourrait traduire en français par vierge. Ce booléen sera donc vrai tant qu’il n’y aura pas eu d’interaction, puis faux ensuite.
- ‘$dirty’ : à l’inverse de ‘$pristine’, ‘$dirty’ sera vrai si l’utilisateur a commencé à interagir avec le formulaire. Pour résumer : $dirty == !$pristine.
- ‘$valid’ : sera vrai si l’ensemble des champs (et éventuellement des formulaires imbriqués) sont valides.
- ‘$invalid’ : sera vrai si au moins un champ (ou formulaire imbriqué) est invalide.
- ‘$error’ : représente un dictionnaire des erreurs, avec comme clé le nom de l’erreur, par exemple ‘required’, et comme valeur la liste des champs avec cette erreur, par exemple login et password.

Ces états sont disponibles sur le formulaire global mais également sur chaque champ du formulaire. Si votre formulaire se nomme ‘loginForm’, et contient un champ ‘password’ alors vous pouvez voir si ce champ est valide grâce au code suivant :

    loginForm.password.$valid

Vous vous voyez déjà ajouter du code JS pour surveiller ces états et changer le CSS en cas d’erreur. Pas besoin! Angular ajoute ces états comme classe CSS directement sur chaque champ et le formulaire. Ainsi lorsque le formulaire encore vierge s’affiche, il contient déjà la classe CSS ‘ng-pristine’ :

    <form name='loginForm' class='ng-pristine'>
      <input name='login' ng-model='user.login' class='ng-pristine'/>
      <input name='password' ng-model='user.password' class='ng-pristine'/>
    </form>

Dès la saisie du premier caractère dans le champ ‘input’, le formulaire devient dirty :

    <form name='loginForm' class='ng-dirty'>
      <input name='login' ng-model='user.login' class='ng-dirty'/>
      <input name='password' ng-model='user.password' class='ng-pristine'/>
    </form>

A noter que le formulaire, ainsi que l’input, reste dirty une fois modifié, même si la modification est annulée.

Si l’un des champs présente une contrainte (comme par exemple ‘required’ ou ‘url’), alors le formulaire sera invalide tant que cette contrainte ne sera pas satisfaite. Le champ comme le formulaire aura donc la classe ‘ng-invalid’ ainsi que le champ en question. Une fois la condition satisfaite, la classe ‘ng-valid’ remplace la classe ‘ng-invalid’.

Vous pouvez donc très facilement customiser votre CSS pour ajouter un style selon l’état de votre formulaire. Cela peut être un bord rouge en cas de champ invalide :

    input.ng-dirty.ng-invalid {
      border: 1px solid red;
    }

Ou encore afficher un message d’erreur dans votre HTML :

    <form name='loginForm'>
      <input name='login' type='email' ng-model='user.login'/>
      <span ng-show='loginForm.login.$invalid'>Your login should be a valid email</span>
      <input name='password' ng-model='user.password'/>
    </form>

Ajouter un type ‘email’ sur un champ place une contrainte sur celui-ci, obligeant l’utilisateur à entrer un login sous la forme d’une adresse email valide. Dès que l’utilisateur commencera sa saisie de login, le champ deviendra invalide, rendant l’expression ‘loginForm.login.$invalid’ vraie. La directive ‘ng-show’ activera alors l’affichage du message d’avertissement. Dès que le login saisi sera un email valide, l’expression deviendra fausse et l’avertissement sera caché. Plutôt pas mal pour une ligne de HTML non?

Vous pouvez bien sûr cumuler les conditions d’affichage de l’avertissement, ou faire un avertissement par type d’erreur :

    <form name='loginForm'>
      <input name='login' required type='email' ng-model='user.login'/>
      <span ng-show='loginForm.login.$dirty && loginForm.login.$error.required'>A login is required</span>
      <span ng-show='loginForm.login.$error.email'>Your login should be a valid email</span>
      <input name='password' ng-model='user.password'/>
    </form>

Ainsi si l’utilisateur, après avoir entré un login (rendant ainsi le champ "dirty"), l’efface, un message d’avertissement apparaîtra pour indiquer que le login est nécessaire. Les combinaisons ne sont limitées que par votre imagination!

Plusieurs méthodes sont disponibles sur le controller :
- ‘addControl()’, ‘removeControl()’ permettent d’ajouter ou de supprimer des champs du formulaire. Par défaut tous les inputs "classiques" (input, select, textarea) que vous utilisez avec un ‘ng-model’ sont ajoutés au formulaire pour vous. Ils ont tous un controller nommé ngModelController, qui gère justement les états ($pristine, $valid, etc…), la validation, l’ajout au formulaire pour vous ainsi que le binding des vues au modèle. Les méthodes ‘addControl()’ et ‘removeControl()’ peuvent être intéressantes si vous voulez ajouter un autre type de champ à votre formulaire.
- ‘setDirty()’, ‘setPristine()’ vont respectivement mettre le formulaire dans un état ‘dirty’ou ‘pristine’ avec les classes CSS associées positionnées. A noter que les méthodes se propagent vers les formulaires parents si ils existent. En revanche, seule la méthode ‘setPristine()’ s’applique sur chaque champ du formulaire. Vous pouvez donc faire un ‘reset’ du formulaire et de ses champs grâce à ‘$setPristine()’.
- ‘setValidity(errorType, isValid, control)’ va, comme son nom l’indique, passer un champ de votre formulaire comme $valid ou $invalid pour le type d’erreur précisé, affectant par le même coup la validité du formulaire ainsi que celles des éventuels formulaires parents.

La dernière chose à retenir sur les formulaires concerne la soumission. Angular étant conçu pour les "single page applications", on cherche à éviter les rechargements non nécessaires. Ainsi l’action par défaut du formulaire sera désactivée, à moins que vous le vouliez explicitement en précisant une ‘action’ dans la balise ‘form’. Angular cherchera plutôt à vous faire gérer vous même la soumission du formulaire, soit en utilisant la directive ‘ngSubmit’ dans la balise ‘form’ soit en utilisant la directive ‘ngClick’ sur un ‘input’ de type ‘submit’ (mais pas les deux à la fois, sinon vous avez une double soumission!).

Vous avez maintenant toutes les clés pour faire une bonne validation côté client de vos formulaires en Angular. Mais que cela ne vous empêche de vérifier côté serveur! ;-)

Envie d’en savoir plus? Je donne une formation sur AngularJs!

Angular filter – Part 1

L’une des fonctionalités les plus appréciables et méconnues d’Angular réside dans les filtres disponibles. Dans toutes applications web, il est courant de devoir filtrer ou réordonner une collection pour l’afficher. Les filtres Angular sont applicables à la fois en HTML ou en Javascript, à un seul élément ou un tableau. En HTML, la syntaxe se rapproche du style Unix, où l’on peut chaîner les commandes à l’aide du pipe. Par exemple, on peut appliquer un filtre nommé ‘uppercase’ sur une expression de la façon suivante :

   {{ expression | uppercase }}

On peut également chaîner plusieurs appels de filtre :

    {{ expression | uppercase | trim }}

Certains filtres prennent des paramètres : c’est le cas du filtre ‘number’, qui nécessite de préciser le nombre de chiffres suivant la virgule. Pour passer les paramètres au filtre, il suffir de procéder comme suit :

    {{ expression | number:2 | currency:'$'}}

Il est également possible d’invoquer les filtres depuis le code Javascript :

    $filter('uppercase')

Angular va alors retrouver la fonction de filtre correspondant à la chaîne de caractères passée en paramètre.

Angular propose par défaut certains filtres communs :

- number : permet de préciser le nombre de chiffres après la virgule à afficher (arrondi au plus proche).

    {{ 87.67 | number:1 }} // 87.7 
    {{ 87.67 | number:3 }} // 87.670

- currency : permet de préciser la monnaie.

    {{ 87.67 | currency:'$' }} // $87.67

- date : permet de formatter l’affichage des dates, en précisant un pattern. On retrouve l’écriture classique de pattern :

    {{ today | date:'yyyy-MM-dd' }} // 2013-06-25

Un certain nombre de patterns sont disponibles (avec un rendu différent selon la locale) :

    {{ today | date:'longDate' }} // June 25, 2013

- lowercase/uppercase : de façon assez évidente, ces filtres vont convertir l’expression en majuscules ou minuscules.

    {{ "Cedric" | uppercase }} // CEDRIC   
    {{ "Cedric" | lowercase }} // cedric

- json : moins connu, ce filtre permet d’afficher l’objet au format JSON. Il est également moins utile, car, par défaut, afficher un object avec la notation ‘{{ }}’ convertit l’objet en JSON.

    {{ person | json }} // { name: 'Cedric', company: 'Ninja Squad'} 
    {{ person }} // { name: 'Cedric', company: 'Ninja Squad'} 

- limitTo : ce filtre s’applique quant à lui à un tableau, en créant un nouveau tableau ne contenant que le nombre d’éléments passés en paramètre. Selon le signe de l’argument, les éléments sont retenus depuis le début ou la fin du tableau.

    {{ ['a','b','c'] | limitTo:2 }} // ['a','b'] 
    {{ ['a','b','c'] | limitTo:-2 }} // ['b','c'] 

- orderBy : là encore un filtre s’appliquant à un tableau. Celui-ci va trier le tableau selon le prédicat passé en paramètre. Le prédicat peut être une chaîne de caractères représentant une propriété des objets à trier ou une fonction. Le prédicat sera appliqué sur chaque élément du tableau pour donner un résultat, puis le tableau de ces résultats sera trié selon les opérateur ‘. Une propriété peut être précédée du signe ‘-’ pour indiquer que le tri doit être inversé. A la place d’un simple prédicat, il est possible de passer un tableau de propriétés ou de fonctions (chaque propriété ou fonction supplémentaire servant à affiner le tri primaire). Un second paramètre, booléen, permet quant à lui d’indiquer si le tri doit être inversé.

    var jb = {name: 'JB', gender: 'male'};    
    var cyril = {name: 'Cyril', gender: 'male'};     
    var agnes = {name: 'Agnes', gender: 'female'};     
    var cedric = {name: 'cedric', gender: 'male'};     
    $scope.ninjas = [jb, cyril, agnes, cedric];  
    
    // order by the property 'gender' 
    {{ ninjas | orderBy:'gender'}} // Agnes,JB,Cyril,Cédric 

    // order by a function (lowercase last) 
    $scope.lowercaseLast = function(elem){ 
      return elem.name === elem.name.toLowerCase() 
    }; 
    {{ ninjas | orderBy:lowercaseLast }} // Agnes,JB,Cyril,cedric 

    // order by an array of properties or functions 
    {{ ninjas | orderBy:['-gender','name'] }} // cedric,Cyril,JB,Agnes 

Dans le prochain billet, nous verrons comment créer nos propres filtres.

MongoDB Aggregation Framework

Vous avez probablement entendu parlé de MongoDb, une solution NoSQL orientée document développée par 10Gen. Les documents sont stockés en JSON, et bien que vous ayez un driver disponible pour chaque language, on se retrouve souvent à coder les requêtes en javascript dans le shell mongo fourni. Je vais vous parler de la version 2.2 qui est la dernière version stable et contient le framework d’aggregation, grande nouveauté attendue par les développeurs. Pour votre information, les numéros de version de Mongo suivent le vieux modèle du kernel Linux : les numéros pairs sont stables (2.2) alors que les versions de développement sont instables (2.1). Node.js suit le même modèle par exemple.

L’aggrégation donc, qu’est ce que c’est? Pour vous faire comprendre l’intérêt nous allons prendre un petit exemple (version simplifée d’un vrai projet). Admettons que vous stockiez les connexions à votre application toute les minutes, par exemple avec un document qui ressemblerait à

{"timestamp": 1358608980 , "connections": 150}

C’est à dire un timestamp qui correspond à la minute concernée et un nombre de connexions total.

Disons que vous vouliez récupérer les statistiques sur une plage de temps, par exemple sur une heure : il faudrait alors aggréger ces données pour obtenir le nombre total de connexion et le nombre moyen par minute. Seulement voilà, MongoDb ne propose pas de “group by”, de “sum” ou de “avg” comme l’on pourrait avoir en SQL. Ce genre d’opération est même déconseillé, car fait en javascript cela prend un plus de temps que dans une base classique. C’est en tout cas à éviter pour répondre à des requêtes en temps réel. Mais bon des fois, on est obligé…

 The old way : Map/Reduce
Jusqu’à la version 2.2 donc, on utilisait un algo map/reduce pour arriver à nos fins. Si vous ne connaissez pas, je vous invite à lire cet article de votre serviteur expliquant le fonctionnement. Dans un algo map/reduce, Il faut écrire une fonction map et une fonction reduce, qui vont s’appliquer sur les données selectionnées par une requête (un sous ensemble de votre collection MongoDb).

La requête qui permet de selectionner ce sous ensemble serait par exemple :

// stats comprises entre 15:00 et 16:00

var query = { timestamp : { $gte: 1358607600, $lte: 1358611200 }}

La fonction map va renvoyer les informations qui vous intéressent pour une clé. Ici nous voulons les connexions pour l’heure qui nous intéresse, donc nous aurons une fonction comme suit :

// on renvoie les infos pour la clé 15:00

var map = function(){ emit(1358607600, { connections : this.connections}) }

La fonction reduce va ensuite aggréger les informations, en ajoutant les connexions totales pour la clé 15:00 et calculer la moyenne associée.

// calculer la somme de toutes les connexions et la moyenne

var reduce = function(key, values){
 var connections = Array.sum(values.connections);
 var avg = connections/values.length;
 return { connections: connections, avg: avg}
 }

Maintenant que nous avons nos fonctions map et reduce, ainsi que la requête pour remonter les données qui nous intéressent, on peut lancer le map reduce.

// dans le shell mongo

db.statistics.mapReduce(map, reduce, { query: query, out: { inline: 1 }})

Le out inline permet d’écrire la réponse dans le shell directement (sinon il faut préciser une collection qui acceuillera le résultat). On obtient une réponse du style :

{connections: 180000, avg: 3000}

en 4,5 secondes environ sur ma collection de plusieurs millions de document légèrement plus complexes que l’exemple.

The new way : Aggregation Framework
Maintenant voyons la nouvelle façon de faire avec le framework d’aggrégation. Une nouvelle opération apparaît : aggregate. Celle-ci remplace mapReduce et fonctionne comme le pipe sous Linux : de nouveaux opérateurs sont disponibles et on peut les enchaîner. Par exemple, le “group by” est simplifié avec un nouvel attribut $group. La requête qui permet de filtrer un sous ensemble de la collection est écrite avec un opérateur $match. Enfin de nouveaux opérateurs viennent nous simplifier la vie : $sum, $avg, $min, $max… J’imagine que vous avez saisi l’idée.

Ici on veut un élément match qui limite l’opération aux données de l’heure concernée, on peut réutiliser la même query que tout à l’heure. On groupe ensuite les documents avec une seule clé : celle de l’heure qui nous intéresse, puis l’on demande le calcul de deux valeurs, le nombre total de connexions (une somme) et la moyenne des connections (une moyenne donc).

db.statistics.aggregate(
 { $match: query},
 { $group: { _id: 1358607600, totalCompleted: {$sum: "$connections"}, totalAvg: {$avg: "$connections"}
 }})

Le résultat est le suivant (en 4,2 secondes, soit un temps légérement inférieur au précédent) :

{ result: [{
 "_id": 1358607600,
 "totalCompleted": 180000,
 "totalAvg": 3000
 }], ok: 1}

L’avantage principal du framework d’aggrégation réside dans sa plus grande simplicité d’écriture et de lecture : plus besoin d’écrire des fonctions js soi-même pour des opérations somme toute assez courantes. Spring Data Mongo par exemple, le très bon projet de SpringSource pour vous simplifier la vie, demande d’écrire des fonctions en js pour faire du map/reduce. Vous avez donc un projet Java, qui contient quand même quelques fichiers js au milieu pour faire certaines opérations. Beaucoup attendent donc avec impatience l’arrivée du support du framework d’aggrégation dans Spring Data. Espérons qu’il ne tarde pas trop! En attendant d’autres frameworks comme Jongo l’ont déjà intégré. Il y a toutefois quelques limites comme le résultat de l’aggregate qui doit faire moins de 16Mo. Bref tout n’est pas idéal, mais ce très bon produit s’améliore à chaque version!

Meetup W3C de Lyon

Lundi 28 Octobre avait lieu à Lyon le W3C meetup. Le principe est simple, le w3c prend l’avion avec quelques uns de ses développeurs et speakers et débarque pour faire une série de mini talks sur le web. Organisé en partenariat avec le Grand Lyon, des startups du coin étaient aussi conviées à présenter leurs produits en essayant de les lier, au moins vaguement au web.

Premier bon point pour les locaux, dans l’hôtel de ville, ce qui a quand même autrement plus la classe que le bar ou l’école du coin! Par contre, pas de chaises prévues, tout le monde s’assoit par terre, pendant que les speakers se préparent pour leurs 5 à 10 minutes de talk.

On commence avec ohmytoast, une startup lyonnaise, qui propose une solution pour enrichir vos photos avec des métadonnées, du web semantique, pour créer des albums avec un sens. Le concept a l’air sympa, niveau techno, l’équipe se repose sur html5, css3 et Apache Camel pour la partie serveur.

Le deuxième talk, extrêmement court, était pour moi le plus intéressant de la soirée. En 3 minutes, Rudy Rigot nous montre l’histoire du webdesign et l’intérêt du responsive design. Prenez deux minutes pour voir ses slides, et jouer avec le resize, ca vaut le détour.

Vient ensuite, Eric Daspet qui présente Tea, une solution de lecture d’ebook dans le navigateur, qui repose donc uniquement sur des technos web. Le choix full web du reader n’a pas été simple, mais Eric voit de nombreux avantages (navigateurs présents sur tous les devices, pas de frais liés à Apple ou Google) malgré quelques inconvénients (moins de performances, pas de présence sur les marketplaces). Tea est encore en phase de développement, à revoir dans quelques mois donc.

Viennent ensuite des speakers W3C qui présentent les nouveautés HTML5. Mais bon, ça commence à sentir le réchauffé avec les différentes balises video, audio… Rien d’exceptionnel. Deux développeurs de Mozilla font une démo d’un jeu 3D qui tourne dans Firefox 16 : ils ont développé le jeu en interne (un quake-like) en C++ et un compilateur transpile le code en JS. Ils prédisent donc que de vrais jeux vont voir le jour dans le navigateur dans les prochaines années. Ils montrent également une fonction de login dans le navigateur qui permet de partager facilement des pages avec ses amis par tchat.

Les mêmes développeurs enchaînent ensuite sur une démo de Firefox OS, un OS full html, qui vise les plateformes mobiles. C’est en version très très alpha, avec peu de téléphones qui fonctionnent. Un market sera disponible, les applications étant des pur webapps, avec un packaging léger (un peu comme les webapps Chrome, un fichier json servant à la description de l’application). Des apis supplémentaires ont bien sûr été développées pour accéder à l’appareil photo, passer des appels, etc… Ces apis ont été soumises au W3C pour devenir un jour des standards accessibles dans le navigateur.

Un speaker vient ensuite parler des hyperdevices, autrement dit connecter plusieurs devices avec plusieurs technologies (websockets, réalité augmentée, web sémantique…) et propose quelques démos sympathiques mais souvent déjà vues (dessiner sur un téléphone et afficher le résultat en temps réel sur son écran de laptop…).

Dernière partie, sur les nouveautés du W3C. La seule notable est présentée par Lea Verrou, nouvelle arrivée au W3C, qui nous parle du sitee WebPlatform.org sorti ce mois-ci. L’ambition du site est de devenir la référence en matière de documentation sur les technologies web. Il devrait notamment être enrichi et traduit dans les prochaines semaines et, à terme, une API sera disponible pour permettre aux outils comme les IDEs de récupérer cette documentation.

La soirée se termine avec un buffet excellent qui permet de discuter avec les nombreux participants et quelques speakers. Pour un développeur web qui se tient un peu au courant de l’actualité, ce n’était pas une soirée extrêmement palpitante, mais elle a le mérite d’exister et d’amener quelques noms connus du W3C en France. Et puis le buffet était vraiment bien!

JUGSummerCamp 2012

Premier voyage de l’équipe NinjaSquad, direction La Rochelle pour le JUG Summer Camp. Du Java, du Web, l’océan, une conf gratuite d’une journée avec une organisation irréprochable, il faudrait être difficile pour ne pas aimer!

JUG Summer Camp 2012

Keynote : Nicolas de Loof - @ndeloof

Nicolas nous a fait un numéro de stand up très drôle en parodiant le podcast bien connu dans le monde Java : les Castcodeurs. Comme aucun d’entre eux n’étaient présents, Nicolas a eu l’idée de faire un puppet show en reprenant les traits caractéristiques de chacun d’entre eux, pour faire une keynote originale sur notre métier. Franc succès dans la salle (évidemment seulement drôle si on écoute ce podcast).

La journée se déroule ensuite sur deux tracks de confèrence, il faut donc faire des choix.

Google TV : Olivier Gonthier - @rolios

Première présentation sur la Google TV, petit boîtier qui permet de faire tourner des applis Android sur votre télé, mais pas encore disponible en France (on ne connait même pas les partenariats avec les opérateurs). Le principe est simple : une prise HDMI en entrée reçoit le flux vidéo et une prise HDMI de sortie le renvoie vers la TV. A noter que le code de Google TV n’est pas open source. Sinon techniquement c’est le même market que les applis Android traditionnelles.

Commençons par le point qui fâche et qui, à mon sens, fait perdre tout l’intérêt de la chose : il n’est pas possible de récupérer le flux video, ni la chaine visionnée par l’utilisateur, donc vous pouvez oublier toutes les idées d’applications contextuelles: IMDB sur le film en cours ou les stats du match que vous êtes en train de regarder, c’est foutu!

Mais il y a deux ou trois trucs intéressants quand même : par exemple, le "second screen app", qui permet aux devices Android de s’interfacer avec la GoogleTV et de vous servir de télécommande ou mieux, d’écran annexe pour certaines applications. L’exemple que je trouve assez cool : un jeu de poker Hold’em où la TV affiche la table de jeu (avec les cartes communes et les mises) et chaque joueur voit ses cartes sur son téléphone. Ce genre d’application peut avoir un grand potentiel, je suis sûr que l’on va voir apparaître des applications géniales!

Le développement est de la programmation Android traditionnelle, le SDK étant complété avec des fonctions pures TV (touches telecommande par ex). Si vous souhaitez développer une application Android utilisant le "second screen", vous pouvez utiliser Anymote library (voir dans les exemples de code fournis par Google, dans l’application Blackjack TV).

Il est également possible de développer des applications en html5, la GoogleTV ayant un très bon navigateur Chrome intégré (très bien documenté d’après le speaker). Il est aussi possible de packager votre application avec Phonegap pour la distribuer directement sur le Market.

En plus j’ai gagné la GoogleTV du concours, yay!

Node.js : Romain Maton - @rmat0n

Romain faisait une présentation générale de Node.js (voir articles précédents et les excellents articles de Romain) avec quelques rappels sur les principes de base. C’était une présentation très orientée web-app avec le framework web Express et son moteur de template par défaut Jade (cf article précédent également).

Puis les modules importants :

- l’incontournable Socket.io pour faire des websockets

- logging avec Winston

- nodemon, redémarrage automatique dès que vous modifiez un fichier.

- forever pour relancer l’application en cas d’erreur qui coupe l’appli

- jasmine, qunit pour les tests

Et pour terminer une petite démo sympa avec la librairie speak qui fait parler le navigateur pour annoncer le prochain bus qui passe.

Start me up : Nicolas de Loof - @ndeloof

Après le buffet repas le plus incroyable pour une conf que j’aie vu (les membres de l’orga Mix-it présents étaient impressionnés), on reprend avec ‘Start me up’ ou comment passer rapidement de l’idée à la réalisation (en utilisant Cloudbees, dont Nicolas est employé). L’idée est ici de faire un mini moteur de recherche sur les talks de la conf. Nicolas utilise au passage un autre service dans le cloud que je ne connaissais pas : WebSolr, un Solr as a Service. Cloudbees on aime bien, Mix-it est hébergé gracieusement dessus et ça marche très bien (le support a toujours été très réactif en cas de problème).

La présentation est intéressante, Nicolas étant un bon speaker, mais si vous avez déjà vu une présentation de Cloudbees le contenu ne vous surprendra pas (comment déployer, comment gérer ses instances, comment déclarer des propriétés pour le déploiement etc.). La nouveauté la plus notable est sans doute le Click Start, qui permet en un clic de créer tout ce qui va bien pour un type d’application (squelette du projet, repository de code, instance jenkins, base de données et instance de run). Pour l’instant, quatre types de Click Start sont disponibles (JavaEE6, Hibernate/Tomcat, Rest/Backbone, Scala/Lift).

Du legacy au cloud : David Gageot - @dgageot

David est un excellent speaker que je vous recommande de voir si il est dans une conférence à laquelle vous assistez. Son talk est du pur live coding, sans aucun slide, et reprenait le kata de Gilded Rose où une application existante doit être refactorée.  Une spécification est disponible, mais David ne recommande pas particulièrement de la lire pour commencer mais plutôt de créer des tests sur le code existant que l’on doit retravailler. La logique étant que si l’application convient aux utilisateurs actuellement, le plus important est de préserver son fonctionnement. Les tests sont assez simples à écrire, on appelle chaque méthode et on colle dans le assert le résultat renvoyé : on obtient ainsi une série de tests au vert qui seront notre sécurité.

David utilise le plugin infinitest qui relance les tests dès que le code est modifié : si vos tests sont très courts, le feed-back est immédiat.

La marche à suivre pour refactorer le code est la suivante :

- augmenter la symétrie (mettre les if/else et les equals de la même façon, en enlevant les conditions inversées par exemple).

- puis faire apparaître les duplications de code afin d’extraire de nouvelles méthodes

David finit par introduire de la délégation (un objet était passé dans toutes les méthodes de la classe), en utilisant une annotation de Lombok.

Une fois le code propre, David écrit un petit serveur http qui expose les données en JSON, déploie l’application sur heroku, puis déploie un front statique sur Github Pages (comme le blog de NinjaSquad) qui consomme les données.

Le tout en 45 minutes, en expliquant très bien ses choix et en utilisant IntelliJ avec maestria. C’est la présentation que j’ai préféré de la journée, même si parfois le refactoring était un peu magique, David connaissant bien le code et étant pressé par le temps. Si vous voulez tester le dojo par vous même, les projets sont disponibles sur le compte Github de David.

Beaglebone = Arduino^10 : Laurent Huet – @lhuet35

Laurent nous faisait descendre de quelques niveaux d’abstraction avec un talk sur Beaglebone, une carte plus puissante qu’un Arduino, un peu du même type que le Raspberry Pi. La présentation était intéressante, avec une explication générale des principes, une démo, et les technos que l’on peut faire tourner sur ce type de cartes (C/C++, Java, Python, Node.js …). Manque de chance pour Laurent, sa carte de démo avait grillé la veille (les risques du métiers), mais son talk n’en a pas été trop perturbé, bravo à lui!

Programatoo pour les grands : Audrey Neveu - @audrey_neveu et Ludovic Borie - @ludovicborie

Vous avez peut être entendu parler de Programatoo, un atelier de programmation pour initier les enfants dès l’age de 6 ans aux joies du code. Audrey et Ludovic nous ont montré les différents outils que l’on peut utiliser pour  éveiller la curiosité des plus petits (je ne sais pas si cela peut fonctionner avec vos collègues également) : Scratch, KidsRuby ou encore TortueScript. Très sympa, si vous avez des enfants, ce genre d’outils devraient vous intéresser!

La journée de conf se termine déjà, l’assemblée se dirige vers le port pour un repas tous ensemble. Le JUGSummerCamp aura été une très belle journée, superbement organisée par Jerôme Petit, Orianne Tisseuil et leur équipe. L’équipe Mix-it en partie présente compte bien leur emprunter quelques bonnes idées! Si vous avez l’occasion de vous rendre à la prochaine édition, n’hésitez pas, la conférence, gratuite, est l’une des toutes meilleures en France et la Rochelle et ses alentours ne manquent pas de charme pour rester quelques jours supplémentaires!

Un an de hype!

Après plus d’un an de blog, et 18 articles, voici le moment idéal de faire un petit résumé des thèmes abordés en 12 mois de hype!

Node
Pas mal de Node.js, peut être le sujet le plus hype de l’année, avec une série d’articles d’introduction :
- Getting started with Node.js (part 1)
- Getting started with Node.js (part 2)
Un complément à cette série avec la présentation du framework web Express (et mise en oeuvre avec un exemple dispo sur github) : Node, Express et Jade.
Si vous voulez coder, il faut également un IDE pratique : Cloud9 propose un outil en ligne, prévu pour faire du node.js.
Enfin deux billets autour de l’actualité de Node et de son écosystème :
- Trello qui utilise Node (de façon assez étrange l’article le plus lu de l’année avec plusieurs milliers de lecture)
- La sortie d’un framework full stack : Meteor.js, assez intéressant pour son côté temps réél intégré.

Hadoop
La deuxième série d’article a été écrite pour le magazine Programmez et publiée en Septembre dernier. Hadoop est un incroyable outil, si vous voulez le découvrir :
- Getting started with Hadoop (part 1)
- Getting started with Hadoop (part 2)

Le site Mix-it
Une partie du succés de Mix-it de cette année est dû au site communautaire mis en place, que nous avons développé avec amour :
- Le pourquoi
- Le comment (avec plein d’outils sympas dedans).

Less
Ou comment le combo Less et Twitter Bootstrap va changer votre vie de développeur web : CSS sucks, do Less!

Play!
Sans avoir d’article vraiment consacré, Play! se retrouve un peu partout avec notamment un article assez lu sur l’annonce de la 2.0 beta à Devoxx :
- Back from Devoxx : Play! 2, hopes and fears
Vous trouverez aussi des traces de Play! dans l’article consacré à Typesafe

Des retours de conf
De la What’s next de l’année dernière à fOSSa en passant par Mix-it (vu du côté orga, comment choisit-on les sessions)

Cast-it
Le podcast qui parle Java, mais pas que, continue! Si vous n’avez pas écouté depuis l’annonce, jetez-y une oreille, l’année fut bien remplie avec des invités locaux et internationaux (Romain Guy, Pamela Fox, Guillaume Laforge…)!

Thanks all for reading!


Le site Mix-it : making-of

Mix-IT est terminé et beaucoup de participants ont apprécié le nouveau site avec ses facettes communautaires et social gaming. En tout cas, nous avons pris beaucoup de plaisir à le faire. Car oui, ce site a été entièrement développé par les soins de notre équipe, particulièrement par Cyril Lacote (qui, il faut le dire doit avoir 60% du code à lui seul), Agnès Crépet et moi même, aidé par le reste de la team, avec leurs propositions, tests et feedback.

Voici donc une liste non exhaustive des outils et technos utilisés :

Trello : nous sommes des fans de la première heure de cet outil, qui nous a beaucoup servi pour échanger (mes camarades globe trotteur étant toujours décalés de plusieurs heures). Trello permet de faire un scrumboard interactif (on est notifié des échanges sur une tache), temps reel, avec un système de vote, label et filtre. Ça n’est pas JIRA mais pour un outil gratuit, c’est un outil génial.

Github : les sources du projet sont gérées sous Git. Aucun d’entre nous n’est un expert mais nous n’avons pas rencontré de problème majeur passés les premiers réglages. Nous avons utilisé le modèle décrit par Github (voir le talk de Zach Holman, et les articles GitHub), a savoir des pull requests, revues par un autre développeur avant d’être acceptées dans le master. C’est une bonne façon de garder une ‘collective ownership’ du code, même sans commiter.

Cloudbees : l’application est hébergée gracieusement par Cloudbees, qui a de plus acceptée généreusement de nous offrir les services additionnels qui nous était nécessaires (SendGrid, base de données en mode étendu, application en mode On Demand). La plateforme est très bien réalisée, le déploiement prend quelques minutes et est très simple à configurer. Ajoutez à ça un support ultra réactif et le fait qu’un déploiement est invisible pour les utilisateurs et vous avez une plateforme de choix pour vos développements.

Techniquement, l’application est codée avec le framework Play! (1.2.4 à l’heure actuelle) : rien à dire là dessus, Cyril et Agnès ne connaissaient pas et étaient productifs en quelques heures, peu de problèmes rencontrés, et avec tout un tas de modules à disposition (recherche full text Lucene, export PDF, parser Markdown). Bref, un outil génial! Un peu de Guava en plus et nous avions nos briques côté serveur. La base de données est un MySQL (hébergement cloudbees oblige).

Côté client, rien de très original, du bon vieux jQuery pour la manipulation de DOM. Et pour faire la même chose côté serveur (en Java donc), nous avons utilisé Jerry, qui nous permet de manipuler le contenu HTML des posts Google+ pour transformer les mentions d’utilisateurs. Nous avons également utilisé un plugin jQuery bien pratique pour gérer la dirtiness des formulaires et empêcher la sortie des pages en cours d’édition : dirtyforms.

Twitter Bootstrap : probablement notre coup de coeur, car même si nous faisons tous du développement, aucun d’entre nous n’est très doué en CSS. Et là, Twitter Bootstrap peut vous sauver : c’est un bootstrap CSS qui vous donne juste ce qu’il faut de cadre pour faire une application web présentable. Inconvénient : beaucoup de sites utilisent la même chose, il faut donc faire un peu de customisation pour différencier votre site. Tous les icones utilisés proviennent de fontawesome. Nous utilisons la version Less de Bootstrap plutôt que la version CSS : pour plus d’infos voir article précédent.

Ce qui n’a jamais atteint la mise en ligne

Nous avions envie de mettre un peu de communication temps réel sur le site avec un système de notifications lorsqu’un participant auquel vous étiez relié effectuait une action sur le site. Pour ça, un projet annexe (disponible sur github également) utilisant nodejs était utilisé. Dès qu’une action était effectuée sur le site, une requête était envoyée à un serveur nodejs, qui notifiait les utilisateurs intéressés connectés (par websocket en utilisant socket.io). La notification se fait sous forme d’une notification HTML5 si disponible dans le navigateur, ou en utilisant le plugin noty. Malheureusement nous n’avons pas eu le temps de terminer cette fonctionnalité.

Maybe next year… D’ici là, vous pouvez trouver les sources sur Github et vous amusez avec!

So what is Meteor?

Il y a quelques jours, un (enième) framework javascript faisait son lancement : Meteor. Un très bon lancement d’ailleurs, avec un site agréable, 3 petites applications d’exemple, presentées avec des screencasts clairs. Cette sortie est remarquée et se retrouve rapidement commentée sur Hacker News, Twitter et Quora. Car Meteor est un framework de développement d’application web full stack en javascript qui entend bien révolutionner notre façon de coder.


Pourquoi autant d’attention pour un framework vieux de quelques jours ? Parce qu’il y a quelques idées très intéressantes à étudier! Le site annonce la couleur de suite : développer rapidement une application web de qualité dont l’une des qualités, et pas des moindres, est de pouvoir faire du temps réel. Et il faut reconnaitre que leurs démos sont enthousiasmantes : il y a longtemps que je ne m’étais pas dit ‘il faut que j’essaye ce truc!’ en regardant un framework web! Pour avoir fait un petit essai d’appli, c’est simple à mettre en oeuvre, et en une heure j’avais une petite démo qui tournait en ligne (meteor propose son service d’hébergement). L’une des fonctions extrêmement agréable en code est l’auto refresh du navigateur. Play! mettait déjà en avant son cycle de développement rapide, à la portée d’un refresh manuel d’une seconde (enfin ca c’était avant la version 2…). Ici même plus besoin de cette étape, votre navigateur est automatiquement notifié d’un changement et les affiche à l’écran. En dual-screen, c’est un bonheur à coder! Faisons un petit tour sous le capot maintenant.


Real time

Plutot que d’envoyer du html a votre client, Meteor propose d’envoyer seulement les données et de laisser le client décider de la façon dont elles doivent être affichées. La où Meteor donne son effet “wahou”, c’est par sa gestion native du temps réel. L’objet affiché dans votre navigateur a été modifié par un autre utilisateur ? No problem, Meteor va informer tous les clients de cette modification, et vous allez voir votre affichage se modifier en conséquence! C’est vraiment impressionnant d’obtenir un tel résultat sans rien coder, et rien que pour ça, prenez 5 minutes et essayez. D’autres outils proposent également de vous aider à bâtir des applications avec temps réels dont socketstream qui est très bon et s’appuie sur socket.io (le lead développeur de socketstream explique la différence de philosophie, socketstream etant beaucoup plus léger et prévu pour s’intégrer en complément d’autres frameworks). Ici Meteor a fait le choix d’utiliser SockJS, une librairie un peu équivalente. Mais pour l’instant rien ne passe par les websockets, tous les transferts de data sont par requête xhr (dans le code source il est indiqué que c’est par soucis de compatibilité avec les différentes navigateurs, mais c’est évidement modifiable). Tout se passe par un système de publish/suscribe que l’on retrouve de plus en plus et qui est très intéressant (vos clients s’abonnent à des événements qui les intéressent et réagissent en conséquence).


Auto refresh

Lorsque vous êtes en train de développer, la sauvegarde d’un fichier sur votre poste va automatiquement rafraichir le navigateur avec vos modifications. Comme je le disais en introduction, c’est un vrai bonheur et c’est quelque que l’on voit apparaître un peu partout. Ce principe de modification à chaud est aussi disponible en production : Meteor annonce qu’une nouvelle version de votre application peut être déployée de façon transparente pour vos utilisateurs (bon ça je pense que personne n’a vraiment testé…).


Node.js as runtime

Node.js gagne en maturité et devient un runtime vraiment intéressant pour bâtir des applications (pas forcément des webapps d’ailleurs). On trouve déjà des frameworks webs par poignées, l’un de mes préférés étant Express. Celui ci est différent à bien des égards par rapport à ce qu’il existe déjà, par son aspect full-stack et temps réel. Mais un point a dérangé pas mal de monde, une phrase de la doc indiquant : “In Meteor, your server code runs in a single thread per request, not in the asynchronous callback style typical of Node”. L’encapsulation de Node est donc différente de ce à quoi nous sommes habitués dans la majeure partie des cas. Mais tout ça est transparent pour le développeur, et l’équipe derrière a l’air d’avoir une certaine “street cred” (notamment les développeurs d’Etherpad, un Google Docs avant l’heure, d’ailleurs racheté par Google par la suite), donc leur choix n’est peut être pas aussi absurde qu’il peut en avoir l’air a première vue. Cette gestion différente de Node se fait grâce à la librairie node-fibers entre autre. En tout cas, même si vous n’avez jamais fait de Node.js, aucun problème pour se lancer avec Meteor, tout est transparent. Nodejs est d’ailleurs le seul prérequis pour déployer une application Meteor.


Partage du code client et serveur

Meteor est un framework full stack qui donne les outils nécessaires pour faire votre application depuis le templating client à la persistance en base de données. Mais de plus pour Meteor, vos objets javascripts clients sont les mêmes que les objets javascripts serveurs. On dénombre quelques frameworks javascripts qui ont la même idée, comme par exemple Tower.js, voire même des choses assez proches de Meteor comme Derby (beaucoup de features identiques sont présentes, au point que l’équipe de Derby a fait un billet pour expliquer leurs différences). Plus que les objets, se sont même les fonctions qui peuvent s’exécuter indifféremment côté client ou côté serveur!

Le code est à tel point partagé que par défaut, vous écrivez les deux parties dans le même fichier (chaque partie étant quand même identifiée, mais on peut partager des fonctions entre les deux). Vous pouvez également scinder ce fichier, la convention étant de créer un dossier ‘client’ et un dossier ‘serveur’ qui contiennent vos fichiers.


Base de données

Par défaut, c’est une instance MongoDB qui est lancée pour la persistence. MongoDB est une base NoSQL, orientée document, dont l’API est en javascript. Cette API est d’ailleurs disponible aussi bien dans la partie serveur que dans la partie cliente! Hein? Oui, en fait, Meteor va répliquer la base de données dans le navigateur, pour que vous puissiez manipuler un ensemble valide de données directement depuis le client (on imagine bien que ce système a des limites, mais n’est pas trop détaillé à ma connaissance).


Côté client

Le système de templating retenu est Handlebars par défaut, mais il est à priori possible de choisir son préféré. Pour le reste, le comportement ressemble à beaucoup d’autres frameworks à la Backbone : vous définissez à quels ‘events’ vont réagir vos objets et la façon dont ils vont réagir. Pour manipuler le DOM vous pouvez utiliser votre bibliothèque favorite (en interne Meteor utilise JQuery). Ce qui est intéressant c’est qu’une action côté client n’attend pas forcément la réponse du serveur : elle va effectuer son action immédiatement (en simulant la requête, puisque votre base de code fonctionne aussi bien côté client que côté serveur). Quand le serveur renvoie sa réponse, le client compare les résultats et se met à jour en conséquence. Cette fonctionnalité s’appelle la ‘compensation de latence’ et permet également de faire fonctionner Meteor en offline : si votre serveur est indisponible, le client va effectuer tous les traitements localement, donnant l’impression que tout fonctionne normalement. Lorsque la connection est rétablie, les requêtes en attente sont jouées sur le serveur et le client se met à jour. Ce mécanisme est détaillé par l’un des développeurs sur stack overflow.

Le protocole de communication client serveur est de leur cru et baptisé DDP (ce n’est donc pas du REST par exemple, bien que les développeurs indiquent qu’il est simple d’adapter DDP pour en faire du REST, ou le connecter à d’autres protocoles, mais cela manque un peu de doc là encore).


Packaging

Meteor vient avec son propre système de gestion de dépendances et de packaging. C’est bien fait et efficace mais cela ne s’appuie pas sur NPM qui est pourtant devenu le standard de facto de la communauté Node, et qui s’avère très très pratique. Un choix un peu discutable donc. Un certain nombre de packages sont déjà disponibles, dont backbone ou less par exemple. Côté déploiement, c’est vraiment efficace : un simple “meteor deploy” pousse votre application sur le service de hosting maison de Meteor (sur une url etant par défaut lenomdemonappli.meteor.com). Il est possible de sécuriser le déploiement de l’application avec un mot de passe (option -P).

Sécurité

L’un des points non traités pour l’instant, et non des moindres, est la partie sécurité/authentification. Pour cette version, on ne peut tout simplement rien faire dans ce domaine, donc une application mise en ligne peut voir sa base de données vidée en quelques secondes (l’API de la base étant exposée côté client, une petite requête dans la console javascript et c’est plié).

Licence

Un dernier mot sur la licence : Meteor est en GPL, licence virale par excellence. Donc tant que vous faites vous aussi du GPL et que vous redistribuez votre code pas de soucis, sinon vous êtes encouragés à contacter l’équipe de Meteor (entendez, éventuellement payer) pour une utilisation commerciale. Ca n’est pas fondamentalement gênant, et on comprend bien qu’ils veulent gagner leur vie. Bien d’autres outils connus utilisent cette double licence (MySQL par exemple), mais c’est finalement assez peu courants dans les projets Javascript, qui ont habituellement des licences plus permissives. La question qui se pose est : est ce que cela va limiter l’adoption et les contributions à Meteor? Cet article vous expliquera tout ça mieux que moi si le sujet des licences vous intéresse.

Edit : depuis l’écriture de ce post, la licence est passée en MIT. Comme quoi, le pouvoir de la communauté…


J’espère que cet article vous aura fait partager mon enthousiasme pour Meteor, bien que j’explique également les quelques choix qui font débat. Le meilleur moyen de vous faire votre avis est vraiment de regarder les quelques screencasts disponibles. Il y a d’excellentes idées dans cet outil, et nous allons voir de plus en plus de frameworks nous offrir ce genre de fonctionnalités pour faire des applications web bien différentes de ce que nous faisons actuellement.

Suivre

Recevez les nouvelles publications par mail.

Joignez-vous à 864 followers