All posts in Technologies Web

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

 

Transformation digitale des entreprises : l’expertise ne suffit pas !

Depuis plus d’une dizaine d’années, l’évolution des architectures logicielles a pris le virage du web. Cette transformation n’a pas été simple pour les entreprises. Ses détracteurs relevaient des failles de sécurité ou des problèmes de disponibilité. Ils se sont néanmoins laissés convaincre peu à peu par les apports incontestables des systèmes web tant en terme d’ergonomie – gage d’un engagement accru des utilisateurs – que de scalabilité. 

Cette dernière permet en effet d’ouvrir un potentiel quasi-illimité pour répondre aux enjeux de production de données, liées à la transformation digitale des entreprises et de leurs modèles de développement au global.

Traduire la réflexion stratégique en solutions informatiques concrètes

L’engagement de DocDoku sur des projets d’accompagnement à l’évolution technologique est visible à chaque étape de la transformation de l’entreprise. 

DocDoku a ainsi accompagné dernièrement la réflexion stratégique 
de l’informatique de la MSA, le GIE AGORA.
Le projet entendait expérimenter la faisabilité technique de la ré-écriture d’un outil de gestion avec la technologie ELECTRON. Pour rappel, ce framework a été la source du développement de nombreuses applications basées sur des technologies web comme WordPress ou Slack. 

Nicolas Cazottes, manager équipe Socles Techniques au sein du GIE AGORA, exprime son ressenti à l’issue du projet : « DocDoku a atteint l’objectif que nous avions fixé, à savoir la réalisation d’un éclairage pertinent sur une technologie que nous ne maitrisions pas a priori ». L’efficacité de l’action de DocDoku a permis au client de réaliser qu’en quelques semaines, « le résultat est significatif (…) et nous permet de disposer d’une solution technique détaillée pour notre potentielle future mise en oeuvre ».

Introduire la composante indispensable au succès

En parallèle de la maîtrise technique, une autre composante de la réalisation a retenu l’attention du GIE AGORA : les qualités humaines des intervenants, qui ont été déterminantes dans ce projet.

Nicolas Cazottes évoque alors qu’en plus de ses compétences techniques, « le consultant DocDoku a su spontanément s’adapter au contexte qui demandait beaucoup d’autonomie et une intégration rapide dans l’équipe en place ». Il insiste sur le fait que le consultant était «pédagogue et très bon communiquant », des softskills très recherchées dans les contextes actuels et qu’il a su « générer des échanges riches et constructifs avec nos équipes en interne ».

Franchir avec succès une étape d’un projet de transformation passe donc par l’expertise et l’expérience du prestataire retenu. Mais l’approche humaine est également indispensable et doit s’inscrire dans une logique collaborative et d’accompagnement au changement.

Retrouvez le cas Client complet MSA – GIA AGORA.

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 !

OW2con 2016 : les logiciels open source répondent aux besoins des entreprises

Morgan tech lead logiciel libre

Morgan, notre tech lead

OW2con’16 une huitième édition toujours autant plébiscitée

Morgan, notre tech lead s’est rendu à lOW2con’16 à Paris pour présenter notre plateforme digitale de gestion des données industrielles DocDokuPLM et plus particulièrement son approche PaaS au service du métier des industriels

Retrouvez sa présentation en vidéo ici et en pdf ici.

Pour cette édition l’événement s’est déroulé dans les locaux de Mozilla Paris.

Organisé pour la huitième année consécutive, OW2con’16 est l’événement communautaire annuel qui rassemble les experts, architectes logiciels, développeurs informatiques, chefs de projet et les décideurs de partout dans le monde. Il s’agit d’un événement célèbre par ses présentations et démonstrations de projets open source pertinents et ainsi que sa table ronde.

Du code au produit : relever le défi de la distribution du logiciel open source

Le thème d’OW2con’16 était « Du code au produit : relever le défi de la distribution du logiciel open source”. Un thème qui nous allait donc à merveille. Les présentations ont su démontrer la maturité du logiciel open source, ainsi que sa capacité à s’adapter et à répondre aux différentes problématiques des entreprises.

Qualité et gouvernance logicielle, accessibilité, plate-forme applicative d’entreprise, sécurité, IoT et mobilité ainsi que cloud computing sont des thèmes qui ont été largement abordés lors de cette conférence.

Projet d’innovation : revue de conception produit en temps réel sur le web

