Quando è un numero un numero magico?

4

Negli ultimi due mesi mi sono tuffato nello standard di codifica IfSQ . Come parte di questo standard IfSQ, una regola è di non utilizzare Magic Numbers . Anche se non ho problemi a costruire questa regola in assegni come FxCop o StyleCop, sono confuso su cosa sia effettivamente un numero magico.

Secondo Wikipedia ci sono 3 spiegazioni di numeri magici:

  1. Un valore numerico o di testo costante utilizzato per identificare un formato o protocollo di file;
  2. Valori unici distintivi che difficilmente verranno scambiati per altri significati (ad es. identificatori globalmente univoci);
  3. Valori univoci con significato non spiegato o ricorrenze multiple che potrebbero (preferibilmente) essere sostituite con costanti denominate.

Mi sto concentrando sul terzo significato. Ma questo è anche il punto in cui sono bloccato. Vedendo come sto cercando di costruire questo in una regola FxCop; il controllo deve essere automatizzato. Ma quale bandiera suppongo sia il numero magico?

Lo standard IfSQ spiega quanto segue come numeri magici: Numeric literals (other than 0 or 1) have been embedded directly into the source code. For example "34" or "86400".

Ma questo non mi sembra affatto buono. Ciò significherebbe che dovrei segnalare ogni singola occorrenza di un numero diverso da 0 e 1. Numeri come 24 (ore), 60 (minuti) e 100 (percentuale) sono, nel loro contesto corretto, nessun numero magico; nei miei occhi, cioè.

Perché questo sarà un controllo automatico, non è possibile guardare dalle cose in modo contestuale.

Sulla base di questo ho le seguenti domande:

  1. Come dovrei definire un numero magico?
  2. È possibile definire numeri magici senza contesto?
  3. Devo saltare determinate istruzioni quando controllo i numeri magici?
posta Matthijs 29.07.2014 - 11:06
fonte

3 risposte

5

La maggior parte degli strumenti che conosco, che supportano il rilevamento e la segnalazione degli usi del numero magico, si rivolgono specificamente solo alle dichiarazioni . Hai ragione a dire che eliminare tutti i numeri dal codice sorgente è un po 'inutile.

Chi - con una mente sana - dovrebbe leggere il numero di ore al giorno da un file di configurazione? Certamente, c'è un buon motivo per usare solo il 24, tuttavia non ci sono buoni motivi per usarlo all'interno di un'istruzione che non fa parte di una dichiarazione costante. Confronta le seguenti due occorrenze di 24:

private final int NUMBER_OF_HOURS_PER_DAY = 24;
...
return NUMBER_OF_HOURS_PER_DAY * days;

vs

return 24 * days;

Il secondo esempio sopra sarebbe tipicamente contrassegnato come usando un numero magico, mentre il primo non lo farebbe. La differenza principale deriva dal fatto che un secondo utilizzo all'interno del codice rende chiara la differenza: nel primo esempio, si farebbe semplicemente riferimento nuovamente a NUMBER_OF_HOURS_PER_DAY e, in caso di modifica costante in qualsiasi momento, si è certi che è aggiornato ovunque subito. Nel secondo esempio dovresti scrivere di nuovo 24 , il che aumenta l'effetto del problema del numero magico.

Inoltre, le costanti possono essere nominate in modo appropriato, in modo da ottenere più significato da esso rispetto a un semplice numero magico, che potrebbe non sembrare magico per te (perché sai che un giorno ha 24 ore), ma potrebbe sembrare davvero abbastanza magico per qualcun altro. E se il fattore non fosse 24, ma 7? È meno magico? e ha anche qualcosa a che fare con il numero di giorni in una settimana?

In entrambi i casi, l'effetto netto è che i numeri (diversi da 0 e 1) dovrebbero essere definiti tramite costanti e non si dovrebbero contrassegnare tali occorrenze come numeri magici. I numeri all'interno delle istruzioni, che non sono utilizzati in un sito di dichiarazione costante, dovrebbero tuttavia essere contrassegnati.

Casi di confine: cosa fare con qualcosa come final int HOURS = 20 + 4; ? e per quanto riguarda final int CONSTANT = OTHER_CONSTANT * 4 ? Il 4 deve essere contrassegnato come numero magico o no? Nella mia esperienza, i diversi strumenti differiscono almeno in questi casi di confine. Alcuni sono molto rigidi e non consentono numeri in espressioni più grandi della costante stessa (cioè, nessuna aggiunta / moltiplicazione / ecc.). Gli altri sono un po 'più rilassati e lo accettano come un uso per definire la costante.

    
risposta data 29.07.2014 - 11:21
fonte
5

Solo per estendere un po 'la risposta di Frank , prendi la seguente:

private final int NUMBER_OF_HOURS_PER_DAY = 24;
private final int FRAMES_PER_SECOND = 24;
...
return NUMBER_OF_HOURS_PER_DAY * days;
...
return FRAMES_PER_SECOND * seconds;

Ora confrontalo con:

return 24 * days;
...
return 24 * seconds;

Se consideri che uno degli aspetti più importanti della qualità del codice è il modo in cui trasmette le intenzioni, il più tardi è un disastro.

    
risposta data 29.07.2014 - 11:45
fonte
2

Ho lottato anche con questa definizione, nel mio caso con CheckStyle.

Un particolare problema è nel framework di convalida Spring, in cui le stringhe di errore vengono cercate in un file .properties. CheckStyle si lamenta quando scrivo qualcosa come

addError ( "error.invalid.email.address");

Se questo è l'unico posto in cui viene utilizzata la stringa, faccio fatica a vedere cosa aggiunge l'alternativa:

stringa finale statica privata ERROR_INVALID_EMAIL_ADDRESS="error.invalid.email.address";

.. 200 linee di codice qui ...

addError (ERROR_INVALID_EMAIL_ADDRESS);

Altri sono certo che avranno punti di vista diversi ...

    
risposta data 29.07.2014 - 11:19
fonte

Leggi altre domande sui tag