Rébus dans le code et comment les décrypter. Le pouvoir secret des identifiants

Le code pur se lit comme une prose bien écrite.
Grady Butch dans Clean Code

Rebus comme code




Qu'est-ce qu'un rébus? Ceci est un message crypté. L'auteur du rébus prend un texte humain ordinaire et le code à l'aide de dessins, de chiffres et de lettres. Et nous examinons un tel cryptage et essayons de lire le texte source.

Le rébus a deux formes. D'une part, le rébus est le texte original non chiffré, et de l'autre, les dessins chiffrés. Le texte est le «quoi» du rébus, sa signification, son message. Les images sont «comment»: comment exactement le message est crypté, par quels moyens. Devinant le rébus, nous traduisons «comment» en «quoi».

Les dessins sont le langage du rébus, son arsenal de moyens expressifs. Le rebusnik, pour ainsi dire, nous parle à l'aide de ces dessins, communique quelque chose. Il n'est pas autorisé à utiliser des mots humains normaux.

Voici comment les puzzles se lisent:



Le code est comme un rébus


Le code du programme a quelque chose en commun avec le rébus: il a aussi ses propres «quoi» et «comment». Et il doit aussi parfois être décrypté.

Le «quoi» d'un code est son but, sa signification, cet effet et le résultat final que nous attendons de lui. Que fait-il exactement.

«Comment» du code - de quelle manière concrète remplira-t-il son «quoi», avec quelles missions spécifiques, multiplications, comparaisons; mise en œuvre de l'algorithme, instructions au processeur. C'est un langage de code autorisé, son arsenal de moyens expressifs.

Martin Fowler en parle ainsi ( «Function Length» , original ):
Smalltalk a travaillé sur ces machines en noir et blanc. Si vous aviez besoin de mettre en évidence du texte ou des graphiques, vous deviez inverser la vidéo. La classe de Smalltalk, responsable du programme, contenait la méthode «surlignage», et dans son implémentation, il n'y avait qu'une seule ligne - un appel à la méthode «inverse». Le nom de la méthode était plus long que l'implémentation, mais cela n'avait pas d'importance, car il y a une grande distance entre l'intention et l'implémentation de ce code.
Ici, le point fort est le «quoi». Dans la terminologie de Martin - intention : "mettre en évidence un fragment de l'image." Le nom exprime ce que fait cette fonction. L'inverse est de savoir comment, la mise en œuvre . Comment exactement la surbrillance est effectuée (en utilisant l'inversion d'image). C’est la différence entre «quoi» et «comment».

Malgré le fait que le nom de la méthode soit plus long que sa mise en œuvre, l'existence d'une telle méthode est logique pour une raison très simple. Lorsque nous voyons un appel inverse dans le code, nous devons comprendre ou nous souvenir que l'inversion d'image est utilisée pour rendre cette image plus visible. Lorsque nous voyons un point culminant, nous lisons simplement: "rendre ce fragment plus visible". Dans le premier cas, nous passons un peu d'effort mental pour comprendre la mission assignée au code, dans le second - non. Dans le premier cas, nous voyons un rébus devant nous, nécessitant un décryptage, dans le second - une histoire dans un langage compréhensible.

Un programmeur, quand il écrit un programme, c'est comme un rébus. Le programmeur crypte la description humaine de l'algorithme à l'aide des outils de langage de programmation disponibles (plus primitifs que le langage humain). Crypte «quoi» avec «comment». Et plus tard, lui ou son collègue lit le code, déchiffrant ces rébus la description initiale de l'algorithme. Si dans le processus de lecture du code, nous ne pouvons pas immédiatement comprendre quel résultat entraînera l'exécution de chaque fragment, c'est-à-dire quel est le but, la signification du code, alors ce code est un rébus, et il doit être réécrit dans un langage clair.

Le problème avec les énigmes du code est qu'elles nécessitent toujours un effort mental. Même si nous n'effectuons pas l'ensemble des opérations de décryptage dans notre esprit, mais que nous nous souvenons stupidement de la signification de certains rébus, cela créera toujours une charge: premièrement, se souvenir de sa signification, et deuxièmement, au moment de l'enregistrement de la transformation rébus dans cette valeur.