Depuis début 2014, nous travaillons en collaboration avec l’IRIT et plus particulièrement l’équipe Vortex, sur un projet de recherche appliquée dans le cadre de l’appel à projets régional Agile IT 2013.

Objectif du projet

L’objectif de ce projet était de créer un Environnement Virtuel Collaboratif (EVC) rendant accessible, manipulable et modifiable la maquette numérique des produits à tous les métiers de l’entreprise.

D’un point de vue logiciel, il s’agissait donc de développer le module web pour :

  • la visualisation collaborative 3D web temps réel,
  • l’édition et la manipulation web de pièces 3D.

Utilisable depuis un navigateur internet, sans qu’il soit nécessaire d’installer le moindre plugin, ce composant logiciel fait donc partie intégrante de notre plateforme digitale open source DocDokuPLM

Fonctionnalités et bénéfices

Bien plus qu’un simple partage d’écrans, notre plateforme permet donc désormais à la fois de réaliser le design du produit en 3D tout en gérant son cycle de vie depuis le même outil, accessible de n’importe où au travers de votre navigateur.

Véritablement extensible, ce module permet de gérer plusieurs EVC (room en anglais) avec plusieurs utilisateurs simultanés. Entièrement développé grâce aux nouveaux standards du Web, ce dernier ne nécessite aucune installation complémentaire.

De plus, ce module offre toute la sécurité que l’on peut en attendre : les participants invités sur l’EVC (ou la room) pour la revue n’auront jamais accès aux documents ou articles sur lesquels ils n’ont pas les droits d’accès.

La vidéo ci-dessous (filmée par téléphone) montre l’utilisation de cette fonctionnalité.

L’ordinateur de droite initie la réunion de groupe (EVC ou room) et invite les utilisateurs connectés (sur l’autre PC à gauche).

Nous vous invitons également à découvrir gratuitement tout cela en créant un compte et un espace de travail sur notre plateforme cloud : http://www.docdokuplm.net

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.

Point Eco – Cap sur l’usine du futur dans l’entreprise DocDoku

Lundi matin, nous avons eu l’honneur de recevoir dans nos locaux l’équipe de TLT avec Boris Georgelin ainsi que la CCI de Toulouse représentée par son Président Alain Di Crescenzo et son Vice-Président Bernard Ourmières.

Diffusé à plusieurs reprises sur TLT cette semaine, l’objectif était le tournage du magazine bimensuel « Point Eco », qui propose un regard expert sur l’économie à Toulouse.

Le thème abordé pour cette quinzaine étant l’usine du futur, Florent Garin et toute l’équipe ont été sollicités pour présenter les apports technologiques de DocDoku sur ce sujet d’avenir à construire dès maintenant :

Salon Innovation Connecting Show de Toulouse du 16 au 18/09/2014

Nous avons en effet exposé pendant ces trois jours sur le salon international Innovation Connecting Show de Toulouse du 16 au 18/09/2014.

Au programme de ce salon : conférences, pitchs et démonstrations de notre technologie sur notre stand.

J’ai également eu le plaisir de répondre aux questions de la ravissante Ginie sur le plateau TV du salon :

Interview Eric Descargues – plateau TV salon Innovation Connecting Show 2014 from DocDoku on Vimeo.

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

Grunt, Gulp, le match !

Comme nous en avions précédemment discuté ici et ici, Grunt et Gulp sont deux outils fantastiques, bâtis autour de la plateforme Node.js, qui nous permettent d’automatiser les tâches fastidieuses mais essentielles du développement front-web. Si la finalité de ces deux outils est la même, comment se distinguent-ils ?

La configuration

Gulp est un outil qui est tourné vers le code plutôt que vers la configuration. Les tâches Grunt sont configurées dans un objet de configuration alors que les tâches Gulp sont plutôt configurées en utilisant un style de syntaxe à la Node.js.
Le style de configuration de chaque plugin Grunt peut varier d’un plugin à un autre alors que les options de configuration des plugins sous Gulp sont bien plus standardisées.
Sachez aussi que l’on peut facilement se retrouver avec de très gros fichiers de configuration Grunt cela étant dû en partie à cause des configurations un peu trop over-kill pour des tâches qui restent simples.

L’exemple ci-dessous nous permet de constater la différence entre Grunt et Gulp pour automatiser la compilation de fichiers LESS:

Gruntfile.js

