JavaScript vient du début du Web. Au début, des scripts simples étaient écrits dessus pour «animer» les pages des sites. Maintenant, JS est devenu un langage de programmation à part entière qui peut même être utilisé pour développer des projets côté serveur.
Les applications Web modernes reposent largement sur JavaScript. Cela est particulièrement vrai pour les applications monopages (application monopage, SPA). Avec l'avènement des bibliothèques et des frameworks tels que React, Angular et Vue, JavaScript est devenu l'un des principaux éléments constitutifs des applications Web.

La mise à l'échelle de ces applications, qu'il s'agisse de leurs parties client ou serveur, peut être une tâche très difficile. Si de telles applications sont basées sur une architecture mal pensée, leurs développeurs seront tôt ou tard confrontés à certaines limitations. Ils se noient dans une mer de mauvaises surprises.
L'auteur de l'article, dont nous publions la traduction aujourd'hui, souhaite partager des conseils sur l'écriture de code JavaScript pur. Il dit que l'article s'adresse aux programmeurs JS de tout niveau de compétence. Mais il sera particulièrement utile pour ceux qui connaissent JavaScript au moins à un niveau intermédiaire.
1. Isolement du code
Afin de garder la base de code du projet propre afin que le code puisse être facilement lu, il est recommandé de séparer les fragments de code en blocs séparés en fonction de leur objectif. Ces blocs sont généralement des fonctions. Je considère que cette recommandation est la plus importante que je puisse faire. Si vous écrivez une fonction, vous devez immédiatement vous concentrer sur le fait que cette fonction viserait à résoudre un seul problème. La fonction ne doit pas être conçue pour résoudre plusieurs problèmes.
De plus, vous devez vous assurer que les appels de fonction n'entraînent pas d'effets secondaires. Dans la plupart des cas, cela signifie que la fonction ne doit pas changer quelque chose qui est déclaré en dehors d'elle. Les données sont reçues via des paramètres. Elle ne devrait pas travailler avec autre chose. Vous devez
return
une des fonctions à l'aide du mot clé
return
.
2. Décomposition du code en modules
Les fonctions utilisées de manière similaire ou effectuant des actions similaires peuvent être regroupées dans un module (ou, si vous le souhaitez, dans une classe distincte). Supposons que vous deviez effectuer divers calculs dans votre projet. Dans une telle situation, il est logique d'exprimer les différentes étapes de ces calculs sous la forme de fonctions séparées (blocs isolés), dont les appels peuvent être combinés en chaînes. Cependant, toutes ces fonctions peuvent être déclarées dans un seul fichier (c'est-à-dire dans un module). Voici un exemple du module computing.js qui contient des fonctions similaires:
function add(a, b) { return a + b } function subtract(a, b) { return a - b } module.exports = { add, subtract }
Et voici comment vous pouvez utiliser ce module dans un autre fichier (appelons-le
index.js
):
const { add, subtract } = require('./calculations') console.log(subtract(5, add(3, 2))
Les développeurs d'applications frontales peuvent recevoir les recommandations suivantes. Pour exporter les entités les plus importantes déclarées dans le module, utilisez les options d'exportation par défaut. Pour les entités secondaires, vous pouvez utiliser l'exportation nommée.
3. Utilisez plusieurs paramètres de fonction au lieu d'un seul objet avec des paramètres
Lors de la déclaration d'une fonction, vous devez vous efforcer d'utiliser plusieurs paramètres, plutôt qu'un seul objet avec des paramètres. Voici quelques exemples:
La présence d'une fonction avec plusieurs paramètres vous permet de découvrir immédiatement ce qui doit lui être transmis en regardant la première ligne de sa déclaration. C'est précisément la raison pour laquelle je donne cette recommandation.
Malgré le fait que lors du développement de fonctions, vous devez vous efforcer de garantir que chacune d'elles ne résout qu'un seul problème, la taille du code de fonction peut être assez importante. Si une fonction accepte un seul objet avec des paramètres, afin de savoir exactement ce qu'elle attend, vous devrez peut-être regarder tout son code, en y consacrant beaucoup de temps. Parfois, il peut sembler que lorsque vous travaillez avec des fonctions, il est beaucoup plus facile d'utiliser un seul objet avec des paramètres. Mais si vous écrivez des fonctions, compte tenu de la mise à l'échelle future possible de l'application, il est préférable d'utiliser plusieurs paramètres.
Il convient de noter qu'il existe une certaine limite après laquelle l'utilisation de paramètres individuels perd son sens. Dans mon cas, ce sont quatre à cinq paramètres. Si une fonction a besoin de tant d'entrées, un programmeur devrait envisager d'utiliser un objet avec des paramètres.
La principale raison de cette recommandation est que les paramètres individuels attendus par la fonction doivent lui être transmis dans un ordre spécifique. Si certains des paramètres sont facultatifs, vous devez plutôt passer des fonctions comme
undefined
ou
null
. Lorsque vous utilisez un objet avec des paramètres, l'ordre des paramètres dans l'objet n'a pas d'importance. Avec cette approche, vous pouvez vous passer de définir les paramètres facultatifs sur
undefined
.
4. Restructuration
La restructuration est un mécanisme utile qui est apparu dans ES6. Il vous permet d'extraire les champs spécifiés des objets et de les écrire immédiatement dans des variables. Il peut être utilisé lorsque vous travaillez avec des objets et des modules:
En particulier, lorsque vous travaillez avec des modules, il est logique d'importer dans un fichier non pas le module entier, mais uniquement les fonctions nécessaires, en leur donnant des noms compréhensibles. Sinon, vous devrez accéder aux fonctions à l'aide d'une variable symbolisant le module.
Une approche similaire est applicable aux cas où un seul objet est utilisé comme paramètre de fonction. Cela permet de regarder la première ligne de la fonction pour savoir immédiatement ce qu'elle attend exactement comme objet avec des paramètres:
function logCountry({name, code, language, currency, population, continent}) { let msg = `The official language of ${name} ` if(code) msg += `(${code}) ` msg += `is ${language}. ${population} inhabitants pay in ${currency}.` if(contintent) msg += ` The country is located in ${continent}` } logCountry({ name: 'Germany', code: 'DE', language 'german', currency: 'Euro', population: '82 Million', }) logCountry({ name: 'China', language 'mandarin', currency: 'Renminbi', population: '1.4 Billion', continent: 'Asia', })
Comme vous pouvez le voir, malgré le fait que la fonction accepte un seul objet avec des paramètres, sa déstructuration vous permet de savoir exactement ce qui doit y être placé lors de l'appel de la fonction. L'astuce suivante sera de savoir comment dire plus précisément à l'utilisateur ce que la fonction attend.
Soit dit en passant, la restructuration peut également être utilisée lorsque vous travaillez avec des composants fonctionnels de React.
5. Définissez les valeurs par défaut des paramètres de fonction
Les valeurs standard des paramètres des fonctions, les valeurs par défaut des paramètres, il est logique de les utiliser lors de la déstructuration d'objets avec des paramètres, et dans les cas où les fonctions acceptent des listes de paramètres. Premièrement, il donne au programmeur un exemple des fonctions qui peuvent être transmises. Deuxièmement, il vous permet de savoir quels paramètres sont obligatoires et lesquels sont facultatifs. Nous complétons la déclaration de fonction de l'exemple précédent avec des valeurs de paramètres standard:
function logCountry({ name = 'United States', code, language = 'English', currency = 'USD', population = '327 Million', continent, }) { let msg = `The official language of ${name} ` if(code) msg += `(${code}) ` msg += `is ${language}. ${population} inhabitants pay in ${currency}.` if(contintent) msg += ` The country is located in ${continent}` } logCountry({ name: 'Germany', code: 'DE', language 'german', currency: 'Euro', population: '82 Million', }) logCountry({ name: 'China', language 'mandarin', currency: 'Renminbi', population: '1.4 Billion', continent: 'Asia', })
Il est évident que dans certains cas, si un paramètre de fonction ne lui a pas été transmis lors de l'appel d'une fonction, il est nécessaire de donner une erreur plutôt que d'utiliser la valeur standard de ce paramètre. Mais souvent, cependant, la technique décrite ici est très utile.
6. Ne transmettez pas de données inutiles aux fonctions
La recommandation précédente nous amène à une conclusion intéressante. Elle consiste dans le fait que les fonctions n'ont pas besoin de transférer les données dont elles n'ont pas besoin. Si vous suivez cette règle, le développement des fonctions peut nécessiter du temps supplémentaire. Mais à long terme, cette approche conduira à la formation d'une base de code qui se distingue par une bonne lisibilité. De plus, il est extrêmement utile de savoir quel type de données est utilisé à chaque endroit particulier du programme.
7. Limiter le nombre de lignes dans les fichiers et le niveau maximal d'imbrication de code
J'ai vu de gros fichiers avec du code de programme. Très gros. Certains avaient plus de 3 000 lignes. Dans de tels fichiers, il est très difficile de s'y retrouver.
Par conséquent, il est recommandé de limiter la taille des fichiers mesurée en lignes de code. Je m'efforce généralement de m'assurer que la taille de mes fichiers ne dépasse pas 100 lignes. Parfois, quand il est difficile de briser une certaine logique en petits fragments, la taille de mes fichiers atteint 200-300 lignes. Et très rarement, leur taille atteint 400 lignes. Les fichiers qui dépassent cette limite sont difficiles à lire et à gérer.
Au cours du travail sur vos projets, créez audacieusement de nouveaux modules et dossiers. La structure du projet doit ressembler à une forêt composée d'arbres (groupes de modules et fichiers de modules) et de branches (sections de modules). Veillez à ce que vos projets ne ressemblent pas à des chaînes de montagnes.
Si nous parlons de l'apparence des fichiers eux-mêmes avec le code, ils devraient être similaires au terrain avec des collines basses. Il s'agit d'éviter de grands niveaux d'imbrication de code. Il convient de s'efforcer de s'assurer que l'imbrication du code ne dépasse pas quatre niveaux.
L'observation de ces recommandations aidera peut-être à appliquer les règles de linter ESLint appropriées.
8. Utilisez des outils pour formater automatiquement le code
Lorsque vous travaillez sur des projets JavaScript en équipe, vous devez développer un guide clair sur le style et la mise en forme du code. Vous pouvez automatiser la mise en forme du code avec ESLint. Ce linter offre au développeur un énorme ensemble de règles personnalisables. Il existe une
eslint --fix
qui peut corriger certaines erreurs.
Cependant, je recommande d'utiliser Prettier plutôt que ESLint pour automatiser la mise en forme du code. Avec cette approche, le développeur peut ne pas avoir à se soucier du formatage du code. Il n'a qu'à écrire des programmes de qualité. Tout le code formaté automatiquement à l'aide d'un seul ensemble de règles sera cohérent.
9. Utilisez des noms de variables bien conçus
Le nom de la variable devrait idéalement refléter son contenu. Voici quelques conseils pour sélectionner des noms de variables informatifs.
▍ Fonctions
Habituellement, les fonctions exécutent une sorte d'action. Les gens, lorsqu'ils parlent d'actions, utilisent des verbes. Par exemple - convertir (convertir) ou afficher (afficher). Il est recommandé de former les noms de fonction afin qu'ils commencent par un verbe. Par exemple,
convertCurrency
ou
displayUser
.
▍ Tableaux
Les tableaux contiennent généralement des ensembles de certaines valeurs. Par conséquent, il est logique d'ajouter la lettre
s
au nom de la variable qui stocke le tableau. Par exemple:
const students = ['Eddie', 'Julia', 'Nathan', 'Theresa']
▍Valeurs logiques
Les noms de variables booléennes ont un sens pour commencer par
is
ou
has
. Cela les rapproche des constructions disponibles en langage ordinaire. Par exemple, voici la question: «Cette personne est-elle enseignante?». La réponse à cette question peut être «Oui» ou «Non». Vous pouvez faire de même en sélectionnant des noms pour les variables logiques:
const isTeacher = true
▍ Paramètres des fonctions passées aux méthodes de tableau standard
Voici quelques méthodes de tableau JavaScript standard:
forEach
,
map
,
forEach
,
filter
. Ils vous permettent d'effectuer certaines actions avec des tableaux. Ce sont des fonctions transmises qui décrivent les opérations sur les tableaux. J'ai vu combien de programmeurs passent simplement des paramètres avec des noms comme
el
ou
element
à de telles fonctions. Bien que cette approche libère le programmeur de la possibilité de nommer ces paramètres, il est préférable de les appeler en fonction des données qui y figurent. Par exemple:
const cities = ['Berlin', 'San Francisco', 'Tel Aviv', 'Seoul'] cities.forEach(function(city) { ... })
▍ Identifiants
Il arrive souvent qu'un programmeur doive travailler avec les identifiants de certains ensembles de données ou objets. Si de tels identifiants sont imbriqués, rien de spécial ne doit être fait avec eux. Par exemple, lorsque je travaille avec MongoDB, je convertis généralement
_id
en
id
avant de renvoyer l'objet à l'application frontale. Lors de l'extraction des identifiants des objets, il est recommandé de former leurs noms en définissant le type de l'objet avant
id
. Par exemple:
const studentId = student.id
Une exception à cette règle est l'utilisation des références MongoDB dans les modèles. Dans de tels cas, il est recommandé de nommer les champs conformément aux modèles qui y sont référencés. Ceci, lors du remplissage des documents vers lesquels il existe des liens dans les champs, permettra de garder le code propre et uniforme:
const StudentSchema = new Schema({ teacher: { type: Schema.Types.ObjectId, ref: 'Teacher', required: true, }, name: String, ... })
10. Utilisez la construction async / wait lorsque cela est possible.
L'utilisation de rappels dégrade la lisibilité du code. Cela est particulièrement vrai pour les rappels imbriqués. Les promesses ont un peu arrangé les choses, mais je crois que le code qui utilise la construction async / wait est mieux lu. Même les débutants et les développeurs qui sont passés à JavaScript à partir d'autres langues peuvent facilement comprendre ce code. La chose la plus importante ici est de maîtriser les concepts sous-jacents asynchrones / attendent. N'utilisez pas ce design partout en raison de sa nouveauté.
11. La procédure d'importation des modules
Les recommandations 1 et 2 ont démontré l'importance de choisir le bon endroit pour stocker le code pour s'assurer qu'il est pris en charge. Des idées similaires s'appliquent à l'ordre d'importation des modules. À savoir, nous parlons du fait que l'ordre logique d'importation des modules rend le code plus clair. Lors de l'importation de modules, je respecte le schéma simple suivant:
Cet exemple est basé sur React. La même idée ne sera pas difficile à transférer dans un autre environnement de développement.
12. Évitez d'utiliser console.log
La commande
console.log
est un outil simple, rapide et pratique pour le débogage de programmes. Il existe, bien sûr, des outils plus avancés de ce type, mais je pense que presque tous les programmeurs utilisent toujours
console.log
. Si, en utilisant
console.log
pour le débogage, si vous ne supprimez pas les appels de cette commande qui deviennent inutiles à temps, la console deviendra bientôt complètement désordonnée. Il convient de noter qu'il est logique de laisser certaines équipes de journalisation même dans le code de projets qui sont complètement prêts pour le travail. Par exemple, des commandes qui affichent des messages d'erreur et des avertissements.
En conséquence, nous pouvons dire qu'il est tout à fait possible d'utiliser
console.log
à des fins de débogage, et dans les cas où les commandes de journalisation sont prévues pour être utilisées dans des projets de travail, il est logique de recourir à des bibliothèques spécialisées. Parmi eux,
Loglevel et
Winston . De plus, ESLint peut être utilisé pour combattre les commandes de journalisation inutiles. Cela permet une recherche globale et la suppression de ces commandes.
Résumé
L'auteur de ce document dit que tout ce dont il a parlé ici l'aide beaucoup à maintenir la propreté et l'évolutivité de la base de code de ses projets. Nous espérons que ces conseils vous seront utiles.
Chers lecteurs! Que pourriez-vous ajouter aux 12 conseils ici pour écrire du code JS propre et évolutif?
