Ce blog post se consacre à quelques pratiques que j'ai adopté dans mes développements, et en particulier les plus "borderlines" : celles qui sont sans doute les moins couramment utilisées, ou les plus sujets à débats.

Notez que certains exemples ne suivent pas l'ensemble des conventions de ce document. J'ai essayé de ne pas surcharger les exemples afin de bien mettre en valeur le point évoqué.


Toujours mettre un espace entre les opérateurs, y compris (particularité) entre les parenthèses et autres brackets.

Simplement pour aérer le code, et permettre de séparer rapidement chaque composant à la lecture.

L'humain n'est pas très bon pour lexer manuellement un bloc de code (d'où l'existence de la coloration syntaxique), autant lui simplifier la vie en séparant clairement les débuts et fin des différents éléments.

var makePair = function ( first, second ) {  
  return [ first, second ];
};

Faire un usage intensif des lignes vides pour séparer les blocs sémantiques.

Faire cela permet d'aérer le code, le rendant plus aisé à relire par la suite.

Un conseil pour une découpe correcte : imaginez le pseudo-code de votre fonction, aussi simple qu'elle soit. Chaque ligne de ce pseudo-code peut être transcrit comme un bloc sémantique. Séparez-les par des lignes vides, et la fonction n'en sera que plus lisible et compréhensible.

var inheritor = function ( Base, Source ) {

  var F = function ( ) { };
  F.prototype = Base.prototype;

  Source.prototype = new F( );

  return Source;
};

Si un morceau de code peut être rendu fluide, envisager d'en tirer parti.

Un bloc fluide représente généralement une unique instruction mais, plus important : elle n'est pas censée en contenir d'autres (c'est à dire qu'aucune évolution du code ne devrait à priori la complexifier).

Ce style d'écriture convient donc particulièrement à des fonctions et méthodes helpers, comme dans l'exemple qui suit :

var buildAuthConfiguration = function ( user, pass ) {  
  return { user : user
         , pass : pass }; }

var buildAdditionAST = function ( functionName, a, b ) {  
  return new AST.Addition(
    new AST.Number( a ),
    new AST.Number( b ) ); };

Éviter les closures libres.

Les closures sont un composant important de Javascript, a tel point que les développeurs les découvrant ont une légère tendance à les utiliser partout à la fois. Ce n'est pas une bonne idée : bien que puissantes, elles introduisent une complexité supplémentaire lorsque le code doit être lu : où est définie la fonction ? Quelles variables utilise-t-elle ? Quelles variables viennent du scope global (argh), et quelles autres du scope parent ?

En règle générale, une closure peut assez souvent être remplacée, au moins en grande partie, par une méthode ou fonction dédiée. L'idéal est de ne les utiliser que dans un seul cas : en tant que callback (celles-ci n'introduisant pas d'ambigüité quand à leur champs d'action.


Utiliser la bibliothèque standard, y compris les fonctions apportées par ES5.

Trop de codes Javascript utilisent à mon goût certains 'templates' de code, dont vous pouvez quelques exemples sur ce gist. Bien que certains pourraient arguer que ces codes sont plus optimisés, dans le sens où ils ne nécessitent pas d'"inutiles" appels de fonction, je préfère considérer d'une part que les performances d'un forEach ou d'un map sont rarement le bottleneck d'une application classique, et d'autre part que le moteur d'exécution sait probablement mieux optimiser certains cas que moi.

Utiliser les fonctions standard permet d'apporter un style de développement conventionné : un développeur lisant le code aura certainement plus de facilité à comprendre la façon dont il est censé s'exécuter, et l'état d'esprit de la personne l'ayant écrit.


Se limiter à un composant par fichier.

Je rencontre régulièrement des projets disposant de plusieurs classes / prototypes par fichier. C'est à mon sens une erreur, principalement parce que compartimenter une classe dans un fichier permet de mieux souligner leur indépendance.

Regardez par exemple le tree de Castel. Simple et élégant : vous avez instantanément accès à toutes les informations dont vous pourriez avoir besoin. Vous savez comment sont agencées les classes, vous savez lesquelles sont disponibles. Aucune documentation particulière n'est ainsi requise.

Ce concept se transpose également dans les applications web. A l'heure où nous disposons de systèmes de gestion de dépendances efficaces (Require.js, CommonJS-Everywhere, ...), il est dommage de rester sur des architectures où retrouver du code revient à faire des grep et espérer tomber sur le filon.