grunt.initConfig({
  less: {
      options: {
        paths: ["app/styles/css"]
      },
      files: {
        "build/styles/result.css": "app/styles/source.less"
      }
  },

  watch: {
    styles: {
      files: ['app/styles/{,*/}*.less'],
      tasks: ['less']
    }
  }
});

grunt.registerTask('default', ['less', 'watch']);

Gulpfile.js

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

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

Selon votre style, vous préférerez le code plutôt que la configuration ou inversement.
Personnellement, je trouve que le style de syntaxe de Gulp est plus lisible que celui de Grunt.

Les performances

J’ai pu constaté sur différents projets que Gulp était deux fois plus rapides que Grunt dans la majeure partie des cas.
Cela est du au fait que Gulp utilise le système de streams qui lui permet de monter les flux de données en mémoire, ce qui limite grandement les lectures/ecritures dans les fichiers.

Ce n’est pas le cas de Grunt, il n’utilise pas de streams mais va plutôt mulitplier les accès aux fichiers et avoir recours à des fichiers temporaires pour écrire les contenus d’une étape à une autre, ce qui peut être particulièrement coûteux en terme de performance suivant la taille du projet.

La communauté

Gulp est encore jeune et de ce fait il dispose d’une petite communauté et je trouve que la documentation est très souvent insuffisante.
Avec pratiquement 2 ans d’existence, Grunt se pose comme référence dans le domaine des task runners, il dispose d’une solide communauté et d’un peu moins de 3000 plugins (contre 650 pour Gulp).
Mais attention toutefois à Gulp qui pourrait s’imposer dans le futur car de plus en plus de developpeurs l’ont adopté pour les différentes raisons que nous avons pu voir.

Conclusion

La finalité de ces deux outils est la même : automatiser les tâches récurrentes pour nous faire gagner du temps !

Il faudra garder un oeil sur les évolutions futures de Grunt. Il se murmure que dans ses prochaines versions il pourrait prendre en charge le piping et les streams, ce qui réduirait considérablement son retard par rapport à Gulp en terme de performances. De ce fait, la configuration des plugins serait minime puisque nous pourrions nous passer totalement des fichiers temporaires.

Si vous devez faire un choix, il faut se demander quel style vous correspond le mieux. Est-ce que je prèfere un outil basé sur de la configuration ou sur du code ? À chaque style son outil, choisissez Grunt si vous êtes plus à l’aise avec de la configuration plutôt qu’avec du code, sinon choisissez Gulp.

Si au final vous avez du mal à faire un choix sachez que les deux cohabitent parfaitement !

grunt_logo gulp_logo
Grunt Gulp
3000 plugins 650 plugins
Configuration Code
Fichiers temporaires Streams
Grande communauté Communauté naissante
Rapide comme l’éclair
Documentations perfectible

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.

Quel éditeur JavaScript ?

JavaScript est devenu, qu’on le veuille ou non, un langage incontournable. Indispensable sur le poste client et plus précisément sur le navigateur, il prend sa place, peu à peu, sur le serveur avec notamment nodejs.

Bon nombre de développeurs sont donc amenés à écrire de plus en plus de JavaScript, pour cela il convient de s’équiper et de choisir un IDE adapté. Essayons de balayer les choix possibles.

Les IDE Java vétérans que sont Eclipse ou Netbeans supportent plus ou moins bien le JavaScript. On peut attribuer sur ce terrain un avantage à Netbeans qui s’en sort mieux que son rival de toujours. Dans la catégorie des environnements de développement généralistes, IntelliJ IDEA demeure un poids lourd. Il sait tout faire : du JEE, Android, Spring, Grails…et donc forcément aussi du JavaScript. JetBrains, l’éditeur, propose d’ailleurs une déclinaison de son logiciel phare, dénommé WebStorm, uniquement centré sur le JS, HTML et CSS. C’est un choix intéressant car moins onéreux qu’IDEA Ultimate Edition.

Au delà des outils historiques du développeur Java, d’autres éditeurs « pure player » ont fait leur apparition. Parmi ceux-ci Sublime Text tient le haut du pavé. Léger, performant, multiplateforme Sublime Text présente de nombreux avantages. Toutefois il pourrait dérouter les aficionados d’IDE traditionnels ; pour tirer la pleine puissance de Sublime il faut faire l’effort d’apprendre ses raccourcis clavier, de se plonger dans ses options de configuration et de parcourir la liste des plugins disponibles. Enfin, il faut savoir que si une version gratuite est disponible Sublime reste un logiciel propriétaire dont la licence coûte $70.

