Domanda

Che cosa è un numero magico?

Perché dovrebbe essere evitato?

Ci sono casi in cui non è appropriato?

È stato utile?

Soluzione

Un numero magico è un uso diretto di un numero in codice.

Per esempio, se si dispone di (in Java):

public class Foo {
    public void setPassword(String password) {
         // don't do this
         if (password.length() > 7) {
              throw new InvalidArgumentException("password");
         }
    }
}

Questo dovrebbe essere rielaborato:

public class Foo {
    public static final int MAX_PASSWORD_SIZE = 7;

    public void setPassword(String password) {
         if (password.length() > MAX_PASSWORD_SIZE) {
              throw new InvalidArgumentException("password");
         }
    }
}

Migliora la leggibilità del codice, ed è più facile da mantenere.Immaginare il caso in cui ho impostato la dimensione del campo password nella GUI.Se io uso un numero magico, ogni volta che la dimensione massima modifiche, devo modificare nel codice di due posizioni.Se ho dimenticato uno, questo porterà ad incoerenze.

Il JDK è piena di esempi di come in Integer, Character e Math classi.

PS:Strumenti di analisi statica come FindBugs e PMD rileva l'utilizzo di numeri di magia nel codice e suggerisce il refactoring.

Altri suggerimenti

Un Numero Magico è hardcoded di un valore che può cambiare in una fase successiva, ma che può essere quindi difficile da aggiornare.

Per esempio, supponiamo di avere una Pagina che visualizza gli ultimi 50 Ordini in "i Tuoi Ordini" della Pagina di Riepilogo.50 è il Numero Magico qui, perché non standard o convenzione, è un numero che è fatto per i motivi descritti nella specifica.

Ora, quello che devi fare è di avere il 50 in luoghi diversi - il tuo script SQL (SELECT TOP 50 * FROM orders), il tuo Sito web (le Ultime 50 Ordini), l'ordine di accesso (for (i = 0; i < 50; i++)) e probabilmente molti altri luoghi.

Ora, cosa succede quando qualcuno decide di cambiare 50 a 25?o 75?o 153?È ora di sostituire il 50 in tutti i luoghi, ed è molto probabile che a perdere.Trova/Sostituisci non può funzionare, perché 50 può essere utilizzato per altre cose, e ciecamente sostituzione di 50 con 25 può avere altri effetti collaterali negativi (es.il Session.Timeout = 50 chiamata, che è anche il set per 25 utenti e avviare la creazione di report troppo frequenti timeout).

Inoltre, il codice può essere difficile da capire, cioè"if a < 50 then bla"- se si verifica che, nel mezzo di una complicata funzione, altri sviluppatori che non hanno familiarità con il codice potrebbe chiedersi: "WTF è di 50???"