Déchiffrer le rébus en lisant le code est la transformation très mentale dont parle Tim Ottinger dans le livre Clean Code. Certes, il en discute dans le contexte de l'attribution de noms intelligibles aux variables, mais le problème est affecté exactement de la même manière. Mot à Tim:
En règle générale, les programmeurs sont très intelligents. Et les gens intelligents aiment parfois montrer la puissance de l'intelligence, démontrant leur capacité à jongler mentalement. En fin de compte, si vous vous souvenez que la variable r contient une URL avec un hôte distant et un schéma converti en minuscules, cela indique clairement votre esprit.
L'une des différences entre un programmeur intelligent et un programmeur professionnel est qu'un professionnel le comprend: la clarté est primordiale. Les professionnels utilisent leur pouvoir pour le bien et écrivent du code compréhensible pour les autres.
Même une petite charge de chaque rébus peut devenir un problème s'il existe de nombreux rébus. Vous avez probablement rencontré du code dont la lecture est tout simplement épuisante. Savoir: les rébus dans le code sont à blâmer pour votre fatigue. Les rébus exacerbent la fatigue de même leur propre auteur directement dans le processus d'écriture de code. Après tout, lors de l'écriture de code, le programmeur relit également en continu ce qui a été écrit. Malgré le fait que l'auteur ne déchiffre pas ses propres puzzles, mais se souvient simplement, ils créent toujours une charge. Le piège est que l' auteur ne voit tout simplement pas les puzzles dans son propre code ! Essayez d'imaginer combien d'effort mental vous pouvez économiser le soir, si vous commencez à vous débarrasser des puzzles dans votre code le matin!

Ainsi, pour réduire la fatigue liée à l'écriture et à la lecture de code, vous devez éviter les énigmes. Mais comment faire?

La langue du code. Force de l'identifiant


Je suis d'accord avec la déclaration de Grady Butch selon laquelle un code propre se lit comme une bonne prose. Il s'agit d'une condition nécessaire, mais non suffisante. La plupart d'entre nous comprendront intuitivement ce qui est en jeu, mais je voudrais obtenir au moins une définition: qu'est-ce que c'est - une bonne prose.

J'ai demandé à mes collègues écrivains: en quoi la bonne prose est-elle différente de la mauvaise prose? Tout le monde a répondu différemment, mais a souligné d'une certaine manière l'importance du langage: il doit être riche, il doit créer des images claires dans l'esprit et l'âme du lecteur. Lorsque le lecteur a facilement une image claire que l'auteur a voulu lui dessiner, nous avons affaire à une bonne prose.

Le code indique au processeur ce qu'il doit faire. Un bon code en même temps dit au programmeur - et, en plus, très honnêtement! - que fait-il ici. Autrement dit, il présente son algorithme aussi près que possible de la façon dont l'auteur lui-même l'aurait fait dans un langage naturel. Notre code doit le faire très bien, sinon un maniaque débridé avec une tronçonneuse ou un fusil de chasse pourrait venir chez nous. Le code ne doit pas être un rébus.

De quels outils dispose le code pour ne pas être un rébus?

Une histoire au nom du code sera facilement comprise par une personne si le code lui-même parle en langage humain. Cela ne peut être réalisé qu'à l'aide d'identifiants: noms de fonctions, classes, variables et constantes - car ce n'est que dans les identifiants que nous pouvons utiliser les mots du langage humain dont nous avons besoin .

Bien sûr, les mots clés d'un langage de programmation sont aussi des mots humains, mais leur vocabulaire est trop misérable. Quelque chose comme la langue d'Ellochka l'Ogre - vous ne pouvez pas y écrire une bonne prose.

Par conséquent, il est essentiel que le code du programme contienne autant d'identifiants correctement choisis que possible. Pour que leur totalité forme la prose très bien écrite.

Voyez à quel point il est facile de lire des lignes de code lorsque les noms des variables et des méthodes sont bien choisis:

pageData.hasAttribute("Test") dom_tree.to_html() emails_str.split(',') 

En regardant ces courtes phrases, il est facile de comprendre de quoi ils parlent. Nous savons quel résultat nous obtenons, car les identifiants nous en parlent. Imaginez maintenant qu'à la place de chaque appel se trouve sa mise en œuvre - quelle sera la vitesse de lecture d'un tel code "crypté"?