Pour ceux ne pouvant concevoir utiliser autre chose que des logiciels open source, je recommanderais d’essayer Brackets.

brackets

Il est proposé par Adobe et est développé lui même en JavaScript (il tourne sur WebKit). Assez jeune, il est néanmoins prometteur, il semble s’inspirer de Sublime avec sa barre latérale très ressemblante et son architecture modulaire visant à promouvoir un riche écosystème de plugins. L’édition de CSS avec une prévisualisation intégrée est particulièrement réussie. Une fonctionnalité intéressante de Brackets est son « Aperçu en direct » qui permet d’héberger les ressources du projet (fichiers JS, HTML, CSS…) sur un serveur embarqué (nodejs). Chaque modification est alors automatiquement prise en compte par le navigateur web sans devoir rafraîchir la page. En plus du gain de productivité que cela procure, servir les scripts JavaScript par HTTP évite les erreurs que l’on peut rencontrer en utilisant des URLs de type fichier.

Enfin, comment terminer notre petite liste d’outils sans parler des Chrome dev Tools. Connus de tous les développeurs web et disponible directement depuis le navigateur de Google, les dev Tools servent à examiner l’arbre DOM, le trafic réseau, positionner des points d’arrêt dans le code JavaScript…Bref, on ne présente plus ces fonctionnalités, essentielles à l’implémentation de clients HTML. Néanmoins depuis récemment Chrome s’est enrichi d’une nouvelle option le rapprochant encore un peu plus d’un éditeur de code. Effet depuis l’onglet « Sources », un simple clic droit permet de relier les ressources délivrer par le serveur à une arborescence locale de fichiers.

add-folder-to-workspace

select-folder

Une fois ce mapping établi, tout changement fait dans un source JavaScript ou CSS se persiste durablement par un rapide « Ctrl-s ». Plus besoin de copier/coller les modifications opérées dans Chrome pour les reporter dans le code.

Web 3D 2013

Cette année nous étions invités par Christophe Mouton, expert PLM chez EDF, à participer à la fameuse conférence web 3D. Après Las Vegas en 2012, l’édition 2013 se déroulait en Espagne à San Sebastian au Miramar Palace. Le cadre était donc vraiment très agréable, seul le temps, comme en témoigne la photo ci-dessous, n’était pas au beau fixe.

image

En plus de la rédaction d’un poster, j’ai pu présenter pendant près de 40mn un cas d’usage de notre solution DocDokuPLM. « Web 3D » oblige j’ai concentré mon discours sur la partie visualisation 3D de la maquette numérique. J’ai notamment expliqué les nombreuses optimisations que nous avons faites pour s’affranchir des limites intrinsèques des moteurs JavaScript des navigateurs.

Par exemple Chrome ne pouvant allouer plus de 1,4 Go de mémoire, nous devons enlever de la scène les objets non visibles dans le champ de la caméra. Nous avons également implémenté un système de type LOD (Level Of Detail) où chaque pièce d’un assemblage existe en différentes qualités de représentation, plus l’objet étant proche de la caméra meilleur sera son affichage.

Par ailleurs, j’ai moi même assisté à quelques belles sessions, notamment une sur le format XML3D concurrent du X3DOM qui par son héritage de X3D et VRML traine les lacunes inévitables de toutes technologies legacy. XML3D, conçu lui à partir de la feuille blanche, entend devenir le standard pour la 3D déclarative du web. Enfin, j’ai bien apprécié la démonstration de réalité augmentée s’appuyant sur WebRTC, domaine très prometteur que nous explorons déjà !

Retour sur le salon SIANE 2012 avec DocDokuPLM

Exposant pour la première année sur le salon SIANE (Salon des Partenaires de l’Industrie du Grand-Sud) qui avait lieu du 23 au 25 octobre 2012 au Parc des Expositions de Toulouse, je vous propose ici notre REX sur ce salon.

Stand SIANE-DocDokuPLM

Notre première participation était pour nous l’occasion de continuer de promouvoir au sein du tissu industriel régional, national et international notre solution innovante DocDokuPLM et donc également de capter sur le terrain les besoins des industriels en matière de PLM.

