Utilizzo di stringhe / numeri magici [chiuso]


31

Questo è un argomento alquanto controverso, e immagino ci siano tante opinioni quanti sono i programmatori. Ma per il gusto di farlo, voglio sapere quali sono le pratiche comuni negli affari (o nei luoghi di lavoro).

Nel mio posto di lavoro abbiamo una rigida guida alla programmazione. Una sezione è dedicata a stringhe / numeri magici. Indica (per C #):

Non usare valori letterali, numerici o di stringhe, nel tuo codice se non per definire costanti simboliche. Utilizzare il modello seguente per definire le costanti:

public class Whatever  
{  
   public static readonly Color PapayaWhip = new Color(0xFFEFD5);  
   public const int MaxNumberOfWheels = 18;  
}

Ci sono eccezioni: i valori 0, 1 e null possono quasi sempre essere usati in sicurezza. Molto spesso anche i valori 2 e -1 sono OK. Le stringhe destinate alla registrazione o alla traccia sono esenti da questa regola. I letterali sono ammessi quando il loro significato è chiaro dal contesto e non soggetto a cambiamenti futuri.

mean = (a + b) / 2; // okay  
WaitMilliseconds(waitTimeInSeconds * 1000); // clear enough

Una situazione ideale sarebbe un documento di ricerca ufficiale che mostri effetti sulla leggibilità / manutenibilità del codice quando:

  • I numeri / stringhe magici sono ovunque
  • Le stringhe / i numeri magici sono sostituiti da costanti dichiarazioni ragionevolmente (o in diversi gradi di copertura) - e per favore non gridarmi per aver usato "ragionevolmente", so che ognuno ha un'idea diversa di cosa sia "ragionevolmente"
  • Stringhe / numeri magici sono collocati in eccesso e in luoghi dove non dovrebbero essere (vedi il mio esempio di seguito)

Vorrei fare questo per avere degli argomenti scientificamente basati quando discuto con uno dei miei colleghi, che sta per dichiarare costanti come:

private const char SemiColon = ';';
private const char Space = ' ';
private const int NumberTen = 10;

Un altro esempio potrebbe essere (e questo è in JavaScript):

var someNumericDisplay = new NumericDisplay("#Div_ID_Here");

Attacchi gli ID DOM sopra il tuo file javascript se quell'ID viene utilizzato solo in 1 posizione?

Ho letto i seguenti argomenti:
StackExchange
StackOverflow
Byte Comunità IT
Ci sono molti altri articoli e dopo aver letto questi emergono alcuni schemi.

Quindi la mia domanda è: usare stringhe e numeri magici nel nostro codice? Sto specificatamente cercando risposte di esperti che sono supportate da riferimenti se possibile.


2
Una variabile magica è una variabile che contiene un significato che non si riflette nei suoi contenuti. Il valore intero '10' riflette il significato del numero 10, quindi non è necessario renderlo una costante. Lo stesso vale per spazio e punto e virgola. D'altra parte se hai un valore '%% ?? %%' e questo è un delimitatore personalizzato, allora deve essere posizionato come costante perché il suo contenuto non riflette il fatto che è un delimitatore.
Jeroen Vannevel,

23
NumberTen = 10Questo è inutile in quanto il numero 10 non verrà ridefinito. MaxRetryCount = 10Questo ha un punto a: potremmo voler cambiare il numero massimo di tentativi. private const char SemiColon = ';'; Dumb. private const char LineTerminator = ';'; Inteligente.
Mike,

1
La domanda reale non è chiara.
Tulains Córdova,

Risposte:


89

... quando discuto con uno dei miei colleghi, che sta per dichiarare costanti come:

private const char SemiColon = ';';
private const char Space = ' ';
private const int NumberTen = 10;

L'argomento che devi fare con il tuo collega non è di nominare uno spazio letterale come Spacema la sua scarsa scelta del nome per le sue costanti.

Supponiamo che il lavoro del tuo codice sia analizzare un flusso di record che contengono campi separati da punti a;b;ce virgola ( ) e sono essi stessi separati da spazi ( a;b;c d;e;f). Se chiunque abbia scritto le tue specifiche ti chiama tra un mese e dice "ci siamo sbagliati, i campi nei record sono separati da simboli di pipe ( a|b|c d|e|f)", cosa fai?

Sotto lo schema value-as-name che il tuo collega preferisce, dovresti cambiare il valore di literal ( SemiColon = '|') e vivere con il codice che continua a usare SemiColonper qualcosa che non è più un punto e virgola. Ciò porterà a commenti negativi nelle revisioni del codice . Per ovviare a ciò, potresti cambiare il nome del letterale in PipeSymbole passare attraverso e cambiare ogni occorrenza di SemiColona PipeSymbol. A quel ritmo avresti anche potuto usare solo un punto e virgola ( ';') in primo luogo, perché dovrai valutare ogni singolo utilizzo e farai lo stesso numero di modifiche.

Identificatori per le costanti devono essere descrittivo di ciò che il valore fa , non ciò che il valore è , ed è lì che il vostro collega ha fatto una svolta a sinistra tra le erbacce. Nell'applicazione di divisione del campo sopra descritta, lo scopo del punto e virgola è un separatore di campo e le costanti devono essere nominate di conseguenza:

private const char FieldSeparator = ';';    // Will become '|' a month from now
private const char RecordSeparator = ' ';
private const int MaxFieldsPerRecord = 10;

In questo modo, quando cambia il separatore di campo, si cambia esattamente una riga di codice, la dichiarazione della costante. Qualcuno che guarda la modifica vedrà solo quella riga e capirà immediatamente che il separatore di campo è cambiato da un punto e virgola a un simbolo di pipe. Il resto del codice, che non ha dovuto cambiare perché utilizzava una costante, rimane lo stesso e il lettore non deve scavarlo per vedere cos'altro gli è stato fatto.


Sono totalmente d'accordo. Qualche decennio fa ho lavorato a un progetto in cui i messaggi venivano inviati in segmenti, ciascuno con 8 registri generali. Qualcuno aveva dichiarato #define one 1 #define two 2 ecc. (O qualunque fosse l'equivalente in UK Post Office Coral, la lingua scelta in quel momento). La parola veniva dall'alto che in futuro il campo della lunghezza sarebbe stato il numero di byte, non di segmenti, quindi ovviamente il codice è stato cambiato in #define one 8 #define two 16 ecc.
Mawg