Beaucoup des techniques de refactorisation les plus simples: constantes nommées, sélection d'une méthode, remplacement d'une variable par un appel de méthode, une variable explicative, fractionnement d'une variable temporaire, etc. sont toutes sur la façon de faire parler le code en langage humain, en d'autres termes, comment éviter les énigmes .

Méthode Rebus


Quand j'ai lu Pure Code, j'ai été périodiquement visitée par la pensée: "What the hell!".

Du haut de ses 40 années d'expérience, Robert Martin nous donne des conseils sur la façon d'améliorer le code. Par exemple:
Première règle: les fonctions doivent être compactes. Deuxième règle: les fonctions doivent être encore plus compactes.
Et puis il admet qu'il ne peut pas étayer scientifiquement sa demande. Honnêtement, non scientifique, il fait aussi mal. L'exigence de compacité des fonctions commence déjà à ressembler à un dogme - c'est pourquoi le débat sur la question de la durée d'une fonction n'a pas disparu depuis tant de décennies.

Et Bob propose également d'écrire chaque fonction afin qu'elle n'effectue qu'une seule opération. De plus, quelle est cette opération - n'est pas très claire non plus. Nous devons appeler à l’aide le principe d’un niveau d’abstraction unique, qui brouille encore la situation. Tout cela est trop brumeux.

Martin Fowler est plus pragmatique.

Il me semble que l'argument de la séparation de l'intention et de la réalisation a plus de sens. Si, en regardant un morceau de code, vous devez faire un effort pour comprendre ce qu'il fait, alors vous devez le mettre dans une fonction et lui donner un nom conformément à ce «quoi». Ensuite, la prochaine fois, le but de la fonction sera immédiatement évident, et dans la plupart des cas, vous ne vous soucierez pas de la façon dont la fonction fait son travail.

L'original
L'argument qui me semble le plus logique, cependant, est la séparation entre l'intention et la mise en œuvre. Si vous devez consacrer des efforts à regarder un fragment de code pour comprendre ce qu'il fait, vous devez l'extraire dans une fonction et nommer la fonction après ce «quoi». De cette façon, lorsque vous la relisez, le but de la fonction vous saute aux yeux et, la plupart du temps, vous n'aurez pas à vous soucier de la façon dont la fonction remplit son objectif - qui est le corps de la fonction.
Déjà mieux. Vous voyez maintenant ce que Martin voulait dire dans ce passage? Il voulait dire: éliminons les énigmes. Que le code lui-même nous dise quel sera le résultat et comment - qu'il soit caché quelque part plus loin, dans la définition de la fonction. Laissez tous les puzzles être décryptés. Pas de puzzles - pas d'effort.

Vous ne devez en aucun cas appliquer aveuglément des méthodes de refactoring. C'est tellement évident, mais comment comprendre quand une refactorisation est vraiment nécessaire, et quand non? La méthode rebus dit: si après refactoring, le rébus ne disparaît pas, alors le refactoring n'est pas nécessaire .

Si vous ne pouvez pas trouver un nom pour une nouvelle fonction qui expliquera clairement ce qui s'y passe, c'est une cloche que vous faites quelque chose de mal ici. Essayez de sélectionner un fragment de code légèrement différent dans la fonction - à laquelle vous pouvez trouver rapidement un nom court et compréhensible.

Un exemple de décodage de puzzles en code (pas très réussi)


À ce titre, je citerai un fragment du livre «Clean Code» que j'ai aimé. Avant de refactoring, nous voyons du code plein de puzzles. Le refactoring a été effectué par l'auteur du livre conformément aux règles de bon code promues par lui, et - juste une coïncidence - le code refactoré ressemble exactement au code dans lequel les rébus sont décryptés.

L'auteur de la refactorisation a entièrement appliqué des identificateurs lisibles par l'homme (noms de classe, méthodes et variables) pour indiquer ce que fait réellement le code. Il est dommage que cela ne se soit pas produit partout avec succès, et à certains endroits, de nouvelles énigmes sont apparues à la place des puzzles précédents.

Par exemple, la méthode include la plus couramment utilisée dans ce passage

 private void include(String pageName, String arg) throws Exception { WikiPage inheritedPage = findInheritedPage(pageName); if (inheritedPage != null) { String pagePathName = getPathNameForPage(inheritedPage); buildIncludeDirective(pagePathName, arg); } } 

