Devrais-je réutiliser des variables?

59

Devrais-je réutiliser des variables?

Je sais que beaucoup de bonnes pratiques disent que vous ne devriez pas le faire, cependant, plus tard, lorsqu'un développeur différent débogue le code et que 3 variables se ressemblent et que la seule différence est qu'elles sont créées à des endroits différents du code. confus. Les tests unitaires en sont un excellent exemple.

Cependant, je ne sais que les meilleures pratiques sont la plupart du temps contre elle. Par exemple, ils disent de ne pas "écraser" les paramètres de la méthode.

Les meilleures pratiques sont même contre l'annulation des variables précédentes (en Java, Sonar vous avertit lorsque vous affectez nullune variable, qu'il n'est pas nécessaire de le faire pour appeler le ramasse-miettes depuis Java 6. Vous ne pouvez pas toujours contrôler quels avertissements sont désactivés; la plupart du temps, la valeur par défaut est activée.)

IAdapter
la source
11
Depuis Java 6? Vous n'avez jamais eu besoin d'affecter null à des variables dans une version de Java. Lorsqu'une variable sort de la portée, elle libère la référence à son objet.
Kevin Panko
35
La réutilisation de variables est l'une des premières choses qu'utilisent les obfuscateurs de code
Lelouch Lamperouge
7
La réutilisation des variables entre en conflit avec le choix d’identificateurs décents pour vos variables. Dans les langues modernes, la réutilisation variable ne présente pas vraiment d'avantages qui l'emporte sur les avantages d'avoir de bons identifiants.
Joren
4
Notez également que toute réutilisation n’est pas réutilisation. Les anciens programmeurs FORTRAN, même ceux qui sont passés à d’autres langages, utilisent régulièrement I, J, K, L, M, N (ou i, j, k, l, m, n) pour toutes nos boucles boucle) compteurs. Nous sommes habitués à voir des choses comme SOMME = SOMME + A (I, K) * B (K, J), ou somme + = a [i] [k] * b [k] [j] ;.
John R. Strohm Le
1
La réutilisation de variables pourrait être justifiée lors de la programmation de microcontrôleurs avec des ressources très limitées (quelques kilo-octets de RAM).
m.Alin

Réponses:

130

Votre problème n'apparaît que lorsque vos méthodes sont longues et effectuent plusieurs tâches dans une séquence. Cela rend le code plus difficile à comprendre (et donc à maintenir) en soi. La réutilisation des variables ajoute en plus un élément de risque supplémentaire, rendant le code encore plus difficile à suivre et plus sujet aux erreurs.

La meilleure pratique de l'OMI consiste à utiliser des méthodes suffisamment courtes qui ne font qu'une chose, éliminant ainsi tout le problème.

Péter Török
la source
Qu'en est-il des tests unitaires? Par exemple, je dois vérifier si, après avoir exécuté la méthode pour la deuxième fois, elle fonctionne toujours comme prévu.
IAdapter
20
@IAdapter, le code de test unitaire est un problème différent, dans lequel les normes peuvent être plus souples que pour le code de production. Cependant, le rendre lisible et facile à maintenir est une priorité. Vous pouvez (et devriez) extraire des méthodes de vos tests unitaires afin de les garder courtes et faciles à lire (et pour éliminer le besoin de réutiliser des variables).
Péter Török
3
@IAdapter, pour le scénario que vous avez décrit, je ne voudrais pas réutiliser une variable. La chose appropriée serait quelque chose comme result1 = foo(); result2 = foo(); Assert.AreEqual(result1, result2);si je ne voyais pas beaucoup d’endroits où vous auriez besoin de réutiliser une variable dans ce cas.
JSB
1
@IAdapter pour (int i = 0; i <2; i ++) {result = foo (); assertEquals (attendRésultat, résultat);}
Bill K
2
+1 - c'est une bonne odeur de code pour savoir quand faire des méthodes plus petites.
49

La réutilisation de variables dans une méthode est un signe fort que vous devez la refactoriser / scinder.

Donc, ma réponse serait que vous ne devriez pas les réutiliser, car si vous le faisiez, il serait beaucoup plus difficile de le reformuler plus tard.

Thanos Papathanasiou
la source
19

Ça dépend.