Ecco perché è meglio avere tale ambiguo e numeri arbitrari esattamente 1 posto - "const int NumOrdersToDisplay = 50"perché, che rende il codice più leggibile ("if a < NumOrdersToDisplay"significa che avete solo bisogno di cambiare in 1 ben definito luogo.

Luoghi dove i Numeri Magici sono appropriato è tutto ciò che è definito uno standard, cioè SmtpClient.DefaultPort = 25 o TCPPacketSize = whatever (non so se è standardizzato).Inoltre, tutto solo definito entro 1 funzione potrebbe essere accettabile, ma che dipende dal Contesto.

Hai dato un'occhiata alla voce in Wikipedia numero magico?

Si va in un po ' di dettaglio su tutti i modi in cui il numero magico è fatto riferimento.Qui una citazione su " numero magico, come una cattiva pratica di programmazione

Il termine "numero magico" si riferisce anche alla cattiva pratica di programmazione di utilizzare i numeri direttamente nel codice sorgente, senza spiegazione.Nella maggior parte dei casi questo rende i programmi più difficile da leggere, capire e gestire.Sebbene la maggior parte delle guide di fare un'eccezione per i numeri zero e uno, è una buona idea per definire tutti gli altri numeri in codice denominato costanti.

Numero Magico Vs.Costante Simbolica:Quando sostituire?

Magia:Unknown semantica

Costante simbolica -> Fornisce sia corretta semantica e contesto corretto per l'uso

Semantica:Il significato o lo scopo di una cosa.

"Creare una costante, il nome, il significato, e sostituire il numero con esso." -- Martin Fowler

Primo, numeri di magia non sono solo numeri.Qualsiasi valore di base può essere la "magia".I valori di base sono manifesto di enti come numeri interi, reali, doppie, galleggianti, date, stringhe, booleani, caratteri, e così via.Il problema non è il tipo di dati, ma la "magia" aspetto di valore come appare nel nostro codice di testo.

Cosa si intende per "magia"?Per essere precisi:Da "magia", si intende per scegliere la semantica (significato o scopo) di valore nel contesto del nostro codice;che è ignoto, l'inconoscibile, poco chiare o confuse.Questa è la nozione di "magia".Un valore di base non è magia, quando il suo significato semantico, o come scopo, di essere facilmente e rapidamente noto, chiaro e comprensibile (non confondere) dal surround contesto senza l'aiuto speciale di parole (ad es.costante simbolica).

Pertanto, siamo in grado di identificare numeri di magia, misura la capacità di un lettore di codice a sapere, essere chiaro, e di comprendere il senso e lo scopo di un valore di base dal contesto circostante.Il meno conosciuto, meno chiaro e più confuso il lettore è, il più "magico" il valore di base è.

Definizioni Utili

  • confondere:causa (qualcuno) per diventare disorientato o perplesso.
  • disorientato:causa (qualcuno) per diventare perplesso e confuso.
  • perplesso:completamente sconcertato;molto perplesso.
  • sconcertati:totalmente strano o perplesso.
  • perplesso:in grado di capire;perplessi.
  • capire:percepire il significato (parole, una lingua, o altoparlante).
  • significato:qual è il significato di una parola, testo, concetto, o di azione.
  • significato:intende trasmettere, indicare, o fare riferimento a una particolare cosa o concetto);significano.
  • indicare:essere un'indicazione di.
  • indicazione:un segno o un pezzo di informazioni che indica qualcosa.
  • indicare:punto di uscita;spettacolo.
  • segno:un oggetto di qualità, o di un evento la cui presenza o la comparsa indica la probabile presenza o l'insorgenza di qualcos'altro.

Nozioni di base

Abbiamo due scenari per la magia dei nostri valori fondamentali.Solo il secondo è di primaria importanza per i programmatori di codice:

  1. Un solo valore di base (ad es.numero), da cui il suo significato è ignoto, l'inconoscibile, poco chiare o confuse.
  2. Un valore di base (ad es.numero) in un contesto, ma il significato rimane ignoto, l'inconoscibile, poco chiare o confuse.

Generale dipendenza di "magia" è come il lone valore di base (ad es.numero) non ha conosciuto comunemente semantica (come Pi), ma è un locale conosciuto semantica (ad es.il programma), che non è del tutto chiaro dal contesto o potrebbe essere abusato di una buona o una cattiva contesto(s).

La semantica dei linguaggi di programmazione non ci permetterà di utilizzare lone valori di base, tranne (forse) come dati (es.tabelle di dati).Quando ci imbattiamo in "magic numbers", generalmente si fanno in un contesto.Pertanto, la risposta alla

"Posso sostituire questo numero magico con una costante simbolica?"

è:

"Quanto velocemente si può valutare e comprendere il significato semantico del numero (il suo scopo per essere lì) nel suo contesto?"

Tipo di Magia, ma non abbastanza

Con questo pensiero in mente, siamo in grado di vedere rapidamente come un numero, come Pi (3.14159) non è un "numero magico" quando messo nel contesto giusto (ad es.2 x 3.14159 raggio x o 2*Pi*r).Qui, il numero di 3,14159 è mentalmente riconosciuto Pi senza la costante simbolica identificatore.

Ancora, abbiamo generalmente sostituire 3.14159 con una costante simbolica identificatore come Pi a causa della lunghezza e della complessità del numero.Gli aspetti di lunghezza e la complessità del Pi (accoppiato con un bisogno per la precisione), di solito significa l'identificatore simbolico o costante è meno soggetta a errori.Il riconoscimento di "Pi" come un nome, è semplicemente una comoda bonus, ma non è il motivo principale per avere la costante.

Nel frattempo:Torna al Ranch

