Blog ENI : Toute la veille numérique !
🐠 -25€ dès 75€ 
+ 7 jours d'accès à la Bibliothèque Numérique ENI. Cliquez ici
Accès illimité 24h/24 à tous nos livres & vidéos ! 
Découvrez la Bibliothèque Numérique ENI. Cliquez ici

Adopter les bonnes pratiques

Espace de noms

1. Principe

Lorsque nous développons, nous éviterons toujours d’exposer un trop grand nombre de fonctions ou de variables dans l’espace de noms global afin d’éviter des conflits de nom. Cela signifie de ne donner l’accès qu’à ce qui est utile et masquer tout le reste. C’est un peu le principe d’une boîte noire avec des entrées et sorties bien définies mais la mécanique interne reste cachée.

C’est d’autant plus important si le code risque d’être utilisé dans d’autres contextes. Le problème vient que nous avons l’habitude d’ajouter des fonctions dans nos fichiers sans prendre en compte la réutilisation. Notre projet devenant plus conséquent, il devient de plus en plus difficile à gérer. Associer deux codes peut alors provoquer des conflits qui ne sont pas forcément visibles au premier coup d’œil et le résultat devient incertain.

Pour limiter les conflits de nom, nous ajouterons un contexte supplémentaire (une sorte de super contexte) qui garantira que nos fonctions et variables ne pourront être altérées/utilisées accidentellement. Cet espace de noms est une sorte de conteneur de noms. Un nom n’a alors de sens que par rapport à son espace de noms. Invoquer une fonction qui n’est pas dans l’espace de noms attendu devient donc impossible.

Chaque code ayant son espace de noms, il n’y a plus de risque de collisions associé à un code appartenant à un autre espace de noms.

Un espace de noms est une possibilité associée à de nombreux langages. Dans le langage Java, par exemple, le mot-clé package sert à effectuer la déclaration, de même en C# avec namespace. En JavaScript, nous n’avons malheureusement pas de mot-clé pour cet usage mais nous avons d’autres astuces tout aussi puissantes pour l’obtenir.

Ce principe est important pour la qualité de vos programmes. Une fois que l’aurez compris, il deviendra naturel et votre développement s’améliorera d’autant plus.

Plus votre programme est important et plus vous avez besoin d’espaces de noms. C’est la dimension qui en impose l’usage. Prendre en compte l’espace...

Module

1. Présentation

Le concept de module découle de la structure précédente. L’idée est de proposer un format universel aux briques de fonctionnalités. Un module représente une partie indépendante de notre code. Par exemple nous pourrions avoir un module chargé d’un type de calcul ou un module représentant un composant graphique. Un module ne doit pas être confondu avec une fonction ; il est au-dessus de la fonction et masque toutes les fonctions et propriétés utiles pour rendre un service.

Nous avons vu précédemment que la fonction pouvait servir d’espace de noms protégeant des conflits certaines méthodes ou variables de notre code. Cela a conduit à la conception de notre module :

function monModule { 
   // Définition privée 
   variables ... 
   fonctions ... 
 
   return { 
      // Définition publique 
      propriétés... 
      méthodes... 
   } 
} 

Cette structure peut être employée partout et remplace même vos classes. Nous pourrons également retourner indifféremment un objet unique, un constructeur ou bien une fonction. 

Si par exemple vous voulez obtenir plusieurs instances, dans ce cas, il faut un constructeur qui se chargera de produire les instances à la demande :

