Bonnes pratiques de développement JavaScript Titre présentation Conférencier François Béliveau Romain Dorgueil
A propos de nous... François Béliveau Développeur web depuis 8 ans Utilise symfony depuis 2 ans Membre de l équipe SensioLabs Romain Dorgueil Utilisateur symfony depuis 0.4 SensioLabs depuis Décembre 2007 Développeur Core-Team
Bonnes pratiques? Rapidement, on passe en revue le côté serveur. Romain
Bonnes pratiques Découplage Moins de code par classe / par fichier Romain (speed)
Bonnes pratiques Découplage Moins de code par classe / par fichier Lisible
Bonnes pratiques Découplage Moins de code par classe / par fichier Lisible Aéré
Bonnes pratiques Organisation Arborescence François (speed) Profiter de la structure du système de fichiers (arbo)
Bonnes pratiques Organisation Arborescence Tri par fonctionnalité Utiliser les répertoires pour classer le code
Bonnes pratiques Organisation Arborescence Tri par fonctionnalité Problèmes de couplages apparents
Bonnes pratiques Commentaires & documentation Romain (speed)
Bonnes pratiques Commentaires & documentation Outil personnel Comprendre d un coup d œil son code PHPDoc: typage, valeur de retours
Bonnes pratiques Commentaires & documentation Outil personnel Comprendre d un coup d œil son code PHPDoc: typage, valeur de retours Outil d équipe Comprendre d un coup d oeil du code inconnu Comportement attendu lire le code
Bonnes pratiques Don t Repeat Yourself Code à deux endroits = Erreur à deux endroits François (speed)
Bonnes pratiques Don t Repeat Yourself Code à deux endroits = Erreur à deux endroits Réutilisation facilitée François
Bonnes pratiques Don t Repeat Yourself Code à deux endroits = Erreur à deux endroits Réutilisation facilitée Simplifie la maintenance François
Bonnes pratiques, pourquoi? Romain
Bonnes pratiques, pourquoi? Ne pas créer une boîte noire!
Bonnes pratiques, pourquoi? Ne pas créer une boîte noire! = contrôle du projet
Bonnes pratiques, pourquoi? Ne pas créer une boîte noire! = contrôle du projet = maîtrise des temps
Bonnes pratiques, pourquoi? Ne pas créer une boîte noire! = contrôle du projet = maîtrise des temps = maîtrise des coûts
Et en JavaScript? François
Organisation des développements JavaScript sfdynamicsplugin Titre présentation Conférencier Romain Dorgueil On va commencer par une première problématique: lʼorganisation des dev js dans un projet
Organisation d un projet Qu a t on aujourd hui? On regarde côté serveur, et on voit ce que ca donne sur les comportements dynamiques clients.
Organisation d un projet Deux approches Organisation par application Organisation par fonctionnalité Différentes approches d organisation des projets. Principalement, deux, bien sur ce n est pas exhaustif.
Organisation par application C est l approche la plus simple, aucun travail organisationnel préalable est nécessaire. Si on organise le projet par application, le code javascript/css va se retrouvé mélangé dans web/js.
Organisation par application Avantages Démarrage rapide L application est organisée comme le site
Organisation par application Inconvénients Plus l application grossis, plus le niveau de désorganisation augmente Couplage: effets de bord entre modules Modèle monobloc web/js deviens vite ingérable Difficile de visualiser le projet sous forme d un ensemble de fonctionnalités, toutes les sous fonctionnalités sont mélangées (dans app/.../modules, dans lib, lib/model, etc...) Ce couplage deviens vite apparent côté javascript également.
Organisation par fonctionnalité Du coup, on peut penser à une autre organisation, par fonctionnalité avec un plugin = une fonctionnalité.
Organistaion par fonctionnalité Avantages: Nombreuses fonctions simples plutôt qu une grosse fonction complexe Tests isolés Découplage, moins d effets de bord Maintenance facile Beaucoups d avantages côté serveur. Mais ça ne résoud pas pour autant les problématiques d inclusion JS. A l heure actuelle: - liens symboliques à tout va - signature symfony, et plus grave, signature des plugins utilisés - faille potentielle
Organisation par fonctionnalité Inconvénients Pas organisé comme le site Moins évident pour un intégrateur L intégrateur a besoin de notions symfony pour travailler efficacement sur un projet.
Etat des lieux Qu a t on aujourd hui?
JavaScript - Etat des lieux Dans une application Moins de requêtes? Moins de fichiers Plus léger? Obfuscation de code Mauvaise pratique Si on décide d inclure un comportement dynamique client dans une application... En fait aujourd hui on approche ça comme ca: * slide * On prends des solutions simples qui n en sont pas.
JavaScript - Etat des lieux Dans les plugins symfony Dépendances communes Ingérables ou difficiles Duplication de code Problème de versions concurrentes Eviter les double inclusions Mauvaise pratique
JavaScript - Etat des lieux Le problème est pris à l envers. On a besoin de performances, ce qui est souvent fait au détriment du bon sens. On ne veux pas sacrifier la qualité du code pour les performances.
Une solution sfdynamicsplugin
Rôle et contraintes Quels étaient les prérequis pour dynamics?
Le plugin - Rôle Eviter les redondances ((( *hint conclusion* Contrainte majeure: ORGANISATION )))
Le plugin - Rôle Eviter les redondances Gestion des dépendances et conflits ((( *hint conclusion* Contrainte majeure: ORGANISATION )))
Le plugin - Rôle Eviter les redondances Gestion des dépendances et conflits Ajout de fonctions dynamiques client par plugin ((( *hint conclusion* Contrainte majeure: ORGANISATION )))
Le plugin - Rôle Eviter les redondances Gestion des dépendances et conflits Ajout de fonctions dynamiques client par plugin Organisation Rôle principal: ORGANISER les développements de comportements dynamiques client.
Le plugin - Contraintes Nombre de requêtes ((( *hint conclusion* Contrainte majeure: PERFORMANCES )))
Le plugin - Contraintes Nombre de requêtes Taille des fichiers finaux ((( *hint conclusion* Contrainte majeure: PERFORMANCES )))
Le plugin - Contraintes Nombre de requêtes Taille des fichiers finaux Lisibilité du code «dev» ((( *hint conclusion* Contrainte majeure: PERFORMANCES )))
Le plugin - Contraintes Nombre de requêtes Taille des fichiers finaux Lisibilité du code «dev» Performances Contrainte majeure: PERFORMANCES
Configuration A partir d ici, on regarde chacun des composants principaux de dynamics 1 par 1.
sfdynamicsplugin Gestionnaire de dépendances JavaScript Système de configuration XML flexible Surcharge «destructive» Flexible: chaque morceau de projet a son mot a dire. Surcharge: Le projet est maître, sauf si l application veux prendre le dessus Par défaut, sfdynamics a la main. Le projet peux surcharger, les applications peuvent surcharger.
Configuration Par défaut, on ne charge rien Ce n est pas le rôle du plugin que de présupposer quoique ce soit sur un projet.
Configuration La configuration des principaux framework JavaScript est fournie. PrototypeJS Mais propose des ensembles de librairies, qu on peut inclure facilement.
Configuration jquery (tronqué)
Configuration ExtJS (tronqué, le fichier fait environ 600 lignes) Mais encore: scriptaculous, et peut etre un jour yahooui
Configuration Script spécifique à un plugin? dynamics-plugin.xml dynamics-*.xml But du plugin: permettre l extensibilité.
Configuration Pourquoi XML? validation lisibilité facile à étendre facile à tester universel validation: schema lisibilité: n importe qui peut lire et comprendre la structure d un xml extensibilité: un tag = une classe test: Possible de tester unitairement chacune des classes parser de la config
Utilisation Configuration, en action
Utilisation On définit un package Pour s en servir...
Utilisation On charge ce package il suffit de charger les paquets nécessaires. sfdynamics gère les dépendances, et inclus dans l ordre chacun des paquets requis.
Utilisation Si on est méfiant, on vérifie... Ce qu on peut voir ici.
Utilisation Reste à tester...
Autre exemple Arianespace, outil de planification
Préprocesseur
sfdynamicsplugin Préprocesseur Javascript Packer Minifier chaque préprocesseur est activable/désactivable en configuration
sfdynamicsplugin Préprocesseur CSS Résolution des chemins des images Résolution des @import chaque préprocesseur est activable/désactivable en configuration
Cache
sfdynamicsplugin Ces fonctionnalités ont un coût 3 niveaux de cache Bien sur le préprocesseur (entre autres) est coûteux. C est pourquoi le cache rentre en jeu.
sfdynamicsplugin Cache de la configuration sérialisation set_state() A l instar des fichiers de configuration de symfony, toute la configuration XML est cachée après être parsée, en prenant en compte l héritage.
sfdynamicsplugin Cache du code sortant du préprocesseur à l instar du cache des partial, on cache les parties précalculées.
sfdynamicsplugin SuperCache On place le rendu des fichiers dans web/dynamics On génère une fois, le serveur web se charge du reste Le plugin a sa propre implémentation, inspirée su sfsupercacheplugin. On écrit des fichiers statiques sous l arborescence web publique accessible.
Debug Bien sur grouper des assets (entre autres) peut être génant pour debugger ces derniers.
sfdynamicsplugin Web debug (à partir de symfony 1.2) Visualiser les dépendances Visualiser les fichiers groupés Résolution rapide des problèmes Une barre de debug est disponible pour visualiser les différents groupes, et pour ouvrir directement les fichiers correspondants.
sfdynamicsplugin Exceptions explicites
sfdynamicsplugin Ajout de commentaires (en mode debug)
Documentation
sfdynamicsplugin Documentation complète http://dynamics.dakrazy.net/ Markdown, site, exemples... LAST TODO
Et après...
Et après? Support des «scope d inclusion» Inclusion conditionelle Medias Head vs body merci pascal :)
Et après? Gestion des thèmes et de l I18n nativement
Et après? Support des «Content Delivery Network» (CDN) FTP, rsync, scp, S3,...
Et après? <insérez votre idée géniale ici> <insérez votre ticket génial ici> <insérez votre patch génial ici> http://dynamics.dakrazy.net/ idée: mail, irc ticket: lighthouseapp patch: lighthouse, git, github
Enrichir l expérience utilisateur sfunobstrusivewidgetplugin Titre présentation Conférencier François Béliveau page internet riche mais dégradable
Bonnes pratiques JavaScript complément de la présentation de Romain sur un axe plus fonctionnel qu organisationnel
Bonnes pratiques JavaScript bien placer son code éviter les effets de bord dégradation élégante (unobstrusive) accessibilité
bonnes pratiques JavaScript bien placer son code head inclusion de fichiers définition de fonctions body appel de fonction dans le body pour des questions de performance
bonnes pratiques JavaScript éviter les effets de bord contrôler la portée des variables éviter les variables globales «var» crée une variable dans la fonction dans laquelle il se trouve, sinon, globale
bonnes pratiques JavaScript éviter les effets de bord utiliser un gestionnaire d'événements (mauvaise méthode) gestionnaire d événement : window.onload...
bonnes pratiques JavaScript éviter les effets de bord utiliser un gestionnaire d'événements (bonne méthode) gestionnaire d événement : window.onload...
bonnes pratiques JavaScript Dégradation élégante (unobstrusive) vérifier qu'un objet est disponible avant de le manipuler le JavaScript n'est pas une fonctionnalité fiable à 100%
bonnes pratiques JavaScript Dégradation élégante (unobstrusive) séparer la structure du comportement» pas de style inline le JavaScript permet d'améliorer l'expérience de l'utilisateur, ce n'est cependant pas une fonctionnalité fiable à 100% écrivez du JavaScript, et non un dialecte particulier à un navigateur
bonnes pratiques JavaScript Accessibilité ne soyez pas dépendant de la souris focus ne fonctionne qu avec les inputs et les liens...
JavaScript & symfony
JavaScript & symfony Etat des lieux 3 façon de faire du JS en symfony
JavaScript & symfony : état des lieux Intégrer son JavaScript à la main directement dans un template fichier externe view.yml dans une action
JavaScript & symfony : état des lieux Intégrer son JavaScript à la main multiplication des sources possibles» maintenance plus difficile sur de gros projets plus de code à écrire» augmente les risques d erreurs Mauvaise pratique
JavaScript & symfony : état des lieux Intégrer son JavaScript à l aide de helper avec la compatibilité symfony 1.0 activée résultat
JavaScript & symfony : état des lieux Intégrer son JavaScript à l aide de helper regroupement de fonctionnalités moins de code à écrire JavaScript intégré directement dans le (x)html peu de souplesse quant à l utilisation de différent framework pratique obsolète Mauvaise pratique
JavaScript & symfony : état des lieux Intégrer son JavaScript à l aide d un widget méthodes getjavascripts résultat existe aussi pour les CSS
JavaScript & symfony : état des lieux Intégrer son JavaScript à l aide d un widget regroupement de fonctionnalités moins de code à écrire développement objet helper pour charger le JavaScript structure et comportement mélangés peu de souplesse quant à l utilisation de différent framework Incomplet
JavaScript & symfony Qu est ce qui manque?
JavaScript & symfony : ce qui manque Chargement automatique des fichiers JavaScript» de même que les CSS Indépendance quant aux solutions javascript choisies» framework JavaScript» librairie «maison» Structure html hermétique à tout type de JavaScript Réflexion sur l accessibilité
Une solution... sfunobstrusivewidget plugin http://www.symfony-project.org/plugins/sfunobstrusivewidgetplugin approche widget - form - mais pas que...
sfunobstrusivewidget le découplage structure présentation comportement
sfunobstrusivewidget, le découplage commencer avec un contenu brut lui donner une structure sémantique
sfunobstrusivewidget, le découplage lui appliquer une couche graphique ajouter des fichiers dans la réponse ajout des fichiers automatiques
sfunobstrusivewidget, le découplage créer des comportements dynamiques» transformation du DOM ajouter des fichiers dans la réponse ajout des fichiers automatiques
sfunobstrusivewidget, le découplage Découplage...» structure» présentation» comportement... pour obtenir un seul rendu (x)html et une multitude de transformations possibles
sfunobstrusivewidget, le découplage une structure.. sfuowidgetformselectmany > double liste PURE HTML
sfunobstrusivewidget, le découplage... des transformations sfuowidgetformselectmany > double liste TRANSFORMATION DU DOM 100% JS
sfunobstrusivewidget, le découplage... des transformations sfuowidgetformselectmany > asm (alternative select many) TRANSFORMATION DU DOM 100% JS
sfunobstrusivewidget, le découplage... des transformations sfuowidgetformselectmany > drop down check list TRANSFORMATION DU DOM 100% JS
sfunobstrusivewidget Options JavaScript des widgets une structure, des transformaion -> possible grâce à des options primordiale
sfunobstrusivewidget, options js_adapter» le framework ou la librairie JavaScript utilisé js_transformer» le comportement à appliquer sur un rendu HTML js_selector» le sélecteur utilisé pour cibler le HTML avec les CSS et les JS js_config» configuration JSON passée au constructeur JavaScript la classe d un widget est selector. _.transformer js_config, exemple : url à utiliser pour un script ajax
sfunobstrusivewidget Configuration tout est dans un fichier yaml «sfuowidget.yml»
sfunobstrusivewidget, configuration pourquoi un fichier spécifique? centraliser la définition des fichiers javascript et CSS» faciliter la maintenance» faciliter l intégration dans un projet (extensible)
sfunobstrusivewidget, configuration le choix du YAML natif en symfony habitude permettre la modification (merge des fichiers)» pour le projet» pour une application
sfunobstrusivewidget, configuration composition du fichier valeur par défaut adapters» définition de tous les adapters disponibles thèmes» définition de tous les thèmes disponibles default_adapter: adapter par défaut utilisé dans les widgets lazy_mode: ajouté automatiquement l initialisation des scripts dans le html (valeur par défaut)
sfunobstrusivewidget, configuration définition des adapters un thème par défaut plusieurs templates possible plusieurs packages
sfunobstrusivewidget, configuration définition des thèmes
sfunobstrusivewidget JavaScript
sfunobstrusivewidget, JavaScript chaque JavaScript intégré au plugin propose... une dégradation élégante (unobstrusive) un modèle objet une utilisation clavier ou souris les bonnes pratiques de base» commentaires, découplage, DRY... la classe d un widget est selector. _.transformer évidemment, les JS sont développer en respectant (le plus souvent) les bonnes pratiques énuméré tout à l heure
sfunobstrusivewidget En action
sfunobstrusivewidget en action Créer un menu
sfunobstrusivewidget en action contenu d un menu type backend libellé route ou url multi-niveau droits sfuowidgetadminmenu -> yaml sfuowidgetmenu -> normal
sfunobstrusivewidget en action menu sans javascript» dans l action» rendu» dans le template main dans le render correspond à «main» dans le YAML
sfunobstrusivewidget en action menu treeview» dans l action» rendu» dans le template main dans le render correspond à «main» dans le YAML
sfunobstrusivewidget en action menu liste déroulante» dans l action» dans le template» rendu main dans le render correspond à «main» dans le YAML
sfunobstrusivewidget en action Créer un sélecteur de date
sfunobstrusivewidget en action sans javascript» dans le formulaire» dans le template» rendu
sfunobstrusivewidget en action date picker» dans le formulaire» dans le template» rendu
sfunobstrusivewidget en action plage de date avec date picker» dans le formulaire» dans le template» rendu JS prend en charge la date min et max de manière auto
sfunobstrusivewidget Et dans l avenir?
sfunobstrusivewidget, et dans l avenir? améliorer la compatibilité avec les styles de jquery UI l accessibilité utilisation du clavier
sfunobstrusivewidget, et dans l avenir? ajouter des widgets éditeur de template (textarea) ajout à la volée de sous formulaires
sfdynamics & sfunobstrusivewidget solution complémentaire
sfunobstrusivewidget & sfdynamics détection automatique de la présence de sfdynamics tous les packages sont prêts à l emploi même résultat avec sfdynamics ou sans
Questions? François Béliveau - Sensio Labs francois.beliveau@sensio.com Romain Dorgueil - Sensio Labs romain.dorgueil@sensio.com - twitter: hartym
Engagez vous! Open Source, pourquoi? faire profiter et profiter des expériences de chacuns