Nous avons ainsi rencontré un grand nombre d’industriels et de partenaires sur ce salon, ce qui nous a réellement permis de confronter les besoins concrets des entreprises avec notre solution innovante de PLM. Il est en effet toujours indispensable de garder à l’esprit que la technologie n’a de réelle valeur que si elle est au service des usages.

En résumé donc, je retiendrais que les industriels sont très captifs au fort ROI que propose notre solution Open Source.

En effet, nous avons noté que trois éléments technico-économiques ont retenu l’attention de tous nos visiteurs lors de ce salon :

– la possibilité de visualiseur tous types de modèles  3D  (Catia, Inventor, AutoCAD, NX…) sur tous types de terminaux (PC/Mac/Tablettes/Smartphones) directement dans le navigateur internet sans aucune installation ou plugin,
– notre modèle de coût non proportionnel au nombre de postes déployés puisque aucun déploiement nécessaire (donc pas de coût de licence, modèle Open Source), ceci permettant de ne pas limiter les usagers et les usages pour encore plus de ROI,
– la facilité d’intégration de notre solution moderne et résolument orientée web et cloud-ready avec l’existant (CAO, autre PLM, ERP, applications métiers…).

Mais nous avons surtout constaté que les avantages technico-écoonomiques de notre solution procurent une réelle valeur ajoutée métier au sein des industries puisque capables de susciter des nouveaux usages :

– pour le partage des données autour des modèles 3D dans un contexte d’entreprise encore plus étendue (entre clients, fournisseurs et partenaires) grâce au cloud,
– pour une meilleure information produit en situation de mobilité lors des phases d’assemblage et de maintenance,
– pour les managers souhaitant visualiser simplement l’avancement du produit, le montrer et communiquer atour de ce dernier,
– pour le marketing et les commerciaux pouvant enfin disposer simplement depuis n’importe où de la dernière version produit en clientèle !

Enfin, nous avons également relevé une fonctionnalité qui nous a été demandée à plusieurs reprises et qui sera donc prochainement incluse dans notre roadmap  : la possibilité d’effectuer des relevés ou mesures 3D des produits directement sur le modèle 3D, très utile pour les opérationnels mais également pour les utilisateurs devant réaliser des devis et tarifer selon les dimensions des solides.

Bilan extrêmement positif et enrichissant donc pour ce salon SIANE 2012 avec quelques contacts très intéressants à approfondir !

Pour information, le prochain salon où nous serons présent avec DocDokuPLM est un salon international plus orienté grands comptes de l’aéronautique et du spatial,du 4 au 6 décembre 2012 à Toulouse : Aeromart 2012.

Retour sur DevoxxFR

Jeudi 19 et vendredi 20 avril avait lieu à Paris la conférence DevoxxFR,  par et pour les développeurs java.

La première chose à souligner est l’immense succès de cette première grande conférence puisque nous étions 1250 personnes réunies à l’hôtel Mariott pour les deux derniers jours.

À l’occasion de la sortie des vidéos sur la plateforme Parleys, petit retour sur quelques conférences que j’ai eu l’occasion de voir.

Keynotes

Les deux keynotes qui m’ont particulièrement marquées sont celles de Neal Ford et de Patrick Chanezon.

Dans Abstraction Distractions, Neil Ford nous parle de l’empilement des couches d’abstractions qui envahissent notre quotidien sans qu’on y prête plus vraiment attention et qui peuvent parfois nous induire en erreur. Il nous conseille de toujours avoir à l’esprit ce qui se passe en dessous de la couche que l’on utilise.  Sa keynote est agrémentée d’anecdotes qui font sourire l’auditoire.  Du gros niveau !

Patrick Chanezon enchaîne ensuite avec le portrait d’un développeur en reprenant la trame de The Artist.  On suit le parcours d’un mec qui pendant plusieurs années est le roi du pétrole à coder du cobol dans des SI bien complexes dont seul lui a le secret (=période où Jean Dujardin est une star du cinéma muet).  Puis à l’arrivée de nouvelles technos sympa type mobile, cloud, html5 (=l’arrivée du cinémas parlant) le dev ne s’y intéresse pas et reste dans sa zone de confort.  Malheureusement pour lui ces nouvelles technos prennent de plus en plus de place et notre ami se retrouve rapidement dépassé et remisé au placard (=dépression de Jean Dujardin).