Mettere da parte le costanti comuni come il Pi, ci concentreremo principalmente sui numeri con significati particolari, ma che questi significati sono vincolati all'universo del nostro software di sistema.Tale numero potrebbe essere "2" (come fondamentale valore intero).

Se io uso il numero 2 di per sé, la mia prima domanda potrebbe essere:Cosa significa "2" significa?Il significato di "2" di per sé è sconosciuto e inconoscibile, senza contesto, lasciando il suo uso poco chiaro e confuso.Anche se avendo appena "2" nel nostro software non accadrà a causa della lingua semantica, noi vogliamo vedere che il "2" di per sé non comporta alcun semantica o evidente scopo di essere da solo.

Mettiamo il nostro unico "2" in un contesto: padding := 2, dove il contesto è una "GUI Contenitore".In questo contesto, il significato di 2 (come pixel o altre unità grafiche) ci offre un rapido indovinare la sua semantica (significato e di scopo).Potremmo fermarci qui e dire che 2 è ok, in questo contesto, e non c'è altro che dobbiamo sapere.Tuttavia, forse il nostro software universo questa non è tutta la storia.C'è di più, ma "padding = 2" in un contesto che non può rivelare.

Facciamo un ulteriore fingere di 2 pixel di padding nel nostro programma è di "default_padding" varietà in tutto il nostro sistema.Pertanto, la scrittura di istruzione padding = 2 non è abbastanza buono.La nozione di "default" non è rivelato.Solo quando scrivo: padding = default_padding come contesto, e poi altrove: default_padding = 2 non sono pienamente realizzare un migliore e più pieno significato (semantica e di scopo) di 2 nel nostro sistema.

L'esempio di cui sopra è abbastanza buona perché "2" potrebbe essere qualsiasi cosa.Solo quando ci limitare la gamma di dominio e di comprensione "il mio programma" dove 2 è il default_padding nella GUI UX parti di "il mio programma", possiamo finalmente dare un senso a "2" nel suo giusto contesto.Qui il "2" è una "magia", il numero che si somma a una costante simbolica default_padding nel contesto della GUI UX di "il mio programma", per farne uso come default_padding rapidamente, inteso nel più ampio contesto della allegando il codice.

Pertanto, qualsiasi valore di base, il cui significato (semantica e di scopo) non possono essere sufficientemente e rapidamente capito che è un buon candidato per una costante simbolica in luogo del valore di base (ad es.numero magico).

Di Andare Avanti

Numeri su una scala potrebbe avere semantica così.Per esempio, far finta che stiamo facendo un D&D gioco, dove abbiamo l'idea di un mostro.Il nostro mostro oggetto ha una funzione chiamata life_force, che è un numero intero.I numeri hanno un significato che non è conoscibile o cancellare senza parole per la fornitura di significato.Quindi, cominciamo da arbitrariamente dicendo:

  • full_life_force:INTEGER = 10 -- Molto vivo (e non)
  • minimum_life_force:INTEGER = 1 -- a Malapena (molto male)
  • morti:INTEGER = 0 -- Morto
  • non morti:INTEGER = -1 -- Min non morti (quasi morto)
  • zombie:INTEGER = -10 -- Max non morti (molto undead)

Dal costanti simboliche di cui sopra, si inizia ad avere un immagine mentale di vitalità, morta, e "undeadness" (e le possibili implicazioni o conseguenze) per i nostri mostri D&D gioco.Senza queste parole (costanti simboliche), si sono lasciati con solo i numeri che vanno da -10 .. 10.Solo l'intervallo senza le parole ci lascia in un luogo possibilmente in una grande confusione e, potenzialmente, con errori nel nostro gioco, se in diverse parti del gioco sono le dipendenze, su cosa intervallo di numeri significa varie operazioni come attack_elves o seek_magic_healing_potion.

Pertanto, quando si cerca e considerando la sostituzione dei "numeri magici" vogliamo chiedere a scopo pieni di domande circa i numeri nel contesto del nostro software e anche come i numeri di interagire dal punto di vista semantico con l'altro.

Conclusione

Esaminiamo quali domande si dovrebbe chiedere:

Si potrebbe avere un numero magico se ...

  1. Può il valore di base hanno un particolare significato o scopo nel vostro software universo?
  2. Può il particolare significato o scopo probabilmente ignoto, l'inconoscibile, poco chiare o confuse, anche nel suo giusto contesto?
  3. Può un corretto valore di base, impropriamente utilizzato con conseguenze negative nel contesto sbagliato?
  4. Può un improprio valore di base essere usati correttamente e con conseguenze negative nel contesto giusto?
  5. Il valore di base hanno una semantica, o come scopo, di relazioni con altri valori di base in contesti specifici?
  6. Può un valore di base esistono in più di un posto nel nostro codice con una semantica diversa in ogni, causando in tal modo al lettore di confusione?

Esaminare stand-alone manifesto costante i valori di base nel vostro testo del codice.Chiedi a ogni domanda lentamente e accuratamente su ogni istanza di tale valore.Considerare la forza della tua risposta.Molte volte, la risposta non è in bianco e nero, ma ha sfumature frainteso il significato e lo scopo, velocità di apprendimento, e la velocità di comprensione.C'è anche bisogno di vedere come si collega al software della macchina intorno ad esso.

Alla fine, la risposta per la sostituzione è di rispondere a misura (nella tua mente) la forza o la debolezza del lettore per effettuare la connessione (ad es."get it").Il più rapidamente capiscono il significato e lo scopo, il meno "magia" che si hanno.

CONCLUSIONE:Sostituire i valori di base con costanti simboliche solo quando la magia è grande abbastanza per provocare difficile rilevare i bug derivanti da confusioni.

Un numero magico è una sequenza di caratteri all'inizio di un formato di file o un protocollo di scambio.Questo numero serve come un controllo di integrità.

Esempio:Aprire qualsiasi file GIF, si vedrà all'inizio:GIF89."GIF89" essere il numero magico.

Altri programmi in grado di leggere i primi caratteri di un file e di identificare correttamente le Gif.

Il pericolo è che casuale di dati binari possono contenere questi stessi personaggi.Ma è molto improbabile.

Come per il protocollo di exchange, è possibile utilizzare per identificare rapidamente che l'attuale "messaggio" che viene passato è danneggiato o non valido.

I numeri magici sono ancora utili.

Nella programmazione, un "numero magico" è un valore che deve essere dato un nome simbolico, ma è invece scivolato in il codice come un letterale, di solito in più di un posto.

E ' un male per lo stesso motivo SPOT (Punto Unico di Verità) è buona:Se si vuole cambiare questa costante più tardi, si sarebbe dovuto cercare con il vostro codice di trovare ogni istanza.È anche un male, perché potrebbe non essere chiaro per altri programmatori che questo numero rappresenta, quindi, la "magia".

A volte la gente prendere il numero magico eliminazione ulteriormente, spostando queste costanti, in un file separato di agire come configurazione.Questo a volte è utile, ma può anche creare una complessità maggiore di quanto ne vale la pena.

Un problema che non è stato menzionato con l'utilizzo di numeri di magia...

Se si dispone di molti di loro, le probabilità sono abbastanza buone che si dispone di due diversi fini che si sta utilizzando numeri di magia, dove la valori capita di essere la stessa.

E poi, certo, basta, è necessario modificare il valore...per un solo scopo.

Un numero magico può anche essere un numero speciale, hardcoded semantica.Per esempio, una volta ho visto un sistema in cui il record Id > 0 sono stati trattati normalmente, 0 sé era "nuovo record", -1 è stato "questa è la radice" e -99 è stata "questo è stato creato nella root".0 e -99 causerebbe il WebService per la fornitura di un nuovo ID.

La cosa brutta di questo è che si sta riutilizzo di uno spazio (che firma interi record Id) per le abilità speciali.Forse non avrai mai voglia di creare un record con ID 0, o con un ID negativo, ma anche se non, ogni persona che guarda sia al codice o al database potrebbe inciampare su questo e essere confuso in un primo momento.Va da sé quei valori non erano ben documentato.

Probabilmente, 22, 7, -12 e 620 conte come numeri di magia, troppo.;-)

Presumo che questa è una risposta al mio risposta per la tua domanda precedente.In programmazione, un numero magico è un integrato costante numerica che appare senza spiegazione.Se appare in due località distinte, può portare a casi in cui un esempio è cambiato e non in un altro.Per entrambe queste ragioni, è importante isolare e definire le costanti numeriche fuori dai luoghi in cui sono utilizzati.

