All posts in Javascript

Décorateurs TypeScript et Web Components

Chez DocDoku nous animons des formations sur les outils et frameworks pour le développement front-end. Les trois principaux acteurs du marché sont aujourd’hui React, Vue et Angular. Ils offrent tous les trois la possibilité d’écrire du code de manière déclarative pour créer nos interfaces.Néanmoins, si nous devions réaliser une petite application, choisir un de ces framework pourrait paraître surdimensionné. Alors pourquoi ne pas réaliser un petit framework maison ? Il y a en effet plusieurs technologies à notre disposition pour ce faire. Nous vous proposons d’en étudier quelques-unes dans cet article.

Les deux technologies que nous allons aborder sont les Web Components (suite de technologies HTML5) et les décorateurs TypeScript qui vont nous permettre d’effleurer la surface de la réalisation d’un framework.

Les Web Components

Les Web Components sont un regroupement de trois technologies HTML5 :

  • Les custom elements
  • Les shadow root
  • Les templates

La principale caractéristique des Web Components est la possibilité de créer des éléments personnalisés, par exemple enrichir des éléments existants comme un champ de texte, un bouton, etc. C’est aussi la possibilité de créer de nouveaux éléments HTML (balises) avec un apport sémantique dans la construction de nos applicatifs, par exemple une nouvelle balise HTML my-todo-list qui construirait elle même ses sous-éléments. Nous parlons alors de custom elements.

Voici le code le plus simple pour définir une nouvelle balise :


class MyTodoList extends HTMLElement {
  constructor() {
    super();
  }
}
customElements.define("my-todo-list", MyTodoList);

Une autre caractéristique notable est l’isolement (encapsulation) de l’HTML sous-jacent. Notre nouvelle balise et son contenu enfant peuvent être totalement « détachés » du reste de la page et ainsi ne subir aucun impact du reste du DOM, avoir sa propre feuille de style locale, et ne pas impacter les autres éléments voisins. C’est le rôle du shadow DOM.

Finalement nous pouvons nous passer de l’écriture fastidieuse en JavaScript de la construction des éléments enfants en utilisant la balise template. Cette balise nous permet d’écrire le contenu de nos éléments personnalisés directement en HTML. Aussi nous pouvons combiner les templates avec l’utilisation de la balise slot afin de rendre nos templates paramétrables.

Utilisation de la balise template :



 

Instanciation d’un élément depuis ce template :


let template = document.getElementById("my-todo-list-template");
let templateContent = template.content;
document.body.appendChild(templateContent);

Exemple complet avec ces trois technologies :



   Hello todo list 1




class MyTodoList extends HTMLElement {
  constructor() {
    super();
    const template = document.getElementById('my-todo-list-template');
    const templateContent = template.content;

    this.attachShadow({ mode: 'open' }).appendChild(
      templateContent.cloneNode(true)
    );
  }
}
customElements.define('my-todo-list',MyTodoList)

Les décorateurs TypeScript

TypeScript est une extension du langage JavaScript qui nous apporte le confort des contraintes. Etudions ce code JavaScript :

var i = 2
i = "hello"

Nous ne savons pas lors de l’écriture du code si la variable i est un nombre ou une chaine de caractères et cela peut être fatal si nous ne faisons pas l’effort de vérifier son type lors de son utilisation.

Avec TypeScript nous sommes contraints à garder le type défini lors de l’initialisation.

let i : number = 2
i = "hello" // Interdit

Cet exemple nous montre seulement un des aspects de TypeScript. Ce qui nous intéresse ici est l’apport des décorateurs.

Imaginons que nous souhaitions automatiser l’exécution de code pour deux classes différentes. Par exemple une classe Voiture et une classe Animal qui auraient toutes les deux leur table associée dans la base de données.


class Animal {
  static {
    // code pour initialiser la table ANIMAL
  }
}

class Voiture {
  static {
    // code pour initialiser la table VOITURE
  }
}

Dans cet exemple, difficile de mutualiser du code, nos classes ont un bloc d’initialisation static qui peut contenir de plus en plus de choses, difficile de maintenir, etc.

Avec les décorateurs TypeScript nous pouvons imaginer écrire nos classes différemment :

@CreateTable("ANIMAL")
class Animal {
}

@CreateTable("VOITURE")
class Voiture {
}

Et pourquoi pas leur ajouter d’autres fonctionnalités, par exemple l’utilisation d’un utilitaire de log différent :

@CreateTable("ANIMAL")
@Logger(SomeLogger)
class Animal {
}

@CreateTable("VOITURE")
@Logger(AnOtherLogger)
class Voiture {
}

Derrière ces décorateurs se cachent en fait de simples fonctions. Celles-ci ne sont exécutées qu’une fois au chargement de la classe, et non lors de nouvelles instances de celles-ci.

const CreateTable = (name: string) => {
  return (target: Function) => {
    console.log(name)    // Le nom passé en paramètre, ici "ANIMAL"
    console.log(target)  // L'objet de type class, ici class Animal
    console.log(Object.getOwnPropertyDescriptors(target.prototype)) // Liste des méthodes
  };
};


@CreateTable("ANIMAL")
class Animal {
    _age: number
    get age(){ return this._age }

    manger(){
        //...
    }
}

/*
ANIMAL
[class Animal]
{
  constructor: {
    value: [class Animal],
    writable: true,
    enumerable: false,
    configurable: true
  },
  age: {
    get: [Function: get age],
    set: undefined,
    enumerable: false,
    configurable: true
  },
  manger: {
    value: [Function: manger],
    writable: true,
    enumerable: false,
    configurable: true
  }
}
*/

Début d’un framework basé sur ces deux technologies

En combinant les Web Components et les décorateurs TypeScript, nous pouvons alors imaginer réaliser un début de framework maison inspiré d’Angular.

Avec Angular, la création d’un composant est déclarative, et son utilisation très simple depuis un fichier HTML :