Certaines variables peuvent être créées précisément dans le but de contenir un certain type de données, qui peut changer pendant l'exécution d'une fonction. Les codes de retour me viennent à l’esprit, par exemple:

void my_function() {
    HRESULT errorcode;
    errorcode = ::SomeWindowsApiFunction();
    if (FAILED(errorcode)) { /* handle error */ }
    errorcode = ::AnotherWindowsApiFunction();
    if (FAILED(errorcode)) { /* handle error */ }
}

Le nom de la variable indique très clairement ce que cette variable est destinée à stocker. Je pense que d'autres cas tels que celui-ci sont possibles, où une variable est conceptuellement un conteneur qui est utilisé logiquement par différentes instances d'éléments très similaires au cours d'une fonction.

En général, toutefois, cela ne devrait être fait que dans des circonstances parfaitement claires pour les lecteurs potentiels du code. En aucun cas, à l'exception peut-être d'une optimisation extrême sans égard pour la lisibilité du code, une variable doit-elle être réutilisée simplement parce que le type convient?

Tout cela découle essentiellement des bonnes pratiques en matière de nommage des variables. Les noms doivent parler pour eux-mêmes. S'il est difficile de définir le nom exact de toutes les réutilisations dans un nom abrégé, il est préférable d'utiliser simplement des variables distinctes.

Felix Dombek
la source
15

La principale raison pour laquelle je ne réutilise pas de variables (en particulier dans les tests unitaires) est qu’il introduit un chemin de code non nécessaire, difficile à tester et à déboguer. Un bon test unitaire doit être indépendant des autres tests et lorsque vous réutilisez une variable de niveau classe (instance) dans un appareil de test unitaire, vous devez vous assurer de leur état avant chaque test. Un bon test unitaire isole également les défauts et, en théorie, chaque test élémentaire (méthode) ne doit donc affirmer qu'un comportement pour le système testé. Si vos méthodes de test sont écrites de cette manière, il est rarement nécessaire ou avantageux de réutiliser une variable de niveau méthode. Enfin, dans les langues qui prennent en charge les fermetures et le traitement asynchrone, il est vraiment difficile de raisonner sur ce qui se passe si vous réutilisez des variables dans une méthode.

Sbrenton
la source
donc je devrais écrire des méthodes de test comme -testSomething et assert pour une invocation de méthode unique -testSomethingTwoInvocations et des assertions pour une seconde invocation?
IAdapter
2
Oui. Cela vous aide à déterminer si c'est la première ou la deuxième itération qui a échoué. mspec peut aider à cela, son arbre d'héritage sera très utile.
Bryan Boettcher
Si vous utilisez "variable" lorsque vous voulez dire "variable de classe" ou "variable d'instance", vous devez vous exprimer plus clairement.
gnasher729
13

Vous devriez utiliser différentes variables. Si vous craignez que votre collègue ne soit confus, donnez-leur des noms qui couvrent clairement leurs rôles.
La réutilisation de variables est une source probable de confusion dans l’avenir; Mieux vaut éclaircir maintenant.
Dans certains cas, le même nom de variable peut être réutilisé; par exemple idans une simple boucle de comptage. Dans ces cas, vous devez bien sûr vous assurer que les variables sont dans leur propre champ.

EDIT: Réutiliser des variables est parfois le signe que le principe de responsabilité unique est violé. Vérifiez si la variable réutilisée est utilisée dans le même rôle. Si c'est le cas, il se peut qu'il ne soit pas du tout réutilisé (bien qu'il soit toujours préférable d'avoir deux variables différentes pour limiter la portée de ces variables). S'il est utilisé dans différents rôles, vous avez une violation de SRP sur vos mains.

SL Barth - Rétablir Monica
la source
4

Il existe une situation dans laquelle vous pouvez souhaiter réutiliser une variable sans tenir compte des conseils judicieux fournis par d’autres réponses: lorsque votre compilateur a besoin d’un coup de main.

Dans certains cas, votre compilateur peut ne pas être assez intelligent pour se rendre compte qu'une certaine variable allouée à un registre n'est plus utilisée par la partie suivante du code. Par conséquent, il ne réutilisera pas ce registre théoriquement libre pour les variables suivantes et le code généré peut être sous-optimal.

