Questo uso di un eccessivo simbolico costante?


34

Sono abbastanza nuovo nell'ingegneria del software, quindi come esercizio di apprendimento ho scritto una partita a scacchi. Il mio amico ha dato un'occhiata e ha sottolineato che il mio codice sembrava

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

mentre ha insistito che invece dovrebbe essere

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

con un nome simbolo migliore a cui non posso preoccuparmi di pensare in questo momento.

Ora ovviamente so generalmente evitare di usare numeri magici, ma mi sento come da allora

  1. questo numero non cambierà mai;
  2. il nome non potrebbe essere comunque così descrittivo poiché il numero è usato in così tanti punti del codice; e
  3. chiunque passi attraverso il codice sorgente per un programma di scacchi dovrebbe sapere abbastanza sugli scacchi da sapere a cosa serve l'8,

non c'è davvero bisogno di una costante simbolica.

Allora, cosa ne pensate? È eccessivo o dovrei semplicemente andare con la convenzione e usare un simbolo?


46
CHESS_CONST è molto peggio che usare semplicemente il numero 8, ma una costante con un nome descrittivo sarebbe un miglioramento. Dici che chiunque dovrebbe sapere cosa significa 8 nel codice, ma questo non è vero. Un intero letterale senza contesto potrebbe significare qualsiasi numero di cose, come un numero di mosse, un numero di pezzi sul tabellone e così via. Un nome descrittivo per la costante renderebbe chiara l'intenzione e quindi il codice più facile da capire.
JacquesB,

43
Personalmente, ciò che trovo molto più stridente del numero magico sono i nomi ie jle variabili del ciclo. Non posso per la vita di me capire quale dovrebbe rappresentare il grado e quale dovrebbe rappresentare il file. Le classifiche vanno da 1..8 e i file vanno da a..h, ma nel tuo caso entrambi ie jvanno da 0..7, quindi questo non mi aiuta a vedere quale sia quale. Esiste una crisi internazionale relativa alla carenza di lettere di cui non sono a conoscenza, o cosa c'è di sbagliato nel rinominarli ranke file?
Jörg W Mittag

4
Gioca l'avvocato del diavolo per un secondo; Immagina di leggere il codice degli scacchi di qualcuno in cui hanno usato un numero magico 8. Puoi presumere di sapere a cosa serve? Come puoi essere sicuro al 100%? C'è qualche possibilità che possa significare qualcos'altro? Non sarebbe stato solo un po 'più bello se non avessi nemmeno dovuto fare un'ipotesi? Quanto tempo potresti dedicare a rintracciare il codice per capire se il tuo presupposto è giusto? Passeresti meno tempo se il codice fosse stato più autodocumentante usando un nome significativo e approfondito?
Ben Cottrell,

16
@JacquesB: In effetti. Ci sono 8 gradi, 8 file, 8 pedine. Alcuni motori di scacchi utilizzano un sistema di punti in cui determinati pezzi, determinati campi e determinate mosse hanno punti assegnati ad essi e il motore sceglie la mossa con il punteggio più alto. 8 potrebbe essere un tale punteggio. 8 potrebbe essere una profondità di ricerca predefinita. Potrebbe essere praticamente qualsiasi cosa.
Jörg W Mittag

9
Considererei l'utilizzo di un ciclo foreach, ad es foreach(var rank in Ranks). Considererei anche la fusione di entrambi i loop in uno in cui ogni elemento è una tupla (rango, file).
CodesInChaos

Risposte:


101

IMHO il tuo amico ha ragione nell'usare un nome simbolico, anche se penso che il nome dovrebbe essere sicuramente più descrittivo (come BOARD_WIDTHinvece di CHESS_CONST).

Anche quando il numero non cambierà mai per tutta la durata del programma, potrebbero esserci altri punti nel programma in cui il numero 8 si verificherà con un significato diverso. Sostituire "8" BOARD_WIDTHovunque sia intesa la larghezza della scheda e usare un altro nome simbolico quando si intende una cosa diversa rende questi diversi significati espliciti, ovvi e il tuo programma generale più leggibile e mantenibile. Ti consente anche di fare una ricerca globale sul tuo programma (o una ricerca di simboli inversi, se il tuo ambiente lo fornisce) nel caso in cui tu abbia bisogno di identificare rapidamente tutte le posizioni nel codice che dipendono dalla larghezza della scheda.

