Le code qui convertit une valeur en une représentation différente, puis la reconvertit à son point de départ est mauvais, mais comment? [fermé]

35

Je lisais un article sur les mauvaises pratiques de programmation .

Il a mentionné -

"Code Yo-Yo" qui convertit une valeur en une représentation différente, puis la reconvertit à son point de départ (par exemple: convertir une décimale en chaîne, puis la transformer en décimale, ou compléter une chaîne puis la couper)

Je ne comprends pas pourquoi l'exemple qu'il donne est un mauvais moyen d'écrire des programmes. Il me semble correct de reconvertir si la situation l'exige pour que la valeur puisse être utilisée.

Quelqu'un peut-il expliquer plus à ce sujet?

utilisateur13107
la source
4
Lecture conseillée: Discutez de cette $ {blog}
gnat
8
La plupart du temps, c'est simplement redondant et cela ne se produit que parce que le programmeur ne connaissait pas le meilleur moyen d'obtenir ce qu'il voulait. L'entrée de blog donne un exemple typique quelques paragraphes plus loin: "Roundabout code" that accomplishes in many instructions what could be done with far fewer (eg: rounding a number by converting a decimal into a formatted string, then converting the string back into a decimal). if the situation is so that they have to be used?- quelle situation serait-ce?
Konrad Morawski
3
@gn je ne comprends pas comment cela fait que c'est une mauvaise question. Si vous voulez, je peux l'éditer pour dire "le code qui convertit et reconvertit une valeur est-il mauvais?" et il ne correspondra plus à ce modèle.
Djechlin
5
J'ai récemment trouvé un code en Java qui itère sur un tableau, en sérialisant chaque objet dans un objet JSON, à l'aide d'une concaténation de chaînes, et non d'un sérialiseur JSON. Le résultat a ensuite été transmis à une méthode privée, qui a analysé le tableau JSON pour en extraire un lot d'identifiants, puis l'a passé ailleurs. C'était la seule utilisation de ce tableau JSON dans le système. C'est le code yo-yo. Il n'y avait aucune raison de transformation dans les deux sens. Nous aurions pu simplement transmettre l'ID des objets d'origine.
Brandon
3
decimal myValue = decimal.Parse(dataReader["myColumn"].ToString())est ma bête noire
Matthew

Réponses:

125

Même si vous avez besoin à la fois le numérique et la représentation de chaîne d'un nombre, il est préférable de convertir une seule fois et accrocher aussi à la valeur d' origine, au lieu de convertir à nouveau chaque fois que vous avez besoin d' un ou l'autre.

Le principe est, comme toujours, que le code qui n'existe pas ne peut pas avoir de défauts subtils , alors que le code qui existe en a souvent. Cela peut sembler paranoïaque, mais l'expérience nous enseigne que c'est approprié. Si vous abordez la programmation avec une légère anxiété permanente de "Je ne suis pas assez intelligent pour comprendre ce système complexe", vous êtes sur la bonne voie.

Kilian Foth
la source
5
Bien dit. Nous, les programmeurs, devrions tous être si prudents.
Neil
58
"Le code qui n'existe pas ne peut pas avoir de défauts subtils, alors que le code qui existe fait souvent" souhaite que je puisse +2 pour cela. Ne sous-estimez jamais la valeur de ne pas avoir à écrire du code.
Benjamin Gruenbaum,
2
Mais effectuer quelques opérations simples (convertir en chaîne et retour) peut être beaucoup moins complexe (plus facile à comprendre et à coder) que la "bonne" façon de manipuler les bits. Et conserver toutes les données d'une catégorie dans un seul formulaire est souvent une bonne idée, même si certaines données seront inévitablement converties en d'autres formulaires.
Daniel R Hicks
36
@DanielRHicks alors convertissons cette simple date (10 novembre 2014) en chaîne, -> 10-11-2014 et retour à une date -> (11 octobre 2014) hé, attendez quoi?
Pieter B
20
@PieterB Il existe un grand logiciel de comptabilité allemand qui ne fonctionne pas sur des ordinateurs avec des paramètres régionaux non allemands, car il le fait. Il convertit d'abord la date en chaîne à l'aide des paramètres régionaux du système, puis tente de l'analyser avec des paramètres régionaux fixes et se plaint du format non conforme. Il fait la même chose avec les nombres et les séparateurs décimaux, sauf qu'il ne se plaint pas, il corrompt les données et présente un comportement étrange. Il m'a fallu des jours pour comprendre cela.
CodesInChaos
23

C'est mauvais pour trois raisons principales:

  1. Cela montre que vous n'avez pas pensé au type / format que la variable devrait réellement être mais que vous la convertissez plutôt à ce dont vous avez besoin à ce moment-là. Cela montre le manque de pensée de conception.
  2. C'est probablement inutile. Vous gaspillez presque certainement des cycles et des lignes de code, en effectuant des conversions inutiles. Cela rendra votre code plus lent et plus gonflé qu'il ne le faut.
  3. Les conversions de types sont sujettes à des erreurs subtiles. En pointant ces conversions dans votre code, vous augmentez le risque d'erreur.

Je soupçonne que la raison 1 est la raison à laquelle votre source pensait en fonction du contexte dans lequel elle a été mentionnée.

Jack Aidley
la source
6

Je reformulerais la description en "code qui convertit un type en une représentation différente dans le but de faire quelque chose qui aurait pu être fait aussi bien ou mieux dans l'original et le reconvertit ensuite. Il existe de nombreuses situations dans lesquelles convertir quelque chose en type différent, qui agissent sur lui, et de le convertir est de retour tout à fait approprié et non à faire serait donc entraîner un comportement incorrect.