Mais finalement tout est bien qui finit bien car notre développeur se prend en main, réalise qu’il fait partie d’une communauté de passionnés, participe à des jugs et vient à Devoxx. Et finalement cela donne une keynote plutôt rafraîchissante et pleine d’humour.  Bien joué.

Play Framework 2.0

Un mois après la release de la version 2, Sadek Drobi, CTO de Zenexity et Guillaume Bort, cofondateur de Zenexity et créateur de Play Framework retracent l’histoire du web pour expliquer les fondements du framework.

Au départ, le web était constitué de pages statiques puis nous sommes passés dans une phase de langages dynamiques avec notamment PHP, il a fallu ensuite structurer tout ça et c’est à cette époque que sont apparus les premiers frameworks MVC. Plus proche de nous, on a assisté à la démocratisation d’Ajax qui nous a apporté la mise à jour des pages sans besoin de recharger le navigateur.

Aujourd’hui, une page est bien souvent constituée de fragments autonomes, « bindés » sur des flux de données.  Sadek et Guillaume prennent l’exemple de twitter.  Le besoin est réel de structurer ces flux car nous sommes en plein dans l’ère du web temps réel.

C’est sur ce constat qu’a été bâti Play Framework 2,  apporter un socle pour structurer l’interaction avec des streams de manière efficace.

Et voilà du coup ce qu’il est possible de faire : http://console-demo.typesafe.com l’explication ici : http://typesafe.com/products/console

La présentation continue avec comme leitmotiv « don’t fight the web » :  il ne sert à rien d’abstraire le web mais au contraire il faut bâtir en s’appuyant dessus.  Ce que l’on retiendra c’est que Play Framework est un framework stateless full stack qui embrasse le protocole http.

D’un point de vue personnel, cette présentation m’a donné envie d’explorer plus en détail la version 2 de Play, la version 1 apportait déjà beaucoup de fun dans les développements.  Chez DocDoku, nous l’utilisons d’ailleurs en production sur certains projets.

Behind the Scenes of Day-To-Day Software Development at Google

Petra Cross de Google vient nous parler des méthodes de développement chez Google, elle nous présente d’abord la hiérarchie type d’une équipe de développement puis nous parle des méthodes de travail.  On apprend que les maîtres mots sont ‘pragmatisme’ et ‘efficacité’. Par exemple l’équipe de Petra applique l’agilité dans le sens où ils utilisent un backlog de tâches, par contre ils ont totalement supprimé le standup meeting qui selon elle est une perte de temps  (j’entends les agilistes hurler !).

Un concept intéressant massivement utilisé chez Google est le ‘eating your own food’,  il s’agit d’utiliser soit même les produits que l’on conçoit. Ainsi  les googlers utilisent en interne les nighlty build de leurs produits ce qui permet d’avoir un feedback très rapide et de qualité sur les développements.

Conférences Android

J’ai eu l’occasion d’assister à deux conférences sur Android :  « Optimiser vos applications HTML pour Android » et « Android, Graphisme et Performance ». La première présentée par Romain Guy était un condensé de trucs et astuces afin d’optimiser l’IHM des applications Android.

Parmi les astuces et optimisations vues :

  • ViewStub : permet d’instancier (« inflater ») des vues au runtime uniquement si besoin. Cela limite l’empreinte mémoire des View qui peut être très coûteuse, par exemple une TextView vide prend 800 octets en mémoire.
  • StrictMode : outil de debug qui permet d’être notifié lorsqu’une opération lente est effectuée (écriture et lecture disque, opération réseau) ou lorsque une fuite mémoire est détectée (fuite sur les objets sqlite, objet closable non fermé, fuite des activity)
  • GridLayout : nouveau layout introduit d’ICS, moins gourmand que LinearLayout.  Pour les versions Android précédentes, Romain nous conseille RelativeLayout là où c’est possible plutôt que LinearLayout
  •  hierarchyviewer : outil du sdk qui permet de visualiser les grappes de vues et d’analyser leurs performances.

Romain nous détaille également une spécificité des AsyncTask : à partir de l’API level 12 les AsyncTask sont exécutées de manières sérialisées, les unes après les autres. Attention donc à ne pas ralentir la file d’exécution avec une tâche trop longue. Google justifie ce changement en expliquant que la programmation multithread est compliquée. Ils ont donc décidé de revenir sur le comportement par défaut pour limiter les bugs potentiels. Par contre si l’on est sûr que les tâches sont totalement thread-safe, il est tout a fait possible programmatiquement de revenir au comportement précédent.  Ainsi pour paralléliser les AsyncTask il suffit d’appeler :