Vedi anche questo precedente post SE.SE per una discussione su come (o come non) scegliere i nomi per i numeri.

Come nota a margine, poiché è stato discusso qui nei commenti : se, nel codice del tuo programma reale, importa se la variabile si iriferisce alle righe e jalle colonne della scheda, o viceversa, allora è consigliabile scegliere nomi di variabili che chiarire la distinzione, come rowe col. Il vantaggio di tali nomi è che fanno apparire sbagliato il codice sbagliato.


22
Vorrei aggiungere che, se l'OP avesse scritto un motore di scacchi davvero eccezionale e desiderasse ampliarlo per includere gli scacchi 3D o altre varianti, allora gli 8 che dovranno cambiare saranno una sfida.
Steve Barnes,

32
@SteveBarnes: cerco di evitare tali argomenti, dal momento che conduce troppo facilmente a un argomento ripristinato come "Penso che sia estremamente diverso da mai rendere questo programma un diverso tipo di gioco, quindi posso lasciare il numero magico 8 dove si trova. "
Doc Brown,

4
@IllusiveBrian Questo è un classico argomento "uomo di paglia" per due motivi: (1) la definizione di una costante non significa che il programmatore non può ancora digitare "8" (sia per caso, design o malizia!) E (2) solo perché esiste una costante BOARD_WIDTH = 8 non rende BOARD_WIDTH la costante corretta da utilizzare in un determinato punto del programma.
alephzero,

3
@Blrfl ... o porterà alla sovrastima del codice. È responsabilità dello sviluppatore realizzare ciò che può cambiare in futuro e codificare di conseguenza. La codifica come i requisiti non cambierà causa problemi, ma l'altro estremo non è migliore.
Malcolm,

4
@corsiKa Quando le variabili del loop corrispondono agli assi fisici, dovrebbero essere denominate x, y o row, col o, per scacchi, file, rank.
user949300

11

Ok, ecco alcuni commenti che ho:

Sbarazzarsi dei numeri magici è un'ottima idea. Esiste un concetto noto come DRY, che è spesso travisato, ma l'idea è di non duplicare la conoscenza dei concetti nel progetto. Quindi se hai una classe chiamata ChessBoard, potresti tenere una costante chiamata BOARD_SIZE o ChessBoard.SIZE ad essa collegata. In questo modo esiste un'unica fonte per queste informazioni. Inoltre, ciò aiuta la leggibilità in un secondo momento:

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

Anche se il numero non cambia mai, il tuo programma è probabilmente migliore. Chiunque lo legga conosce ulteriori informazioni su ciò che sta facendo il codice.

Un brutto nome è peggio di nessun nome, ma ciò non significa che qualcosa non debba essere nominato. Basta cambiare il nome. Non buttare via il bambino con l'acqua del bagno. : p Il nome può essere descrittivo purché si capisca bene cosa sta descrivendo. Quindi, quel concetto può essere utilizzato per più cose diverse.


8
questo sembra semplicemente ripetere i punti già formulati e spiegati nella risposta migliore
moscerino

-7

Che cosa si vuole veramente è quello di eliminare fino alla nausea i riferimenti a costanti, siano essi nominati o nudo:

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

Se in realtà stai per proliferare la costante ripetendo tali cicli e quant'altro, è meglio attenersi 8.

8si auto-descrive; non è una macro che sta per qualcos'altro.

You Ain't Never Gonna (TM) lo trasforma in un programma di scacchi 9x9 e se mai lo farai, la proliferazione di 8 non sarà la maggiore difficoltà.

Possiamo cercare una base di codice di 150.000 righe per il token 8 e classificare quali occorrenze significano cosa in pochi secondi.

Molto più importante è modulare il codice in modo che la conoscenza degli scacchi sia concentrata nel minor numero di posti possibile. È meglio avere uno, due, forse tre moduli specifici degli scacchi in cui si verifica un 8 letterale, piuttosto che trentasette moduli intrecciati con responsabilità specifiche degli scacchi, riferendosi a 8 con un nome simbolico.

Quando o se questa costante 8 diventa una fonte di tensione nel tuo programma, puoi facilmente risolverlo in quel momento. Risolvi i problemi reali che stanno accadendo ora. Se non senti di essere ostacolato da quel particolare 8, segui quell'istinto.

