Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

A translation of Ryan McDermott's "Clean Code Javascript" repository to French

License

NotificationsYou must be signed in to change notification settings

gavbarosee/clean-code-javascript-fr

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

13 Commits
 
 
 
 

Repository files navigation

Ceci est une traduction française de ce lien:https://github.com/ryanmcdermott/clean-code-javascript

Table Des Matières

  1. Introduction
  2. Variables
  3. Fonctions
  4. Objets Et Structures De Données
  5. Classes
  6. SOLID
  7. Testage
  8. Simultanéité
  9. La Gestion Des Erreurs
  10. Mise En Forme
  11. Commentaires
  12. Traduction

Introduction

Humorous image of software quality estimation as a count of how many expletives you shout when reading code

Principes d'ingénierie logicielle, de l'ouvrage de Robert C. MartinClean Code,adapté pour JavaScript. Ce n'est pas un guide de style. C'est un guide pour la production de logicielslisibles, réutilisables et refactorables en JavaScript.

Tous les principes énoncés ici ne doivent pas être strictement suivis, et encore moins seront universellement acceptés. Ce sont des lignes directrices et rien de plus, mais ce sont des lignes codifiées au fil de nombreuses années d'expérience collective par les auteurs deClean Code.

Notre métier de génie logiciel a un peu plus de 50 ans et nous apprenons encore beaucoup. Lorsque l'architecture logicielle est aussi ancienne que l'architecture elle-même, nous aurons peut-être des règles plus strictes à suivre. Pour l’instant, laissez ces instructions servir de point de repère pour évaluer la qualité du code JavaScript que vous et votre équipe produisez.

Encore une chose: savoir que cela ne fera pas de vous un meilleur développeur de logiciels et travailler avec eux pendant de nombreuses années ne signifie pas que vous ne ferez pas d'erreurs. Chaque morceau de code commence par un premier brouillon, comme l'argile humide qui prend sa forme finale. Enfin, nous corrigeons les imperfections lorsque nous les examinons avec nos pairs. Ne vous battez pas pour les premières ébauches à améliorer. Battez le code à la place!

Variables

Utilisez des noms de variables significatifs et prononçables

Mal:

constyyyymmdstr=moment().format("YYYY/MM/DD");

Bien:

constdateActuelle=moment().format("YYYY/MM/DD");

⬆ retour au sommet

Utilisez le même vocabulaire pour le même type de variable

Mal:

obtenirInformationDeUtilisateur();obtenirDonéesDuClient();obtenirFicheDuClient();

Bien:

obtenirUtiilisateur();

⬆ retour au sommet

Utilisez des noms interrogeables

Nous lirons plus de code que nous n'en écrirons jamais. Il est important que le code nousécrire est lisible et consultable. Parpas nommer les variables qui finissent paravoir un sens pour comprendre notre programme, nous avons blessé nos lecteurs.Rendez vos noms consultables. Des outils commebuddy.js etESLintpeuvent aider à identifier des constantes non nommées.

Mal:

// Qu'est-ce que c'est que 86400000?setTimeout(misÀFeu,86400000);

Bien:

// Déclarez-les comme des constantes nommées capitalisées.constMILLISECONDES_PAR_JOUR=86400000;setTimeout(misÀFeu,MILLISECONDES_PAR_JOUR);

⬆ retour au sommet

Utiliser des variables explicatives

Mal:

constadresse="One Infinite Loop, Cupertino 95014";constcodePostalVilleRegex=/^[^,\\]+[,\\\s]+(.+?)\s*(\d{5})?$/;enregistrerCodePostalVille(adresse.match(codePostalVilleRegex)[1],adresse.match(codePostalVilleRegex)[2]);

Bien:

constadresse="One Infinite Loop, Cupertino 95014";constcodePostalVilleRegex=/^[^,\\]+[,\\\s]+(.+?)\s*(\d{5})?$/;const[,ville,codePostal]=adresse.match(codePostalVilleRegex)||[];enregistrerCodePostalVille(ville,codePostal);

⬆ retour au sommet

Éviter la cartographie mentale

Explicite est meilleur qu'implicite.

Mal:

constendroits=["Austin","New York","San Francisco"];endroits.forEach(l=>{faireDesTrucs();faireAutreChoses();// ...// ...// ...// Attendez, à quoi sert "l`"?dispatch(l);});

Bien:

constendroits=["Austin","New York","San Francisco"];endroits.forEach(endroit=>{faireDesTrucs();faireAutreChoses();// ...// ...// ...dispatch(endroit);});

⬆ retour au sommet

Ne pas ajouter de contexte inutile

Si votre nom de classe / d’objet vous dit quelque chose, ne répétez pas cela dans votreNom de variable.

Mal:

constVoiture={marqueDeVoiture:"Honda",modèleDeVoiture:"Accord",couleurDeVoiture:"Bleue"};functionpeindreLaVoiture(voiture){voiture.couleurDeVoiture="Rouge";}

Bien:

constVoiture={marque:"Honda",modèle:"Accord",couleur:"Bleue"};functionpeindreLaVoiture(voiture){voiture.couleur="Rouge";}

⬆ retour au sommet

Utiliser des arguments par défaut au lieu de court-circuiter ou conditionnels

Les arguments par défaut sont souvent plus propres que les courts-circuits. Sachez que si vousutilisez-les, votre fonction ne fournira que les valeurs par défaut pourundefinedarguments. Autres valeurs "fausses" telles que''," ",false,null,0 etNaN, ne sera pas remplacé par une valeur par défaut.

Mal:

functioncréerUneMicroBrasserie(nom){constnomDeBrasserie=nom||"Hipster Brew Co.";// ...}

Good:

functioncréerUneMicroBrasserie(nom="Hipster Brew Co."){// ...}

⬆ retour au sommet

Fonctions

Arguments de fonction (idéalement 2 ou moins)

Limiter le nombre de paramètres de fonction est extrêmement important carfacilite le test de votre fonction. Avoir plus de trois prospects à unexplosion combinatoire où vous devez tester des tonnes de cas différents avecchaque argument séparé.

Un ou deux arguments est le cas idéal, et trois devraient être évités si possible.Quelque chose de plus que cela devrait être consolidé. Habituellement, si vous avezplus de deux arguments, votre fonction essaie de faire trop. Dans les casoù il n'est pas, la plupart du temps un objet de niveau supérieur suffira en tant queargument.

Puisque JavaScript vous permet de créer des objets à la volée, sans trop de classepasse-partout, vous pouvez utiliser un objet si vous vous trouvez nécessitant unbeaucoup d'arguments.

Pour rendre évidentes les propriétés attendues par la fonction, vous pouvez utiliser le logiciel ES2015 / ES6.syntaxe de déstructuration. Cela présente quelques avantages:

  1. Quand quelqu'un regarde la signature de la fonction, on voit immédiatement ce qui     les propriétés sont utilisées.
  2. La destruction clone également les valeurs primitives spécifiées de l'argument     objet passé dans la fonction. Cela peut aider à prévenir les effets secondaires. Remarque:     les objets et les tableaux qui sont déstructurés à partir de l'objet argument ne sont PAS     cloné.
  3. Les linters peuvent vous avertir des propriétés inutilisées, ce qui serait impossible     sans déstructuration.

Mal:

functioncréerUnMenu(titre,corps,boutonTexte,annulable){// ...}

Bien:

functioncréerUnMenu({ titre, corps, boutonTexte, annulable}){// ...}créerUnMenu({titre:"Foo",corps:"Bar",boutonTexte:"Baz",annulable:true});

⬆ retour au sommet

Les fonctions doivent faire une chose

C’est de loin la règle la plus importante en génie logiciel. Quand fonctionnefaire plus d’une chose, il est plus difficile de composer, de tester et de raisonner.Lorsque vous pouvez isoler une fonction à une seule action, elles peuvent être refactorisées.facilement et votre code lira beaucoup plus propre. Si vous ne prenez rien d'autre dece guide autre que celui-ci, vous serez en avance sur de nombreux développeurs.

Mal:

functionemailClients(clients){clients.forEach(client=>{constenregistrementDuClient=database.lookup(client);if(enregistrementDuClient.estActif()){email(client);}});}

Good:

functionemailClientsActifs(clients){clients.filter(estClientActif).forEach(email);}functionestClientActif(client){constenregistrementDuClient=database.lookup(client);returnenregistrementDuClient.estActif();}

⬆ retour au sommet

Les noms de fonction doivent dire ce qu'ils font

Mal:

functionajouterÀLaDate(date,mois){// ...}constdate=newDate();// Il est difficile de dire à partir du nom de la fonction ce qui est ajoutéajouterÀLaDate(date,1);

Bien:

functionajouterMoisÀDate(mois,date){// ...}constdate=newDate();ajouterMoisÀDate(1,date);

⬆ retour au sommet

Les fonctions ne devraient être qu'un seul niveau d'abstraction

Lorsque vous avez plus d'un niveau d'abstraction, votre fonction est généralementfaire trop. La scission des fonctions conduit à la réutilisation et à la facilitéessai.

Mal:

functionmieuxAnalyserAlternatifJS(code){constREGEXES=[// ...];constdéclarations=code.split(" ");constjetons=[];REGEXES.forEach(REGEX=>{déclarations.forEach(déclaration=>{// ...});});constast=[];jetons.forEach(jeton=>{// lex...});ast.forEach(node=>{// parse...});}

Bien:

functionmieuxAnalyserAlternatifJS(code){constjetons=tokenize(code);constarbreDeSyntaxe=analyser(jetons);arbreDeSyntaxe.forEach(node=>{// parse...});}functiontokenize(code){constREGEXES=[// ...];constdéclarations=code.split(" ");constjetons=[];REGEXES.forEach(REGEX=>{déclarations.forEach(déclaration=>{jetons.push(/* ... */);});});returnjetons;}functionanalyser(jetons){constarbreDeSyntaxe=[];jetons.forEach(jeton=>{arbreDeSyntaxe.push(/* ... */);});returnarbreDeSyntaxe;}

⬆ retour au sommet

Supprimez le code en double

Faites de votre mieux pour éviter le code en double. Dupliquer le code est mauvais parce quesignifie qu'il y a plus d'un endroit pour changer quelque chose si vous avez besoin de changerun peu de logique.

Imaginez que vous dirigiez un restaurant et que vous gardiez une trace de votre inventaire: tous vostomates, oignons, ail, épices, etc. Si vous avez plusieurs listes quivous gardez ce sur, alors tous doivent être mis à jour lorsque vous servez un plat avectomates en eux. Si vous n'avez qu'une seule liste, il n'y a qu'un seul endroit pour mettre à jour!

Vous avez souvent un code en double parce que vous en avez deux ou plus légèrementchoses différentes, qui partagent beaucoup en commun, mais leurs différences vous forcentd'avoir deux ou plusieurs fonctions distinctes qui font beaucoup de choses identiques. Enleverdupliquer le code signifie créer une abstraction capable de gérer cet ensemble dechoses différentes avec une seule fonction / module / classe.

Il est essentiel de bien comprendre l’abstraction, c’est pourquoi vous devriez suivrePrincipes SOLID énoncés dans la sectionClasses. Les mauvaises abstractions peuvent êtrepire que le code en double, alors soyez prudent! Cela dit, si vous pouvez faireune bonne abstraction, faites-le! Ne te répète pas, sinon tu te retrouverasmettre à jour plusieurs endroits chaque fois que vous voulez changer une chose.

Mal:

functionafficherLaListeDesDéveloppeurs(développeurs){développeurs.forEach(développeur=>{constsalairePrévu=développeur.calculerSalairePrévu();constexpérience=développeur.obtenirExpérience();constlienGithub=développeur.obtenirLienGithub();constdonnées={      salairePrévu,      expérience,      lienGithub};rendre(données);});}functionafficherLaListeDesGestionnaires(gestionnaires){gestionnaires.forEach(gestionnaire=>{constsalairePrévu=gestionnaire.calculerSalairePrévu();constexpérience=gestionnaire.obtenirExpérience();constportfolio=gestionnaire.obtenireProjetsMBA();constdonnées={      salairePrévu,      expérience,      portfolio};rendre(données);});}

Bien:

functionafficherLaListeDesEmployés(employés){employés.forEach(employé=>{constsalairePrévu=employés.calculerSalairePrévu();constexpérience=employés.obtenirExpérience();constdonnées={      salairePrévu,      expérience};switch(employés.type){case"gestionnaire":data.portfolio=employés.obtenireProjetsMBA();break;case"développeur":data.lienGithub=employés.obtenirLienGithub();break;}rendre(données);});}

⬆ retour au sommet

Définir des objets par défaut avec Object.assign

Mal:

constconfigMenu={titre:null,corps:"Bar",boutonTexte:null,annulable:true};functioncréerUnMenu(config){config.titre=config.titre||"Foo";config.corps=config.corps||"Bar";config.boutonTexte=config.boutonTexte||"Baz";config.annulable=config.annulable!==undefined ?config.annulable :true;}créerUnMenu(configMenu);

Good:

constconfigMenu={titre:"Commande",// L'utilisateur n'a pas inclus la clé 'corps'boutonTexte:"Envoyer",annulable:true};functioncréerUnMenu(config){config=Object.assign({titre:"Foo",corps:"Bar",boutonTexte:"Baz",annulable:true},config);// config est maintenant égal à: {titre: "Commande", corps: "Bar", boutonTexte - "Envoyer", annulable: true}// ...}créerUnMenu(configMenu);

⬆ retour au sommet

Ne pas utiliser les drapeaux comme paramètres de fonction

Les drapeaux indiquent à l'utilisateur que cette fonction fait plus d'une chose. Les fonctions devraient faire une chose. Répartissez vos fonctions si elles suivent différents chemins de code basés sur un booléen.

Mal:

functioncréerUnFichier(nom,temp){if(temp){fs.create(`./temp/${nom}`);}else{fs.create(nom);}}

Bien:

functioncréerUnFichier(nom){fs.create(nom);}functioncréerUnFichierTemp(nom){créerUnFichier(`./temp/${nom}`);}

⬆ retour au sommet

Éviter les effets secondaires (partie 1)

Une fonction produit un effet secondaire si elle fait autre chose que prendre une valeur danset renvoyer une ou plusieurs valeurs. Un effet secondaire pourrait être l'écriture dans un fichier,modifier une variable globale ou transférer accidentellement tout votre argent à unétranger.

Maintenant, vous devez avoir des effets secondaires dans un programme à l'occasion. Comme le précédentPar exemple, vous devrez peut-être écrire dans un fichier. Ce que tu veux faire c'estcentraliser où vous faites cela. Ne pas avoir plusieurs fonctions et classesqui écrivent dans un fichier particulier. Avoir un service qui le fait. Seul et l'unique.

Le principal est d'éviter les pièges courants tels que le partage d'état entre objetssans aucune structure, en utilisant des types de données mutables qui peuvent être écrits par n'importe quoi,et ne pas centraliser où vos effets secondaires se produisent. Si vous pouvez faire cela, vous voudrezêtre plus heureux que la grande majorité des autres programmeurs.

Mal:

// Variable globale référencée par la fonction suivante.// Si nous avions une autre fonction qui utilisait ce nom, maintenant ce serait un tableau et cela pourrait le casser.letnom="Gavish Barosee";functiondiviséEnPrénomEtNom(){nom=nom.split(" ");}diviséEnPrénomEtNom();console.log(nom);// ['Gavish', 'Barosee'];

Bien:

functiondiviséEnPrénomEtNom(nom){returnnom.split(" ");}constnom="Gavish Barosee";constnouveauNom=splitIntoFirstAndLastName(nom);console.log(nom);// 'Gavish Barosee';console.log(nouveauNom);// ['Gavish', 'Barosee'];

⬆ retour au sommet

Éviter les effets secondaires (partie 2)

En JavaScript, les primitives sont passées par valeur et les objets / tableaux parréférence. Dans le cas d'objets et de tableaux, si votre fonction effectue un changementdans un tableau de panier, par exemple, en ajoutant un article à acheter,alors toute autre fonction utilisant ce tableaucart sera affectée par cetteune addition. Cela peut être formidable, mais cela peut aussi être mauvais. Imaginons un mauvaissituation:

L'utilisateur clique sur le bouton "Acheter", qui appelle une fonction "achat" quigénère une requête réseau et envoie le tableaucart au serveur. Parce qued’une mauvaise connexion réseau, la fonctionpurchase doit continuer à réessayer lademande. Maintenant, qu'en est-il si, dans l'intervalle, l'utilisateur clique accidentellement sur "Ajouter au panier"bouton sur un élément dont ils ne veulent pas avant le début de la demande réseau?Si cela se produit et que la demande de réseau commence, alors cette fonction d'achatenverra l'élément ajouté accidentellement car il a une référence à un achatcart array que la fonctionaddItemToCart a modifiée en ajoutant un élément indésirablearticle.

Une bonne solution serait pour leaddItemToCart de toujours cloner lecart,éditez-le et retournez le clone. Cela garantit qu'aucune autre fonction ne soitconserver une référence du panier d'achat sera affecté par tout changement.

Deux mises en garde à mentionner à cette approche:

  1. Il peut arriver que vous souhaitiez réellement modifier l’objet d’entrée,     mais lorsque vous adoptez cette pratique de programmation, vous constaterez que ces cas     sont assez rares. La plupart des choses peuvent être refactorisées sans effets secondaires!

  2. Le clonage de gros objets peut être très coûteux en termes de performances. Heureusement,     ce n'est pas un gros problème dans la pratique car il y agrandes libraries qui permettent     ce type d’approche de programmation doit être rapide et ne nécessite pas autant de mémoire que     ce serait à vous de cloner manuellement des objets et des tableaux.

Mal:

constAjouterUnArticleAuPanier=(panier,article)=>{cart.push({ article,date:Date.now()});};

Bien:

constAjouterUnArticleAuPanier=(panier,article)=>{return[...panier,{ article,date:Date.now()}];};

⬆ retour au sommet

Ne pas écrire dans les fonctions globales

Les globaux polluants sont une mauvaise pratique en JavaScript car vous pourriez vous heurter à un autrebibliothèque et l'utilisateur de votre API serait absolument inutile jusqu'à ce qu'ils obtiennent unexception en production. Pensons à un exemple: et si vous vouliezétendre la méthode Array native de JavaScript pour avoir une méthodediff qui pourraitmontrer la différence entre deux tableaux? Vous pouvez écrire votre nouvelle fonctionArray.prototype, mais il pourrait entrer en conflit avec une autre bibliothèque qui a essayéfaire la même chose. Et si cette autre bibliothèque utilisait simplementdiff pour trouverla différence entre le premier et le dernier élément d'un tableau? C'est pourquoi çaIl serait bien mieux d’utiliser simplement les classes ES2015 / ES6 et d’étendre simplement leArray global.

Mal:

Array.prototype.diff=functiondiff(tableauDeComparaison){consthash=newSet(tableauDeComparaison);returnthis.filter(elem=>!hash.has(elem));};

Bien:

classSuperArrayextendsArray{diff(tableauDeComparaison){consthash=newSet(tableauDeComparaison);returnthis.filter(elem=>!hash.has(elem));}}

⬆ retour au sommet

Privilégier la programmation fonctionnelle à la programmation impérative

JavaScript n'est pas un langage fonctionnel comme Haskell, mais il aune saveur fonctionnelle à elle. Les langages fonctionnels peuvent être plus propres et plus faciles à tester.Privilégiez ce style de programmation quand vous le pouvez.

Mal:

constsortieDuProgrammeur=[{nom:"Oncle Bobby",linesDeCode:500},{nom:"Suzie Q",linesDeCode:1500},{nom:"Jimmy Gosling",linesDeCode:150},{nom:"Gracie Hopper",linesDeCode:1000}];letsortieTotale=0;for(leti=0;i<sortieDuProgrammeur.length;i++){sortieTotale+=sortieDuProgrammeur[i].linesDeCode;}

Bien:

constsortieDuProgrammeur=[{nom:"Oncle Bobby",linesDeCode:500},{nom:"Suzie Q",linesDeCode:1500},{nom:"Jimmy Gosling",linesDeCode:150},{nom:"Gracie Hopper",linesDeCode:1000}];constsortieTotale=sortieDuProgrammeur.reduce((linesTotal,sortie)=>linesTotal+sortie.linesDeCode,0);

⬆ retour au sommet

Encapsuler des conditions

Mal:

if(fsm.state==="chercher"&&estVide(listNode)){// ...}

Bien:

functiondevraitMontrerSpinner(fsm,listNode){returnfsm.state==="chercher"&&estVide(listNode);}if(devraitMontrerSpinner(fsmInstance,listNodeInstance)){// ...}

⬆ retour au sommet

Éviter les conditionnels négatifs

Mal:

functionDOMNodeNestPasPrésent(node){// ...}if(!DOMNodeNestPasPrésent(node)){// ...}

Bien:

functionestDOMNodePresent(node){// ...}if(estDOMNodePresent(node)){// ...}

⬆ retour au sommet

Éviter les conditionnels

Cela semble être une tâche impossible. En entendant cela, la plupart des gens disent:"comment suis-je censé faire quoi que ce soit sans une déclarationif? " La réponse est quevous pouvez utiliser le polymorphisme pour accomplir la même tâche dans de nombreux cas. La deuxièmela question est généralement, "bien c'est génial, mais pourquoi voudrais-je faire cela?" leanswer est un précédent concept de code propre que nous avons appris: une fonction ne devrait faire queune chose. Quand vous avez des classes et des fonctions qui ont des instructionsif, vousdites à votre utilisateur que votre fonction fait plus d’une chose. Rappelles toi,faites juste une chose.

Mal:

classAvion{// ...obtenirAltitudeDeCroisière(){switch(this.type){case"777":returnthis.obtenirAltitudeMax()-this.obtenirLeNombreDePassagers();case"Air Force One":returnthis.obtenirAltitudeMax();case"Cessna":returnthis.obtenirAltitudeMax()-this.obtenirDépensesDeCarburant();}}}

Good:

classAvion{// ...}classBoeing777extendsAvion{// ...obtenirAltitudeDeCroisière(){returnthis.obtenirAltitudeMax()-this.obtenirLeNombreDePassagers();}}classAirForceOneextendsAvion{// ...obtenirAltitudeDeCroisière(){returnthis.obtenirAltitudeMax();}}classCessnaextendsAvion{// ...obtenirAltitudeDeCroisière(){returnthis.obtenirAltitudeMax()-this.obtenirDépensesDeCarburant();}}

⬆ retour au sommet

Éviter la vérification de type (partie 1)

JavaScript n'est pas typé, ce qui signifie que vos fonctions peuvent accepter n'importe quel type d'argument.Parfois, vous êtes mordu par cette liberté et cela devient tentant de le fairevérification de type dans vos fonctions. Il y a plusieurs façons d'éviter d'avoir à le faire.La première chose à considérer est des API cohérentes.

Mal:

functionvoyagerAuTexas(véhicule){if(véhiculeinstanceofvélo){véhicule.pédale(this.localisationActuelle,newLocation("texas"));}elseif(véhiculeinstanceofvoiture){véhicule.conduire(this.localisationActuelle,newLocation("texas"));}}

Bien:

functionvoyagerAuTexas(véhicule){véhicule.déplacer(this.localisationActuelle,newLocation("texas"));}

⬆ retour au sommet

Éviter la vérification de type (partie 2)

Si vous travaillez avec des valeurs primitives de base telles que des chaînes et des entiers,et vous ne pouvez pas utiliser le polymorphisme mais vous ressentez toujours le besoin de vérifier le type,vous devriez envisager d'utiliser TypeScript. C'est une excellente alternative à la normaleJavaScript, car il fournit du typage statique en plus du JavaScript standardsyntaxe. Le problème avec la vérification manuelle du code JavaScript normal est quebien le faire nécessite tellement de verbiage supplémentaire que le faux "type-safety" que vous obtenezne compense pas la lisibilité perdue. Gardez votre JavaScript propre, écrivezde bons tests et de bonnes critiques de code. Sinon, faites tout cela mais avecTypeScript (qui, comme je l'ai dit, est une excellente alternative!).

Mal:

functioncombiner(val1,val2){if((typeofval1==="number"&&typeofval2==="number")||(typeofval1==="string"&&typeofval2==="string")){returnval1+val2;}thrownewError("Doit être de type String ou Number");}

Bien:

functioncombiner(val1,val2){returnval1+val2;}

⬆ retour au sommet

Ne pas trop optimiser

Les navigateurs modernes effectuent beaucoup d’optimisation au moment de l’exécution. Beaucoup deParfois, si vous optimisez, vous perdez simplement votre temps.Il y a de bonsRessourcespour voir où l'optimisation fait défaut. Ciblez-les entre-temps, jusqu'à ce queils sont fixes s'ils peuvent l'être.

Mal:

// Sur les anciens navigateurs, chaque itération avec `list.length` non mis en cache serait coûteuse// à cause du recalcul de `list.length`. Dans les navigateurs modernes, cela est optimisé.for(leti=0,len=list.length;i<len;i++){// ...}

Bien:

for(leti=0;i<list.length;i++){// ...}

⬆ retour au sommet

Supprimer le code mort

Le code mort est aussi grave qu'un code en double. Il n'y a aucune raison de le garder dansvotre base de code. Si ce n'est pas appelé, éliminez-le! Il sera toujours en sécuritédans votre historique de version si vous en avez toujours besoin.

Mal:

functionancienModuleDeDemande(url){// ...}functionnouveauModuleDeDemande(url){// ...}constreq=nouveauModuleDeDemande;traqueurInventaire("pommes",req,"www.inventory-awesome.io");

Bien:

functionnouveauModuleDeDemande(url){// ...}constreq=nouveauModuleDeDemande;traqueurInventaire("pommed",req,"www.inventory-awesome.io");

⬆ retour au sommet

Objets et Structures De Données

Utilisez des getters et des setters

Utiliser des getters et des setters pour accéder aux données sur des objets pourrait être mieux que simplementchercher une propriété sur un objet. "Pourquoi?" vous pourriez demander. Eh bien, voici unliste non organisée des raisons pour lesquelles:

  • Lorsque vous voulez faire plus que d'obtenir une propriété d'objet, vous n'avez pas   pour rechercher et changer tous les accesseurs de votre base de code.
  • Facilite l'ajout d'une validation lors d'unset.
  • Encapsule la représentation interne.
  • Facile à ajouter la journalisation et la gestion des erreurs lors de l'obtention et la configuration.
  • Vous pouvez charger paresseux les propriétés de votre objet, disons l'obtenir d'un   serveur.

Mal:

functionfaireUnCompteBancaire(){// ...return{bilan:0// ...};}constcompte=faireUnCompteBancaire();compte.bilan=100;

Bien:

functionfaireUnCompteBancaire(){// celui-ci est privéletbilan=0;// un "getter", rendu public via l'objet renvoyé ci-dessousfunctionobtenirLeBilan(){returnbilan;}// un "setter", rendu public via l'objet retourné ci-dessousfunctionfixerLeBilan(montante){// ... valider avant de mettre à jour le soldebilan=montante;}return{// ...    obtenirLeBilan,    fixerLeBilan};}constcompte=faireUnCompteBancaire();compte.fixerLeBilan(100);

⬆ retour au sommet

Faire en sorte que les objets aient des membres privés

Ceci peut être accompli par des fermetures (pour ES5 et moins).

Mal:

constEmployé=function(nom){this.nom=nom;};Employé.prototype.obtenirNom=functionobtenirNom(){returnthis.nom;};constemployé=newEmployé("John Doe");console.log(`Nom de l'employé:${employé.obtenirNom()}`);// Nom de l'employé: John Doedeleteemployé.nom;console.log(`Nom de l'employé:${employé.obtenirNom()}`);// Nom de l'employé: undefined

Bien:

functionfaireEmployé(nom){return{obtenirNom(){returnnom;}};}constemployé=faireEmployé("John Doe");console.log(`Nom de l'employé:${employé.obtenirNom()}`);// Nom de l'employé: John Doedeleteemployé.nom;console.log(`Nom de l'employé:${employé.obtenirNom()}`);// Nom de l'employé: undefined

⬆ retour au sommet

Classes

Préférez les classes ES2015 / ES6 aux fonctions simples de ES5

Il est très difficile d'obtenir un héritage de classe, une construction et une méthode lisibles.définitions pour les classes ES5 classiques. Si vous avez besoin d'héritage (et soyez conscientque vous ne pourriez pas), alors préférez les classes ES2015 / ES6. Cependant, préférez les petites fonctions auxcours jusqu’à ce que vous ayez besoin d’objets plus grands et plus complexes.

Mal:

constAnimale=function(âge){if(!(thisinstanceofAnimale)){thrownewError("Instancier Animal avec `new`");}this.âge=âge;};Animale.prototype.bouger=functionbouger(){};constMammifère=function(age,couleurDefourrure){if(!(thisinstanceofMammifère)){thrownewError("Instancier Mammifère avec `new`");}Animale.appel(this,âge);this.couleurDefourrure=couleurDefourrure;};Mammifère.prototype=Object.create(Animale.prototype);Mammifère.prototype.constructor=Mammifère;Mammifère.prototype.naissanceVivante=functionnaissanceVivante(){};constHumain=function(âge,couleurDefourrure,langueParlée){if(!(thisinstanceofHumain)){thrownewError("Instancier Humain avec `new`");}Mammifère.appel(this,âge,couleurDefourrure);this.langueParlée=langueParlée;};Humain.prototype=Object.create(Mammifère.prototype);Humain.prototype.constructor=Humain;Humain.prototype.parler=functionparler(){};

Bien:

classAnimale{constructor(âge){this.âge=âge;}bouger(){/* ... */}}classMammifèreextendsAnimale{constructor(âge,couleurDefourrure){super(âge);this.couleurDefourrure=couleurDefourrure;}naissanceVivante(){/* ... */}}classHumainextendsMammal{constructor(âge,couleurDefourrure,languageSpoken){super(âge,couleurDefourrure);this.languageSpoken=languageSpoken;}parler(){/* ... */}}

⬆ retour au sommet

Utiliser la méthode de chaînage

Ce modèle est très utile en JavaScript et vous le voyez dans de nombreuses bibliothèques telles quecomme jQuery et Lodash. Cela permet à votre code d’être expressif et moins bavard.Pour cette raison, dis-je, utilisez la méthode de chaînage et jetez un coup d'œil à la propreté de votre codesera. Dans vos fonctions de classe, retournez simplementthis à la fin de chaque fonction,et vous pouvez y chaîner d’autres méthodes de classe.

Mal:

classVoiture{constructor(marque,modèle,couleur){this.marque=marque;this.modèle=modèle;this.couleur=couleur;}fixerLaMarque(marque){this.marque=marque;}fixerLaModèle(modèle){this.modèle=modèle;}fixerLaCouleur(couleur){this.couleur=couleur;}enregistrer(){console.log(this.marque,this.modèle,this.couleur);}}constvoiture=newVoiture("Ford","F-150","rouge");voiture.fixerLaCouleur("rose");voiture.enregistrer();

Bien:

classVoiture{constructor(marque,modèle,couleur){this.marque=marque;this.modèle=modèle;this.couleur=couleur;}fixerLaMarque(marque){this.marque=marque;// NOTE: Renvoyer ceci pour chaînerreturnthis;}fixerLaModèle(modèle){this.modèle=modèle;// NOTE: Renvoyer ceci pour chaînerreturnthis;}fixerLaCouleur(couleur){this.couleur=couleur;// NOTE: Renvoyer ceci pour chaînerreturnthis;}enregistrer(){console.log(this.marque,this.modèle,this.couleur);// NOTE: Returning this for chainingreturnthis;}}constvoiture=newVoiture("Ford","F-150","rouge").fixerLaCouleur("rose").enregistrer();

⬆ retour au sommet

Préfère la composition à l'héritage

Comme l'a déclaré célèbre dansDesign Patterns par la Gang of Four, vous devriez préférer la composition à l'héritage lorsque vous le pouvez. Il y a beaucoup debonnes raisons d'utiliser l'héritage et beaucoup de bonnes raisons d'utiliser la composition.Le point principal de cette maxime est que si votre esprit opte instinctivement pourhéritage, essayez de penser si la composition pourrait mieux modéliser votre problème. Dans certainescas il peut.

Vous vous demandez peut-être alors "quand devrais-je utiliser l'héritage?" Ildépend de votre problème actuel, mais ceci est une liste décente des cas où l'héritageest plus logique que la composition:

  1. Votre héritage représente une relation "est-une" et non une relation "a-une"     relation (Humain-> Animal contre Utilisateur-> UserDetails).
  2. Vous pouvez réutiliser le code des classes de base (les humains peuvent se déplacer comme tous les animaux).
  3. Vous souhaitez apporter des modifications globales aux classes dérivées en modifiant une classe de base.     (Changer la dépense calorique de tous les animaux quand ils bougent).

Mal:

classEmployé{constructor(nom,email){this.nom=nom;this.email=email;}// ...}// Bad because Employees "have" tax data. EmployeeTaxData is not a type of EmployeeclassDonnéesFiscalesDuEmployéextendsEmployé{constructor(ssn,salaire){super();this.ssn=ssn;this.salaire=salaire;}// ...}

Bien:

classDonnéesFiscalesDuEmployé{constructor(ssn,salaire){this.ssn=ssn;this.salaire=salaire;}// ...}classEmployé{constructor(nom,email){this.nom=nom;this.email=email;}définirDonnéesFiscales(ssn,salaire){this.donnéesFiscales=newDonnéesFiscalesDuEmployé(ssn,salaire);}// ...}

⬆ retour au sommet

SOLID

Principe de responsabilité unique (PRU)

Comme indiqué dans Clean Code, "Il ne devrait jamais y avoir plus d'une raison pour une classepour changer ". Il est tentant de confier une classe avec beaucoup de fonctionnalités, commelorsque vous ne pouvez emporter qu'une valise par vol. Le problème avec ceci estque votre classe ne sera pas conceptuellement cohérente et cela lui donnera de nombreuses raisonschanger. Il est important de minimiser le nombre de fois que vous avez besoin de changer de classe.C'est important car si trop de fonctionnalités sont dans une classe et que vous modifiezun morceau de celui-ci, il peut être difficile de comprendre comment cela affectera les autresmodules dépendants dans votre base de code.

Mal:

classParamètresUtilisateur{constructor(utilisateur){this.utilisateur=utilisateur;}changerParamètres(paramètres){if(this.vérifierIdentifications()){// ...}}vérifierIdentifications(){// ...}}

Bien:

classAuthentificationUtilisateur{constructor(utilisateur){this.utilisateur=utilisateur;}vérifierIdentifications(){// ...}}classParamètresUtilisateur{constructor(utilisateur){this.utilisateur=utilisateur;this.auth=newAuthentificationUtilisateur(utilisateur);}changerParamètres(paramètres){if(this.auth.vérifierIdentifications()){// ...}}}

⬆ retour au sommet

Principe Ouvert / Fermé (POF)

Selon Bertrand Meyer, "les entités logicielles (classes, modules, fonctions,etc.) devrait être ouvert pour extension, mais fermé pour modification. "Qu'est-ce que celasignifie cependant? Ce principe stipule essentiellement que vous devez permettre aux utilisateurs deajouter de nouvelles fonctionnalités sans changer le code existant.

Mal:

classAdaptateurAjaxextendsAdaptateur{constructor(){super();this.nom="adaptateurAjax";}}classAdaptateurNodeextendsAdaptateur{constructor(){super();this.nom="adaptateurNode";}}classRequêtementHttp{constructor(adaptateur){this.adaptateur=adaptateur;}fetch(url){if(this.adaptateur.nom==="adaptateurAjax"){returnfaireAppelAjax(url).then(réponse=>{// transformer la réponse et le retour});}elseif(this.adaptateur.nom==="adaptateurNode"){returnfaireAppelHttp(url).then(réponse=>{//transformer la réponse et le retour});}}}functionfaireAppelAjax(url){// demande et retour promesse}functionfaireAppelHttp(url){// demande et retour promesse}

Bien:

classAdaptateurAjaxextendsAdaptateur{constructor(){super();this.nom="adaptateurAjax";}demande(url){// demande et retour promesse}}classAdaptateurNodeextendsAdaptateur{constructor(){super();this.nom="adaptateurNode";}demande(url){// demande et retour promesse}}classRequêtementHttp{constructor(adaptateur){this.adaptateur=adaptateur;}rapporter(url){returnthis.adaptateur.demande(url).then(réponse=>{//transformer la réponse et le retour});}}

⬆ retour au sommet

Principe de substitution de Liskov (PSL)

C'est un terme effrayant pour un concept très simple. Il est formellement défini comme "Si Sest un sous-type de T, les objets de type T peuvent être remplacés par des objets de type S(c’est-à-dire que les objets de type S peuvent se substituer aux objets de type T) sans modifierdes propriétés souhaitables de ce programme (exactitude, tâche effectuée,etc.). "C’est une définition encore plus effrayante.

La meilleure explication à cela est si vous avez une classe parent et une classe enfant,alors la classe de base et la classe enfant peuvent être utilisées de manière interchangeable sans obtenirrésultats incorrects. Cela peut encore être déroutant, alors jetons un coup d'oeil à laexemple classique de Square-Rectangle. Mathématiquement, un carré est un rectangle, maissi vous modélisez en utilisant la relation "est-une" via l'héritage, vous rapidementavoir des problèmes.

Mal:

classRectangle{constructor(){this.largeur=0;this.taille=0;}définirLaCouleur(couleur){// ...}rendre(surface){// ...}définirLaLargeur(largeur){this.largeur=largeur;}définirLaTaille(taille){this.taille=taille;}avoireLaSurface(){returnthis.largeur*this.taille;}}classCarréextendsRectangle{définirLaLargeur(largeur){this.largeur=largeur;this.taille=largeur;}définirLaTaille(taille){this.largeur=taille;this.taille=taille;}}functionrendreLesGrandsRectangles(rectangles){rectangles.forEach(rectangle=>{rectangle.définirLaLargeur(4);rectangle.définirLaTaille(5);constsurface=rectangle.avoireLaSurface();// BAD: renvoie 25 pour Square. Devrait être 20.rectangle.rendre(surface);});}constrectangles=[newRectangle(),newRectangle(),newCarré()];rendreLesGrandsRectangles(rectangles);

Bien:

classForme{définirLaCouleur(couleur){// ...}rendre(surface){// ...}}classRectangleextendsForme{constructor(largeur,taille){super();this.largeur=largeur;this.taille=taille;}avoireLaSurface(){returnthis.largeur*this.taille;}}classCarréextendsForme{constructor(longeur){super();this.longeur=longeur;}getArea(){returnthis.longeur*this.longeur;}}functionrendreLesGrandesFormes(formes){formes.forEach(forme=>{constsurface=forme.avoireLaSurface();forme.rendre(surface);});}constformes=[newRectangle(4,5),newRectangle(4,5),newSquare(5)];rendreLesGrandesFormes(formes);

⬆ retour au sommet

Principe de séparation des interfaces (ISP)

JavaScript n'a pas d'interface donc ce principe ne s'applique pas aussi strictementcomme d'autres. Cependant, il est important et pertinent même avec le manque de JavaScript de JavaScript.système de type.

ISP déclare que "les clients ne doivent pas être obligés de dépendre d’interfaces quiils n'utilisent pas. "Les interfaces sont des contrats implicites en JavaScript en raison decanard en tapant.

Un bon exemple à regarder qui démontre que ce principe en JavaScript est pourles classes qui nécessitent des objets de paramètres volumineux. Ne nécessite pas de clients à configurerd'énormes quantités d'options est bénéfique, car la plupart du temps, ils n'auront pas besointous les paramètres. Les rendre facultatifs aide à éviter d'avoir un"interface grasse".

Mal:

classDOMTraverser{constructor(réglages){this.réglages=réglages;this.installer();}installer(){this.rootNode=this.réglages.rootNode;this.moduleDAnimation.installer();}traverse(){// ...}}const$=newDOMTraverser({rootNode:document.getElementsByTagName("body"),moduleDAnimation(){}// La plupart du temps, nous n'avons pas besoin d'animer lorsque vous traversez.// ...});

Bien:

classDOMTraverser{constructor(réglages){this.réglages=réglages;this.options=réglages.options;this.installer();}installer(){this.rootNode=this.réglages.rootNode;this.optionsInstallation();}setupOptions(){if(this.options.moduleDAnimation){// ...}}traverse(){// ...}}const$=newDOMTraverser({rootNode:document.getElementsByTagName("body"),options:{moduleDAnimation(){}}});

⬆ retour au sommet

Principe d'inversion de dépendance (DIP)

Ce principe énonce deux choses essentielles:

  1. Les modules de haut niveau ne doivent pas dépendre de modules de bas niveau. Les deux devraient    dépend des abstractions.
  2. Les abstractions ne doivent pas dépendre des détails. Les détails devraient dépendre de    abstractions.

Cela peut être difficile à comprendre au début, mais si vous avez travaillé avec AngularJS,vous avez vu une mise en œuvre de ce principe sous la forme de dépendanceInjection (DI). Bien qu’ils ne soient pas des concepts identiques, DIP conserve un haut niveau de qualité.modules de connaître les détails de ses modules de bas niveau et de les configurer.Cela peut être accompli grâce à DI. Un énorme avantage de cela est qu'il réduitle couplage entre les modules. Le couplage est un très mauvais schéma de développement carcela rend votre code difficile à refactoriser.

Comme indiqué précédemment, JavaScript n'a pas d'interface, donc les abstractionsqui sont dépendantes sont des contrats implicites. C'est-à-dire les méthodeset les propriétés qu'un objet / classe expose à un autre objet / classe. dans leexemple ci-dessous, le contrat implicite est que tout module de demande pour unInventoryTracker aura une méthoderequestItems.

Mal:

classDemandeurInventaire{constructor(){this.REQ_METHODS=["HTTP"];}demanderUnArticle(article){// ...}}classSuiviInventaire{constructor(articles){this.articles=articles;// BAD: Nous avons créé une dépendance sur une implémentation de requête spécifique.// On devrait juste avoir demanderUnArticles dépendent d'une méthode de requête: `request`this.demandeur=newDemandeurInventaire();}demanderDesArticles(){this.articles.forEach(article=>{this.demandeur.demanderUnArticle(article);});}}consttraqueurInventaire=newSuiviInventaire(["pommes","bananes"]);traqueurInventaire.demanderDesArticles();

Bien:

classSuiviInventaire{constructor(articles,demandeur){this.articles=articles;this.demandeur=demandeur;}demanderDesArticles(){this.articles.forEach(article=>{this.demandeur.demanderUnArticle(article);});}}classDemandeurInventaireV1{constructor(){this.REQ_METHODS=["HTTP"];}demanderUnArticle(article){// ...}}classDemandeurInventaireV2{constructor(){this.REQ_METHODS=["WS"];}demanderUnArticle(article){// ...}}// En construisant nos dépendances à l'extérieur et en les injectant, on peut facilement// substitue notre module de requête à un nouveau module utilisant WebSockets.consttraqueurInventaire=newSuiviInventaire(["pommes","bananes"],newDemandeurInventaireV2());traqueurInventaire.demanderDesArticles();

⬆ retour au sommet

Testage

Le test est plus important que l'expédition. Si vous n'avez pas de test ou unquantité insuffisante, alors chaque fois que vous expédiez du code, vous ne serez pas sûr den'a rien casser. Décider de ce qui constitue un montant adéquat est en placeà votre équipe, mais avoir une couverture de 100% (tous les états et branches) est lavous obtenez une très grande confiance et une tranquillité d'esprit développeur. Cela signifie queen plus d'avoir un excellent framework de test, vous devez également utiliser unbon outil de couverture.

Il n'y a aucune excuse pour ne pas écrire de tests. Il y abeaucoup de bons frameworks de test JS, Alors, trouvez-en un que votre équipe préfère.Lorsque vous en trouvez un qui convient à votre équipe, essayez de toujours écrire des testspour chaque nouvelle fonctionnalité / module que vous introduisez. Si votre méthode préférée estTest Driven Development (TDD), c’est génial, mais l’essentiel est de simplementassurez-vous d'atteindre vos objectifs de couverture avant de lancer une fonctionnalité,ou refactoriser un existant.

Concept unique par test

Mal:

importassertfrom"assert";describe("Rendre MomentJS encore une fois génial",()=>{it("gère les limites de la date",()=>{letdate;date=newRendreMomentJSEncoreUneFoisGénial("1/1/2015");date.addDays(30);assert.equal("1/31/2015",date);date=newRendreMomentJSEncoreUneFoisGénial("2/1/2016");date.addDays(28);assert.equal("02/29/2016",date);date=newRendreMomentJSEncoreUneFoisGénial("2/1/2015");date.addDays(28);assert.equal("03/01/2015",date);});});

Bien:

importassertfrom"assert";describe("Rendre MomentJS encore une fois génial",()=>{it("gère les mois de 30 jours",()=>{constdate=newRendreMomentJSEncoreUneFoisGénial("1/1/2015");date.ajouterLesJours(30);assert.equal("1/31/2015",date);});it("gère l'année bissextile",()=>{constdate=newRendreMomentJSEncoreUneFoisGénial("2/1/2016");date.ajouterLesJours(28);assert.equal("02/29/2016",date);});it("gère l'année non bissextile",()=>{constdate=newRendreMomentJSEncoreUneFoisGénial("2/1/2015");date.ajouterLesJours(28);assert.equal("03/01/2015",date);});});

⬆ retour au sommet

Simultanéité

Utilisez des promesses, pas des rappels

Les rappels ne sont pas propres et provoquent des quantités excessives d'imbrication. Avec ES2015 / ES6,Les promesses sont un type global intégré. Utilise les!

Mal:

import{get}from"request";import{writeFile}from"fs";get("https://en.wikipedia.org/wiki/Robert_Cecil_Martin",(errDemande,réponse)=>{if(errDemande){console.error(errDemande);}else{writeFile("article.html",réponse.body,writeErr=>{if(writeErr){console.error(writeErr);}else{console.log("Fichier écrit");}});}});

Bien:

import{get}from"request";import{writeFile}from"fs";get("https://en.wikipedia.org/wiki/Robert_Cecil_Martin").then(réponse=>{returnwriteFile("article.html",réponse);}).then(()=>{console.log("Fichier écrit");}).catch(err=>{console.error(err);});

⬆ retour au sommet

Async / Await sont encore plus propres que Promises

Les promesses sont une alternative très propre aux callbacks, mais ES2017 / ES8 apporte async et attendqui offrent une solution encore plus propre. Tout ce dont vous avez besoin est une fonction préfixéedans un mot cléasync, et vous pourrez alors écrire votre logique impérativement sansune chaîne de fonctions "alors". Utilisez-le si vous pouvez tirer parti des fonctionnalités de ES2017 / ES8aujourd'hui!

Mal:

import{get}from"request-promise";import{writeFile}from"fs-promise";get("https://en.wikipedia.org/wiki/Robert_Cecil_Martin").then(réponse=>{returnwriteFile("article.html",réponse);}).then(()=>{console.log("Fichier écrit");}).catch(err=>{console.error(err);});

Bien:

import{get}from"request-promise";import{writeFile}from"fs-promise";asyncfunctionobtenirUnArticleDeCodePropre(){try{constresponse=awaitget("https://en.wikipedia.org/wiki/Robert_Cecil_Martin");awaitwriteFile("article.html",réponse);console.log("Fichier écrit");}catch(err){console.error(err);}}

⬆ retour au sommet

La Gestion des Erreurs

Les erreurs jetées sont une bonne chose! Ils veulent dire que le runtime a réussiidentifié quand quelque chose dans votre programme a mal tourné et il laissevous savez en arrêtant l'exécution de la fonction sur la pile en cours, tuant leprocessus (en nœud), et vous notifiant dans la console avec une trace de pile.

Ne pas ignorer les erreurs interceptées

Ne rien faire avec une erreur interceptée ne vous donne pas la possibilité de réparerou réagir à cette erreur. Consigner l'erreur dans la console (console.log)n'est pas beaucoup mieux que souvent, il peut se perdre dans une mer de choses impriméesà la console. Si vous intégrez un morceau de code dans untry / catch, cela signifie que vouspense qu'une erreur peut se produire là-bas et que vous devriez donc avoir un plan,ou créer un chemin de code, pour quand il se produit.

Mal:

try{fonctionQuiPourraitJeter();}catch(error){console.log(error);}

Bien:

try{fonctionQuiPourraitJeter();}catch(error){// Une option (plus bruyante que console.log):console.error(error);// Une autre option:notifierUtilisateurDuErreur(error);// Une autre option:signalerAuServiceDuErreur(error);// OU faire tous les trois!}

Ne pas ignorer les promesses rejetées

Pour la même raison, vous ne devez pas ignorer les erreurs interceptéesdetry / catch.

Mal:

getdata().then(données=>{fonctionQuiPourraitJeter(données);}).catch(error=>{console.log(error);});

Good:

getdata().then(données=>{fonctionQuiPourraitJeter(données);}).catch(error=>{// Une option (plus bruyante que console.log):console.error(error);// Une autre option:notifierUtilisateurDuErreur(error);// Une autre option:signalerAuServiceDuErreur(error);// OU faire tous les trois!});

⬆ retour au sommet

Mise En Forme

Le formatage est subjectif. Comme beaucoup de règles, il n’existe pas de solution simple et rapide.règle que vous devez suivre. L'essentiel est de NE PAS ARGUER sur le formatage.Il y ades tonnes d'outils pour automatiser cela.Utilisez-en un! Discuter de la mise en forme est une perte de temps et d'argent pour les ingénieurs.

Pour les choses qui ne relèvent pas du formatage automatique(indentation, tabulations vs espaces, guillemets doubles vs simples, etc.) regardez icipour des conseils.

Utilisez une capitalisation cohérente

JavaScript n'est pas typé, la capitalisation en dit beaucoup sur vos variables,fonctions, etc. Ces règles sont subjectives, votre équipe peut donc choisir ce queIls veulent. Le fait est que, peu importe ce que vous choisissez tous, soyez juste cohérent.

Mal:

constJOURS_PAR_SEMAINE=7;constjoursParMois=30;constchansons=["Back In Black","Stairway to Heaven","Hey Jude"];constArtists=["ACDC","Led Zeppelin","The Beatles"];functioneffacerLeDatabase(){}functionrestaurer_Ledatabase(){}classanimale{}classAlpaga{}

Bien:

constJOURS_PAR_SEMAINE=7;constJOURS_PAR_MOIS=30;constCHANSONS=["Back In Black","Stairway to Heaven","Hey Jude"];constARTISTS=["ACDC","Led Zeppelin","The Beatles"];functioneffacerLeDatabase(){}functionrestaurerLeDatabase(){}classAnimale{}classAlpaga{}

⬆ retour au sommet

Les appelants et les correspondants doivent être rapprochés

Si une fonction en appelle une autre, gardez ces fonctions verticalement proches dans la sourcefichier. Idéalement, laissez l'appelant juste au-dessus de l'appelé. Nous avons tendance à lire le code dede haut en bas, comme un journal. Pour cette raison, faites votre code lu de cette façon.

Mal:

classExamenDuRendement{constructor(employé){this.employé=employé;}lookupCollègues(){returndb.lookup(this.employé,"collègues");}lookupDirecteur(){returndb.lookup(this.employé,"directeur");}obtenirEvaluationsDesCollègues(){constcollègues=this.lookupCollègues();// ...}examenDuRendement(){this.obtenirEvaluationsDesCollègues();this.obtenirEvaluationsDuDirecteur();this.obtenirEvaluationDeSoi();}obtenirEvaluationsDuDirecteur(){constmanager=this.lookupDirecteur();}obtenirEvaluationDeSoi(){// ...}}constevaluation=newExamenDuRendement(employé);evaluation.examenDuRendement();

Bien:

classExamenDuRendement{constructor(employé){this.employé=employé;}examenDuRendement(){this.obtenirEvaluationsDesCollègues();this.obtenirEvaluationsDuDirecteur();this.obtenirEvaluationDeSoi();}obtenirEvaluationsDesCollègues(){constcollègues=this.lookupCollègues();// ...}lookupCollègues(){returndb.lookup(this.employé,"collègues");}obtenirEvaluationsDuDirecteur(){constmanager=this.lookupDirecteur();}lookupDirecteur(){returndb.lookup(this.employé,"directeur");}obtenirEvaluationDeSoi(){// ...}}constevaluation=newExamenDuRendement(employé);evaluation.examenDuRendement();

⬆ retour au sommet

Commentaires

Ne commentez que les choses qui ont une complexité de logique métier.

Les commentaires sont des excuses, pas une exigence. Bon codemostly se documente.

Mal:

functionhasher(données){// La hashlethash=0;// Longeur du stringconstlongeur=données.longeur;// Boucle à travers chaque caractère dans les donnéesfor(leti=0;i<length;i++){// Obtenez le code de caractère.constchar=données.charCodeAt(i);// Faire le hashhash=(hash<<5)-hash+char;// Convertir en entier 32 bitshash&=hash;}}

Bien:

functionhasher(données){lethash=0;constlongeur=données.longeur;for(leti=0;i<length;i++){constchar=données.charCodeAt(i);hash=(hash<<5)-hash+char;// Convertir en entier 32 bitshash&=hash;}}

⬆ retour au sommet

Ne laissez pas de code commenté dans votre base de code

Le contrôle de version existe pour une raison. Laissez l'ancien code dans votre historique.

Mal:

faireUneChose();// faireAutreChoses();// faireEncoreAutreChoses();// faireTropDeChoses();

Bien:

faireUneChose();

⬆ retour au sommet

Je n'ai pas de commentaires dans le journal

Rappelez-vous, utilisez le contrôle de version! Il n'y a pas besoin de code mort, de code commenté,et surtout les commentaires de journaux. Utilisezgit log pour obtenir l'historique!

Mal:

/** * 2016-12-20: Monades supprimées, je ne les ai pas comprises (RM) * 2016-10-01: Amélioration de l'utilisation de monades spéciales (JP) * 2016-02-03: Suppression de la vérification de type (LI) * 2015-03-14: Ajout d'une combinaison avec la vérification de type (JR) */functioncombiner(a,b){returna+b;}

Bien:

functioncombiner(a,b){returna+b;}

⬆ retour au sommet

Évitez les marqueurs de position

Ils ne font généralement qu'ajouter du bruit. Laissez les fonctions et les noms de variables avec leL’indentation et le formatage appropriés donnent la structure visuelle à votre code.

Mal:

////////////////////////////////////////////////////////////////////////////////// Instanciation du modèle de portée////////////////////////////////////////////////////////////////////////////////$scope.model={menu:"foo",nav:"bar"};////////////////////////////////////////////////////////////////////////////////// Configuration de l'action////////////////////////////////////////////////////////////////////////////////constactions=function(){// ...};

Bien:

$scope.model={menu:"foo",nav:"bar"};constactions=function(){// ...};

⬆ retour au sommet

Traduction

Ceci est également disponible dans d'autres langues:

⬆ retour au sommet

About

A translation of Ryan McDermott's "Clean Code Javascript" repository to French

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

[8]ページ先頭

©2009-2025 Movatter.jp