@Component({
  selector: 'app-my-component',
  template: '

{{ title }}

', styles: ['h1 { font-weight: normal; }'] }) class MyComponent { title = "Hello world" }

Nous allons nous inspirer de cela pour écrire un début de framework. Nous avons besoin d’un décorateur qui va créer automatiquement son shadow DOM depuis le template passé dans les arguments du décorateur « Component ».


// Paramètres du décorateur
interface ComponentOptions {
  selector: string; // Nom de la nouvelle balise
  template: string; // Le template associé
  style: string; // Un peu de css
}

// Fonction décorateur
function Component(options: ComponentOptions) {
  return function < T extends { new (..._args: any[]): HTMLElement } >(
    target: T
  ) {
    const cls = class extends target {
      constructor(..._args: any[]) {
        super();

        // Creation du shadow DOM
        let root = this.attachShadow({ mode: "open" });

        // Création des balises enfants avec EJS (moteur de template)
        root.innerHTML = options.template;

        // Ajout de style local
        let style = document.createElement("style");
        style.textContent = options.style;
        root.appendChild(style);
      }
    };

    // Enregistrement automatique en tant que custom element
    customElements.define(options.selector, cls);

    return cls;
  };
}

@Component({
  selector: "my-todo-list",
  template: `
   

<%= title %>

  • Do this
  • Do that
`, style: `h2 {color: blue}`, }) export default class HelloWorld extends HTMLElement { title = "Hello world !"; }

Bien entendu, notre framework maison est encore loin d’être complet. Nous aurions besoin d’y ajouter une détection des changements, du routing, une couche HTTP, etc. Seule la partie de création de composants et d’affichage a été abordée dans cet article.

ElasticSearch ILM et répartition des données

Description

La gestion d’une centaine de milliards de documents (données issues de logs applicatifs, équipements réseau, middlewares, etc.) s’avère coûteuse (machines, disques, espace de sauvegarde, etc.).
Pour alléger ce coût d’infrastructure nous devons distinguer les données brûlantes des données tièdes et froides (voir gelées). C’est ce que propose ElasticSearch avec l’ILM (Index Lifecycle Management). Nous vous proposons ainsi d’analyser sa mise en œuvre sur un cluster de production d’un de nos clients.
Les données considérées brûlantes doivent être exploitables dans des temps de réponse très courts, nous devons donc les placer sur des machines dimensionnées correctement. Les requêtes sur les données tièdes et froides n’ont pas besoin d’être aussi performantes, ces données peuvent donc automatiquement être déplacées vers des machines plus modestes grâce aux règles de rétention offertes par ILM.

Limitations des écrans dans Kibana et Cerebro

Kibana, l’interface graphique de la suite Elastic ne propose pas une vue synthétique de cette répartition. Nous pouvons obtenir cette information de répartition grâce à plusieurs requêtes, mais nous devons alors croiser les résultats, ce qui est fastidieux.
Cerebro, une interface graphique issue de la communauté open source, est excellent dans la visualisation de la répartition de la charge, mais ne propose pas cette visualisation au niveau du cycle de vie.
Même constat pour Elasticvue, qu’il s’agisse de sa version desktop, extension Chrome ou webapp.
Un moyen d’obtenir les informations souhaitées est donc de passer par l’API d’ElasticSearch.
Avec une première API nous pouvons obtenir les rôles des machines :

GET _nodes/settings?filter_path=nodes.*.roles,nodes.*.name

{
  "nodes": {
    "ECNRRDP2SUKmcu3s9qJgnA": {
      "name": "es3",
      "roles": [
        "data_cold",
        "ingest",
        "master"
      ]
    },
    "NXZNCa_BQ_SE613oSnDf-g": {
      "name": "es6",
      "roles": [
        "data_cold",
        "ingest",
        "master"
      ]
    },
    "jqmdwzdeQHG84601oQjpGw": {
      "name": "es1",
      "roles": [
        "data",
        "data_hot",
        "ingest",
        "master"
      ]
    },
    "4z2k13n8SZS4t2JmLielaQ": {
      "name": "es4",
      "roles": [
        "data",
        "data_hot",
        "ingest",
        "master"
      ]
    },
    "AFRMIIagRWK4Cu-ZhbLH2A": {
      "name": "es5",
      "roles": [
        "data_warm",
        "ingest",
        "master"
      ]
    },
    "sxljzKF-Q1app0VSkVgTxg": {
      "name": "es2",
      "roles": [
        "data_warm",
        "ingest",
        "master"
      ]
    }
  }
}

Puis avec une deuxième API nous pouvons récupérer le cycle de vie des indices (index au pluriel).

GET /*/_settings?filter_path=*.settings.index.routing.allocation.include,*.settings.index.uuid,*.settings.index.provided_name

{
  ".ds-my-index-1-2024.09.17-003772": {
    "settings": {
      "index": {
        "routing": {
          "allocation": {
            "include": {
              "_tier_preference": "data_hot"
            }
          }
        },
        "provided_name": ".ds-my-index-1-2024.09.17-003772",
        "uuid": "HyELPU6oTpC_EfskAxP5BQ"
      }
    }
  },
  ".ds-my-index-1-2024.09.17-003748": {
    "settings": {
      "index": {
        "routing": {
          "allocation": {
            "include": {
              "_tier_preference": "data_warm,data_hot"
            }
          }
        },
        "provided_name": ".ds-my-index-1-2024.09.17-003748",
        "uuid": "QNC-Z2loT4SCKFb2-LJKAw"
      }
    }
  },
  ".ds-my-index-1-2024.09.17-003714": {
    "settings": {
      "index": {
        "routing": {
          "allocation": {
            "include": {
              "_tier_preference": "data_cold,data_warm,data_hot"
            }
          }
        },
        "provided_name": ".ds-my-index-1-2024.09.17-003714",
        "uuid": "zIP72E-qTBSfKbZdAYmFEQ"
      }
    }
  },
  [...]
}

Et avec une troisième API nous pouvons restituer le détails des blocs de données correspondant aux indices :

GET /_cat/shards?format=json&h=index,node,state,prirep,docs

[
  {
    "index": ".ds-my-index-1-2024.09.17-003848",
    "node": "es1",
    "state": "STARTED",
    "prirep": "p",
    "docs": "120"
  },
  {
    "index": ".ds-my-index-1-2024.09.17-003848",
    "node": "es4",
    "state": "STARTED",
    "prirep": "r",
    "docs": "47"
  },
  {
    "index": ".ds-my-index-1-2024.09.17-003828",
    "node": "es5",
    "state": "STARTED",
    "prirep": "p",
    "docs": "29"
  },
  {
    "index": ".ds-my-index-1-2024.09.17-003828",
    "node": "es2",
    "state": "STARTED",
    "prirep": "r",
    "docs": "147"
  },
  [...]
]

En croisant les résultats de ces trois requêtes, nous pouvons donc savoir si un bloc de données d’un index « brûlant » est bien placé sur un noeud « brûlant ». Mais pour des milliers d’index, cela devient beaucoup plus laborieux.

Développement d’une solution de visualisation

Quelques lignes de JavaScript (64), d’HTML (80) et de CSS (118) plus tard et voici un aperçu d’un rapport réalisé sur un cluster ElasticSearch en local.

ElasticSearch ILM test

Résultat de l’analyse du cluster local

L’outil génère un fichier de rapport en format HTML, consultable depuis n’importe quel navigateur. Alors, en un coup d’œil on peut savoir si un bloc est à la bonne place.
Le code source est disponible sur Github.
Pour résumer ce que fait techniquement ce code source :

  • Lancement des 3 requêtes précédemment étudiées
  • Injection de ces données dans un moteur de template HTML
  • Sauvegarde du résultat dans un fichier HTML

Premier rapport réalisé sur une infrastructure de production et analyse

Ensuite, nous avons intégré l’outil dans une chaîne d’intégration continue de Gitlab pour automatiser la génération des rapports. Nous pouvons ainsi désormais nous interfacer avec le cluster à analyser et donc générer un premier rapport.
Quelques données sur la taille du cluster :

  • 10 machines ElasticSearch
  • 110 milliards de documents
  • 125 To de données stockées
  • 25 000 événements par seconde

Le premier rapport montre une répartition de la charge logique comme ci-dessous :

ElasticSearch ILM

Résultat de l’analyse du cluster de production

Les nœuds ayant le rôle data_warm reçoivent bien les blocs data_warm. Les nœuds ayant le rôle data (tout les rôles) reçoivent tout type de blocs.
Cependant ce n’est pas encore optimisé pour réduire les coûts car :

  • Il reste des blocs data_warm non alloués à des nœuds data_warm car ElasticSearch cherche l’équilibre en termes de nombre de blocs par machine.
  • Aucun bloc de données froides n’apparaît car les règles de rétention ne définissent pas de phase « cold ». Des nœuds data_cold doivent être ajoutés au cluster.
  • Il y a légèrement trop de données brûlantes en proportion, la durée de rétention en phase « hot » doit être revue à la baisse.

Evolution du cluster

Ainsi, après réflexions avec les équipes en charge de la maintenance du cluster, nous avons définit la cible à atteindre :

  • 3 nœuds cold (à venir)
  • 5 nœuds warm (node-3 node-9 node-10 node-1 node-2)
  • 2 nœuds hot warm master (node-4 node-5)
  • 3 nœuds hot ingest master content (node-6 node-7 node-8)

Les raisons de ces choix dépendent des caractéristiques des machines à disposition (CPU, disques, RAM).
Les mouvements de blocs vont être nombreux, et nous réfléchissons déjà à la procédure de migration afin de perturber au minimum le service. Il faut bien prendre en compte que l’espace disque pris par chaque bloc est de 50Go, et que chaque déplacement prend entre 30 minutes et 1 heure sur cette infrastructure réseau.
Nous avons ensuite planifié l’exécution de l’outil pour fournir un rapport tous les jours afin de suivre l’évolution de la répartition. Nous aurons donc un joli jeu de couleurs d’ici quelques semaines 😉

8 thématiques incontournables à connaître pour maîtriser HTML5

L’HTML va bientôt fêter ses 30 ans. Ce langage de balisage a beaucoup évolué depuis sa création, avec l’intégration de JavaScript et CSS (Cascading Style Sheets) qui sont venus grossir les rangs des technologies web.
Et côté utilisateurs, dynamiser dans son ensemble la navigation web.

Développer des applications web modernes comme le permet HTML5 et CSS3 ne s’improvise pas.
Voici le top 8 des sujets incontournables à connaître pour maîtriser ce langage :

  • Une brique essentielle : JavaScript
  • Les API de communication
  • Le stockage côté client
  • Graphisme et multimédia
  • Les nouveaux tags HTML5
  • La présentation avec CSS3
  • Architecture et conception
  • L’outillage et l’environnement de développement

Vous êtes Architectes, développeurs ou webmasters et certains de ces sujets vous échappent encore ?

Nous avons une piste pour vous permettre de mettre à jour rapidement vos compétences : rejoignez notre prochaine session de formation Développer des applications HTML 5.

Prochaines sessions HTML5 à Toulouse :
Du 26 au 28 février 2020 (dernières places disponibles!)
Du 18 au 20 mai 2020

Prochaines sessions HTML5 à Paris :
Du 22 au 24 janvier 2020
Du 18 au 20 mars 2020

 

DevFest Toulouse 2017 : passion et innovation

Merci aux 450 participants du DevFest et bravo à nos équipes pour avoir suscité l’interêt de nos visiteurs lors de cette journée dédiée aux développeurs !

Une occasion pour l’écosystème toulousain de se retrouver et d’assister à des conférences de pointe sur l’évolution du métier de développeur, le développement mobile ou encore l’IoT.

Chez DocDoku, nous encourageons nos collaborateurs à prendre part à cette journée.
Plusieurs membres de nos équipes ont ainsi participé aux conférences : un réel atout pour renforcer leur veille technologique, réseauter et trouver de l’inspiration sur les méthodologies et outils de demain.

Rendez-vous l’année prochaine !

Retour sur l’EclipseCon France 2016 (partie 2)

eclipsecon

Cet article fait suite à celui de Bertrand, afin de détailler certains sujets et présenter d’autres sessions auxquelles j’ai eu l’opportunité d’assister.

iotConnecting low power IoT devices with LoRa, MQTT, and The Things Network

De mon point de vue, l’IoT était vraiment à l’honneur cette année à Toulouse, notamment par la présence de The Things Network, ayant été invité par la Fondation Eclipse à donner un workshop et à tenir la première Keynote de la conférence.

Comme l’a mentionné Bertrand, cette équipe venue tout droit d’Amsterdam est en train de fédérer des communautés du monde entier autour de leur réseau dédié aux objets connectés, basé sur la technologie LoRa.

Alors qu’est-ce que LoRa ? Et qu’est-ce que The Things Network ?

LoRalora

D’après le site de la LoRa Alliance (traduit par mes soins) :

LoRa est un diminutif pour LoRaWAN™: Low Power Wide Area Network (LPWAN).

LoRa est donc une spécification de communication sans fil basée sur les fréquences radio ISM (https://en.wikipedia.org/wiki/ISM_band).

Cette technologie est tout particulièrement adaptée comme couche de communication pour les objets connectés en ce qu’elle permet la localisation et la mobilité des appareils, à basse consommation, sans grosse installation de départ, ainsi qu’une communication bi-directionnelle.

Avec une simple antenne disposée en haut d’un immeuble en milieu urbain, ou dans un environnement plus dégagé, LoRa permet de connecter un nombre impressionnant d’appareils sans dégradation, bien plus qu’un routeur sans fil (WiFi, Bluetooth) et en consommant bien moins d’énergie et en étant moins onéreuse qu’un routeur 3G par exemple.

Quelques exemples d’utilisation:

  • Réseaux électriques : prédire la consommation et produire de l’électricité en fonction des besoins réels
  • Logistique : livraison avec une localisation plus précise
  • Transport : appels d’urgence automatisés
  • Santé : appareils de mesure de constantes
  • Et tellement plus…

LoRa est en concurrence avec la technologie SigFox, que nous connaissons bien à Toulouse. Cependant son approche est différente, puisqu’à la différence de la technologie SigFox qui est propriétaire et induit des coûts de license, la spécification LoRa est libre.

Quelques relevés ayant été effectués par l’équipe de The Things Network, et autres caractéristiques :

  • Environnement urbain dense : 500m à 3km
  • Environnement rural : 10-50km (jusqu’à 92km lorsque très dégagé)
  • Jusqu’à 10.000 appareils par routeur
  • Jusqu’à 3 ans d’autonomie (à prendre avec des pincettes)
  • Très basse consommation (et pas de « handshake »)
  • License libre, en envoi et réception
  • Pas de pré-requis à l’installation d’un tel réseau
  • Couverture multiple (plusieurs routeurs peuvent relayer l’information).

Les appareils se connectant au réseau LoRa peuvent être classés en trois catégories :

  1. Liaison montante uniquement, l’appareil initie la communication et le serveur peut y répondre.
  2. L’appareil et le réseau se synchronisent sur une « fenêtre de tir » afin d’échanger des données.
  3. L’appareil est en écoute constante du réseau.

Evidemment les classes d’appareils influent sur leur consommation.

The Things Networkttn

The Things Network est une initiative née à Amsterdam, pour construire un réseau mondial et libre permettant la communication entre objets connectés.

Après une campagne de crowfounding, les membres de l’équipe ont commencé la création d’une plateforme Web afin de permettre la connection d’appareils via des brokers.

Tout le code source applicatif de The Things Network est open source et disponible sur Github, pour aller de pair avec leur engagement pour permettre une vaste adoption de ces technologies.

En parallèle, une entité commerciale propose des Starter kits à visée éducative ainsi que des routeurs afin de permettre aux gens d’équiper leurs quartiers, leurs villes et d’initier le mouvement pour une couverture mondiale.

Des communautés existent déja de part le monde, principalement en Europe pour le moment. Ces communautés sont parfois à l’origine des membres de l’équipe de The Things Network, qui voyagent beaucoup afin de faire connaitre la technologie LoRa et leur projet, et parfois il s’agit d’initiatives spontanées.

A titre personnel, j’espère qu’une communauté verra le jour prochainement à Toulouse.

What every Java developer should know about AngularJS

angular

Tout est dans le titre.

Cette session était dédiée aux développeurs plus habitués aux technologies backend et qui voulaient avoir une introduction au framework le plus en vogue actuellement côté frontend: AngularJS.

Ce workshop fut l’occasion de présenter succintement les controlleurs, les scopes, les services et autres directives, sous la forme d’un mini TP.

En tant que développeur fullstack ayant des bases d’AngularJS, je trouve que ce workshop a été bien mené, en plusieurs étapes afin d’itérer et d’introduire successivement de nouveaux concepts sur le petit cas concret présenté.

Les speakers ont même fait le choix de baser le code d’exemple sur TypeScript, afin de ne pas trop perturber leur audience plus habituée aux constructions objets classiques qu’à la spécification ECMAScript. Mes co-équipiers ont pu retrouver leurs petits dans un projet architecturé sur une base d’interfaces et d’implémentations, agrémenté de types génériques et autres héritages. Ils ont cependant eu affaire à la pauvreté du tooling Eclipse pour ce qui est du développement front.

Le tooling, parlons-en justement.

Tooling

Cette année les visiteurs ont pu assister à plusieurs sessions sur l’état des outils de développement intégrés à Eclipse. Voici un petit tour d’horizon des outils dont j’ai pu avoir un aperçu lors des sessions.

JSDT 2.0

Ce talk était dédié à la présentation du la nouvelle version des JavaScript Development Tools (JSDT), actuellement en cours de développement.

Les objectifs de JSDT 2.0 sont de supporter les méthodes et outils de l’état de l’art actuel du développement JavaScript moderne.

Actuellement, JSDT 2.0 profite d’un nouveau parseur bien plus efficace que le précédent, notamment capable de supporter la spécification ECMAScript 6.

Le reste des objectifs s’axent autour de l’intégration de gestionnaires de paquets (npm / bower), des « task builders » (grunt, gulp) ainsi que le support de Node.js et l’ajout d’outils de débugging et d’intégration avec les navigateurs, notamment Chrome.

The State of Docker and Vagrant Tooling in Eclipse

Chez DocDoku nous expérimentons déjà les outils Vagrant et Docker, notamment pour nos environnements de développement et d’intégration, afin de fournir à nos équipes une infrastructure immutable et des processus de déploiement répétables.

Dans cette présentation, j’ai pu avoir un aperçu de deux plugins, l’un pour l’intégration de Docker, et l’autre pour celle de Vagrant.

En l’état actuel, ces deux plugins présentent de nouvelles « perspectives » dans l’IDE Eclipse, qui permettent de faire tout (ou presque) ce qu’il est possible de faire en ligne de commande:

  • Créer et gérer ses « box » Vagrant.
  • Configurer son Vagrantfile.
  • Créer et configurer ses machines virtuelles.
  • Créer et gérer ses images Docker.
  • Lister et manager ses containers Docker.
  • Editer son Dockerfile.

Continuous Delivery: Pipeline As Code With Jenkinsjenkins

Pour ma part, j’étais très curieux de voir ce qui allait être présenté dans ce talk. La perspective de pouvoir gérer ses builds sous forme de « pipelines » de traitements et la notion de « Continuous Delivery » (ainsi que le « Continuous Deployment » mais c’est un autre sujet) m’intéressent beaucoup.

Alors de quoi s’agit-t-il ? Principalement de ce que l’on pourrait décrire par la capacité d’orchestration, d’interruptibilité et de résilience de vos jobs de build. Rien que ça…

Comme décrit dans les slides de la présentation, que ce passe-t-il lorsque vous avez des jobs de build assez complexes, inter-dépendants, nécessitant des inputs d’opérateurs et éventuellement nécessitant de tourner en parallèle ?

Hormis le fait de créer de multiples jobs individuels que vous lierez par la suite en une cascade de builds à la chaîne, il n’y a pas de solution clé.

C’est ce problème que propose de résoudre le « Jenkins Pipeline Plugins », qui est en réalité un regroupement de plugins permettant d’orchestrer vos builds de manière plus fine. A la base de ce plugin se trouve un DSL, le « Pipeline DSL », qui permet de décrire l’enchainement des builds, sous forme d’étapes, et d’y attacher des options de configuration, comme le parallélisme pour n’en citer qu’une.

Il devient alors possible, par exemple, de configurer plusieurs dizaines de jobs similaires (à quelques variables près) formant de briques de bases (les dépendances d’un job de build suivant) et d’ordonner l’exécution de tous ces builds en parallèle, avant l’exécution du build suivant qui en dépend. Tout en spécifiant que la séquence de build complète doit stopper en cas d’échec d’un seul de ces builds de base (fail-fast).

Pour l’anecdote, le speaker a présenté exactement cet exemple, sur un cluster de build mis à sa disposition par un fournisseur « cloud » :

  • 336 CPUs
  • 1.032 TiB RAM.

Evidemment on a tous le même dans notre garage…

Quoiqu’il en soit, j’étais assez intrigué par le choix d’un DSL, en opposition à une description déclarative via des fichiers de configuration.
Il est assez facile d’imaginer comment décrire via des structures de données simples telles que des maps et des collections, l’orchestration d’un job, et la description de chacune de ses étapes.

Je n’ai pas eu de réponse claire à ce sujet, si ce n’est le poids de l’histoire : la plupart des contributeurs étant des développeurs Java, un DSL (très proche de Java d’ailleurs) semblait un choix logique.

Conclusion

Pour ma première participation à un évènement comme celui-ci, je dois dire que je suis conquis. L’organisation était parfaite et la qualité des intervenants largement satisfaisante.

J’aurai plaisir à participer de nouveau à l’EclipseCon, et je recommande à tout développeur ayant la possibilité de s’y rendre, d’y aller sans hésiter.

L’ensemble des vidéos des Keynotes et des sessions est à retrouver sur la chaine Youtube de la Fondation Eclipse, ici.

EDIT 26/07/2016:

Un nouvel article est apparu sur le site de Fondation au sujet du tooling Docker, le voici: http://www.eclipse.org/community/eclipse_newsletter/2016/july/article2.php

Retour sur l’EclipseCon France 2016

StandDocDolu

Comme l’an dernier nous étions présents à l’EclipseCon France, événement incontournable dans le milieu du logiciel libre à Toulouse. Cette année encore l’organisation était sans faille, avec une grande diversité de thèmes (modélisation, IoT, devops…), chacun représenté par des intervenants de grande qualité.DocDokuPLM

DocDoku était en effet présent afin d’y présenter sa plateforme DocDokuPLM. Ceci a donné lieu à de nombreux échanges avec des acteurs industriels de Toulouse, ce qui a permis de constater que nous sommes au coeur de problématiques essentielles telles que l’interopérabilité, l’ouverture de la plate-forme, la sémantique des modèles.

Retour sur quelques présentations auxquelles j’ai eu la chance d’assister.

La modélisation à l’honneur avec Sirius, Papyrus et Capella

La modélisation de logiciels ou de systèmes est une des problématiques majeures développées au sein de la fondation Eclipse.

Étaient présents cette années, entre autres, le CEA avec l’outil Papyrus, Obeo avec l’outil Sirius, et PolarSys avec l’outil Capella.

Chaque outil a ses particularités. Pour ma part j’ai assisté au workshop sur Sirius animé par une équipe très motivée et maîtrisant parfaitement son outil. Sirius a la particularité de permettre la définition de Domain Specific Languages pour ensuite définir des modèles dans ce langage de modélisation.

Mention spéciale à l’équipe du CEA qui est venue avec une véritable usine en Lego de fabrication de petites voitures (en Lego elles aussi), la partie logicielle étant modélisée à l’aide de Papyrus.

Papyrus

Un IoT open source et innovant avec LoRa

L’IoT était très bien représenté, avec notamment la présence de Benjamin Cabé, animateur du meetup IoT-Toulouse, et Johan Stokking, de The Things Network qui a pour but de développer unLoRa réseau mondial et libre permettant la collecte et l’échange de données provenant d’objets connectés.

Ce projet est basé sur la technologie LoRa qui permet la communication à bas débit, par radio, alternative libre à SigFox, et soutenu par une alliance d’entreprises parmi lesquelles nous retrouvons Orange et Bouygues Télécom.

Eclipse Che : la révolution de l’environnement de développement

Eclipse Che, développé par Codenvy (connu pour son service d’IDE dans le cloud) est un outil permettant de gérer des environnements de développement virtualisés dans le cloud.

EclipseCheEclipse Che permet de mettre en place dans le cloud, non seulement un IDE, mais également un environnement d’exécution et de test automatisé du code.

Ceci permet de ne pas avoir à installer tout un environnement de développement/exécution/test sur la machine de chaque développeur. L’IDE en ligne renforce également le travail collaboratif : plusieurs développeurs peuvent éditer en même temps un même fichier (comme sur Google Docs).

L’équipe d’Eclipse Che est jeune et dynamique et de nombreuses améliorations sont à venir en ce qui concerne le pair programing et les tests JUnit.

TypeScript: du typage pour améliorer la scalabilité de JavaScript

TypeScript

Saurez-vous trouver les membres de DocDoku sur cette photo ?

TypeScript nous a été présenté par Sébastien Pertus, évangéliste technique chez Microsoft. TypeScript est en effet un projet libre développé par Microsoft, principalement par Anders Hejlsberg qui est aussi le principal inventeur de C#.

TypeScriptLogoCette présentation était à la fois pleine d’humour et abordait des questions techniques pointues avec des démonstrations de programmation très pertinentes.

TypeScript est à considérer comme un langage de programmation à part entière qui est trans-compilé en JavaScript. Ce nouveau langage ajoute à JavaScript de nombreuses fonctionnalités de typage comparables à ce qu’on retrouve dans le langage Java. On peut citer le typage statique, les classes, les interfaces…

De nombreuses fonctionnalités ajoutés par TypeScript sont maintenant présentes dans ECMAScript Edition 6, mais TypeScript conserve une longueur d’avance en proposant par exemple la notion de décorateur qui permet de programmer avec des annotations. D’autres améliorations sont prévues dans la future version de Javascript comme par exemple les non nullables types.

Tuleap : l’ALM open source

Enfin, l’aspect gestion de cycle de vie des applications/gestion de projet était également présent avec Tuleap développé par Enalean. Tuleap propose un outil de gestion de projet complet intégrant tous les aspects de tous les processus de développement (Cycle en V, Kaban, Scrum, Extreme Programming etc):

  • Intégration des principaux systèmes de configuration  (Git, SVN, CVS)
  • Intégration continue (Jenkins)
  • Wiki
  • Revue de code
  • Gestionnaire de bugs
  • Gestionnaire de post-it configurable style Trello.

 

Encore un grand merci à tous les organisateurs et conférenciers de cet événement et à l’année prochaine !

Le meilleur d’AngularJS et de Cordova : ngCordova

 cta-image

ngCordova

Si vous voulez développer rapidement une application Phonegap/Cordova sans vouloir utiliser toute la stack mean.io ou ionic, je vous conseille vivement ngCordova.

L’idée est d’encapsuler des plugins Phonegap/Cordova dans des services AngularJS. Mais dans quel but exactement… ?

Ne pas ré-inventer la roue

Bénéficiant d’une communauté active, ngCordova implémente la plupart des plugins nécessaires (photo, network, vidéo…). Trouver son bonheur parmi tous ces plugins n’est donc pas chose difficile. En quelques étapes d’installation, notre plugin est prêt à être utilisé et s’intègre parfaitement dans nos contrôleurs AngularJS. Pas besoin donc de créer soi-même l’encapsulation de ces services, si ce n’est pour savoir le faire.

Installation

L’installation de ngCordova se fait de la même façon que n’importe quel autre composant bower.

bower install ngCordova

Les sources sont téléchargées et copiées dans le sous-répertoire bower_components.

bower_components/ngCordova/
├── bower.json
├── CHANGELOG.md
├── dist
│   ├── ng-cordova.js
│   ├── ng-cordova.min.js
│   ├── ng-cordova-mocks.js
│   └── ng-cordova-mocks.min.js
├── LICENSE
├── package.json
└── README.md

Les sources de ngCordova sont maintenant prêtes à être injectées dans votre application AngularJS. Pour cela, il faut renseigner le fichier dans index.html et la dépendance dans votre fichier app.js.

index.html

<script src="lib/ngCordova/dist/ng-cordova.js"></script>
<script src="cordova.js"></script>

app.js

angular.module('myApp', ['ngCordova'])

Et voila !

Utilisation

Tous les services ngCordova sont directement injectables dans vos composants AngularJS, par exemple pour utiliser le service des dialogues :

module.controller('MyCtrl', function($scope, $cordovaDialogs) {

  $cordovaDialogs.alert('message', 'title', 'button name')
    .then(function() {
      // Le bouton a été cliqué, écrire le code correspondant ...
    });

});

Et c’est la même chose pour tous les autres services : autre exemple pour utiliser le service de fichiers et des photos :

module.controller('MyCtrl', function($scope, $cordovaFile) {

    $cordovaFile.getFreeDiskSpace()
      .then(function (success) {
         // success in kilobytes
      }, function (error) {
          // error
      });

});

module.controller('MyCtrl', function($scope, $cordovaMedia) {

    var media = $cordovaMedia.newMedia("/src/audio.mp3").then(function() {
        // success
    }, function () {
        // error
    });

    media.play();

});

Il devient alors très facile d’imbriquer tous ces composants afin de construire une application HTML5 riche. Toutes les fonctionnalités de base sont couvertes et sont disponibles sur Github.

ngCordovaMocks

Tester son code sur du vrai matériel n’est pas toujours possible. Pour cela, il nous faut une solution pour tester ses composants sur notre navigateur préféré. C’est là qu’intervient ngCordovaMocks.

Comme son nom l’indique, cette librairie vas nous permettre de “mocker” les appels à certains services.

L’installation se fait de la même manière que pour ngCordova : via bower.

bower install ng-cordova-mocks

Ensuite, il faut rajouter le script dans sa page :

<script src="lib/ngCordova/dist/ng-cordova-mocks.js"></script>

Et dans son fichier app.js :

angular.module('myApp', ['ngCordovaMocks'])

Ceci dit, on ne peut pas ajouter ngCordova et ngCordovaMocks sur la même page, et il devient très pénible de devoir changer ces deux lignes à chaque changement d’environnement. Pour cela on va utiliser gulp (site officiel) et son plugin gulp-preprocess (npm) pour éviter de le faire manuellement. Pour une installation et utilisation de gulp, voir cet article.

La page html devient alors :

<!-- @if NODE_ENV='DEVICE-DEVELOPMENT' -->
<script src="lib/ngCordova/dist/ng-cordova.js"></script>
<!-- @endif -->

<!-- @if NODE_ENV='DESKTOP-DEVELOPMENT' -->
<script src="lib/ngCordova/dist/ng-cordova-mocks.js"></script>
<!-- @endif -->

Le fichier app.js devient :

// @if NODE_ENV == 'DEVICE-DEVELOPMENT'
angular.module('myApp', ['ngCordova'])
// @endif

// @if NODE_ENV == 'DESKTOP-DEVELOPMENT'
angular.module('myApp', ['ngCordovaMocks'])
// @endif

Et le gulpfile associé :

gulp.task('device-development', function() {
    gulp.src('./www/gulp_preprocess_me/*.js')
    .pipe(preprocess({context: { NODE_ENV: 'DEVICE-DEVELOPMENT'}}))
    .pipe(gulp.dest('./www/js/'));

    gulp.src('./www/gulp_preprocess_me/index.html')
    .pipe(preprocess({context: { NODE_ENV: 'DEVICE-DEVELOPMENT'}}))
    .pipe(gulp.dest('./www/'));
});

gulp.task('desktop-development', function() {
    gulp.src('./www/gulp_preprocess_me/*.js')
    .pipe(preprocess({context: { NODE_ENV: 'DESKTOP-DEVELOPMENT'}}))
    .pipe(gulp.dest('./www/js/'));

    gulp.src('./www/gulp_preprocess_me/index.html')
    .pipe(preprocess({context: { NODE_ENV: 'DESKTOP-DEVELOPMENT'}}))
    .pipe(gulp.dest('./www/'));
});

En une ligne de commande vous pouvez maintenant choisir d’utiliser la libriaire ngCordova pour un développement sur mobile, ou bien ngCordovaMocks pour un développement sur desktop.

gulp device-development
gulp desktop-development

Attention quand même au déploiement : ne surtout pas envoyer la librairie des mocks en production 🙂

Conclusion

Pour rapidement utiliser ngCordova et ses plugins, une phase de configuration et d’outillage est nécessaire et peut s’avérer un peu longue. Néanmoins, une fois cette étape réalisée, l’installation de nouveaux plugins, leur utilisation, et leur déboggage sont très simplifiés. Toutes les documentations sont disponibles sur http://ngcordova.com/docs/plugins/ et sur les dépôts des plugins. Maintenant, à vos claviers…

Architecturer ses applications JS à l’aide du pattern MVVM

Pourquoi imposer une architecture à nos applications ?

Nos projets en JavaScript deviennent de plus en plus complexes : par leur taille, par leur fonctionnement et par leur coût de développement.

Le nombre d’outils et de librairies accessibles aux développeurs ne cesse de grandir et ce n’est pas en 2015 que la cadence va s’arrêter. Il est donc de plus en plus facile de se perdre et de rendre notre code illisible, difficilement maintenable et évolutif.

Toute notre problématique est là : rendre nos applications scalables pour les :

  • Maintenir
    -> Facilement améliorer le code courant
    -> Rendre son code compréhensible de tous
  • Adapter
    -> Inclure de nouvelles librairies
    -> Etendre, changer des parties
  • Debugger
    -> Tester chaque partie de manière indépendante
  • Développer plus rapidement
    -> Chaque développeur peut travailler en parallèle.

Le pattern MVVM va nous aider à résoudre ces problèmes tout en nous simplifiant la vie.

Pattern MVVM

Le pattern MVVM est un dérivé du célèbre modèle de conception MVC.

L’ancêtre MVC

L’idée principale du MVC, signifiant Model-View-Controller, est de découper l’application en trois parties interconnectées :

  • Model: représente les données reçues du serveur
  • View: contient l’ensemble des vues affichées à l’utilisateur
  • Controller: contient la logique de l’application

MVC

Le Modèle définit la structure des données et communique avec le serveur.
La Vue affiche les informations du Modèle et reçoit les actions de l’utilisateur.
Le Contrôleur gère les évènements et la mise à jour de la Vue et du Modèle.

Nous avons un premier découpage de l’application qui nous permet déjà de répondre à certaines de nos problématiques. En identifiant clairement les parties logiques, nous pouvons plus facilement maintenir notre application et la tester.

Mais qu’en est-il de l’adaptation et de l’évolution de notre application ? Si le modèle de données est amené à changer, nous devons obligatoirement modifier l’ensemble de nos entités.

Qu’apporte alors le pattern MVVM et que signifie-t-il ?

Principes du MVVM

MVVM est l’acronyme de : Model-View-ViewModel.

On pourrait donc simplement croire qu’on a remplacé le nom Controller par ViewModel. Mais si nous reprenons le schéma précédent avec le pattern MVVM, nous obtenons les interactions suivantes :

MVVM-2

La Vue reçoit toujours les actions de l’utilisateur et interagit seulement avec le ViewModel.
Le Modèle communique avec le serveur et notifie le ViewModel de son changement.

Le ViewModel s’occupe de :

  • présenter les données du Model à la Vue,
  • recevoir les changements de données de la Vue,
  • demander au Model de se modifier.

Data Binding

La Vue n’a donc plus aucun lien avec le Model. Ainsi le ViewModel s’occupe entièrement du cycle de modification de ce dernier. Il réalise à la fois la réception et l’envoi des données à la Vue. On parle alors de « data binding ». Les informations affichées sont liées entre deux entités et mises à jour en temps réel.

Ce dernier mécanisme est la clef du pattern MVVM. Il nous permet de découpler les différentes parties de notre application en étant capable de la faire évoluer de manière modulaire.

Dans le schéma suivant, nous pouvons voir qu’un même Modèle peut notifier plusieurs ViewModel de son changement. Ainsi ces ViewModel vont à leur tour indiquer à leur Vue de se rafraîchir.

mvvm-sample-2

Si la Vue n°2 modifie le Model, la Vue n°1 sera automatiquement mise à jour.

Du fait de cette indépendance entre la Vue et le Modèle, nous pouvons modifier ou remplacer les différents composants visuels sans impacter le cœur de notre application. Nous pouvons également changer, améliorer la logique de notre application à travers le ViewModel sans toucher à la Vue et au Model.

Presenter

Le pattern MVVM est également cité comme une extension du MVP : Model-View-Presenter.

La structure de données que nous recevons du serveur n’est pas forcément celle à afficher à l’utilisateur. Il est néanmoins conseillé de garder cette structure initiale pour pouvoir l’exploiter à d’autres moments.  Le ViewModel peut présenter à la Vue, une autre structure ou des données formatées différemment.

Cet aspect du MVVM va nous permettre de facilement modifier nos services et donc notre Modèle sans toucher à la Vue. Seul le ViewModel devra se réadapter pour fournir à la Vue les mêmes informations.

Un autre avantage est la possibilité de mocker nos Webservices dans le ViewModel. Ainsi nous pouvons travailler sur notre IHM en parallèle de la mise en place de nos WebServices.

Implémentations

Il existe de nombreux frameworks Javascript, qui permettent de développer des applications MVVM et qui fournissent des outils pour réaliser un data-binding.

Voyons comment au travers de trois frameworks : KnockoutJS, AngularJS et ExtJS, nous pouvons créer une application TodoList. Notre exemple sera volontairement simple pour faire apparaître les différents mécanismes du MVVM.

Notre application sera composée de deux vues :

Vue 1 :
Un formulaire d’édition composé de :
– Un bouton : au clic une nouvelle tâche est ajoutée.
– Un input texte : affiche et édite la tâche en cours.
– Un label : affiche le nombre de tâches.

Vue 2 :
Une liste de label : chaque label affichera le titre d’une tâche.
Au clic sur un label, la tâche courante sera modifiée pour afficher dans le formulaire, le titre sélectionné.

Notre modèle sera composé de deux « classes » :

Une classe Task, pour définir une tâche, composée d’un titre

Une classe Setting contenant :
– La tâche courante à éditer.
– La liste de toutes les tâches crées.

class-2

KnockOutJS

KnockoutJS est une libraire Javascript, qui peut facilement s’intégrer à une architecture déjà existante. Elle propose plusieurs outils pour simplifier et automatiser  la mise à jour de l’UI lorsque les données changent.

Model

On définit les deux classes. Chaque propriété doit être attribuée à partir des méthodes « observables » de KnockOutJS. L’appel à ces méthodes va permettre d’enregistrer ces données pour écouter leur modification.

var Task = function (title, index) {
    this.title = ko.observable(title);
};

var Setting = function() {
    var task = new Task("new task");
    this.currentTask = ko.observable(task);
    this.tasks = ko.observableArray([task]);
};
var setting = new Setting();

ViewModel

Les ViewModel contiennent :

  • le modèle, également écouté par KnockOutJS via ko.observable.
  • des données calculées via la méthode ko.computed, qui vont permettre d’étendre le modèle de base.
  • la logique de la Vue.

Chaque ViewModel s’occupe d’une partie logique côté IHM.

// ViewModel associé au formulaire d’édition d’une tâche
var FormViewModel = function () {
    // charge le modèle dans le ViewModel
    this.setting = ko.observable(setting);
    
    // ajoute une nouvelle tâche dans la liste
    // et change la tâche courante avec celle-ci
    this.addNewTask = function() {
        var currentTask = new Task("new task");
        this.setting().tasks.push(currentTask);
        this.setting().currentTask(currentTask);
    }.bind(this);

    // retourne le nombre de tâches
    // propriété calculé, étendant le modèle
    this.remainingCount = ko.computed(function () {
        return this.setting().tasks().length;
    }.bind(this));
};

// crée le ViewModel et l’applique à la bonne vue
var formViewModel = new FormViewModel();
ko.applyBindings(formViewModel, document.getElementById("form"));

// ViewModel associé à la vue de la liste des tâches
var ListViewModel = function () {

    // charge le même modèle
    this.setting = ko.observable(setting);

    // change la tâche courante
    this.editTask = function(item) {
        this.setting().currentTask(item);
    }.bind(this);
}

// crée le ViewModel et l’applique à la bonne vue
var listViewModel = new ListViewModel();
ko.applyBindings(listViewModel, document.getElementById("list"));

View

La Vue, décrite en html, récupère les données et les méthodes depuis le ViewModel. A l’aide de la propriété data-bind, nous déclarons toutes nos liaisons à des données et des méthodes.

// formulaire d’édition d’une tâche
<div id="form">

    // méthode addNewTask définit dans le ViewModel
    <button class="add" data-bind="click: $root.addNewTask"></button>

    //bind la tâche courante depuis le ViewModel
    <input id="new-todo" data-bind="value: setting.currentTask.title , valueUpdate: 'afterkeydown' " autofocus>

    //bind le nombre de tâches ajoutées
    <strong data-bind="text: remainingCount">0</strong>

</div>


//liste des tâches
<div id="list">
    <ul id="todo-list" data-bind="foreach: tasks">
        <li>
            <label data-bind="text: title, event: { click: $root.editTask }"></label>
        </li>
    </ul>
</div>

Le tag « input » affiche et modifie la valeur currentTask.title.

L’objet currentTask est aussi affiché dans la liste, via la propriété tasks du Modèle Setting.

Ainsi lorsque l’utilisateur clique sur un tag « label », le titre de la tâche s’affiche dans l’input du formulaire. Si ce dernier modifie cette valeur, le label de la liste est automatiquement mis à jour.

AngularJS

AngularJS n’est plus vraiment à présenter. La framework JS made in Google n’implémente pas à proprement parlé le pattern MVVM. On utilise le $scope comme ViewModel. On parle alors plus de MVW, pour Model-View-Whatever. L’important ici est de séparer la Vue et le Modèle.

Model

Nous n’avons pas besoin de créer de structure de Model spécifique. Angular se rappelle des valeurs précédemment stockées et envoie un évènement si elles sont différentes. Il nous suffit alors d’instancier un objet avec les propriétés que nous voulons utiliser. On peut également utiliser les Services d’AngularJS pour initialiser nos modèles depuis un serveur et les fournir ensuite au ViewModel.

//initialisation de la première tâche
var task = {title : 'new task'};

//créer un objet global contenant
//un tableau de tâches
//et la tâche courante
var setting = {};
setting.currentTask = task;
setting.tasks = [task];

ViewModel

Côté ViewModel, nous nous rapprochons de ce que peut produire KnockOutJS. C’est pourquoi on compare souvent ces deux frameworks pour créer des applications MVVM. Nous déclarons deux ViewModel, qui garde une référence sur le même objet setting, qui est ajouté un $scope.

angular.module('myApp', [])

    //ViewModel utilisé par le formulaire
    .controller('FormViewModel', ['$scope', function($scope) {

        //charge le modèle dans le ViewModel
        $scope.setting = setting;

        //méthode d’ajout d’une tâche
        $scope.addTask = function() {
            var newtask = {title : "new task"}
            $scope.setting.tasks.push(newtask);
            $scope.setting.currentTask = newtask;
        };

        //retourne le nombre de tâches
        //la propriété calculée, permet d’étendre le modèle
        $scope.nbtasks = function() {
            var count = 0;
            angular.forEach($scope.setting.tasks, function(todo) {
                count += 1;
            });
            return count;
        };
    }])

    //ViewModel utilisé par la liste
    .controller('ListViewModel', ['$scope', function($scope) {

        //charge le même modèle
        $scope.setting = setting;

        //méthode permettant d’éditer une tâche
        $scope.editTask = function(task) {
            $scope.setting.currentTask = task;
        };
    }]);

View

Les Vues, décrites en HTML, déclarent leur ViewModel et indiquent quelles données et méthodes vont être liées. Encore une fois seule la syntaxe diffère de KnockoutJS. On utilise la propriété ng-model ou des doubles accolades pour lier le modèle à la vue.

//formulaire d’édition d’une tâche
<div ng-controller="FormViewModel">
    <span>nb tasks : {{nbtasks()}}</span>
    <form ng-submit="addTask()">
        <input class="btn-primary" type="submit" value="add new task"/>
    </form>
    <input type="text" ng-model="setting.currentTask.title" size="30"/>
</div>

//liste des tâches
<div ng-controller="ListViewModel">
    <ul>
        <li ng-repeat="task in setting.tasks">
            <span ng-click="editTask(task)">{{task.title}}</span>
        </li>
    </ul>
</div>

ExtJS 5

ExtJS dans sa version 5 propose une implémentation revisitée du MVVM . En plus du ViewModel, il introduit une quatrième entité : le ViewController.  Associé à une unique Vue, le ViewController va permettre de gérer le comportement et la logique de la Vue, alors que le ViewModel se cantonne au rôle de Presenter.

2.3.1  Model

Nous déclarons une tâche et un setting, avec la syntaxe ExtJS. Nous créons aussi  une collection de tâches et une collection de settings. Cette dernière va nous permettre de récupérer les settings n’importe où. De plus nous utilisons cette collection pour ajouter des méthodes de manipulation sur le Modèle.

//structure d’une tâche, composée uniquement d’un titre
Ext.define(‘Task’, {
    extend: 'Ext.data.Model',
    fields: [{
        name: 'title',
        type: 'string',
        defaultValue : 'new task'
    }]
});

//donnée globale de l’application
//contient la liste de toutes les tâches
//et la tâche courante
Ext.define(‘Settings', {
    extend: 'Ext.data.Model',
    fields: [{
        name: 'currentTicket',
    },{
        name: 'tasks',
    }]
});

//définit une collection de tâches
Ext.define(‘Tasks, {
    extend: 'Ext.data.Store',
    model : 'Task
    storeId : tasks
});

//définit une collection de settings
//cette collection ne contiendra qu’un seul élément
Ext.define('SettingsStore', {
    extend: 'Ext.data.Store',
    storeId : 'settings',
    model : 'Settings',

    //méthode appelée au chargement de l’application 
    load : function() {

        //ajoute un seul element Settings
        var settings = Ext.create('Settings');
        settings.set(tasks, Ext.create('Tasks'));
        this.add(settings);

        //ajoute une première tâche
        this.addTask();
    },

    //ajoute une nouvelle tâche
    addTask : function() {
        var newTask = Ext.create('Task');
        this.getAt(0).get('tasks').add(newTask);
        this.setCurrentTask(newTask);
    },

    //met à jour la tâche courante
    setCurrentTask : function(task) {
        this.getAt(0).set('currentTask', task);
    }
});

ViewModel et View Controller

Le ViewModel n’est utilisé que pour présenter les données.

Le ViewController est utilisé pour charger les données dans le ViewModel et gérer la logique de la Vue. Chaque ViewController récupère le même modèle Settings et le fournit à son ViewModel.

Ainsi les deux vues manipuleront le même objet sans interagir ensemble.

//ViewModel du composant graphique FormTask
Ext.define('FormTaskViewModel', {
    extend: 'Ext.app.ViewModel',
    alias: 'viewmodel.formtask',

    //data à binder
    data : {
        settings : null
    },

    //data “calculée” à binder
    formulas : {
        nbTasks : function(get) {
            return get('settings.tasks').count();
        }
    }
});

//ViewController du composant graphique FormTask
Ext.define('FormTaskViewController', {
    extend: 'Ext.app.ViewController',
    alias: 'controller.formtask',

    //méthode appelée automatiquement à l’initialisation
    init : function() {

        //récupère le model settings
        var setting = Ext.getStore('settings').getAt(0);

        //charge le modèle dans le ViewModel
        this.getViewModel().set('settings', setting);
    },

    onClickCreateButton : function(cmp) {
        //ajoute une nouvelle task
        this.getViewModel().get('settings').store.addTask();
    }
});

// ViewModel du composant graphique GridTicket
Ext.define('MVVM.view.GridTicketViewModel', {
    extend: 'Ext.app.ViewModel',
    alias: 'viewmodel.gridticket',
    data : {
        settings : null
    }
});

//ViewController associé à la vue GridTicket
Ext.define('MVVM.view.GridTicketViewController', {
    extend: 'Ext.app.ViewController',
    alias: 'controller.gridticket',

    init : function() {

        //récupère le model settings
        var setting = Ext.getStore('settings').getAt(0);

        //charge le modèle dans le ViewModel
        this.getViewModel().set('settings', setting);
    },

    onSelectRow : function(cmp, model) {
        //modifie la tâche courante par celle sélectionné
        this.getViewModel().get('settings').store.setCurrentTicket(model);
    }
});

View

Les Vues en ExtJS sont décrites dans des objets. Chaque Vue déclare son ViewModel et son ViewController, mais n’appelle jamais ses instances. Il suffit alors d’utiliser le mot clef ‘bind’ pour lier la valeur dans le ViewModel à celle de la Vue.

//Composant graphique définissant le formulaire d’édition d’une tâche
Ext.define('FormTask', {
    extend: 'Ext.form.Panel',

    //déclaration du viewcontroller associé
    controller: 'formtask',

    //declaration du viewmodel associé
    viewModel: {
        type: 'formtask'
    },

    items : [{
        xtype : 'button',
        label : 'Create new Task',
        //fonction définit dans le ViewController
        handler : 'onClickCreateButton'
    },{
        xtype : 'textfield',
        fieldLabel : 'Title',
        name: 'title',
        allowBlank: false,
        bind : {
            //affiche le titre de la tâche courante
            value : '{settings.currentTask.title}'
        }
    }, {
        xtype : 'label',
        //affiche le nombre de tâches
        bind : '{nbTasks}'
    }]
});

//Composant graphique définissant la liste des tâches
Ext.define('MVVM.view.GridTicket', {
    extend: 'Ext.grid.Panel',
    xtype : 'grid-ticket',
    controller: 'gridticket',
    viewModel: {
        type: 'gridticket'
    },

        // bind la collection de tâches
        // le composant Ext.grid.Panel s’occupe 
        // d’afficher automatiquement toutes les tâches
    bind : {
        store : '{settings.tickets}'
    },

    //affiche dans cette colonne la propriété ‘title’ de chaque tâche
    columns : [{
        text: 'Tasks',
        dataIndex : 'title'
    }],

    //au clic sur une ligne, on exécute la méthode 'onSelectRow'
    listeners : {
        select : 'onSelectRow'
    }
});

Conclusion

Chaque framework a sa propre manière et syntaxe pour implémenter le pattern MVVM. Le principe d’indépendance entre la Vue et le Modèle est à chaque fois respecté et tous proposent des outils pour mettre en place un data-binding entre la Vue et le ViewModel.

Chaque framework a ses propres avantages :

  • KnockoutJS est peu intrusif en étant une simple librairie.
  • AngularJS est le plus simple syntaxiquement et le plus éprouvé par la communauté.
  • ExtJS pousse encore plus à découper notre application et à structurer notre code.

Mais le pattern MVVM n’a pas que des avantages. Pour de petits projets, il peut être contre-productif de proposer une telle architecture.  De plus pour de très gros projets avec de nombreux ViewModel, le data-binding peut consommer la mémoire de manière considérable.

Il n’est donc pas interdit d’implémenter son propre mécanisme de liaison, tant que l’on respecte le découpage complet entre la Vue et le Modèle.

Grunt, Gulp, quel outil pour automatiser vos tâches front-end ? (2/3)

Gulp

Tout comme Grunt, Gulp est un outil d’automatisation JS (javascript task runner) basé sur la plateforme NodeJS qui va nous permettre d’améliorer notre workflow et d’optimiser nos applications web. Qui dit automatisation dit plus de temps pour se concentrer sur d’autres choses plus importantes comme produire du code de qualité ! Grâce à cet outil, nous allons pouvoir automatiser des tâches telles que la compression d’images, les tests unitaires ou encore la minification.

Depuis sa sortie, Gulp a suscité un grand intérêt auprès de la communauté des developpeurs front-end du fait de la simplicité de sa mise en place et de sa configuration qui lui permette d’être très facilement lisible et maintenable.

Installation

Puisque Gulp est basé sur NodeJS, ce dernier doit être installé sur votre poste avant d’installer Gulp.

Vous pourrez installer NodeJS sur votre machine sans trop de difficulté en vous rendant ici.

Une fois NodeJS installé, vous pourrez installer facilement Gulp en utilisant npm (Node Packet Manager).
Il faut lancer la commande suivante :

$ npm install -g gulp

Cette commande aura pour effet d’aller récupérer Gulp depuis le registre npm et de l’installer globalement dans votre système.
Pour installer gulp uniquement au niveau de votre projet, il ne faut pas mettre l’option -g dans la ligne de commande.

Configuration

À ce niveau, Gulp est installé sur votre système et est prêt à être utiliser dans nos projets.

Tout comme nous l’avions vu dans notre précédent article, il faut avoir mis à la racine de notre projet un fichier package.json dans lequel on va renseigner toutes nos dépendances de développement .

À présent, il faut installer Gulp en tant que dépendance du projet, ce qui permettra aux autres membres de la team, de partir du bon pied lorsqu’ils feront un « npm install » !
La commande à exécuter est la suivante :

$ npm install --save-dev gulp gulp-util

L’option « –save-dev » dans la ligne de commandes va permettre de mettre à jour les dépendances de développement dans le fichier package.json en ajoutant une référence à gulp et gulp util. Si vous omettez cette option, le fichier package.json ne sera pas mis à jour avec la dépendance en question et vous serez obligé de la rajouter manuellement.

Maintenant nous allons pouvoir installer tous les plugins qu’il nous faut pour automatiser l’éxécution des tâches !
Étant donné que les plugins de Gulp sont des modules de node, nous allons utiliser npm pour les installer.

$ npm install --save-dev gulp-less gulp-watch

La ligne de commande ci-dessus va installer le plugin pour compiler nos fichier LESS et va nous permettre de surveiller les fichiers que l’on modifie dans le but d’y associer un traitement particulier. De plus, une entrée sera automatiquement ajoutée au niveau de devDependencies dans le fichier package.json

{
  "devDependencies": {
    "gulp": "^3.7.0"
    "gulp-less": "^1.2.3",
    "gulp-watch": "^0.6.5"
  }
}

À l’heure actuelle, Gulp dispose d’un peu plus de 600 plugins. Certains feront sûrement votre bonheur, tels que :

Gulpfile.js

De la même façon que Grunt, toute la configuration de Gulp réside dans le fichier gulpfile.js situé à la racine du projet.
Nous allons donc commencer par dire à Gulp de quels plugins nous avons besoin pour executer les tâches :

var gulp  = require('gulp'),
    util  = require('gulp-util'),
    less  = require('gulp-less'),
    watch = require('gulp-watch');

Par la suite nous allons specifier quelles tâches nous allons exécuter. Dans notre cas nous allons faire 2 choses :

  • Une tâche « less » qui va compiler les fichiers LESS et placer le résultat à un endroit donné
  • Une tâche « default » qui va exécuter la tâche « less » puis surveiller toutes modifications des fichiers de type .less, si une modification survient la tâche « less » sera rejouée

Pour définir une tâche Gulp, on utilise la méthode task() suivante :

gulp.task('less', function () {
  gulp.src('app/styles/**/*.less')
    .pipe(less())
    .pipe(gulp.dest('build/styles'));
});

