È mai una buona idea codificare i valori nelle nostre applicazioni?


45

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


2
un parametro di configurazione potrebbe aiutarti
Gopi

54
Non si sa mai quando il valore di pipotrebbe cambiare ...
Gabe,

12
Amico, immagino che persone come @gabe siano la ragione per cui questa è una "regola". Se ripeti 3.14 in 20 punti nel tuo codice e poi scopri che in realtà hai bisogno di maggiore precisione, sei fregato. Non mi ero reso conto che non fosse ovvio.
Bill K,

17
È stato un po 'maleducato, @Bill. @Gabe stava chiaramente scherzando, ma a parte questo, la domanda riguardava i parametri hardcoding vs config, non usare una costante contro numeri magici ripetuti in più punti.
David Conrad,

1
Sì, a volte l'hardcoding può essere una buona idea. Vedi l'articolo di Wikipedia sull'anti-pattern "Softcoding".
user16764

Risposte:


64

Sì, ma rendilo ovvio .

Fare:

  • usa costanti
  • usa un nome variabile descrittivo

Non:


44
Qual è più pulito diameter = 2 * radiuso diameter = RADIUS_TO_DIAMETER_FACTOR * radius? Esistono davvero casi angolari in cui un numero magico può essere la soluzione migliore.
Joonas Pulakka,

5
Non posso essere abbastanza d'accordo con questa risposta. Tendo a pensare alla programmazione come a essere un romanziere. Racconti la tua storia attraverso il codice e se le persone non riescono a capire la logica rende il tuo codice inutile secondo me. Ecco perché le convenzioni di denominazione ben ponderate sono essenzialmente per la leggibilità. Inoltre, non ci sono buoni motivi per usare numeri magici. Usando i numeri magici rimuovi il "perché" dall'equazione e rendi più difficile la comprensione. Ad esempio: "diametro = 2 * raggio" A cosa servono i due? Questo "diametro = RADIUS_TO_DIAMETER_FACTOR * raggio" ha molto più senso.
chrisw,

