È mai una buona idea inserire i valori di hardcode nelle nostre applicazioni?

44

È mai una buona idea inserire i valori di hardcode nelle nostre applicazioni? Oppure è sempre la cosa giusta chiamare questi tipi di valori dinamicamente nel caso in cui debbano cambiare?

    
posta Edward 14.04.2011 - 02:26
fonte

14 risposte

64

Sì, ma rendilo ovvio .

fare:

  • utilizza costanti
  • usa un nome di variabile descrittivo

Non:

risposta data 14.04.2011 - 02:31
fonte
23

Quello che trovo strano su questo Q & A finora è che nessuno ha effettivamente tentato di definire chiaramente "hard-code" o, più importante, le alternative.

tl; dr: Sì, è a volte una buona idea per i valori di hard-code, ma non esiste una regola semplice per quando ; dipende completamente dal contesto.

La domanda lo limita a valori , che intendo come numeri magici , ma la risposta a se è una buona idea è relativa a per cosa sono effettivamente utilizzati!

Diversi esempi di valori "hardcoded" sono:

  • Valori di configurazione

    Mi vergogno ogni volta che vedo affermazioni come command.Timeout = 600 . Perché 600? Chi l'ha deciso? È stato il timeout prima, e qualcuno ha alzato il timeout come un hack invece di risolvere il problema prestazionale sottostante? O è in realtà qualche aspettativa conosciuta e documentata per il tempo di elaborazione?

    Queste non dovrebbero essere costanti di numeri magici o , dovrebbero essere esternalizzate in un file o database di configurazione da qualche parte con un nome significativo, perché il loro valore ottimale è determinato in gran parte o interamente dall'ambiente che il l'applicazione è in esecuzione.

  • Formule matematiche

    Le formule di solito tendono ad essere piuttosto statiche, così che la natura dei valori costanti all'interno non è particolarmente importante. Il volume di una piramide è (1/3) b * h. Ci interessa da dove arriva l'1 o il 3? Non proprio. Un commentatore precedente ha giustamente sottolineato che diameter = radius * 2 è probabilmente migliore di diameter = radius * RADIUS_TO_DIAMETER_CONVERSION_FACTOR - ma questa è una falsa dicotomia.

    Quello che dovresti fare per questo tipo di scenario è creare una funzione . Non ho bisogno di sapere come vieni con la formula, ma ho ancora bisogno di sapere a cosa serve . Se, invece di una qualsiasi assurdità scritta sopra, scrivo volume = GetVolumeOfPyramid(base, height) , poi improvvisamente tutto diventa molto più chiaro, ed è perfettamente ok avere numeri magici dentro la funzione ( return base * height / 3 ) perché è ovvio che sono solo parte della formula.

    La chiave qui è ovviamente avere le funzioni brevi e semplici . Questo non funziona per funzioni con 10 argomenti e 30 linee di calcoli. In questo caso usa la composizione della funzione o le costanti.

  • Regole dominio / aziendali

    Questo è sempre l'area grigia perché dipende da quale sia esattamente il valore. La maggior parte del tempo, sono questi particolari numeri magici che sono candidati per trasformarsi in costanti, perché questo rende il programma più facile da capire senza complicare la logica del programma. Considera il test if Age < 19 rispetto a if Age < LegalDrinkingAge ; probabilmente puoi capire cosa sta succedendo senza la costante, ma è più facile con il titolo descrittivo.

    Questi possono anche diventare candidati all'astrazione di funzioni, ad esempio function isLegalDrinkingAge(age) { return age >= 19 } . L'unica cosa è che spesso la tua logica di business è molto più complicata di quella, e potrebbe non avere senso iniziare a scrivere decine di funzioni con 20-30 parametri ciascuna. Se non c'è un'astrazione chiara basata su oggetti e / o funzioni, ricorrere alle costanti è OK.

    L'avvertenza è che, se lavori per il dipartimento delle tasse, diventa veramente veramente oneroso e onestamente inutile scrivere AttachForm(FORM_CODE_FOR_SINGLE_TAXPAYER_FILING_JOINTLY_FOR_DEPRECIATION_ON_ARMPIT_HAIR) . Non hai intenzione di farlo, stai per AttachForm("B-46") perché ogni singolo sviluppatore che abbia mai lavorato o mai funzionerà saprà che "B-46" è il codice del modulo per un singolo deposito di contribuenti blah bla bla: i codici modulo fanno parte del dominio stesso, non cambiano mai, quindi non sono numeri davvero magici.

    Quindi devi usare le costanti con parsimonia nella logica del business; fondamentalmente devi capire se quel "numero magico" è in realtà un numero magico o se è un aspetto ben noto del dominio. Se si tratta di dominio, non lo si codifica in modo soft a meno che non ci siano davvero buone possibilità che cambierà.

  • Codici di errore e flag di stato

    Questi sono mai ok per l'hard-code, come può dirti qualsiasi povero bastardo che sia mai stato colpito con Previous action failed due to error code 46 . Se la tua lingua lo supporta, dovresti usare un tipo di enumerazione. Altrimenti, di solito avrai un intero file / modulo pieno di costanti che specifica i valori validi per un particolare tipo di errore.

    Non farmi mai vedere return 42 in un gestore di errori, capiche? Nessuna scusa.