La méthode task() prend en entrée un nom sémantique « less » qui définit le nom de la tâche et ensuite une fonction anonyme qui contient le traitement en question.

Nous allons décomposer cette méthode ligne par ligne :

gulp.src('app/styles/**/*.less')

La méthode src() va nous permettre de spécifier le chemin vers les fichiers avec l’extension LESS et va les transformer en un stream qui sera diffusé aux plugins pour effectuer les traitements.

.pipe(less())

La méthode pipe() va utiliser le stream provenant de src() et le passer aux plugins référencés. Ici en l’occurrence, le plugin less recevra le stream de fichier pour les traiter.

.pipe(gulp.dest('build/styles'))

La méthode dest() va nous permettre de spécifier l’emplacement où l’on souhaite écrire le résultat du traitement. Les fichiers LESS compilés seront donc placés dans le dossier styles du build.

Pour exécuter cette tâche, il suffira de se placer à la racine du projet et de lancer la commande :

$ gulp less

Si nous ne spécifions pas de tâche dans la ligne de commande, la tâche « default » sera lancée.

gulp.task('default', function() {
  gulp.run('less');
  gulp.watch('app/styles/**/*.less', function() {
    gulp.run('less');
  });
});

La tâche « default » ci-dessus a pour but de lancer la tâche « less » (compilation de LESS pour avoir en sortie une feuille de style CSS) puis surveiller toutes modifications des fichiers LESS. Si une modification survient, la tâche « less » sera re-éxecutée. De cette façon, on n’a plus à se soucier de compiler les fichiers LESS à chaque fois qu’on les modifie !

