Comment rendre le code lisible

Comment rendre le code lisible


Parfois, nous avons tous écrit (et certains écrivent) du mauvais code, et j'espère que nous travaillons tous pour améliorer nos compétences, et pas seulement pour lire des articles comme celui-ci.


Pourquoi devons-nous écrire du bon code, pas seulement du code productif?


Bien que les performances de votre produit ou site soient importantes, l'apparence de votre code l'est également. La raison en est que non seulement la machine lit votre code .


Premièrement, tôt ou tard, vous devrez relire votre propre code et, le moment venu, seul un code bien écrit vous aidera à comprendre ce que vous avez écrit ou à trouver comment le corriger.


Deuxièmement, si vous travaillez en équipe ou collaborez avec d'autres développeurs, tous les membres de l'équipe liront votre code et essaieront de l'interpréter comme ils le comprennent. Pour leur faciliter la tâche, il est important de suivre certaines règles lors de la dénomination des variables et des fonctions, de limiter la longueur de chaque ligne et de préserver la structure de votre code.


Enfin, regardons un exemple spécifique.


Partie 1: Comment identifier le mauvais code?


La façon la plus simple d'identifier un mauvais code, à mon avis, est d'essayer de lire le code comme s'il s'agissait d'une phrase ou d'une phrase .


Par exemple, jetez un œil à ce code:


Capture d'écran d'une mauvaise version de traverseUpUntil


Capture d'écran d'une mauvaise version de traverseUpUntil


La fonction présentée ci-dessus accepte un élément et une fonction conditionnelle et renvoie le nœud parent le plus proche qui satisfait la fonction conditionnelle.


const traverseUpUntil = (el, f) => { 

Sur la base du fait que le code doit être lu comme du texte brut, la première ligne a trois défauts grossiers.


  • Les paramètres de fonction ne sont pas lus comme des mots .
  • Supposons que el puisse être compris, car un tel nom est généralement utilisé pour désigner un élément, mais le nom du paramètre f n'explique rien du tout.
  • Le nom de la fonction peut être lu comme ceci: "commutateur jusqu'à ce que el passe f", qui est probablement mieux lu comme "commutateur jusqu'à ce que f passe pour el". Bien sûr, la meilleure façon de procéder consiste à autoriser la fonction à être appelée el.traverseUpUntil(f) , mais c'est un autre problème.

 let p = el.parentNode 

Ceci est la deuxième ligne. Encore une fois, le problème avec les noms, cette fois avec la variable. Si quelqu'un regardait le code, alors très probablement, il comprendrait ce qu'est p . Il s'agit du parentNode paramètre el . Cependant, ce qui se passe quand on regarde p utilisé ailleurs, on n'a plus de contexte qui explique ce que c'est .


 while (p.parentNode && !f(p)) { 

Sur la ligne suivante, le principal problème auquel nous sommes confrontés est un manque de compréhension de ce que !f(p) signifie ou fait, car «f» peut signifier n'importe quoi . On suppose que la personne qui lit le code doit comprendre que !f(p) est une vérification du nœud actuel pour satisfaire une certaine condition. S'il passe, alors le cycle est interrompu.


 p = p.parentNode 

Tout est clair ici.


 return p 

Ce qui est retourné n'est pas entièrement évident en raison d'un nom de variable non valide.


Partie 2: Refactorons


Capture d'écran d'une bonne version de traverseUpUntil


Capture d'écran d'une bonne version de traverseUpUntil


Tout d'abord, nous changeons les noms des paramètres et leur ordre: (el, f) => en (condition, node) => .
Vous vous demandez peut-être pourquoi au lieu de «élément (élément russe), j'ai utilisé« nœud »( nœud russe). Je l'ai utilisé pour les raisons suivantes:


  • Nous écrivons du code en termes de nœuds, par exemple .parentNode , alors pourquoi ne pas le rendre cohérent.
  • «Node» est plus court que «element», et le sens n'est pas perdu .

Ensuite, nous passons aux noms de variables:


 let parent = node 

Il est très important de divulguer complètement la valeur de votre variable dans son nom , donc "p" est maintenant "parent" ( parent russe). Vous avez peut-être également remarqué que maintenant nous ne commençons pas par obtenir le node.parentNode parent, mais uniquement le nœud.


Nous allons plus loin:


 do { parent = parent.parentNode } while (parent.parentNode && !condition(parent)) 

Au lieu de la while habituelle while j'ai choisi la do ... while . Cela signifie que nous devons obtenir le nœud parent à chaque fois avant de vérifier les conditions, et non l'inverse. L'utilisation de la do ... while permet également de lire du code comme du texte brut.


Essayons de lire: "Affectez le nœud parent du parent au parent, tant que le parent a un nœud parent et que la fonction de condition ne renvoie pas true . " Déjà beaucoup plus clair.


 return parent 

Souvent, les développeurs préfèrent utiliser une sorte de variable commune ret (ou returnValue ), mais c'est une très mauvaise pratique . Si vous nommez correctement vos variables de retour, il devient évident ce qui est retourné. Cependant, les fonctions peuvent parfois être longues et complexes, ce qui crée beaucoup de confusion. Dans ce cas, je suggère de diviser votre fonction en plusieurs fonctions , et si elle est encore trop compliquée, l'ajout de commentaires peut peut-être aider.


Partie 3: Simplification du code


Maintenant que vous avez rendu le code lisible, il est temps de supprimer le code inutile . Je suis sûr que certains d'entre vous ont déjà remarqué que nous n'avons pas du tout besoin de la variable parent .


 const traverseUpUntil = (condition, node) => { do { node = node.parentNode } while (node.parentNode && !condition(node)) return node } 

J'ai simplement supprimé la première ligne et remplacé «parent» par «nœud». J'ai donc sauté l'étape inutile de créer un «parent» et je suis allé directement dans la boucle.


Mais qu'en est-il du nom de variable?


Bien que «nœud» ne soit pas la meilleure description de cette variable, il est satisfaisant. Mais ne nous arrêtons pas là, renommons-le. Qu'en est-il de "currentNode"?


 const traverseUpUntil = (condition, currentNode) => { do { currentNode = currentNode.parentNode } while (currentNode.parentNode && !condition(currentNode)) return currentNode } 

C'est mieux! Maintenant, lorsque nous lisons la méthode, nous savons que currentNode représente toujours le nœud dans lequel nous nous trouvons maintenant, au lieu d'être un nœud "d'une sorte".

Source: https://habr.com/ru/post/fr421867/


All Articles