Probabilmente ho omesso diversi scenari, ma penso che riguardi la maggior parte di essi.

Quindi, sì, a volte è accettabile fare pratica su materiale hard. Basta non essere pigro per questo; dovrebbe essere una decisione consapevole piuttosto che un semplice vecchio codice sciatto.

    
risposta data 14.04.2011 - 20:23
fonte
5

In aggiunta ad altre risposte. Utilizzare le costanti per le stringhe quando possibile. Certo, non vuoi avere

const string server_var="server_var";

ma dovresti avere

const string MySelectQuery="select * from mytable;";

(assumendo che tu abbia effettivamente una query in cui vuoi ottenere tutti i risultati da una tabella specifica, sempre)

Oltre a questo, utilizzare le costanti per qualsiasi numero diverso da 0 (di solito). Se hai bisogno di una maschera di bit di autorizzazione di 255, non utilizzare

const int 8th_bit=255; //or some other obscure naming scheme that equates to 255.

usa invece

const int AllowGlobalRead=255;

Naturalmente, insieme alle costanti, sai quando usare gli enumeratori. Il caso precedente probabilmente si adatterebbe bene in uno.

    
risposta data 14.04.2011 - 04:57
fonte
5

Ci sono vari motivi per assegnare un identificatore a un numero.

  • Se il numero potrebbe cambiare, dovrebbe avere un identificatore. È molto più facile trovare NUMBER_OF_PLANETS che cercare ogni istanza di 9 e considerare se debba essere modificato a 8. (Si noti che le stringhe visibili all'utente potrebbe essere necessario cambiare se il software deve essere utilizzato in una lingua diversa, ed è una cosa difficile da prevedere in anticipo.)
  • Se il numero è difficile da digitare in qualsiasi modo. Per le costanti come pi, è meglio dare una definizione di massima precisione piuttosto che ridigitarla in più punti, possibilmente in modo impreciso.
  • Se il numero si verifica in luoghi diversi. Non dovresti controllare due usi di 45 nelle funzioni adiacenti e chiedermi se significano la stessa cosa.
  • Se il significato non è immediatamente riconoscibile. È lecito ritenere che tutti sappiano cosa sia 3.14159265 .... Non è sicuro assumere che tutti riconosceranno la costante gravitazionale, o anche pi / 2. ("Ognuno" qui dipende dalla natura del software.I programmatori di sistemi possono essere tenuti a conoscere la rappresentazione ottale dei bit di autorizzazione Unix o simili.Nel software di architettura navale / marittima, controllando il numero di Froude di uno scafo e di una velocità proposti a vedere se è 1.1 o maggiore potrebbe essere perfettamente auto-esplicativo per chiunque debba lavorarci sopra.)
  • Se il contesto non è riconoscibile. Tutti sanno che ci sono 60 minuti in un'ora, ma moltiplicare o dividere per 60 può non essere chiaro se non ci sono indicazioni immediate che la quantità sia un valore temporale o un valore di velocità .

Questo ci fornisce i criteri per i letterali hard-coding. Dovrebbero essere immutabili, non difficili da scrivere, che si verificano in un posto o in un contesto solo e con un significato riconoscibile. Non ha senso definire 0 come ARRAY_BEGINNING, ad esempio, o 1 come ARRAY_INCREMENT.

    
risposta data 14.04.2011 - 16:10
fonte
4

Is it ever a good idea to hardcode values into our applications?

I valori di hardcode solo se i valori sono specificati nella Specifica (in una versione finale della specifica), ad es. La risposta HTTP OK sarà sempre 200 (a meno che non cambi nella RFC), quindi vedrai (in alcuni dei miei codici) costanti come:

public static final int HTTP_OK = 200;

Altrimenti, memorizzo le costanti nel file delle proprietà.

Il motivo per cui ho specificato le specifiche è che la modifica delle costanti nelle specifiche richiede una gestione delle modifiche, in cui le parti interessate esamineranno la modifica e approveranno / disapproveranno. Non succede mai da un giorno all'altro e richiede mesi / anni per l'approvazione. Non dimenticare che molti sviluppatori utilizzano specifiche (ad esempio HTTP), quindi modificarlo significa rompere milioni di sistemi.

    
risposta data 14.04.2011 - 15:27
fonte
3
  • se il valore può cambiare, e in effetti potrebbe cambiare, quindi codificarlo quando possibile, a condizione che lo sforzo richiesto non superi il rendimento previsto
  • alcuni valori non possono essere codificati in modo soft; segui le linee guida di Jonathan in quei (rari) casi
risposta data 14.04.2011 - 04:28
fonte
3

Dipende da ciò che consideri hardcoding. Se si tenta di evitare tutte le cose hardcoded, si finisce nel territorio softcoding e si crea un sistema che solo il creatore può gestire (e questo è l'ultimo hardcode)

Un sacco di cose sono hardcoded in qualsiasi quadro ragionevole e funzionano. cioè non c'è una ragione tecnica per cui non dovrei essere in grado di modificare il punto di ingresso di un'applicazione C # (static void Main), ma hardcoding che non crea alcun problema per nessun utente (eccetto il SO domanda )

La regola empirica che uso è che tutto ciò che può e cambierà, senza influenzare lo stato dell'intero sistema, dovrebbe essere confondibile.

Quindi, IMHO, è sciocco non codificare le cose che non cambiano mai (pi, costante gravitazionale, costante in una formula matematica - pensa al volume di una sfera).

Inoltre è sciocco non codificare cose o processi che avranno un impatto sul tuo sistema che richiederanno la programmazione in ogni istanza, cioè è inutile permettere all'utente di aggiungere campi dinamici a un modulo, se qualsiasi campo aggiunto richiederebbe il sviluppatore di manutenzione per entrare e scrivere qualche script che farà funzionare quella cosa. Inoltre è stupido (e l'ho visto poche volte in ambienti aziendali) creare qualche strumento di configurazione, quindi niente è hardcoded, tuttavia, solo gli sviluppatori nel reparto IT possono usarlo, ed è solo leggermente più semplice da usare che per farlo in Visual Studio.

Quindi, in fondo, se una cosa dovrebbe essere hardcoded è una funzione di due variabili:

  • cambierà il valore
  • come cambierà il valore nel sistema
risposta data 14.04.2011 - 09:21
fonte
2

Recentemente ho codificato una funzione MySQL per calcolare correttamente la distanza tra due coppie lat / long. Non puoi semplicemente fare Pitagora; le linee di longitudine si avvicinano di pari passo con l'aumentare della latitudine verso i poli, quindi c'è un qualche tipo di trigide peloso coinvolto. Il punto è che ero piuttosto sconvolto dall'aver hardcoded il valore che rappresenta il raggio terrestre in miglia.

Ho finito per farlo, anche se il fatto è che le linee lat / lng sono molto più vicine tra loro, diciamo, sulla luna. E la mia funzione avrebbe drasticamente sottostimato le distanze tra i punti su Giove. Ho capito che le probabilità che il sito web che sto costruendo con una posizione extraterrestre vengano inserite sono piuttosto ridotte.

    
risposta data 14.04.2011 - 14:27
fonte
1

Ho notato che ogni volta che puoi estrarre dati dal tuo codice, migliora ciò che è rimasto. Inizi a notare nuovi refactoring e migliora intere sezioni del tuo codice.

È semplicemente una buona idea lavorare verso l'estrazione di costanti, non considerarla una regola stupida, considerarla un'opportunità per codificare meglio.

Il più grande vantaggio sarebbe il modo in cui potresti trovare costanti simili che sono l'unica differenza in gruppi di codice: l'astrazione in array ha aiutato a ridurre alcuni file del 90% delle loro dimensioni e a sistemare un bel po 'di copia e amplificazione; incolla i bug nel frattempo.

Devo ancora vedere un singolo vantaggio per non estrarre dati.

    
risposta data 14.04.2011 - 08:13
fonte
1

Beh, dipende se la tua lingua è compilata. Se non è compilato, non è un grosso problema, basta modificare il codice sorgente, anche se sarà un po 'delicato per un programmatore.

Se stai programmando con un linguaggio compilato, questa non è chiaramente una buona idea, perché se le variabili cambiano, devi ricompilare, il che è un grande spreco di tempo se vuoi regolare questa variabile.

Non è necessario creare alcun dispositivo di scorrimento o interfaccia per modificare dinamicamente la sua variabile, ma il minimo che si possa fare è un file di testo.

Ad esempio con il mio progetto ogre, sto sempre usando la classe ConfigFile per caricare una variabile che ho scritto su un file di configurazione.

    
risposta data 14.04.2011 - 14:06
fonte
1

Due occasioni in cui le costanti sono (secondo me almeno) OK:

  1. costanti che non riguardano nient'altro; puoi cambiare quelle costanti quando vuoi senza dover cambiare altro. Esempio: la larghezza predefinita di una colonna della griglia.

  2. Costanti assolutamente immutabili, precise, ovvie, come "numero di giorni alla settimana". days = weeks * 7 Sostituire 7 con una costante DAYS_PER_WEEK non fornisce praticamente alcun valore.

risposta data 14.04.2011 - 14:26
fonte
0

Sono d'accordo completamente con Jonathan ma come tutte le regole ci sono delle eccezioni ...

"Numero magico nelle specifiche: numero magico nel codice"

Sostanzialmente afferma che qualsiasi numero magico che rimane nella specifica dopo i ragionevoli tentativi di ottenere un contesto descrittivo per loro dovrebbe essere riflesso come tale nel codice. Se i numeri magici rimangono nel codice, dovrebbero essere fatti tutti gli sforzi per isolarli e renderli chiaramente collegati al loro punto di origine.

Ho eseguito alcuni contratti di interfaccia in cui è necessario popolare i messaggi con valori mappati dal database. Nella maggior parte dei casi la mappatura è abbastanza semplice e si adatta alle linee guida generali di Jonathan, ma ho riscontrato casi in cui la struttura del messaggio target era semplicemente orribile. Oltre l'80% dei valori che dovevano essere tramandati nella struttura erano costanti imposti dalla specifica del sistema distante. questo, unito al fatto che la struttura del messaggio era gigantesca, fece sì che molte LOT di tali costanti venissero popolate. Nella maggior parte dei casi non hanno fornito un significato o una ragione, hanno appena detto "metti qui" o "metti 4.10.53.10100.889450.4452 qui". Non ho nemmeno tentato di inserire un commento accanto a tutti, avrebbe reso il codice risultante illeggibile. Mi sono comunque assicurato che le sezioni di codice in cui appaiono questi valori magici siano correttamente isolate e che i loro contenitori (classi, pacchetti) abbiano un nome appropriato per puntare direttamente alle specifiche che li applicano.

Detto questo, quando ci pensi ... è praticamente tutto per renderlo ovvio ...

    
risposta data 14.04.2011 - 07:40
fonte
0

Se stai codificando il valore della costante gravitazionale terrestre, a nessuno importa. Se esegui l'hardcode dell'indirizzo IP del tuo server proxy, sei nei guai.

    
risposta data 14.04.2011 - 09:02
fonte
0

Per lo più no, ma penso che valga la pena notare che avrete più problemi quando inizierete a duplicare il valore hard-coded. Se non lo si duplica (ad esempio, utilizzalo solo una volta nell'implementazione di una classe), non utilizzare una costante potrebbe essere accettabile.

    
risposta data 14.04.2011 - 09:23
fonte

Leggi altre domande sui tag