3
Per quanto stupido come nomi come punto e virgola o PipeSymbol sembrano, cambiando uno all'altro utilizzando uno script sarà molto più facile che cambiare ogni colpiti ;a |.
Brandin,

Che dire del caso in cui un dato valore letterale String viene utilizzato più volte in un file, ma non ha altro significato se non il suo valore? Ad esempio, se stai testando che puoi ricevere una determinata chiave in una mappa in 20 scenari di differenza, dovrei definire una costante simile ?: public static final String MY_KEY_NAME = "MyKeyName"
Jordan McQueen

1
@JordanMcQueen C'è un caso da fare per usare letterali nudi se (e solo se) ognuno viene usato esattamente una volta e non è necessario altrove. Se si tratta di qualcosa di simile a ogni codice essere scenario che elabora un formato di file diverso, ogni formato deve definire il proprio costante (ad esempio, CSV_RECORD_SEPARATOR, TSV_RECORD_SEPARATOR, etc.).
Blrfl,

8

La definizione del punto e virgola come costante è ridondante, poiché il punto e virgola è già costante da solo . Non cambierà mai.

Non è che un giorno qualcuno annuncerà "cambio di terminologia, + è il nuovo punto e virgola ora", e il tuo collega si affretterà felicemente ad aggiornare la costante (hanno riso di me - guardali ora).

C'è anche una questione di coerenza. Garantisco che la sua NumberTencostante NON sarà utilizzata da tutti (la maggior parte dei programmatori non è fuori di testa), quindi non servirà comunque allo scopo previsto. Quando arriva l'apocalisse e "dieci" viene ridimensionato globalmente a 9, l'aggiornamento della costante NON farà il trucco, perché ti lascerà comunque con un mucchio di letterali 10nel tuo codice, quindi ora il sistema diventa totalmente imprevedibile anche nell'ambito di un presupposto rivoluzionario che "dieci" significa "9".

Memorizzare tutte le impostazioni come contro è qualcosa su cui ripenserei anche io. Non si dovrebbe fare questo alla leggera.

Quali esempi di questo tipo di utilizzo abbiamo raccolto finora? Terminatore di linea ... conteggio massimo tentativi ... numero massimo di ruote ... siamo sicuri che non cambieranno mai?

Il costo è che la modifica delle impostazioni predefinite richiede la ricompilazione di un'applicazione e, in alcuni casi, anche le sue dipendenze (poiché i valori const numerici possono essere codificati durante la compilazione).

C'è anche l'aspetto di test e beffardo. È stata definita la stringa di connessione come const, ma ora non è possibile simulare l'accesso al database (stabilire una connessione falsa) nel test dell'unità.