Là est toute la puissance de Gulp, une syntaxe très séduisante, claire et facilement lisible et un gain de performance grâce à un système de stream qui évite d’écrire dans un dossier temporaire.
Il n’y a pas autant de plugins disponibles pour Gulp que pour Grunt, c’est un fait, mais la communauté n’en est pas moins active et grandissante, il ne serait pas étonnant que Gulp s’impose comme le prochain standard de l’automatisation JS des tâches, mais d’ici là quel outil choisir ?

La suite, dans notre prochain article consacré au match Grunt / Gulp.

Grunt, Gulp, quel outil pour automatiser vos tâches front-end ? (1/3)

Introduction

En tant que développeurs front-end, nous sommes amenés à réaliser nos projets web en ayant à l’esprit un certain nombre de bonnes pratiques telles que :

  •  La compression des feuilles de styles CSS et la minification des scripts Javascript pour qu’ils soient le plus léger possible en production
  •  L’optimisation des images en réduisant leur poids sans altérer leur qualité
  • Auto-générer des sprites d’images
  •  S’assurer que les scripts Javascript ne contiennent pas d’erreurs de syntaxe
  •  Retirer les alertes/console log en production
  •  etc …

Si  nous voulons avoir une webapp optimisée, nous devons réaliser absolument toutes ces tâches. Des tâches répétitives, quelque soit le projet, et fastidieuses car elles ne se limitent pas seulement aux 4 citées en exemple plus haut.