À titre d’exemple où la conversion est bonne: on
a quatre floatvaleurs de signes arbitraires dont les grandeurs peuvent différer jusqu’à 1 000, et il faut calculer la somme à moins de 0,625 unité à la dernière place. Convertir les quatre valeurs en double, calculer la somme et reconvertir le résultat en floatsera beaucoup plus efficace que ne le serait toute approche utilisantfloat seule.
Les valeurs en virgule flottante sont au mieux précises à 0,5 unité à la dernière place (ULP). Cet exemple exigerait que l'erreur d'arrondi dans le cas le plus défavorable ne dépasse pas de plus de 25% l'erreur optimale dans le cas le plus défavorable. L'utilisation d'un double donnera une valeur précise à 0.5001 ULP. Bien qu'une exigence de 0,625 ULP puisse sembler artificielle, de telles exigences sont souvent importantes dans les algorithmes d'approximation successive. Plus la limite d'erreur est précise, plus l'exigence d'itération dans le pire des cas est faible.

À titre d’exemple où la conversion est mauvaise: l’
un a un nombre à virgule flottante et souhaite produire une chaîne qui représentera sa valeur de manière unique. Une approche consiste à convertir le nombre en une chaîne avec un certain nombre de chiffres, essayez de le reconvertir et de voir si le résultat correspond.

Mais c'est en fait une mauvaise approche. Si une chaîne décimale représente une valeur qui se situe presque exactement à mi-chemin entre deux valeurs à virgule flottante, il est assez coûteux pour une méthode chaîne-à-virgule de garantir qu'elle produira toujours le résultat le plus proche.float valeur , et beaucoup de ces méthodes de conversion ne maintenez pas une telle garantie (entre autres, cela nécessiterait dans certains cas de lire tous les chiffres d’un nombre, même s’il s’agissait de milliards de chiffres).

Il est beaucoup moins coûteux pour une méthode de garantir qu'elle retournera toujours une valeur se situant à moins de 0,5625 unité à la dernière place (ULP) de la valeur représentée. Une routine de formatage "réversible" décimal en chaîne robuste doit calculer la distance entre la valeur de sortie et la valeur correcte et poursuivre la sortie de chiffres jusqu'à ce que le résultat se situe dans les limites de 0,375 (ULP) sinon de 0,25 (ULP). Sinon, il peut générer une chaîne que certaines méthodes de conversion traiteront correctement, mais d'autres méthodes de conversion ne le feront pas.

Il est préférable de produire parfois un chiffre qui pourrait ne pas être "nécessaire" que de produire une valeur qui pourrait être mal interprétée. L’essentiel est que le nombre de chiffres à produire soit déterminé en fonction de calculs numériques liés au processus de sortie, plutôt que du résultat de la tentative d’une méthode particulière de reconvertir la chaîne en nombre.

supercat
la source
1
Votre exemple ne renvoie pas la valeur d'origine, ce que le PO demande. Il renvoie simplement une valeur du même type, calculée à partir de plusieurs entrées.
CJ Dennis
2

Raisons diverses

  1. C'est inutile et ajoute à la complexité - à la fois dans la quantité de code à écrire et à maintenir, et dans la quantité de temps CPU nécessaire

    1. Il peut perdre en précision ou pire, corrompre entièrement la valeur

    2. Cela gaspille de la mémoire (potentiellement, selon la langue) car vous finissez par stocker plus de représentations d'un nombre dont vous avez besoin

Une bonne pratique consiste à ne conserver que la première représentation, la plus précise possible, pour toutes les données que vous recevez. Effectuez tous les calculs à l'aide de ces données et ne les convertissez jamais que si vous devez les générer ou les afficher dans un format plus facile à lire.

Jon Story
la source
cela ne semble rien ajouter de substantiel aux points soulevés et expliqués dans les réponses précédentes
Gnat
2
Cela justifie-t-il un vote négatif? Je pense que mon message est potentiellement plus concis
Jon Story
les réponses précédentes me paraissent plus concises, tous les deux
Gnat,
0

Pourquoi? Parce que même les meilleurs d'entre nous peuvent faire des erreurs.

Regardez ce qui s'est passé lorsque Microsoft a essayé d'implémenter un format "aller-retour" spécialement pour garantir la sécurité des conversions de chaînes flottantes <->: https://stackoverflow.com/q/24299692/541686

Mehrdad
la source
0

Quand j'étais à l'école (et après l'école en génie électrique), on nous a appris à diviser après avoir multiplié. Division souvent beaucoup de chiffres et arrondis. Multiplier après division multiplie l'erreur de division.

Les conversions de types sont les mêmes, vous risquez de perdre des données. CInt (1.3) = 1.

Dans mon langage Basic, nous ne faisons que des conversions de types (un programme VB6 consacre 90% de son temps à la conversion ANSI / Unicode, pour tous les appels d'API effectués par le moteur d'exécution).

La conversion de type est implicite dans tout ce que nous faisons.

 Print 5

La chaîne "5" est imprimée à partir du littéral numérique.

form1.caption = "My Form"

Le littéral de chaîne unicode est converti en chaîne ANSI et envoyé à SetWindowsTextA par le package de formulaires.

Même cela fonctionne en base

a = "5"
b = 3

c = a + b (= 8)

Je suis un programmeur de variantes de nos jours - je ne pense même pas au type. Je me fie simplement aux autoconversions.

Quoi qu'il en soit mes 3 peeves sont

Assigner des littéraux de chaîne à des variables pour les utiliser (gaspillage de mémoire et lent)

Fonctions inutiles lorsque le code pourrait être en ligne (et le compilateur annulera probablement votre fonction et l'inline quand même)

Définir tous les objets à néant comme dernières lignes avant une fonction de fin ou une fin de programme.

et une 4ème pour les programmes courts

Variation inutile de vos 3 variables dans un programme de 5 lignes.

triggeradeadcat
la source