4
"Non cambierà mai". Lo pensavo sull'apostrofo (legato per sempre al valore ASCII 39). Alcune vecchie app utilizzate per arricciare l'apostrofo. Ma ora le app moderne trattano quel valore ASCII come un apostrofo dritto compatibile con le vecchie app e invece le persone usano spesso (virgoletta singola sinistra, Unicode 8217 ) per le app compatibili con mostrare un glifo diverso per il segno arricciato. Essendo che l'Europa usa le virgole come gli americani usano i periodi come un punto decimale, mi trovo un po 'titubante a dichiarare "non ... mai".
TOOGAM,

@TOOGAM bene, il tuo esempio giustifica avere una DecimalPointcostante - ma non Commao Periodcostanti. È abbastanza una differenza: il primo indica una funzione , un ruolo o uno scopo del valore. "Punto e virgola" o "virgola" non rientrano in quella categoria.
Konrad Morawski,

Questo è vero per l'esempio del punto decimale. Tuttavia, l'esempio dell'apostrofo sembra essere una categoria simile (o identica) come una virgola (o punto e virgola).
TOOGAM,

Il punto e virgola @KonradMorawski può essere utilizzato per vari scopi, come la divisione della stringa o la fine della riga. È il significato di esso (non valore) che dovrebbe essere usato per nominare la costanza. Considera il cambiamento futuro, cioè domani consentiremo l'elaborazione di 20 record, quindi la costanza chiamata NumberTen è fuori contesto, mentre maxRecord andrebbe ancora bene.
MaxZoom,

5
private const char SemiColon = ';';
private const char Space = ' ';
private const int NumberTen = 10;

Quindi il tuo collega punta a un ingresso WTF giornaliero. Tali definizioni sono sciocche e ridondanti. Tuttavia, come è stato sottolineato da altri, le seguenti definizioni non sarebbero sciocche o ridondanti:

private const char StatementTerminator = ';';
private const char Delimiter = ' ';
private const int  BalanceInquiryCode = 10;

I numeri e le stringhe "magici" sono costanti che hanno un significato oltre il loro valore immediato e letterale. Se la costante 10ha un significato oltre "dieci cose" (ad esempio un codice per un'operazione specifica o una condizione di errore), è allora che diventa "magica" e deve essere sostituita da una costante simbolica che descriva quel significato astratto.

Oltre a descrivere chiaramente l'intento, le costanti simboliche ti risparmiano anche un po 'di mal di testa quando scrivi male un letterale. Una semplice trasposizione da "CVS" a "CSV" in una riga di codice ha superato i test unitari e il QA e li ha resi in produzione, dove ha causato il fallimento di una particolare operazione. Sì, ovviamente i test unitari e QA erano incompleti e questo è un problema suo, ma l'uso di una costante simbolica avrebbe evitato del tutto quel bruciore di stomaco.


3

Non dovrebbe esserci nulla di controverso al riguardo. Il punto non è se usare numeri magici o no, il punto è avere un codice leggibile.
Considera la differenza tra: if(request.StatusCode == 1)e if(request.HasSucceeded). In questo caso, direi che quest'ultimo è molto più leggibile, ma ciò non significa che non puoi mai avere un codice simile int MaxNumberOfWheels = 18.

PS: Ecco perché odio assolutamente le linee guida per la programmazione. Gli sviluppatori dovrebbero essere abbastanza maturi per essere in grado di effettuare chiamate di giudizio in questo modo; non dovrebbero lasciarlo a un pezzo di testo formato da dio sa chi.


13
I conducenti dovrebbero essere abbastanza maturi da poter giudicare da che parte della strada guidano;)
Konrad Morawski,

2
Il risultato di un giudizio può variare anche tra sviluppatori maturi, quindi anche linee guida di codifica arbitrarie hanno lo scopo di migliorare la leggibilità attraverso la coerenza. Ciò non è correlato al fatto che la creazione di un NumberTen costante non ha senso.
Mike Partridge,

1
Non insisto sul fatto che debbano essere formali, timbrati, ecc., Possono essere informali ma devono essere concordati, e questo va già oltre il semplice uso della maturità individuale del giudizio. Ma adesso hai cancellato il tuo commento Stefan :)
Konrad Morawski,

1
@StefanBilliet - per niente. Il mio punto è che la leggibilità è migliorata grazie alla coerenza. Il problema qui non è la stessa linea guida di codifica, ma una linea guida portata agli estremi a causa di incomprensioni.
Mike Partridge,

@MikePartridge Forse avrei dovuto elaborarlo; le linee guida sulla codifica che ho visto sono più nella tendenza di un manuale generale su come qualcuno da qualche parte pensava che il software dovesse essere scritto, piuttosto che accordi come te e Konrad probabilmente stanno pensando a :-)
Stefan Billiet,
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.