Automatiser ce genre de tâches est donc devenu quasi-vital dans le but, d’une part, de gagner un temps considérable à ne plus tout faire manuellement et d’autre part, d’être sûr de l’optimisation du code livré en production (minification, obfusquation etc…). Tout cela en moins de temps qu’il ne faut pour préparer votre café préféré !

Si votre quotidien est synonyme de tâches à répétition et que vous avez cherché à un moment donné à les automatiser, vous avez forcément entendu parler de Grunt ou encore de Gulp qui s’imposent comme des références en la matière d’outils d’automatisation Javascript.

Outils Javascript d’automatisation

Les outils js d’automatisation des tâches s’appuient sur Node.js, une plateforme software écrite en Javascript orientée serveur qui fut créé il y a quelques années. Elle utilise le moteur V8 de Google Chrome qui va analyser/exécuter ultra-rapidement du code js et qui fonctionne suivant un modèle non bloquant (programmation asynchrone). Node.js a ouvert la voie, entre autres, à de nouveaux outils d’automatisation tel que Grunt et c’est une vraie chance pour nous autres développeurs front-end que d’avoir à notre disposition ce genre d’outils pour :

  • déployer rapidement un serveur de développement
  • rafraîchir sa page lorsque l’on modifie un fichier
  • compiler les templates
  • bouchonner les données renvoyées par un web service,
  • supprimer tous les commentaires dans le code
  • minifier les feuilles de styles
  • obfusquer les scripts JS
  • etc…