function monModule {    
   // Définition privée 
   variables pour toutes les instances... 
   fonctions ... 
 
  // Constructeur intermédiaire pour chaque instance 
  return function() {  
    return {  
      //...

CommonJS

1. Présentation

Si nous souhaitons rendre un module plus accessible, donc facilement exploitable par tous, il faut se conformer à un standard, d’où l’usage de solutions comme ce que propose CommonJS (http://www.commonjs.org/). CommonJS est né en 2009 sous l’impulsion de Kevin Dangoor avec l’idée de pouvoir normaliser certaines API de JavaScript. Comme nous l’avons vu jusqu’ici, JavaScript offre une grande expressivité dans le codage qui s’avère agréable mais qui cache aussi un véritable problème de normalisation et d’interopérabilité.

2. define

Si nous regardons la définition d’un module, il est défini selon CommonJS comme étant :

define( id?, dependencies?, factory); 

define est une fonction proposée par l’API compatible CommonJS servant à décrire un module. Les paramètres de cette fonction (un point d’interrogation est présent pour un paramètre optionnel) sont :

  • id : un identifiant non obligatoire du module, dans la pratique il sera peu employé car le fichier englobant le module sera un id implicite.

  • dependencies : un tableau d’identifiants de modules qui sont nécessaires à l’exécution du module. Ce tableau est optionnel. Lorsque le module est exécuté, la résolution des dépendances doit d’abord être effectuée.

    À noter...

AMD

1. Introduction

a. Présentation

AMD signifie Asynchronous Module Definition. L’idée étant de s’appuyer sur le travail de CommonJS (CJS module) afin de rendre un module exploitable de manière asynchrone. L’usage d’identifiant associé aux modules peut également offrir une certaine flexibilité pour avoir différents mécanismes de résolution selon les besoins (débogage, test...).

Le caractère asynchrone de cette architecture à l’avantage de rendre l’usage non bloquant ou plutôt à la demande. On n’emploie les ressources que selon les besoins. Il est en effet inutile de provoquer un chargement global dont nous n’aurions pas un usage immédiat. Pour rappel lorsque nous utilisons une balise script dans notre code HTML avec un code externe, le chargement de la page se bloque tant que le script n’a pas été chargé (à l’exception de l’usage de l’attribut async en HTML5).

D’autre part, des frameworks importants comme jQuery, Dojo ou Node.js sont maintenant compatibles AMD, cela renforce d’autant le poids de cette architecture qui peut être considérée comme pérenne.

Lorsqu’on parle d’un module AMD, il faut davantage voir l’usage de la fonction define pour la définition du module que son fonctionnement. Dans ce dernier cas, il n’y a pas vraiment de standard et les différentes implémentations ont leur propre système d’invocation de modules, comme nous allons le voir.

Un gestionnaire de modules AMD sera la brique logicielle JavaScript chargée d’effectuer une résolution des modules et donc les faire fonctionner.

L’usage de l’architecture AMD n’est pas limité qu’à des navigateurs récents. On peut considérer par exemple qu’il n’y aura pas de problème d’usage à partir d’IE 6.

b. Quelques conseils

Chaque module est présent dans un fichier. Un fichier contient un seul module. 

Il faut adopter une structuration de vos modules par répertoires et sous-répertoires selon l’usage souhaité afin de les trouver plus naturellement. Par exemple si vous avez un module concernant une activité de finance, on s’attendra à...

Déboguer votre code

1. Fonction alert

a. Usage

La méthode la plus simple pour mettre une trace est l’usage de la fonction alert. Celle-ci déclenche l’affichage d’une boîte de dialogue modale (bloquante) avec un message. Son inconvénient majeur est qu’elle ne doit être invoquée qu’un nombre de fois réduit au risque d’avoir de nombreuses fermetures à effectuer à l’écran pour pouvoir continuer votre programme. L’autre danger est l’oubli de suppression de certaines traces et de laisser en production ces boîtes inutiles.

Exemple

for ( var i = 10; i >= 0; i -- ) { 
  alert( i ); 
} 

Dans ce contre-exemple, nous avons autant de fois l’affichage d’une boîte de dialogue que d’incréments dans la boucle. Inutile d’indiquer qu’avec 11 itérations (10 à 0 inclus) c’est gérable, mais qu’avec une centaine par exemple cela peut vite devenir insurmontable pour l’utilisateur.

b. Simplification

Nous pouvons alléger ces invocations de cette manière :

var tmp = "" 
for ( var i = 10; i >= 0; i -- ) { 
  tmp += " i = " + i + "\n"; 
} 
alert( tmp ); 
images/03EI1.png

Nous avons bien tracé la variable i et nous n’avons qu’un seul affichage.

L’inconvénient étant encore une question de quantité : à partir d’un certain nombre d’itérations, la hauteur de la fenêtre rend le tout ingérable.

c. Module

Nous pouvons dans notre dernier cas distinguer l’initialisation de la trace, la modification de la trace et l’affichage de la trace. Ces trois étapes peuvent être mises à disposition dans un module très réduit.

(function( window ) { 
   var trace = ""; 
   window.trace = function( msg ) { 
     trace += msg + "\n"; 
   } 
   window.traceRes = function() { 
     if ( trace ) 
       alert( trace ); 
     trace = ""; 
   } 
} )( window ); ...