Notez que je ne connais aucun compilateur grand public actuel qui ne parvient pas à résoudre correctement cette situation. Ne le faites jamais, à moins que vous ne sachiez que votre compilateur génère un code sous-optimal. Si vous compilez des systèmes intégrés spéciaux avec des compilateurs personnalisés, vous pouvez toujours rencontrer ce problème.

Joris Timmermans
la source
17
-1 sauf si vous pouvez indiquer une situation réelle où cela se produit réellement et où la réutilisation d'une variable fait une différence appréciable. Ceci est une solution théorique à un problème théorique, et pas très bon à cela. Où le compilateur décide de mettre des variables est la préoccupation du compilateur; si votre compilateur génère un code médiocre et si cela fait vraiment une différence, corrigez ou remplacez le compilateur.
Caleb
3
@Caleb - vous n'avez pas toujours accès au code source du compilateur pour la plate-forme sur laquelle vous développez, en particulier pour les plates-formes intégrées propriétaires. J'ai aussi AI dit dans ma réponse que je ne connais pas de compilateurs traditionnels actuels (ou interprètes / machines virtuelles en fait) qui ne fonctionne pas correctement cette analyse de liveness dans tous les cas que j'ai regardé. Cependant, j'ai travaillé sur les systèmes embarqués propriétaires avec des compilateurs personnalisés qui étaient très bare-bones dans le passé (il y a 10 ans environ ). La capacité du système était très limitée, de même que le compilateur. Cette situation s’est donc produite là-bas.
Joris Timmermans
2
+1 j’ai fait exactement une telle réutilisation dans un projet précédent (code de média hautement optimisé écrit en ANSI C). Autant que je me souvienne, la différence était facilement visible lors de l'assemblage et mesurable dans les points de repère. Jamais jamais fait et espérons que cela ne devra jamais faire une telle réutilisation en Java.
moucher
@Caleb réparer ou remplacer le compilateur peut ne pas être une option pour un certain nombre de raisons, et vous devez simplement vous débrouiller avec ce que vous avez.
@ ThorbjørnRavnAndersen Est-il concevable que l'on puisse être obligé d'utiliser un compilateur moche, et que les performances puissent être si critiques que vous deviez deviner le compilateur et manipuler votre code afin de réutiliser un registre? Oui. Est-ce probable ? Non. MadKeithV convient qu'il ne peut pas donner un exemple concret. Est-ce une bonne pratique ? Est-ce que c'est bon style ? Est-ce un indicateur de la qualité du code ? Définitivement pas. Est-ce une réponse utile à la question telle que écrite? Je tiens à respecter MadKeithV, mais je ne le pense pas.
Caleb
2

Je dirais NON.

Réfléchissez à ce scénario: votre programme s'est écrasé et vous devez déterminer ce qui s'est passé en inspectant un fichier de vidage de mémoire ... pouvez-vous voir la différence? ;-)

fortran
la source
Si votre core dump provient d’une construction optimisée, les variables peuvent quand même partager la mémoire. C'est donc moins utile que cela pourrait être.
Winston Ewert
Bien sûr, une construction optimisée n'est pas très utile pour le débogage! mais dans tous les cas, vous avez toujours la possibilité d’utiliser une version de débogage ... Et lorsque vous avez le débogueur attaché, vous n’avez pas besoin d’aller pas à pas depuis le début d’une fonction pour voir comment les variables changent. ne pas! :-D
Fortran
2

Non, vous n'améliorez pas le code exécuté par la machine (... le code d'assemblage). Laissez la réutilisation de la mémoire que le compilateur utilise pour la variable au compilateur. Très souvent, cela va être un registre, et la réutilisation ne vous a rien acheté. Concentrez-vous sur la lisibilité du code.

Rawbert
la source
0

Ça dépend. Dans un langage dynamique, où le type réside sur des valeurs plutôt que sur des variables, si j’avais un argument bien nommé pour une fonction qui, par exemple, était une chaîne. Un changement d’algorithme signifiait qu’il était toujours utilisé après avoir été interprété comme un entier, puis, comme premier projet, je pouvais faire l’équivalent de

scrote = int (scrote)

Mais je chercherais éventuellement à changer le type envoyé à la fonction et à noter le changement de type de paramètre.