Supponiamo che in futuro desideri supportare dimensioni alternative della scheda. In quel caso, quei loop dovranno cambiare se usano una costante nominata o 8, perché le dimensioni saranno recuperate da alcune espressioni come board.widthe board.height. Se BOARD_SIZEinvece hai 8, questi luoghi saranno più facili da trovare. Quindi questo è meno sforzo. Tuttavia, non devi dimenticare lo sforzo di sostituirlo 8con BOARD_SIZEin primo luogo. Lo sforzo complessivo non è inferiore. Fare un passaggio sul codice per passare 8a BOARD_SIZE, e poi un altro per supportare dimensioni alternative, non è più economico che passare da 8un supporto per dimensioni alternative.

Possiamo anche considerare questo da un'analisi del rischio / beneficio puramente fredda e obiettiva. Il programma contiene costanti nude adesso. Se questi sono sostituiti da una costante, non ci sono benefici; il programma è identico. Con qualsiasi modifica, esiste un rischio diverso da zero. In questo caso, è piccolo. Tuttavia, nessun rischio dovrebbe essere preso senza un beneficio. Per "vendere" il cambiamento di fronte a questo ragionamento, dobbiamo ipotizzare un vantaggio: un vantaggio futuro che aiuterà con un programma diverso: una versione futura del programma che non esiste ora. Se viene pianificato un programma del genere, questa ipotesi e il relativo ragionamento sono in buona fede e dovrebbero essere presi sul serio.

Ad esempio, se ti mancano pochi giorni per aggiungere altro codice che prolifererà ulteriormente queste costanti, potresti voler eliminare. Se quelle istanze delle costanti sono approssimativamente tutte le istanze che possano mai esistere, perché preoccuparsi.

Se lavori su software commerciale, verranno applicati anche gli argomenti ROI. Se un programma non sta vendendo e la modifica di alcuni numeri con codice fisso in costanti non migliorerà le vendite, non sarai compensato per lo sforzo. La modifica ha un ritorno zero sull'investimento di tempo. Gli argomenti del ROI si generalizzano oltre il denaro. Hai scritto un programma, investendo tempo e fatica, e ne hai tratto qualcosa: questo è il tuo ritorno, la tua "R". Se apportando quel cambiamento da solo, ottieni di più di quella "R", qualunque essa sia, allora sicuramente. Se hai qualche piano per un ulteriore sviluppo e quel cambiamento migliora la tua "R", idem. Se la modifica non ha una "R" immediata o prevedibile per te, dimenticala.


13
8NON è così auto-descrittivo, è un numero che potrebbe significare qualsiasi cosa. E forse vogliono fare una partita a scacchi 9x9, perché no? Se hai 150.000 righe di codice, non avrai modo di memorizzare il 8significato di ciascuno di essi nel codice e, anche se tu potessi, perché dovresti? È solo una seccatura extra. Per quanto riguarda la modularizzazione, la sostituzione 8con qualcosa di simile NUM_RANKSnon danneggia la modularità, infatti, aiuta perché rende il codice più facile da armeggiare.
Jerfov2,

4
@Kaz Lo faccio anche io. E poi introduco bug strani significativi perché una manciata di usi non erano quelli che pensavo fossero, perché è difficile prestare così tanta attenzione a un gran numero di sostituzioni ed essere sempre corretti. Per questo motivo evito di entrare in questo scenario in primo luogo, quindi non posso supportare i consigli che perdonano di entrarci.
doppelgreener,

1
"Tuttavia, non si deve dimenticare lo sforzo di sostituire 8con BOARD_SIZEin primo luogo" - Il tempo che aveva trascorso scrutare oltre il codice cercando di capire ciò che ciascuno 8fa nella vostra mesi di programma da oggi molto probabilmente superare il tempo trascorso sostituirlo 8con una costante significativa a livello di modulo.
Christian Dean,

1
@doppelganger Quello scenario è già qui. Non sto dicendo, prendi un programma di scacchi che usa le costanti e sostituiscile con 8. Né sto dicendo "progetta di non usare le costanti in un programma di scacchi non ancora scritto"
Kaz

1
@Kaz Perché dovresti farti leggere tutto il codice intorno all'8, e forse a volte sbagli il contesto quando potresti spendere altri 3 secondi in più dando un nome significativo? Per quanto riguarda la conoscenza del valore effettivo della costante, è molto più semplice cercare il valore esatto per una variabile piuttosto che provare a progettare all'indietro cosa significa un intero numero magico nel codice
Jerfov2
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.