Utilizzo di stringhe / numeri magici [chiuso]

28

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

Nel mio posto di lavoro abbiamo linee guida rigorose per la codifica. Una sezione di questo è dedicata alle stringhe / numeri magici. Indica (per C #):

Do not use literal values, either numeric or strings, in your code other than to define symbolic constants. Use the following pattern to define constants:

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

Ci sono delle eccezioni: i valori 0, 1 e null possono quasi sempre essere usati in modo sicuro. Molto spesso i valori 2 e -1 sono OK pure. 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 mostra gli effetti sulla leggibilità / manutenibilità del codice quando:

  • I numeri / le stringhe magici sono dappertutto
  • Le stringhe / numeri magici vengono sostituiti da dichiarazioni costanti ragionevolmente (o in diversi gradi di copertura) - e per favore non gridare con me per usare "ragionevolmente", so che ognuno ha un'idea diversa di ciò che "ragionevolmente" è
  • Stringhe / numeri magici sparsi in eccesso e in luoghi in cui non dovrebbero essere (vedi il mio esempio sotto)

Mi piacerebbe farlo per avere degli argomenti basati sulla scientificità quando discuti con uno dei miei colleghi, che sta andando al punto di 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");

Tieni DOM ID sopra il tuo file javascript se quell'ID viene usato solo in 1 posto?

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

Quindi la mia domanda dovrebbe essere usare stringhe e numeri magici nel nostro codice? Sono specificamente alla ricerca di risposte esperte supportate da riferimenti, se possibile.

    
posta Daniel Gruszczyk 11.12.2013 - 15:17
fonte

4 risposte

86

... when arguing with one of my collegues, who is going to the point of declaring constants like:

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

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

Diciamo che il lavoro del tuo codice è di analizzare un flusso di record che contengono campi separati da punto e virgola ( a;b;c ) e sono separati da spazi ( a;b;c d;e;f ). Se chi ha scritto le tue specifiche ti chiama da un mese a questa parte e dice "ci siamo sbagliati, i campi nei record sono separati da simboli pipe ( a|b|c d|e|f )," cosa fai?

Sotto lo schema value-as-name che preferisce il tuo collega, dovresti cambiare il valore del letterale ( SemiColon = '|' ) e vivere con il codice che continua a usare SemiColon per qualcosa che non è realmente un punto e virgola più. Ciò porterà a commenti negativi nelle recensioni del codice . Per farlo, puoi cambiare il nome del letterale in PipeSymbol e passare e modificare ogni occorrenza di SemiColon in PipeSymbol . A quel ritmo potresti anche aver appena usato un punto e virgola letterale ( ';' ) in primo luogo, perché dovrai valutare ogni singolo utilizzo singolarmente e dovrai fare lo stesso numero di modifiche.

Gli identificatori per le costanti devono essere descrittivi di quale sia il valore , non quale sia il valore , ed è lì che il tuo collega ha trasformato a sinistra le infestanti. Nell'applicazione di divisione del campo descritta sopra, lo scopo del punto e virgola è un separatore di campo e le costanti devono essere denominate 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 il separatore di campo cambia, si cambia esattamente una riga di codice, la dichiarazione della costante. Qualcuno che osserva il cambiamento 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 bisogno di cambiare perché utilizzava una costante, rimane lo stesso, e il lettore non deve scavare attraverso di esso per vedere cos'altro è stato fatto.

    
risposta data 11.12.2013 - 17:10
fonte
8

La definizione di punto e virgola come costante è ridondante, poiché il punto e virgola è già costante di per sé . Non cambierà mai.

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

C'è anche una questione di coerenza. Garantisco che la sua costante NumberTen NON sarà usata da tutti (la maggior parte dei programmatori non è fuori di testa), quindi non servirà a qualsiasi scopo ci si aspettasse comunque. Quando arriva l'apocalisse e "dieci" viene ridimensionato globalmente a 9, l'aggiornamento della costante NON farà il trucco, perché ti lascerà ancora un mucchio di% letterale10 s nel tuo codice, quindi ora il sistema diventa totalmente imprevedibile nell'ambito di un assunto rivoluzionario che "dieci" significa "9".

Memorizzare tutte le impostazioni come tali è qualcosa su cui avrei ripensato. Non si dovrebbe fare questo alla leggera.

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

Il costo è che la modifica delle impostazioni predefinite richiede la ricompilazione di un'applicazione e, in alcuni casi, anche delle sue dipendenze (dato che i valori cost numerici potrebbero diventare hard-coded durante la compilazione).

C'è anche l'aspetto di prova e di derisione. Hai definito la stringa di connessione come const, ma ora oops non puoi prendere in giro l'accesso al database (stabilire una connessione falsa) nel test dell'unità.

    
risposta data 11.12.2013 - 15:46
fonte
4
private const char SemiColon = ';';
private const char Space = ' ';
private const int NumberTen = 10;

Quindi il tuo collega punta a una voce giornaliera del WTF. Queste 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 al di là del loro valore letterale immediato. Se la costante 10 ha un significato oltre "dieci cose" (come un codice per una specifica operazione o condizione di errore), allora diventa "magica" e dovrebbe essere sostituita da una costante simbolica che descrive quel significato astratto.

Oltre a descrivere chiaramente l'intento, anche le costanti simboliche ti fanno risparmiare alcuni mal di testa quando scrivi un errore letterale. Una semplice trasposizione da "CVS" a "CSV" in una riga di codice ha attraversato tutta la fase di testing e QA e l'ha resa operativa, dove ha causato il fallimento di una particolare operazione. Sì, ovviamente i test di unità e di QA erano incompleti e questo è il suo problema, ma l'uso di una costante simbolica avrebbe evitato del tutto quel bruciore di stomaco.

    
risposta data 11.12.2013 - 18:11
fonte
3

Non dovrebbe esserci nulla di controverso. Il punto non riguarda l'uso di numeri magici o meno, 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 si possa mai avere un codice come int MaxNumberOfWheels = 18 .

P.S .: Questo è il motivo per cui odio assolutamente le linee guida sulla codifica. Gli sviluppatori dovrebbero essere abbastanza maturi per essere in grado di fare chiamate di giudizio come questa; non dovrebbero lasciarlo a un pezzo di testo formato da chissà chi.

    
risposta data 11.12.2013 - 15:38
fonte