Vale la pena notare che, a volte, si desidera non è configurabile "hard-coded" numeri in codice.Ci sono un certo numero di quelli famosi tra 0x5F3759DF che viene utilizzato nel ottimizzato inverso del quadrato della radice algoritmo.

Nei rari casi In cui ho bisogno di utilizzare questi Numeri Magici, ho impostato come un const nel mio codice, e documento perché essi vengono utilizzati, come funzionano, e da dove sono venuti.

Ho sempre usato il termine "numero magico" in modo diverso, come un oscuro valore memorizzato all'interno di una struttura di dati che può essere verificato come un rapido controllo di validità.Per esempio gzip file contengono 0x1f8b08 come i loro primi tre byte, i file di classe Java iniziare con 0xcafebabe, etc.

Si vedono spesso i numeri magici incorporato in formati di file, perché i file possono essere inviati in giro piuttosto promiscuamente e perdere tutti i dati su come sono stati creati.Tuttavia i numeri magici sono anche talvolta utilizzato per strutture di dati in memoria, come ioctl() chiama.

Un rapido controllo del numero magico prima di elaborare il file o la struttura di dati permette di errori di segnale precoce, piuttosto che fatica tutto il percorso attraverso potenzialmente di lunga durata trattamento, per annunciare che l'ingresso era completa balderdash.

Che cosa circa l'inizializzazione di una variabile al top della sua classe con un valore di default?Per esempio:

public class SomeClass {
    private int maxRows = 15000;
    ...
    // Inside another method
    for (int i = 0; i < maxRows; i++) {
        // Do something
    }

    public void setMaxRows(int maxRows) {
        this.maxRows = maxRows;
    }

    public int getMaxRows() {
        return this.maxRows;
    }

In questo caso, 15000 è un numero magico (secondo CheckStyles).Per me, l'impostazione di un valore di default è ok.Non voglio avere a che fare:

private static final int DEFAULT_MAX_ROWS = 15000;
private int maxRows = DEFAULT_MAX_ROWS;

Fa che rendere più difficile la lettura?Non ho mai considerato questo fino a quando ho installato CheckStyles.

@eed3si9n:Vorrei anche suggerire che '1 è un numero magico.:-)

Un principio, che è legato alla magia dei numeri è che ogni fatto che il codice si occupa devono essere dichiarati esattamente una volta.Se si usa la magia dei numeri in codice (ad esempio la lunghezza della password per l'esempio che @marcio ha dato, si può facilmente finire la duplicazione di questo fatto, e quando il capire di che fatto modifiche hai un problema di manutenzione.

Che dire di ritorno variabili?

Ho appositamente trovare difficile quando attuazione le stored procedure.

Immaginare il prossimo stored procedure (sintassi sbagliata, lo so, proprio per mostrare un esempio):

int procGetIdCompanyByName(string companyName);

Ritorna l'Id della società, se esiste, di una particolare tabella.In caso contrario, restituisce -1.In qualche modo è un numero magico.Alcuni dei consigli che ho letto finora, dice che mi hanno veramente a fare la progettazione di qualcosa di simile a questo:

int procGetIdCompanyByName(string companyName, bool existsCompany);

A proposito, che cosa dovrebbe restituire se la società non esiste?Ok:per impostare existesCompany come false, ma anche restituirà -1.

Altro opzione è quella di fare due distinte funzioni:

bool procCompanyExists(string companyName);
int procGetIdCompanyByName(string companyName);

Quindi, una pre-condizione per la seconda stored procedure è la società che esiste.

Ma ho paura della concorrenza, perché in questo sistema, una società può essere creato da un altro utente.

La linea di fondo è:che cosa pensi di usare quel tipo di "numeri magici" che sono relativamente noti e sicuro per dire che qualcosa è successo o che qualcosa non esiste?

Un altro vantaggio di estrarre un numero magico, come una costante, dà la possibilità di documentare in modo chiaro le informazioni di business.

public class Foo {
    /** 
     * Max age in year to get child rate for airline tickets
     * 
     * The value of the constant is {@value}
     */
    public static final int MAX_AGE_FOR_CHILD_RATE = 2;

    public void computeRate() {
         if (person.getAge() < MAX_AGE_FOR_CHILD_RATE) {
               applyChildRate();
         }
    }
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top