Aikido

Éviter les affectations dans les conditionnelles : prévenir les bogues cachés

Lisibilité

Règle
Ne pas placer affectations à l'intérieur conditionnelles. 
Mélanger des affectation et condition logique rend le code sujet aux erreurs
et plus plus plus difficile à comprendre. Séparer devoirs des logiques logiques. 

Langues supportés:** JavaScript, TypeScript, Python, PHP

Introduction

Les opérateurs d'affectation dans les instructions conditionnelles sont une source fréquente de bogues qui échappent souvent aux compilateurs et aux liseurs. L'erreur classique consiste à utiliser = (affectation) au lieu de == ou === (comparaison) dans une instruction if, mais le problème est plus profond. Même les affectations intentionnelles dans les conditionnelles créent un code difficile à lire, à réviser et à déboguer. Lorsque l'affectation et l'évaluation se produisent sur la même ligne, les lecteurs doivent mentalement déterminer quelle opération est prioritaire et quelle valeur est réellement testée.

Pourquoi c'est important

Pourquoi c'est important

Introduction de bogues : Une faute de frappe qui modifie === à = ne provoque pas d'erreur de syntaxe, mais modifie silencieusement le comportement. La condition évalue la valeur attribuée (vrai/faux), et non le résultat de la comparaison.

Lisibilité du code : Les lecteurs attendent des conditionnels qu'ils testent les valeurs et non qu'ils les modifient. Lorsque les deux se produisent simultanément, les responsables doivent savoir quelles variables sont modifiées et à quel moment.

Exemples de code

❌ Non conforme :

function processUser(userData) {
    if (user = userData.user) {
        console.log(`Processing user: ${user.name}`);
        return user.id;
    }
    return null;
}

function validateInput(value) {
    if (result = value.match(/^\d{3}-\d{2}-\d{4}$/)) {
        return result[0];
    }
    return false;
}

Pourquoi c'est faux : Les affectations à l'intérieur des conditionnelles ne permettent pas de savoir s'il s'agit d'une intention ou d'une erreur de frappe. Le premier exemple pourrait être un bogue où === était prévu, et le second mélange la correspondance regex avec l'assignation, ce qui rend le flux de code difficile à suivre.

✅ Conforme :

function processUser(userData) {
    const user = userData.user;
    if (user) {
        console.log(`Processing user: ${user.name}`);
        return user.id;
    }
    return null;
}

function validateInput(value) {
    const result = value.match(/^\d{3}-\d{2}-\d{4}$/);
    if (result) {
        return result[0];
    }
    return false;
}

Pourquoi cela est-il important ? En séparant l'affectation du conditionnel, l'intention est parfaitement claire. Le lecteur voit immédiatement que utilisateur est d'abord extraite, puis testée. Le résultat de la correspondance des expressions rationnelles est capturé, puis évalué. Il n'y a pas d'ambiguïté, pas de surcharge cognitive, et les fautes de frappe comme les = vs === deviennent évidentes.

Conclusion

Séparer les affectations des conditionnelles est une règle simple qui permet d'éviter toute une série de bogues. Le surcoût cognitif lié à l'analyse des opérations combinées l'emporte sur tout avantage perçu en termes de brièveté. Un code clair et explicite dans lequel l'affectation et l'évaluation sont des opérations distinctes améliore la lisibilité, réduit les bogues et rend la révision du code plus efficace.

FAQ

Vous avez des questions ?

Qu'en est-il des cas où l'affectation dans les conditionnels est idiomatique, comme la lecture de fichiers ?

Même dans les langages où while (line = file.readline()) est courant, les meilleures pratiques modernes favorisent une séparation explicite. En JavaScript, utilisez les protocoles itérateurs : for (const line of fileLines). Dans Python 3.8+, l'opérateur morse := rend l'intention explicite lorsque l'affectation dans les conditionnelles est réellement nécessaire, mais même dans ce cas, il convient de se demander si des déclarations séparées ne seraient pas plus claires.

La séparation de l'assignation et des conditionnels a-t-elle une incidence sur les performances ?

Les moteurs JavaScript modernes optimisent les deux modèles de manière identique. La séparation ajoute une déclaration de variable, qui n'a aucun coût d'exécution après la compilation. Toute différence de performance perçue est négligeable par rapport aux avantages en termes de prévention des bogues et de lisibilité. Écrivez d'abord un code clair, n'optimisez que lorsque le profilage identifie les goulets d'étranglement réels.

Comment gérer des motifs comme if ((match = regex.exec(str)) !== null) ?

Divisez-le en deux déclarations : const match = regex.exec(str) ; if (match !== null). Ou mieux, utilisez des alternatives modernes : const match = str.match(regex) ; if (match). La vérification explicite de null devient redondante car match() renvoie null en cas d'échec, ce qui est faux. La clarté s'améliore et l'intention devient évidente.

Qu'en est-il des affectations qui sont intentionnellement utilisées pour leur valeur de retour ?

L'intention n'est pas synonyme de bonne pratique. Le code qui s'appuie sur l'affectation des valeurs de retour dans les conditionnelles crée des risques pour la maintenance. Les futurs éditeurs pourraient "corriger" ce qui ressemble à une faute de frappe. Si vous devez absolument utiliser ce modèle, ajoutez un commentaire expliquant pourquoi, mais réfléchissez à la possibilité de restructurer le code de manière plus claire.

Cette règle s'applique-t-elle aux opérateurs ternaires ?

Oui. Évitez const x = (y = getValue()) ? y : defaultValue. C'est encore plus difficile à lire que dans les instructions if. Utilisez : const y = getValue() ; const x = y ? y : defaultValue. Ou mieux, utilisez la coalescence nulle : const x = getValue() ? ? defaultValue. Les opérateurs modernes existent spécifiquement pour éviter ces schémas gênants.

Comment les linters et les outils d'analyse statique gèrent-ils ce modèle ?

La plupart des linters modernes signalent l'affectation dans les conditionnelles par défaut ou via la configuration. Ils nécessitent généralement des parenthèses supplémentaires if ((x = y)) pour signaler l'affectation intentionnelle, mais il s'agit d'une odeur de code. Il est préférable de désactiver l'exception du linter et de corriger le code correctement. Les outils d'analyse statique peuvent détecter ces schémas pendant le processus CI/CD, les empêchant ainsi d'atteindre la production.

Obtenir la sécurité gratuitement

Sécurisez votre code, votre cloud et votre environnement d'exécution dans un système central.
Trouvez et corrigez rapidement et automatiquement les vulnérabilités.

Aucune carte de crédit n'est requise | Scanner les résultats en 32sec.