Le nom ne reflète pas du tout ce qui se passe dans la mise en œuvre. Qu'est-ce qui inclut et où?

En regardant l'appel à cette méthode:

 include("TearDown", "-teardown"); 

il est impossible de dire quel résultat l'auteur du code allait obtenir ici.

Suivant: que fait buildIncludeDirective? À en juger par son nom, il devrait élaborer une sorte de directive sur l'inclusion, et alors quoi? La ramener? Mais non. Il l'ajoute immédiatement au résultat global.

Et voici un autre updatePageContent. Qu'est-ce que updatePageContent nous dit sur le résultat que nous obtenons après avoir appelé la méthode? Rien. Certains contenus de page seront remplacés par personne ne sait quoi. Pourquoi le refactoring appelé extraction de méthode a-t-il été effectué ici? A-t-il aidé à se débarrasser du rébus? Cela n'a pas aidé, mais a encore plus brouillé le code. Nous avons ici le cas même où le corps de la méthode est préférable. La construction

 pageData.setContent(newPageContent.toString()); 

beaucoup plus clair que le updatePageContent () cryptique.

À titre de divertissement, je suggère aux lecteurs de chercher quels sont les autres mauvais endroits dans le code refactorisé .

Pour justifier Bob, je peux dire que ce code n'est plus dans la version actuelle de FitNesse. Apparemment, à son tour, lui aussi a été refactorisé.

Conclusion


La longueur de la fonction est un critère trop vague pour déterminer la qualité de la fonction. «Fonctions courtes» n'est pas égal à «bonnes fonctions». La longueur de la fonction n'est pas un critère, oubliez tout.

Un bon code devrait donner des réponses aux questions du programmeur - pourquoi est-il (le code) ici, que diable fait-il ici, il atteint le résultat. Ces réponses ne peuvent être données qu'à l'aide d'identifiants.

Comme exemple de ce type de réponses que le code ne devrait pas donner, je veux donner un extrait d'un livre amusant.
"Je suis Ronan, Victor of Evil", dit-il lentement. - Et voici Tarl. Nous vous en voulons
poser des questions. Si tu mens, tu meurs. J'ai compris
«Moi, mon oncle, pour toujours», souffla-t-il. - S'il te plait. Je vais tout dire.
"C'est bien," continua Ronan. - Nom?
- Ronan, vainqueur du mal.
- Oui, pas le mien, idiot!
"Ah, oui, alors Tarle," répondit l'orque en s'excusant.
- Et pas le mien! Tarle marmonné. - Votre nom, club! Prénom!
"Le nom est le nom que j'utilise pour me distinguer des autres", marmonna l'orc.
- Eh bien, donnez ce nom ici! Hurla Tarle.
Orka se leva soudain.
- Ah! Pimple!
"Alors Pimple, que fais-tu ici?"
"Je l'ai mis dans mon pantalon", répondit la vérité.
Ronan plissa le nez de dégoût.
"Non, je demande ce que fait votre bande d'orques ici!"
Les yeux de Pimple se tournèrent rapidement, regardant autour de la scène.
"La plupart des gens sont sans tête ici", marmonna-t-il.
Tarle toucha Ronan sur l'épaule.
"Laisse-moi essayer," dit-il avec confiance et se tourna vers l'orc effrayé. - Dis-moi,
Pimple, continua-t-il, pourquoi es-tu ici?
- Oh, mon oncle, et ne demande pas. La philosophie existentielle pour moi n'est qu'une forêt sombre.
«Écoute, toi dragon rot», grogna-t-il d'un air étouffé. - Votre gang d'orques avait un spécial
raison de venir ici. Qu'est-ce que c'est, dans la forêt?
- Il y a beaucoup d'arbres.
Les yeux de Ronan se gonflèrent et Tarle se détourna. Le bouton, sentant qu'il n'avait pas donné la réponse attendue, commença à marmonner davantage.
- Et si vous voulez en savoir plus sur la raison, et non sur la forêt, c'est parce que cette personne dans le pub
nous a payé pour venir ici et vous tuer.
James Bibby, Ronan le barbare

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


All Articles