web-dev-qa-db-fra.com

Si-sinon, une échelle censée remplir toutes les conditions - une clause finale redondante devrait-elle être ajoutée?

C'est une chose que je fais beaucoup ces derniers temps.

Exemple:

setCircle(circle, i, { current }) {
    if (i == current) {
        circle.src = 'images/25CE.svg'
        circle.alt = 'Now picking'
    } else if (i < current) {
        circle.src = 'images/25C9.svg'
        circle.alt = 'Pick failed'
    } else if (i > current) {
        circle.src = 'images/25CB.svg'
        circle.alt = 'Pick chance'
    }
}

Souvent, l'échelle if/else est beaucoup plus compliquée que cela ...

Voir la clause finale? C'est redondant. L'échelle est censée finalement capturer toutes les conditions possibles. Ainsi, il pourrait être réécrit comme ça:

setCircle(circle, i, { current }) {
    if (i == current) {
        circle.src = 'images/25CE.svg'
        circle.alt = 'Now picking'
    } else if (i < current) {
        circle.src = 'images/25C9.svg'
        circle.alt = 'Pick failed'
    } else {
        circle.src = 'images/25CB.svg'
        circle.alt = 'Pick chance'
    }
}

C'est ainsi que j'écrivais du code, mais je n'aime pas ce style. Ma plainte est que la condition dans laquelle la dernière partie du code sera exécutée n'est pas évidente d'après le code. J'ai donc commencé à écrire explicitement cette condition pour la rendre plus évidente.

Toutefois:

  • L'écriture explicite de la condition exhaustive finale est ma propre idée, et j'ai de mauvaises expériences avec mes propres idées - généralement les gens me crient à quel point ce que je fais est horrible - et (parfois beaucoup) plus tard, je découvre que c'était effectivement le cas sous-optimal;
  • Une indication pourquoi cela peut être une mauvaise idée: non applicable à Javascript, mais dans d'autres langues, les compilateurs ont tendance à émettre des avertissements ou même des erreurs lorsque le contrôle atteint la fin de la fonction. Faire allusion à quelque chose comme ça pourrait ne pas être trop populaire ou je me trompe.
    • Les plaintes du compilateur m'ont parfois fait écrire la condition finale dans un commentaire, mais je suppose que cela est horrible car les commentaires, contrairement au code, n'ont aucun effet sur la sémantique réelle du programme:
    } else { // i > current
        circle.src = 'images/25CB.svg'
        circle.alt = 'Pick chance'
    }

Suis-je en train de manquer quelque chose? Ou est-ce OK de faire ce que j'ai décrit ou est-ce une mauvaise idée?

10
gaazkam

Les deux approches sont valides. Mais regardons de plus près les avantages et les inconvénients.

Pour une chaîne if avec des conditions triviales comme ici, cela n'a pas vraiment d'importance:

  • avec un else final, il est évident pour le lecteur de savoir dans quelle condition le reste est déclenché;
  • avec un else if final, il est aussi évident pour le lecteur qu'aucun else supplémentaire n'est nécessaire puisque vous avez tout couvert.

Cependant, il existe de nombreuses chaînes if qui reposent sur des conditions plus complexes, combinant des états de plusieurs variables, peut-être avec une expression logique complexe. Dans ce cas, c'est moins évident. Et voici la conséquence de chaque style:

  • final else: vous êtes sûr que l'une des branches est prise. S'il vous arrive d'oublier un cas, il passera par cette dernière branche, donc pendant le débogage, si la dernière branche a été choisie et que vous vous attendiez à autre chose, vous comprendrez rapidement.
  • final else if: vous devez dériver la condition redondante à coder, ce qui crée une source d'erreur potentielle avec le risque de ne pas couvrir tous les cas. De plus, si vous avez manqué un cas, rien ne sera exécuté et il pourrait être plus difficile de découvrir que quelque chose manquait (par exemple, si certaines variables que vous vous attendiez à définir conservent des valeurs des itérations précédentes).

La dernière condition redondante est donc une source de risque. C'est pourquoi je préfère suggérer d'aller à une finale else.

Edit: codage haute fiabilité