Paddy3118
la source
1
Mettre une ligne telle que "scrote = int (scrote)" au milieu d'un long lot de code est un excellent moyen de rendre fous les programmeurs de maintenance.
Jochage
Le problème est plus susceptible d'être avec le "lot long de code" que vous mentionnez.
Paddy3118
Comme le notent les réponses acceptées, la réutilisation des variables n’est vraiment un problème que pour de longs lots de code. Fondamentalement, dans toute situation où vous écririez quelque chose comme "scrote = int (scrote)", je préférerais mettre int (scrote) dans une nouvelle variable ou, mieux encore, passer int (scrote) à une nouvelle fonction.
Jhocking
0

Tout d'abord, regardez votre environnement de développement. Si vous avez des problèmes de débogage parce que vous avez cinq variables dans des portées différentes portant des noms identiques et que le débogueur ne vous indique pas laquelle de ces variables est celle dont vous avez besoin, n'utilisez pas cinq variables du même nom. Il y a deux façons d'y parvenir: utilisez une seule variable ou utilisez cinq noms différents.

Votre débogueur peut également rendre difficile le débogage d’une fonction comportant de nombreuses variables. Si une fonction avec 20 variables est plus difficile à déboguer qu’une fonction avec 16 variables, vous pouvez envisager de remplacer 5 variables par une. ("Peut considérer" n'est pas la même chose que "devrait toujours").

Il est correct d'avoir une variable utilisée à plusieurs endroits tant que la variable a toujours le même objectif. Par exemple, si dix appels de fonction renvoient un code d'erreur, qui est traité immédiatement pour chaque appel, utilisez une variable et non pas 10. Mais n'utilisez pas la même variable pour des choses complètement différentes. Par exemple, si vous utilisez "nom" pour un nom de client et 10 lignes plus tard avec la même variable pour un nom de société, c'est mauvais et cela vous causera des problèmes. Pire, en utilisant "customerName" pour un nom de client et 10 lignes plus tard en utilisant la même variable "customerName" pour un nom de société.

Fait important, rien n’est une règle de fer. Tout a des avantages et des inconvénients. Si les "meilleures pratiques" suggèrent une chose et que vous avez des raisons de dire que c'est une mauvaise idée dans votre situation spécifique, ne le faites pas.

gnasher729
la source
0

Tout d'abord, regardez votre environnement de développement. Si vous avez des problèmes de débogage parce que vous avez cinq variables dans des portées différentes portant des noms identiques et que le débogueur ne vous indique pas laquelle de ces variables est celle dont vous avez besoin, n'utilisez pas cinq variables du même nom. Il y a deux façons d'y parvenir: utilisez une seule variable ou utilisez cinq noms différents.

Votre débogueur peut également rendre difficile le débogage d’une fonction comportant de nombreuses variables. Si une fonction avec 20 variables est plus difficile à déboguer qu’une fonction avec 16 variables, vous pouvez envisager de remplacer 5 variables par une. ("Peut considérer" n'est pas la même chose que "devrait toujours").

Il est correct d'avoir une variable utilisée à plusieurs endroits tant que la variable a toujours le même objectif. Par exemple, si dix appels de fonction renvoient un code d'erreur, qui est traité immédiatement pour chaque appel, utilisez une variable et non 10. Il existe un problème avec ceci: En règle générale, le compilateur vous avertit lorsque vous utilisez une variable non initialisée. Mais ici, si vous lisez le code d'erreur après l'appel 6, mais que la variable n'a pas été modifiée après l'appel 5, vous obtiendrez des données inutiles sans que le compilateur vous en avertisse. Parce que la variable a été initialisée, avec des données désormais inutiles.

Fait important, rien n’est une règle de fer. Tout a des avantages et des inconvénients. Si les "meilleures pratiques" suggèrent une chose et que vous avez des raisons de dire que c'est une mauvaise idée dans votre situation spécifique, ne le faites pas.

gnasher729
la source
-2

Utilisez des variables globales lorsque vous devez gérer un état ou stocker des constantes. En réutilisant des variables, vous ne réutilisez que le nom qui pointe vers un emplacement en mémoire. Les noms descriptifs sur les initialisations ne peuvent que gagner en clarté (en supposant que Java et aucun OCD primitif).

À moins que vous ne deveniez obsolète par le code ou irritiez les autres développeurs.

JunoA
la source