task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);

La deuxième conférence Android est celle du googler Nicolas Roard qui travaille sur la webview Android. Nicolas nous délivre quelques astuces pour optimiser les performances dans une webview.  Il nous recommande de privilégier le CSS3 plutôt que le javascript lorsque l’on souhaite faire une animation.

Il nous explique également comment forcer la création de layers qui seront accélérés de façon hardware à partir de la version 3.  Pour cela il suffit d’appliquer une propriété css de transform 3D sur un élément.  On peut également créer un layer sur un scroll afin d’obtenir un rendu proche du natif grâce à la propriété css overflow scroll.

Attention tout de même, ces layers ont certes un rendu fluide mais ils sont très couteux. Il est donc conseillé de les utiliser avec parcimonie, par exemple uniquement durant une animation.

Nicolas termine par 25 minutes de questions/réponses. Les questions majoritairement posées tournent autour des performances de la webview qui souffre de la comparaison avec l’application Google Chrome pour Android.

Il nous explique que même si les deux s’appuient sur le moteur de rendu webkit, les contraintes ne sont pas les mêmes. La webview fait partie intégrante du framework, l’équipe a donc des contraintes quant à la mémoire et l’espace disque utilisé, la webview doit être compatible avec un maximum de choses et rétro compatible avec les précédentes releases. L’équipe de Nicolas a notamment fourni un effort de travail spécifique pour afficher correctement les widgets jquery mobile.

Toutes ces contraintes ne sont pas applicables à Chrome, Chrome est téléchargé depuis le market, c’est un choix de l’utilisateur, par conséquent ils ont beaucoup plus de liberté. Ils peuvent prendre des décisions, avancer vite et releaser souvent, chose impossible à faire pour la webview qui doit attendre une nouvelle version d’Android pour être mise à jour.

Nicolas conclut en nous assurant que les deux équipes mettent en commun beaucoup de travail et que tout le monde en tire un bénéfice.

Quickies

Entre midi et deux avaient lieu les quickies, un format court de conférences où en 15 minutes un speaker présente un sujet qui lui tient à cœur.

J’ai pu notamment voir Mathilde Lemee nous présenter son projet FluentLenium qui facilite l’écriture des tests Selenium en proposant une API très lisible (d’où le fluent !). Et effectivement quand on regarde l’exemple de base, on comprend tout de suite le test :

public class BingTest extends FluentTest {
    @Test
    public void title_of_bing_should_contain_search_query_name() {
        goTo("http://www.bing.com");
        fill("#sb_form_q").with("FluentLenium");
        submit("#sb_form_go");
        assertThat(title()).contains("FluentLenium");
    }
}

FluentLenium s’appuie sur les selectors CSS (même si les regex sont possibles). Enfin la dernière chose à noter sur le projet est qu’il est agnostique du framework d’assertion, ainsi jUnit Assert, Hamcrest et Fest-assert sont supportés.

Un deuxième quickie assez fun fut celui de Philippe Antoine qui s’est proposé de recoder en live le tetris de Martin Kleppe dont une version est jouable ici : http://jsbin.com/egiqul/49

La spécificité initiale de ce Tétris est d’être codé en 140 caractères, cette performance est possible en utilisant le décalage binaire.

Philippe se lance donc dans la réalisation du Tétris avec l’aide de la salle,  il en profite pour nous montrer comment faire du TDD en javascript avec QUnit. Un quickie original qui a bien plu.

Code Story

Pendant les deux jours de conférences, une équipe de quatre développeurs a codé en live une application from scratch. Chaque slot de conférence a donné lieu à un sprint. Ils ont fonctionné en pair programming avec un binôme codant pour la salle : ordinateur relié au vidéo projecteur en commentant le code.  J’ai eu l’occasion d’assister à un sprint, et par la même occasion j’ai pu découvrir Trello un super outil très souple et très simple de gestion de projet.

Conclusion

En tant que développeur, je me suis régalé durant ce Devoxx, j’ai pu satisfaire ma curiosité sur des sujets totalement nouveaux pour moi, comme me plonger dans des astuces plus techniques sur des sujets comme Android.  Si je devais dégager des keywords de cette grande et belle conférence, je choisirais :  cloud, mobile, html5 & javascript, NoSQL.

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.