Si vous développez avec une grande fiabilité en tête, vous pourriez être intéressé par une autre variante: compléter votre final explicite redondant else if Avec un final else afin de détecter toute situation inattendue.

Il s'agit d'un codage défensif. Il est recommandé par certaines spécifications de sécurité telles que SEI CERT ou MISRA . Certains outils d'analyse statique implémentent même cela sous la forme d'un règle qui est systématiquement vérifié (cela pourrait expliquer les avertissements de votre compilateur).

6
Christophe

Ce qui manque jusqu'à présent dans les réponses est de savoir quel type d'échec est moins nocif.

Si votre logique est bonne, peu importe ce que vous faites, le cas important est ce qui se passe si vous avez un bug.

Vous omettez le conditionnel final: l'option finale s'exécute même si ce n'est pas la bonne chose à faire.

Vous ajoutez simplement le conditionnel final: il n'exécute aucune option, selon la situation, cela peut simplement signifier que quelque chose ne s'affiche pas (faible préjudice), ou cela peut signifier une exception de référence nulle à un moment ultérieur (ce qui pourrait être un débogage douleur.)

Vous ajoutez le conditionnel final et une exception: il lève.

Vous devez décider laquelle de ces options est la meilleure. Dans le code de développement, je considère cela comme une évidence - prenez le troisième cas. Cependant, je définirais probablement circle.src sur une image d'erreur et circle.alt sur un message d'erreur avant de lancer - au cas où quelqu'un déciderait de désactiver les assertions plus tard, cela échouerait sans danger.

Une autre chose à considérer - quelles sont vos options de récupération? Parfois, vous n'avez pas de chemin de récupération. Ce que je pense en est l'exemple ultime, c'est le premier lancement de la fusée Ariane V. Une erreur non capturée/0 (en fait un débordement de division) a entraîné la destruction du booster. En réalité, le code qui s'est écrasé ne servait à rien à ce moment-là, il était devenu sans objet à l'instant où les boosters de ceinture s'allumaient. Une fois qu'ils ont allumé l'orbite ou le boom, vous faites de votre mieux, les erreurs ne peuvent pas être autorisées. (Si la fusée s'égare à cause de cela, le gars de la sécurité de la gamme tourne sa clé.)

5
Loren Pechtel

Ce que je recommande, c'est d'utiliser une instruction assert dans votre autre final, dans l'un de ces deux styles:

setCircle(circle, i, { current }) {
    if (i == current) {
        circle.src = 'images/25CE.svg'
        circle.alt = 'Now picking'
    } else if (i < current) {
        circle.src = 'images/25C9.svg'
        circle.alt = 'Pick failed'
    } else {
        assert i > current
        circle.src = 'images/25CB.svg'
        circle.alt = 'Pick chance'
    }
}

Ou une assertion de code mort:

setCircle(circle, i, { current }) {
    if (i == current) {
        circle.src = 'images/25CE.svg'
        circle.alt = 'Now picking'
    } else if (i < current) {
        circle.src = 'images/25C9.svg'
        circle.alt = 'Pick failed'
    } else if (i > current) {
        circle.src = 'images/25CB.svg'
        circle.alt = 'Pick chance'
    } else {
        assert False, "Unreachable code"
    }
}

L'outil de couverture de code peut souvent être configuré pour ignorer le code tel que "affirmer faux" du rapport de couverture.


En plaçant la condition dans une assertion, vous documentez efficacement la condition d'une branche explicitement, mais contrairement à un commentaire, la condition d'assertion peut en fait être vérifiée et échouera si vous gardez les assertions activées pendant le développement ou en production (je recommande généralement de garder les assertions activées en production s'ils n'affectent pas trop les performances).

4
Lie Ryan

J'ai défini une macro "affirmée" qui évalue une condition, et dans une version de débogage tombe dans le débogueur.

Donc, si je suis sûr à 100% qu'une des trois conditions doit être remplie, j'écris

If condition 1 ...
Else if condition 2 .,,
Else if asserted (condition3) ...

Cela montre assez clairement qu'une condition sera vraie et qu'aucune branche supplémentaire pour une assertion n'est nécessaire.

0
gnasher729