Est-ce que cette utilisation d'une surcharge symbolique constante?


34

Je suis assez novice en génie logiciel et j'ai donc écrit un jeu d'échecs comme exercice d'apprentissage. Mon ami a jeté un coup d'oeil et a souligné que mon code ressemblait à

for (int i = 0; i < 8; i++){
    for (int j = 0; j < 8; j++){

alors qu'il a insisté pour qu'il devrait plutôt être

for (int i = 0; i < CHESS_CONST; i++){
    for (int j = 0; j < CHESS_CONST; j++){

avec un meilleur nom de symbole que je ne peux pas être dérangé à penser pour le moment.

Maintenant, bien sûr, je sais qu’il faut généralement éviter d’utiliser des nombres magiques, mais je me sens comme depuis

  1. ce nombre ne changera jamais;
  2. le nom ne pourrait de toute façon pas être descriptif, car le numéro est utilisé à maintes reprises dans le code; et
  3. toute personne passant par le code source d'un programme d'échecs doit en savoir assez sur les échecs pour savoir à quoi sert le 8,

il n'y a vraiment pas besoin d'une constante symbolique.

Alors qu'est-ce que vous en pensez? Est-ce excessif, ou devrais-je simplement utiliser la convention et utiliser un symbole?


46
CHESS_CONST est bien pire que d'utiliser simplement le nombre 8, mais une constante avec un nom descriptif constituerait une amélioration. Vous dites que tout le monde devrait savoir ce que signifie 8 dans le code, mais ce n'est pas vrai. Un littéral entier sans contexte peut vouloir dire beaucoup de choses, comme un nombre de coups, nombre de pièces sur le tableau, etc. Un nom descriptif pour la constante clarifierait l'intention et rendrait donc le code plus facile à comprendre.
JacquesB

43
Personnellement, ce que je trouve beaucoup plus choquant que le nombre magique, ce sont les noms iet jles variables de boucle. Je ne peux pas pour la vie de savoir lequel est censé représenter un rang et lequel est supposé représenter un fichier. Les rangs vont de 1..8 et les fichiers de a..h, mais dans votre cas, les deux iet jvont de 0..7, donc cela ne m'aide pas à voir lequel est lequel. Y a-t-il une crise internationale de pénurie de lettres que je ne connais pas ou qu'est-ce qui ne va pas avec leur changement de nom ranket file?
Jörg W Mittag

4
Jouez l'avocat du diable pendant une seconde; Imaginez-vous en train de lire le code d’échecs d’une personne utilisant un nombre magique 8. Pouvez-vous supposer que vous savez à quoi il sert? Comment pouvez-vous être sûr à 100%? Y at-il une possibilité que cela pourrait signifier autre chose? Cela n'aurait-il pas été un peu plus agréable si vous n'aviez même pas à faire une hypothèse? Combien de temps pourriez-vous passer à parcourir le code pour déterminer si votre hypothèse est correcte? Souhaitez-vous passer moins de temps si le code avait été plus auto-documenté en utilisant un nom significatif et perspicace?
Ben Cottrell

16
@JacquesB: En effet. Il y a 8 rangs, 8 dossiers, 8 pions. Certains moteurs d'échecs utilisent un système de points où certaines pièces, certains champs et certains mouvements ont des points qui leur sont attachés et le moteur choisit le mouvement avec le score le plus élevé. 8 pourrait être un tel score. 8 pourrait être une profondeur de recherche par défaut. Ce pourrait être à peu près n'importe quoi.
Jörg W Mittag

9
J'envisagerais d'utiliser une boucle foreach, par exemple foreach(var rank in Ranks). J'envisagerais également de fusionner les deux boucles en une boucle où chaque élément est un tuple (rang, fichier).
CodesInChaos

Réponses:


101

IMHO votre ami a raison d'utiliser un nom symbolique, bien que je pense que le nom devrait être plus descriptif (comme BOARD_WIDTHau lieu de CHESS_CONST).

Même si le nombre ne changera jamais au cours de la vie du programme, il se peut qu’il existe d’autres endroits dans votre programme où le nombre 8 apparaîtra avec une signification différente. Remplacer "8" parBOARD_WIDTH où que soit la largeur de la planche et utiliser un autre nom symbolique pour désigner une chose différente rend ces différentes significations explicites, évidentes et votre programme global plus lisible et maintenable. Il vous permet également d'effectuer une recherche globale sur votre programme (ou une recherche de symbole inverse, si votre environnement le permet) au cas où vous auriez besoin d'identifier rapidement tous les endroits du code qui dépendent de la largeur de la carte.

Voir également cet ancien article de SE.SE pour une discussion sur la manière de choisir (ou non) de choisir des noms pour les nombres.

En remarque, comme cela a été discuté ici dans les commentaires : si, dans le code de votre programme réel, il importe que la variable fasse iréférence à des lignes et jà des colonnes du tableau, ou inversement, il est recommandé de choisir des noms de variables qui faire la distinction claire, comme rowet col. L'avantage de tels noms est qu'ils donnent l' impression qu'un code erroné est incorrect.


22
Je voudrais ajouter que si le PO avait écrit un très bon moteur d’échecs, il souhaitait l’étendre aux échecs en 3D ou à d’autres variantes. Il serait donc difficile de modifier les 8.
Steve Barnes

32
@SteveBarnes: J'essaie d'éviter de tels arguments, car cela mène trop facilement à un argument inversé du type "Je pense qu'il est extrêmement différent de faire de ce programme un type de jeu différent, pour que je puisse laisser le nombre magique 8 tel qu'il est. "
Doc Brown le

4
@ IllusiveBrian C'est un argument classique de "l'homme de paille" pour deux raisons: (1) le simple fait de définir une constante ne signifie pas que le programmeur ne peut toujours pas taper "8" (par accident, par conception ou par malveillance!) Et (2) juste parce qu'il ya une BOARD_WIDTH constante = 8 ne fait pas BOARD_WIDTH la bonne constante à utiliser à un endroit particulier dans le programme.
alephzero

3
@Blrfl ... ou conduira à une ingénierie excessive du code. Il incombe au développeur de réaliser ce qui peut changer dans le futur et de coder en conséquence. Le codage comme les exigences ne changera pas, pose des problèmes, mais l’autre extrême n’est pas meilleur.
Malcolm

4
@corsiKa Lorsque les variables de la boucle correspondent à des axes physiques, elles doivent être nommées x, y ou rangée, col ou, pour les échecs, fichier, rang.
user949300

11

Ok, voici quelques commentaires que j'ai:

Se débarrasser des chiffres magiques est une excellente idée. Il existe un concept appelé DRY, souvent mal représenté, mais l’idée est de ne pas dupliquer la connaissance des concepts de votre projet. Ainsi, si vous avez une classe appelée ChessBoard, vous pouvez conserver une constante appelée BOARD_SIZE ou ChessBoard.SIZE. De cette façon, il n’existe qu’une source unique pour ces informations. En outre, cela aide la lisibilité plus tard:

for (int i = 0; i < ChessBoard.SIZE; i++){
  for (int j = 0; j < ChessBoard.SIZE; j++){

Même si le nombre ne change jamais, votre programme est sans doute meilleur. Toute personne qui le lit en sait plus sur le code.

Un mauvais nom est pire qu'un non-nom, mais cela ne signifie pas qu'il ne faut pas nommer quelque chose. Il suffit de changer le nom. Ne jetez pas le bébé avec l'eau du bain. : p Le nom peut être descriptif tant que vous comprenez bien ce qu'il décrit. Ensuite, ce concept peut être utilisé pour plusieurs choses différentes.


8
cela semble se limiter à répéter les points déjà formulés et expliqués dans la réponse principale
gnat

-7

Ce que vous voulez vraiment, c'est éliminer les références ad nauseum aux constantes, qu'elles soient nommées ou non:

for_each_chess_square (row, col) {
  /*...*/
}

Si vous voulez réellement multiplier la constante en répétant de telles boucles, etc., il est préférable de vous en tenir à 8.

8se décrit lui-même; ce n'est pas une macro qui représente autre chose.

Vous ne le transformerez jamais (TM) en programme d'échecs 9x9 et si vous le faites déjà, la prolifération de 8 ne sera pas la principale difficulté.

Nous pouvons rechercher une base de codes de 150 000 lignes pour le jeton 8 et classer quelles occurrences signifient quoi en secondes.

Le plus important est de modulariser le code afin que la connaissance des échecs soit concentrée dans le moins d'endroits possible. Il vaut mieux avoir un, deux, voire trois modules spécifiques aux échecs dans lesquels se trouve un 8 littéral, que trente-sept modules avec une responsabilité spécifique aux échecs, faisant référence à 8 par un nom symbolique.

Quand ou si cette constante devient une source de tension dans votre programme, vous pouvez facilement la corriger à ce moment-là. Résoudre les problèmes réels qui se produisent maintenant. Si vous ne sentez pas que cela vous gêne, optez pour cet instinct.

Supposons qu'à l'avenir, vous souhaitiez prendre en charge d'autres dimensions de conseil. Dans ce cas, ces boucles devront changer si elles utilisent une constante nommée ou 8, car les dimensions seront récupérées par une expression telle que board.widthet board.height. Si vous avez BOARD_SIZEau lieu de 8, ces endroits seront plus faciles à trouver. Donc, c'est moins d'effort. Cependant, vous ne devez pas oublier l'effort de remplacer 8par BOARD_SIZE. L'effort global n'est pas inférieur. Faire une passe sur le code de changement 8à BOARD_SIZE, puis une autre pour soutenir d' autres dimensions, n'est pas moins cher que simplement aller de8 l'appui de dimension alternative.

Nous pouvons également examiner cette question à partir d’une analyse objective objective des risques et des avantages. Le programme contient maintenant des constantes nues. Si ceux-ci sont remplacés par une constante, il n'y a aucun avantage; le programme est identique. Avec tout changement, il y a un risque non nul. Dans ce cas, c'est petit. Pourtant, aucun risque ne devrait être pris sans bénéfice. Pour "vendre" le changement face à ce raisonnement, nous devons émettre l'hypothèse d'un avantage: un avantage futur qui aidera avec un programme différent: une version future du programme qui n'existe pas maintenant. Si un tel programme est planifié, cette hypothèse et le raisonnement associé sont de bonne foi et doivent être pris au sérieux.

Par exemple, si vous êtes à quelques jours de l'ajout de code supplémentaire qui générera une prolifération accrue de ces constantes, vous pouvez les supprimer. Si ces instances des constantes sont approximativement toutes les instances qui existeront, pourquoi s'en préoccuper?

Si vous travaillez sur des logiciels commerciaux, les arguments de retour sur investissement s'appliqueront également. Si un programme ne se vend pas et que changer certains nombres codés en dur en constantes n'améliorera pas les ventes, vous ne serez pas rémunéré pour l'effort fourni. Le changement n'a aucun retour sur l'investissement en temps. Les arguments de retour sur investissement se généralisent au-delà de l'argent. Vous avez écrit un programme, vous avez investi du temps et de l’effort et vous en avez tiré quelque chose: c’est votre retour, votre "R". Si en effectuant ce changement seul, vous obtenez plus de ce "R", quoi que ce soit, alors bien sûr. Si vous avez des projets de développement, et que ce changement améliore votre "R", idem. Si le changement n'a pas de «R» immédiat ou prévisible, oubliez-le.


13
8N'est-ce pas que l'auto-description, c'est un nombre qui pourrait signifier n'importe quoi. Et peut-être qu'ils veulent faire une partie d'échecs 9x9, pourquoi pas? Si vous avez 150 000 lignes de code, vous ne pourrez pas mémoriser ce que chaque 8code signifie dans le code, et même si vous le pouviez, pourquoi le feriez-vous? C'est juste beaucoup de tracas supplémentaire. En ce qui concerne la modularisation, remplacer 8par quelque chose comme NUM_RANKScela ne nuit pas à la modularité, en fait, cela aide car cela rend le code plus facile à bricoler.
Jerfov2

4
@ Kaz je le fais aussi. Et puis je présente d’importants bugs étranges parce que quelques utilisations ne sont pas ce que je pensais, car il est difficile d’accorder autant d’attention à un grand nombre de remplacements et d’être correct à chaque fois. Pour cette raison, j’évite d’abord de me lancer dans ce scénario, je ne peux donc pas appuyer un conseil qui tolère de le faire.
doppelgreener

1
"Cependant, vous ne devez pas oublier l'effort de remplacer 8par BOARD_SIZE" " - Le temps que vous avez passé à analyser votre code pour essayer de comprendre ce que chacun 8fait dans votre programme dépasserait probablement le temps passé à remplacer 8par une constante significative au niveau du module.
Christian Dean

1
@doppelganger Ce scénario est déjà là. Je ne dis pas, prenez un programme d'échecs qui utilise des constantes et remplacez-les par 8. Je ne dis pas non plus "ne prévoyez pas d'utiliser des constantes dans un programme d'échecs non encore écrit"
Kaz

1
@Kaz Pourquoi voudriez-vous vous obliger à lire tout le code autour du 8, et peut-être parfois vous tromper de contexte quand vous pourriez dépenser 3 secondes supplémentaires pour donner un nom significatif? Pour ce qui est de connaître la valeur réelle de la constante, il est beaucoup plus facile de rechercher la valeur exacte d'une variable que d'essayer de
reconfigurer
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.