Il n’y a pratiquement pas de limites à ce que l’on peut faire !

Grunt

Grunt est un outil basé sur des tâches exécutées en ligne de commande qui va grandement accélérer nos workflows classiques de développement en réduisant notre effort lors de la préparation des sources pour les mises en production.

Dans la plupart des cas, sachez que lorsque vous effectuez manuellement une tâche, son équivalent automatique existe sous forme de plugin Grunt comme par exemple la minification et la concaténation de scripts.

Grunt est également capable de gérer des tâches qui ne sont pas forcément liées à Javascript comme la compilation CSS depuis SASS ou LESS.

Enfin sachez qu’il dispose d’une incroyable communauté de développeurs et d’une énorme base de plugins mise à jour très régulièrement. Vous n’êtes donc pas seul à vous lancer dans l’aventure !

Installation

Comme évoqué précédemment, Grunt est basé sur Node.js. De ce fait il doit être installé sur votre machine pour que Grunt puisse fonctionner. L’installation de Grunt se fait via le npm (Node Packet Manager), il suffit d’ouvrir votre invité de commandes et d’exécuter cette instruction pour installer Grunt :

$ npm install -g grunt-cli

Package.json

Package.json est un fichier à créer à la racine de votre projet, il va vous permettre de tracker et d’installer toutes les dépendances liées au développement. Ainsi, tous les membres de votre team disposeront des toutes dernières versions des dépendances. Ce qui en fin de compte permet de garder un environnement de développement constamment synchronisé.