9
diametro = 2 * raggio è direttamente dalla matematica delle scuole superiori. La ragione per non nominare il "2" è che per avere un valore di qualsiasi altra cosa richiederebbe una modifica delle leggi della fisica o della matematica, o di entrambi. (D'altra parte, nominare Pi o costante di Plancks è una buona mossa per una semplice leggibilità).
quick_now

8
@Joonas: Pfft. Sicuramente intendi diameter = radius << 1? Suppongo che potrebbe anche essere diameter = radius << RADIUS_TO_DIAMETER_BITS_TO_SHIFT.
Formica

4
che ne dicidiameter = radius.toDiameter()
Carson Myers

27

Ciò che trovo strano su questo Q&A finora è che nessuno ha effettivamente tentato di definire chiaramente "hard-code" o, soprattutto, le alternative.

tl; dr: Sì, a volte è una buona idea codificare i valori, ma non esiste una regola semplice su quando ; dipende completamente dal contesto.

La domanda lo restringe ai valori , che prendo per indicare i numeri magici , ma la risposta al fatto che siano o meno una buona idea è relativa a ciò per cui sono effettivamente utilizzati!

Diversi esempi di valori "hardcoded" sono:

  • Valori di configurazione

    Mi arrabbio ogni volta che vedo dichiarazioni come command.Timeout = 600. Perché 600 Chi l'ha deciso? Era già scaduto il tempo prima e qualcuno ha sollevato il timeout come hack invece di risolvere il problema di prestazioni sottostante? O è in realtà qualche aspettativa nota e documentata per i tempi di elaborazione?

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

  • Formule matematiche

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

    Quello che dovresti fare per questo tipo di scenario è la creazione di una funzione . Non ho bisogno di sapere come ti è venuta la formula, ma devo ancora sapere a cosa serve . Se, invece di una qualsiasi assurdità scritta sopra, scrivo volume = GetVolumeOfPyramid(base, height)all'improvviso, tutto diventa molto più chiaro, ed è perfettamente ok avere numeri magici all'interno della funzione ( return base * height / 3) perché è ovvio che fanno solo parte della formula.

    La chiave qui è ovviamente avere funzioni brevi e semplici . Questo non funziona per le funzioni con 10 argomenti e 30 linee di calcolo. Utilizzare la composizione della funzione o le costanti in quel caso.

  • Dominio / regole aziendali

    Questa è sempre l'area grigia perché dipende da quale sia esattamente il valore. Il più delle volte, sono questi particolari numeri magici che sono candidati per trasformarsi in costanti, perché ciò rende il programma più facile da capire senza complicare la logica del programma. Considera il test if Age < 19vs if Age < LegalDrinkingAge.; probabilmente puoi capire cosa sta succedendo senza la costante, ma è più facile con il titolo descrittivo.

    Questi possono anche diventare candidati per l'astrazione di funzioni, per esempio function isLegalDrinkingAge(age) { return age >= 19 }. L'unica cosa è che spesso la tua logica aziendale è molto più complicata di così, e potrebbe non avere senso iniziare a scrivere dozzine di funzioni con 20-30 parametri ciascuna. Se non c'è una chiara astrazione basata su oggetti e / o funzioni, il ricorso alle costanti è OK.

    L'avvertenza è che, se stai lavorando per il dipartimento delle imposte, diventa davvero, davvero oneroso e onestamente inutile scrivere AttachForm(FORM_CODE_FOR_SINGLE_TAXPAYER_FILING_JOINTLY_FOR_DEPRECIATION_ON_ARMPIT_HAIR). Non lo farai, lo farai AttachForm("B-46")perché ogni singolo sviluppatore che abbia mai lavorato o funzionerà lì saprà che "B-46" è il codice del modulo per un singolo contribuente che presenta bla blah blah - i codici del modulo fanno parte del dominio stesso, non cambiano mai, quindi non sono numeri davvero magici.

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

  • Codici di errore e flag di stato

    Questi non vanno mai bene per il codice, come Previous action failed due to error code 46può dirti qualsiasi povero bastardo che sia mai stato colpito con la . Se la tua lingua lo supporta, dovresti utilizzare un tipo di enumerazione. Altrimenti, di solito avrai un intero file / modulo pieno di costanti che specificano i valori validi per un particolare tipo di errore.

    Non farmi mai vedere return 42in un gestore degli errori, capiche? Niente scuse.

Probabilmente ho lasciato fuori diversi scenari, ma penso che li copra la maggior parte.

Quindi, sì, a volte è pratica accettabile scrivere cose sul codice. Solo non essere pigro al riguardo; dovrebbe essere una decisione consapevole piuttosto che un semplice vecchio codice sciatto.


Grazie per il buon esaurimento! - la maggior parte delle persone non pensa a tutte le opzioni che aggiungerei "Configurazione ambiente" - Penso che dovrebbero essere evitate (non codificate), poiché la maggior parte dei dati dovrebbe essere inserita in un file di configurazione o in un database. Ciò segue il principio di "mantenere separati dati e logica" che è un pilastro di MVC o MVVM. string TestServerVar = "foo"; string ProdServerVal = "bar";
m1m1k

7

Esistono 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 piuttosto che cercare ogni istanza di 9 e considerare se dovrebbe essere cambiato in 8. (Nota che le stringhe visibili all'utente potrebbero dover cambiare se il software dovesse mai essere usato in una lingua diversa, e questo è una cosa difficile da prevedere in anticipo.)
  • Se il numero è difficile da digitare in alcun modo. Per costanti come pi, è meglio dare una definizione di massima precisione piuttosto che ridigitarla in più punti, possibilmente in modo impreciso.
  • Se il numero si presenta in luoghi diversi. Non dovresti guardare due usi di 45 nelle funzioni adiacenti e chiederti se significano la stessa cosa.
  • Se il significato non è immediatamente riconoscibile. Si può presumere che tutti sappiano cos'è 3.14159265 ... Non è sicuro supporre che tutti riconoscano la costante gravitazionale, o anche pi / 2. ("Tutti" qui dipende dalla natura del software. Ci si può aspettare che i programmatori di sistemi conoscano la rappresentazione ottale di bit di autorizzazione Unix o simili. Nel software di architettura navale / navale, controllando il numero di Froude di uno scafo proposto e la velocità di vedere se è 1.1 o superiore potrebbe essere perfettamente autoesplicativo per chiunque dovrebbe lavorarci sopra.)
  • Se il contesto non è riconoscibile. Tutti sanno che ci sono 60 minuti in un'ora, ma moltiplicare o dividere per 60 potrebbe non essere chiaro se non ci sono indicazioni immediate che la quantità sia un valore temporale o un valore di tasso.

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


5

Come aggiunta ad altre risposte. Usa le costanti per le stringhe quando possibile. Certo, non vuoi averlo

const string server_var="server_var";

ma dovresti avere

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

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

A parte questo, usa 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.

invece usa

const int AllowGlobalRead=255;

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


typedef enum {state_0 = 0, state_1 = 1, state_2 = 2, ...} ... Non ridere, l'ho visto fatto. Colpisci quella persona intorno alla testa con un pesce bagnato!
quick_now

@quickly, ovviamente, vorresti qualcosa di più similetypedef enum {init_state=0, parse_state=1, evaluation_state=2, ... }
Earlz,

6
THIS_NAMING_CONVENTION_IS_RECOMMENDED_FOR_CONSTANTS
StuperUser

4
Per le stringhe, non vuoi solo costanti. Vuoi mettere qualsiasi stringa visibile dall'utente in una sorta di file di risorse (i dettagli dipenderanno dalla tua piattaforma) in modo da poter cambiare facilmente in un'altra lingua.
David Thornley,

Potresti anche voler inserire stringhe relative alla logica aziendale (come le query SQL) in un file di risorse con un qualche tipo di crittografia o offuscamento. Ciò impedirà agli utenti "curiosi" di decodificare la logica (o lo schema del database).
TMN,

4

Dipende da cosa consideri hardcoding. Se provi a evitare qualsiasi cosa hardcoded, finisci nel territorio di softcoding e crei un sistema che solo il creatore può gestire (e questo è l'ultimo hardcode)

Un sacco di cose sono codificate in un contesto ragionevole e funzionano. cioè non c'è motivo tecnico per cui non dovrei essere in grado di cambiare il punto di ingresso di un'applicazione C # (vuoto statico Principale), ma hardcoding che non crea alcun problema per nessun utente (tranne la occasionale domanda SO )

La regola empirica che uso è che tutto ciò che può e cambierà, senza influire sullo stato dell'intero sistema, dovrebbe essere confugurabile.

Quindi, IMHO, è sciocco non codificare le cose che non cambiano mai (pi, costante gravitazionale, una 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 richiederà la programmazione in ogni caso, vale a dire è inutile consentire all'utente di aggiungere campi dinamici a un modulo, se qualsiasi campo aggiunto richiederebbe allo sviluppatore di manutenzione di entra e scrivi qualche sceneggiatura che farà funzionare quella cosa. Inoltre è stupido (e l'ho visto alcune volte in ambienti aziendali) creare alcuni strumenti di configurazione, quindi nulla è hardcoded, tuttavia, solo gli sviluppatori del reparto IT possono usarlo, ed è solo leggermente più facile da usare rispetto a per farlo in Visual Studio.

Quindi, in sostanza, se una cosa deve essere hardcoded è una funzione di due variabili:

  • cambierà il valore
  • in che modo un cambiamento nel valore influirà sul sistema

4

È mai una buona idea codificare i valori nelle nostre applicazioni?

I valori hardcode solo se i valori sono specificati nella specifica (su 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 la gestione delle modifiche, in cui le parti interessate esamineranno la modifica e approveranno / disapproveranno. Non succede mai dall'oggi al domani e richiede mesi / anni per un'approvazione. Non dimenticare che molti sviluppatori usano specifiche (ad es. HTTP), quindi cambiarlo significa rompere milioni di sistemi.


3
  • se il valore può cambiare, e in effetti potrebbe cambiare, quindi programmarlo quando possibile finché lo sforzo in questione non supera il rendimento atteso
  • alcuni valori non possono essere codificati; seguire le linee guida di Jonathan in quei (rari) casi

3

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

È solo una buona idea lavorare per l'estrazione di costanti, non considerarla una regola stupida, pensala come un'opportunità per programmare meglio.

Il più grande vantaggio sarebbe il modo in cui potresti trovare costanti simili come l'unica differenza nei gruppi di codice: astrarli in array mi ha aiutato a ridurre alcuni file del 90% delle loro dimensioni e a correggere un bel po 'di copia e incolla bug nel frattempo .

Devo ancora vedere un unico vantaggio nel non estrarre dati.


2

Di recente ho codificato una funzione MySQL per calcolare correttamente la distanza tra due coppie lat / long. Non puoi semplicemente fare pitagora; le linee della longitudine si avvicinano man mano che la latitudine aumenta verso i poli, quindi è coinvolto un po 'di peluria. Il punto è che ero piuttosto lacerato sul fatto che decodificassi o meno 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 riportato le distanze tra i punti su Giove. Ho pensato che le probabilità del sito web che sto costruendo con l'entrata in una posizione extraterrestre siano piuttosto ridotte.


Sì, probabilmente, ma che dire di google.com/moon
Residuum

1

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

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

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

Ad esempio con il mio progetto Ogre, utilizzo sempre la classe ConfigFile per caricare una variabile che ho scritto in un file di configurazione.


1

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

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

  2. Costanti assolutamente immutabili, precise, ovvie, come "numero di giorni alla settimana". days = weeks * 7La sostituzione 7con una costante DAYS_PER_WEEKdifficilmente fornisce alcun valore.


0

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

"Numero magico nelle specifiche: numero magico nel codice"

Sostanzialmente afferma che qualsiasi numero magico che rimane nelle specifiche dopo ragionevoli tentativi di ottenere un contesto descrittivo per loro dovrebbe essere riflesso come tale nel codice. Se i numeri magici rimangono nel codice, ogni sforzo dovrebbe essere fatto 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 adatterebbe alle linee guida generali di Jonathan, ma ho riscontrato casi in cui la struttura del messaggio di destinazione era semplicemente terribile. Oltre l'80% dei valori che dovevano essere tramandati nella struttura erano costanti imposte dalle specifiche del sistema distante. questo insieme al fatto che la struttura del messaggio era gigantesca faceva sì che MOLTE di tali costanti dovessero essere popolate. Nella maggior parte dei casi non hanno fornito un significato o una ragione, hanno semplicemente detto "inserisci M qui" o "inserisci 4.10.53.10100.889450.4452 qui". Non ho nemmeno tentato di inserire un commento accanto a tutti, il che avrebbe reso illeggibile il codice risultante.

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


0

Se stai codificando il valore della costante gravitazionale terrestre, a nessuno importa. Se codifichi l'indirizzo IP del tuo server proxy, hai problemi.


1
Potrebbe essere necessaria una maggiore precisione per la costante gravitazionale terrestre, quindi la sua hardcodifica diverse volte potrebbe causare problemi.
user281377

1
Peter Noone? Dagli Eremiti di Herman?
David Conrad,

L'accelerazione gravitazionale sulla Terra è praticamente 9,81 m / s ^ 2 per la maggior parte delle latitudini e altitudini (ovviamente, se stai cercando petrolio nel sottosuolo o sparando ICBM sul Polo Nord, sapendo che la variazione di gravità è molto importante per molte più cifre decimali), con l'accelerazione gravitazionale su altri pianeti un numero diverso, ma per quanto ne so, la costante gravitazionale è costante attorno all'universo. C'è molta fisica che dovrebbe cambiare se g fosse variabile.
Tangurena,

0

Principalmente no, ma penso che valga la pena notare che avrai più problemi quando inizi a duplicare il valore codificato. Se non lo duplicate (es. Usatelo solo una volta nell'implementazione di una classe), allora non usare una costante potrebbe andare bene.

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.