Quelle limite aux "magic numbers"

Bonjour à  tous !


 


Ayant suivi les conseils d'Alligator, j'ai créé un warning MAGIC_NUMBER que je mets dans mon programme quand j'ai des valeurs en dur.


 


Mais voilà , le problème, c'est que j'ai plein de warnings maintenant, et je me demande si je n'ai pas poussé trop loin le concept ce magic number.


 


Dans quel cas faut-il factoriser un magic number (créer une constante, etc.) ?


A priori, je dirais s'il va être utilisé plusieurs fois (YAGNI). Pour l'instant, je l'ai fait presque systématiquement dans le cas suivants.


 


Je voulais savoir aussi si vous réservez les magic number pour certains types !


 


Voici les "types" de magic number que j'ai :


- CGFloat (margin, etc.)


- taille d'une fonte


- durées pour des animations


 


Merci !


Réponses

  • CéroceCéroce Membre, Modérateur
    décembre 2014 modifié #2
    Il n'y a pas de règle universelle. Il faut juste que tu saches à  quoi correspond la valeur quand tu y reviendras.
    Par exemple, si tu as:
     
    [UIFont fontWithName:@Helvetica size:32];
    tu sais à  quoi correspond le 32. A priori, c'est une valeur empirique, qui donne bien visuellement.

    Par contre, si tu as
    frame.origin.y = 44.0;
    Ce nombre sort de nulle part. Il faut au minimum documenter:

    const CGFloat NavigationBarHeight = 44.0;
    frame.origin.y = NavigationBarHeight;
    Mais le mieux est de le déterminer à  l'exécution:
    frame.origin.y = self.navigationController.navigationBar.frame.size.height;
  • AliGatorAliGator Membre, Modérateur
    décembre 2014 modifié #3
    Pas mieux que Céroce.

    Typiquement je dirais qu'il faut créer une constante à  chaque fois, sauf pour les petits "+1" et "-1" qui servent à  ajuster des index de tableaux par exemple.

    Pour l'exemple de UIFont donné par Céroce, si tu n'utilises cette police qu'une seule fois, c'est la police qu'il faut mettre en constante (genre une méthode de classe sur une classe Constants.m, ou une catégorie sur "+[UIFont CBD_mainFont]", ou "+[UIFont CBD_screenTitleFont]", un truc comme ça), et du coup dans l'implémentation de cette méthode qui te retourne la UIFont, pas la peine de créer une constante, on voit que le 32, qui n'est utilisé qu'à  cet endroit, correspond au corps de la police.
    Sauf si vraiment tu n'utilises cette police qu'une seule et unique fois (par exemple dans ton AppDelegate pour appliquer une UI_APPEARANCE sur tous tes labels avec "[[UILabel appearance] setFont:...]") et ne risques pas dans ton appli d'avoir besoin d'utiliser cette police et ce corps de police ailleurs.


    Au final, si tu hésites sur un cas, ne te pose pas de question, crées une constante.

    Les constantes, c'est un des rares cas où je n'applique pas YAGNI et où je mets systématiquement des constantes au lieu de Magic Numbers très rapidement. Car là  c'est pas comme si c'était une grosse réflexion d'architecture avec des risques d'ajouter de la complexité inutile ou quoi, où là  effectivement il faut mieux appliquer YAGNI/KISS, là  c'est juste une constante à  rajouter en haut de ton fichier .m, donc ça prend pas de temps, et le jour où tu relis ton code plus tard, ça t'évite de nombreuses surprises.
  • AliGatorAliGator Membre, Modérateur
    Autre exemple : en ce moment je fais une application qui fais des graphes avec des valeurs mois par mois.

    J'ai un n° de mois de début et un nombre de mois à  afficher. J'ai donc créé une constante kFirstMonth et une autre kMonthCount. Et je fais tous mes calculs à  partir de ça.
    Par exemple, si kFirstMonth = 9 et kMonthCount = 6, alors je vais afficher mon graphique de Septembre (9ème mois) à  Février (pour un total de 6 mois).

    1) Avoir ces valeurs dans une constante, en plus de permettre d'avoir un nom clair pour dire à  quoi elles correspondent, permet de les changer facilement : si demain le client décide de changer le nombre de mois ou le mois de départ, je n'ai qu'à  le changer à  un seul endroit.

    2) Pour le décalage qu'il y a entre mes numéros pour indiquer les n° de mois (9=Septembre) dans mon raisonnement... et les index de tableaux (par exemple quand j'utilise le tableau "-[NSDateFormatter monthSymbols]" contenant le nom des mois pour les afficher à  l'écran, où 0=Janvier et 8=Septembre), pour ce décalage de "-1" je ne vais pas mettre une constante, faut pas pousser, c'est qu'un décalage d'indice de 1.

    3) Mais pour calculer le mois de fin (février), je vais faire le n° du mois de départ + le nombre de mois - 1, soit kFirstMonth+kMonthCount-1... et si ça dépasse 12 il faut que je reste borné entre 1 et 12. Bah ce "12", je pourrais le mettre en dur comme un bourrin, mais demain un autre qui lit mon code pourrait se demander d'où il sort. Donc je le met en constante. Non pas dans le but de pouvoir le changer facilement à  un seul et unique endroit, car c'est pas demain la veille qu'il n'y aura pas 12 mois dans une année Mais simplement pour ne pas laisser trainer une valeur "qui sort d'on ne sait où" mais lui donner un nom explicite.


    Ainsi, mon code pour calculer le mois de fin pourrait ressembler à  ceci :
    int endMonth = kFirstMonth + kMonthCount - 1;
    endMonth = (endMonth-1) % kMonthPerYear + 1;
    Je pourrais mettre le 12 directement, car il changera pas de sitôt, mais le mettre en constante facilite la lecture. Même si jamais je ne l'utilise qu'à  un seule et unique endroit, là  ce n'est pas une question de risquer d'avoir à  le répéter, mais bien une question de savoir à  quoi il correspond quand on relit le code.

    Si t'avais aucune constante, et que tu voulais tout écrire d'un coup, tu aurais eu un truc comme :
    int endMonth = ((9+6-1)-1)%12+1;
    Va comprendre d'où ça sort, toi, surtout quand tu reviens dessus 3 mois après Et encore, il se trouve justement qu'aujourd'hui les valeurs sur lesquelles le client s'est arrêté, c'est de démarrer en Septembre et d'afficher 9 mois... donc kFirstMonth et kMonthCount ont la même valeur 9... un "(9+9-1-1)%12+1" ça aurait été encore pire à  relire ;)
  • Merci pour vos retours.


     


    + 1 pour "[[UILabel appearance] setFont:...]" : je connaissais pas !


     


     En pratique je trouve que c'est un peu relou de devoir remonter en haut du .m quand on veut changer une valeur.


  • AliGatorAliGator Membre, Modérateur
    En pratique je trouve ça mega relou de devoir parcourir tout le .m pour trouver tous les endroits où sont utilisés une valeur pour la changer.


    Au risque en + de changer un endroit qui n'aurait pas dû l'être tout ça parce qu'il y avait la même valeur utilisée à  cet endroit mais pour complètement autre chose.



    Et puis moi je préfère mettre toutes mes constantes regroupées en haut comme Apple, mais rien ne t'empêche si toi tu préfères de les déclarer juste avant l'endroit où tu les utilise.
Connectez-vous ou Inscrivez-vous pour répondre.