{
  "name": "Example",
  "description": "Un package de test",
  "version": "0.0.1",
  "private": "true",
  "author": "Prenom Nom ",
  "devDependencies": {
    "grunt": "^0.4.5"
  }
}
$ npm install

La commande ci-dessus va dire à npm d’aller récupérer toutes les dépendances qui sont listées dans devDependencies puis de les installer dans le dossier node_modules.
 Dans cet exemple, si la commande réussie, Grunt version 0.4.5 ou supérieure sera installée localement dans le projet.

Gruntfile.js

Comme le fichier package.json, le fichier Gruntfile.js doit être placé à la racine du projet. Il contient toute la configuration des tâches automatiques à exécuter lorsque l’on exécute grunt depuis l’invité de commandes.

module.exports = function(grunt) {

    /* 1. Toute la configuration. 
     * L'ordre n'a pas d'importance.
     */
    grunt.initConfig({
        pkg: grunt.file.readJSON('package.json'),

   /* 2. La configuration du plugin cssmin pour la minification de css.
    * Une sous tâche build qui va minifier index.css dans style.css
    */
        cssmin: {
                   build: {
                             src: 'app/css/index.css',
                             dest:'build/css/style.css'
                          } 
                }
    });
    
    /* Chargement du plugin
     * 3. On dit à Grunt que l'on compte utiliser le plugin grunt-contrib-cssmin.
     */
    grunt.loadNpmTasks('grunt-contrib-cssmin');

    /* Déclaration des tâches
     * On dit à grunt ce qu'il faut faire lorsque l'on execute "grunt" dans l'invité de commandes.
     */
    grunt.registerTask('default', ['cssmin']);

};

À partir de maintenant il n’y a plus qu’à exécuter la ligne de commande suivante dans notre invité de commandes pour minifier notre feuille de style :

$ grunt

Et voila ! Notre feuille de style a été minifiée en une fraction de seconde. grunt-command-line
Imaginez maintenant toutes les tâches que l’on peut automatiser exactement avec la même simplicité! 
Pour vous en rendre compte, je vous invite à jeter un œil à l’impressionnant listing de plugins disponible pour Grunt. Pas moins de 3000 plugins pour faciliter notre quotidien.

Grunt est donc un outil très simple d’usage, qui consiste en un fichier de configuration js facilement lisible, dans lequel on paramètre les plugins que l’on souhaite utiliser pour automatiser nos tâches.
Sachez qu’il n’est pas le seul sur le marché… 
La suite, dans la deuxième partie de ce dossier qui sera consacrée au petit nouveau, Gulp !

Bien démarrer ses projets web avec Yeoman

yeoman

Introduction

Avec autant d’outils disponibles pour les développeurs web aujourd’hui, il peut parfois être difficile de comprendre comment tout cela s’assemble et fonctionne.

Construire la structure de son projet « from scratch » et organiser son code et ses dépendances n’est pas toujours évident. Yeoman va nous aider à résoudre ce problème, et vous lancer sur de bons rails en générant la structure de base de votre projet (scripts, librairies, tests, …). Le code généré par yeoman est le fruit de l’aggrégation des meilleurs pratiques du web qui ont évoluées au sein de l’industrie.

Dans cet article, vous allez apprendre comment exploiter Yeoman afin de pouvoir de créer des applications web solides.

Qu’est-ce que Yeoman ?

Yeoman est une collection de trois outils : Yo, Grunt, et Bower. Combinés ensemble, ces outils fournissent tout ce qu’un développeur a besoin pour démarrer son projet.

Yo – CLI tool for scaffolding out Yeoman projects

Yo est un outil qui est utilisé pour échafauder une nouvelle application. Il permet de créer la structure du projet, l’organisation des feuilles de style, des scripts, des ressources.

Grunt – The javascript task runner

Grunt est un outil basé sur nodejs qui vous permet d’exécuter des tâches écrites en javascript. Par exemple, avec grunt vous pouvez automatiser les builds, les tests, et le développement. Grunt s’appuie sur un grand nombre de plugins parmi lesquels on peut trouver.

Bower – A package manager for the web

Bower est un outil qui va vous permettre de gérer vos dépendances et librairies, les installer automatiquement et surtout les garder à jour, de sorte que vous n’avez pas à les télécharger manuellement.

Installation

Prérequis

Un guide complet est accessible directement ici, pour ceux qui voudrait rapidement l’essayer assurez vous d’avoir installé Nodejs , Git et optionnellement Ruby et Compass (si vous voulez utiliser scss)

Ensuite, en ligne de commande, installer yo

npm install -g yo

Comme yo dépend de grunt et bower, ces derniers seront installés automatiquement !

Maintenant, il faut installer un générateur de projet :

npm install -g generator-webapp

Certains générateurs embarquent yo, grunt et bower, et les installeront si nécessaire automatiquement. La liste des générateurs se trouve sur npm

Utilisation

Une génération de projet avec yeoman se déroule ainsi :

mkdir MyWebApp	&& cd $_       # Crée un dossier nommé MyWebApp et se place dedans
yo webapp                      # Génère une structure de base
bower install underscore       # Installe les dépendances et librairies
grunt                          # Pour builder le projet	
grunt test                     # Lance les tests
grunt serve                    # Lance un serveur

Générateurs

Plusieurs générateurs sont disponibles via npm. Parmi les frameworks les plus utilisés, on trouve facilement les générateurs associés :

Backbone

npm install generator-backbone

yo backbone 			# Génère la structure
yo backbone:model article	# Génère un modèle
yo backbone:collection article  # Génère une collection
yo backbone:router article      # Génère une route
yo backbone:view article	# Génère une vue
grunt serve 			# Lance votre projet dans un serveur local

AngularJS

npm install generator-angular
yo angular 					# Génère la structure
bower install 					# Installe les dépendances
grunt serve 					# Lance votre projet dans un serveur local

Emberjs

npm install generator-ember 	
yo ember 					# Génère la structure
bower install 					# Installe les dépendances
grunt serve 					# Lance votre projet dans un serveur local

Et si cela ne vous suffit pas, vous pouvez aussi écrire votre propre générateur et ainsi optimiser d’avantage votre productivité, ou contribuer à la communauté en soumettant votre générateur sur npm. Pour les plus courageux suivre le guide ici

Plugins grunt

Une multitude de plugins va vous permettre d’augmenter votre productivité et automatiser vos tâches : validation du code, minification et obfuscation du code source, zip des sources, live reload, lancer des commandes shell, déployer sur un serveur … Voir ici pour tous les plugins disponibles.

Pour installer un plugin grunt, éditer le fichier package.json à la racine du projet pour ajouter le plugin. Exemple :

{
	"name": "MaWebApp",
	"version": "1.0.2",
	"dependencies": {},
	"devDependencies": {
		"grunt": "~0.4.1",
		"grunt-contrib-copy": "~0.4.0",
		"grunt-contrib-clean": "~0.5.0",
		"grunt-contrib-compress": "~0.7.0",
		"time-grunt": "~0.2.1"  ## Ajoutez vos dépendances après cette ligne
	},
	"engines": {
		"node": ">=0.8.0"
	}
}

Ensuite, dans votre terminal :

npm install

Cela va installer automatiquement les nouvelles dépendances que vous avez ajoutées.

Conclusion

Ceci n’était qu’un aperçu des possibilités qu’offre Yeoman. En utilisant les générateurs de base et en inspectant le code généré, vous comprendrez mieux comment tout ces composants fonctionnent ensemble, et vous ouvrira surtout de nouvelles perspectives dans vos workflows.

GWT est-il toujours pertinent ?

Il y a 3 ans, lorsqu’il s’agissait de définir le socle technique d’une nouvelle application web, en l’absence de contraintes exogènes, GWT (Google Web Toolkit) était pour nous un choix naturel pour le développement de la partie « front web ». Les arguments massue de l’époque étaient le manque de portabilité de JavaScript, son faible niveau d’outillage par rapport à Java et aussi la grande difficulté que l’on peut rencontrer à développer une large application avec un langage aussi dynamique et faiblement typé que JavaScript. Face à ces écueils, GWT représentait le rempart absolu, la solution ultime.

Aujourd’hui toutefois, les choses ont de mon point de vue quelque peu évolué.
Tout d’abord, le support de navigateurs obsolètes, comme Internet Explorer 6 par exemple, n’est plus l’obsession des DSI qui par contre tiennent de plus en plus à ce que leurs applications offrent également un bon rendu sur les dispositifs mobiles et tactiles.

Ensuite, l’écosystème JavaScript a progressé. Si les jQuery et autres Prototype existaient déjà il y a 3-4 ans, des frameworks de plus haut niveau tels que Backbone.js, JavaScriptMVC, s’appuyant d’ailleurs sur jQuery, ont fait leur apparition. Ceux-ci aident à fournir un cadre à la structuration des applications de grandes tailles, point délicat lorsque le volume de JavaScript devient important. Des moteurs de templates côté client comme mustache ou des starter kits, à l’instar de bootstrap twitter, sont également venus enrichir l’offre JavaScript.

Côté GWT aussi les lignes ont bougé, passés les premiers instants d’émerveillement, quelques défauts se sont fait sentir. Le premier d’entre eux est l’absence d’une vraie bibliothèque de widgets solide et pérenne. GWT étant avant tout un socle technique, Google laisse à la communauté ou aux éditeurs tiers le soin de bâtir sur son framework. Ainsi Ex GWT, SmartGWT, Vaadin pour ne citer qu’eux disposent de composants de plus haut niveau, prêt à l’emploi. Malheureusement ces bibliothèques n’ont jamais donné pleinement satisfaction : licence peu « business friendly », adhérence importante, problème de qualité. Au final, la sagesse recommande de se contenter de GWT et de tout développer soi-même…
Par ailleurs, GWT, au fil des versions, a gagné en complexité, le pattern « activities/places » pour être correctement employé exige que les développeurs soient bien formés ; RequestFactory, CellWidget sont des nouveautés qu’il conviendra à nouveau d’assimiler et qui contraindront la migration d’un bon nombre d’applications.
En outre, si GWT parvient à éloigner complètement JavaScript du développeur, il ne le préserve pas de CSS qui tend à prendre de plus en plus d’importance et devient une nouvelle source d’incompatibilité entre les navigateurs. On touche finalement au coeur du problème : GWT est une abstraction imparfaite ; cette encapsulation des technologies web ne dispense pas les développeurs d’en comprendre les arcanes.

Conclusion
Pour répondre très concrètement à la question posée par ce billet : oui GWT est toujours pertinent surtout s’il s’agit d’implémenter une grosse application de gestion avec des développeurs de niveau hétérogène. Par contre, pour une application innovante, faisant un usage prononcé des dernières fonctionnalités HTML5 (3D, communication temps réel) il est avantageux d’être en prise directe avec le browser (bare metal).
Quoi qu’il en soit, ce qui était annoncé à la sortie du framework de Google ne s’est pas produit : JavaScript n’est pas devenu l’assembleur du web. Qu’on le déplore ou non, ce langage est aujourd’hui incontournable, son champ d’application dépasse d’ailleurs largement le cadre du navigateur (CommonJS). Aucun développeur IT ne peut continuer à le bouder.

Lemmings en Javascript

Il est tout possible de faire en AJAX même le fameux jeu lemmings.
Preuve est faite qu’avec du javascript, du css et beaucoup d’ingéniosité on parvient à implémenter dans un navigateur des applications de bureau.
Il faut toutefois relativiser l’exploit, si le jeu d’origine pouvait tourner sur un 286, la version web requière une configuration musclée !
De plus, la partie son n’est pas portable mais s’appuie sur QuickTime ou Windows Media Player.

Le débat pour ou contre AJAX reste donc entier !