Är det någonsin en bra idé att skriva in värden i våra applikationer? Eller är det alltid rätt sak att kalla dessa typer av värden dynamiskt om de behöver ändras?
Kommentarer
Svar
Ja, men gör det uppenbart .
Gör:
- använd konstanter
- använd en beskrivande variabelnamn
Don ”t:
- har några magiska siffror flyter runt koden
Kommentarer
- Vilket är renare,
diameter = 2 * radius
ellerdiameter = RADIUS_TO_DIAMETER_FACTOR * radius
? Det finns verkligen hörnfall där ett magiskt nummer kan vara en bättre lösning. - Jag kan ’ t håller med det här svaret nog. Jag brukar tänka på att programmera som att vara författare. Du berättar din historia genom koden och om människor inte förstår logiken gör det din kod värdelös enligt min mening. Den ’ varför väl genomtänkta namngivningskonventioner i huvudsak är för läsbarhet. Det finns heller ingen god anledning att använda magiska siffror. Genom att använda magiska nummer tar du bort ” varför ” från ekvationen och gör det svårare att undersöka tand. Till exempel: ” diameter = 2 * radie ” Vad är de två för? Denna ” diameter = RADIUS_TO_DIAMETER_FACTOR * radie ” ger mycket mer mening.
- diameter = 2 * radie är direkt från gymnasiet matematik. Anledningen till att ” 2 ” inte är namngiven är att för att den ska ha ett värde på något annat skulle det behöva ändras lagarna i fysik eller matematik, eller båda. (Å andra sidan är att namnge Pi eller Plancks konstant ett bra drag för enkel läsbarhet).
- @Joonas: Pfft. Du menar verkligen
diameter = radius << 1
? Jag antar att det också kan varadiameter = radius << RADIUS_TO_DIAMETER_BITS_TO_SHIFT
. - hur ’ om några
diameter = radius.toDiameter()
Svar
Vad jag tycker är konstigt med denna Q & A hittills är att ingen faktiskt har försökt att tydligt definiera ”hårdkod” eller, ännu viktigare, alternativen.
tl; dr : Ja, det är ibland en bra idé att värdera kodvärden, men det finns ingen enkel regel om när ; det beror helt på kontext.
Frågan begränsar den till värden vilket jag menar att betyder magiska siffror , men svaret på om de är ”en bra idé eller inte är i förhållande till vad de faktiskt används för!
Flera exempel på” hårdkodade ”värden är:
-
Konfigurationsvärden
Jag kramar mig när jag ser uttalanden som
command.Timeout = 600
. Varför 600? Vem bestämde det? Var det tidsgränser innan, och någon tog upp timeout som ett hack istället för att fixa det underliggande prestandaproblemet? Eller är det egentligen någon känd och dokumenterad förväntan på bearbetningstid?Dessa borde inte vara magiska siffror eller konstanter, de bör vara externa i en konfigurationsfil eller databas någonstans med en meningsfullt namn, eftersom deras optimala värde bestäms till stor del eller helt av den miljö som applikationen körs i.
-
Matematiska formler
Formler brukar vara ganska statiska, så att de konstanta värdenas natur inte är särskilt viktiga. Volymen på en pyramid är (1/3) b * h. Bryr vi oss var 1 eller 3 kom ifrån? Inte riktigt. En tidigare kommentator påpekade med rätta att
diameter = radius * 2
förmodligen är bättre ändiameter = radius * RADIUS_TO_DIAMETER_CONVERSION_FACTOR
– men det är en falsk dikotomi.Vad du bör göra för den här typen av scenarier är att skapa en funktion . Jag behöver inte veta hur du kom upp med formeln men jag behöver fortfarande veta vad det är för . Om jag skriver
volume = GetVolumeOfPyramid(base, height)
istället för något nonsens som skrivits ovan blir allt plötsligt mycket tydligare och det är helt okej att ha magiska siffror inuti funktionen (return base * height / 3
) eftersom det är uppenbart att de bara är en del av formeln.Nyckeln här är naturligtvis att ha korta och enkla funktioner. Detta fungerar inte för funktioner med 10 argument och 30 rader med beräkningar. Använd funktionssammansättning eller konstanter i så fall.
-
Domän / affärsregler
Den här är alltid det grå området eftersom det beror på exakt vilket värde som är. Mest av tiden är det dessa speciella magiska siffror som är kandidater för att förvandlas till konstanter, eftersom det gör programmet lättare att förstå utan att komplicera programlogiken. Tänk på testet
if Age < 19
vs.if Age < LegalDrinkingAge
; du kan antagligen ta reda på vad som händer utan konstanten, men det är lättare med det beskrivande titel.Dessa kan också bli kandidater för funktionsabstraktion, till exempel
function isLegalDrinkingAge(age) { return age >= 19 }
. Det enda är att din affärslogik ofta är mycket mer invecklat än så, och det är kanske inte meningsfullt att börja skriva ut dussintals funktioner med 20-30 parametrar vardera. Om det inte finns någon tydlig abstraktion baserat på objekt och / eller funktioner är det OK att använda konstanter.Förbehållet är att om du arbetar för skatteverket blir det verkligen verkligen besvärligt och ärligt meningslöst att skriva
AttachForm(FORM_CODE_FOR_SINGLE_TAXPAYER_FILING_JOINTLY_FOR_DEPRECIATION_ON_ARMPIT_HAIR)
. Du kommer inte att göra det t, du går tillAttachForm("B-46")
eftersom varje utvecklare som någonsin har arbetat eller någonsin kommer att arbeta där kommer att veta att ”B-46” är formkoden för en enda skattebetalare arkivering bla bla bla – formulärkoderna är en del av själva domänen, de ändras aldrig, så de är inte riktigt magiska siffror.Så du måste använda konstanter sparsamt i affärslogiken; i grund och botten måste du förstå huruvida det ”magiska numret” faktiskt är ett magiskt nummer eller om det är en välkänd aspekt av domänen. Om det är domän, så mjukkodar du det inte såvida det inte finns en sa riktigt bra chans att det kommer att förändras.
-
Felkoder och statusflaggor
Det här är aldrig okej för hårdkodning, som någon fattig jävel som någonsin har drabbats av
Previous action failed due to error code 46
kan berätta för dig. Om ditt språk stöder det bör du använda en uppräkningstyp. Annars har du vanligtvis en hel fil / modul full av konstanter som anger de giltiga värdena för en viss feltyp.Låt mig aldrig se
return 42
i en felhanterare, capiche? Inga ursäkter.
Jag har förmodligen utelämnat flera scenarier men jag tror att det täcker de flesta av dem.
Så ja, det är ibland acceptabelt förfarande till hårda koder. Bara var inte lat om det; det borde vara ett medvetet beslut snarare än vanlig gammal slarvig kod.
Kommentarer
- Tack för bra uppdelning! – de flesta människor tänker inte ’ tänker igenom alla alternativ jag skulle lägga till ” Miljökonfiguration ” – Jag tycker att dessa bör undvikas (inte hårdkodade), eftersom de flesta data ska läggas i en konfigurationsfil eller databas. Detta följer principen om ” att hålla data och logik åtskilda ” som är en grundpelare för MVC eller MVVM. sträng TestServerVar = ” foo ”; sträng ProdServerVal = ” bar ”;
Svar
Det finns olika anledningar till att tilldela ett nummer till ett nummer.
- Om numret kan ändras, det borde ha en identifierare. Det är mycket lättare att hitta NUMBER_OF_PLANETS än att söka efter varje förekomst av 9 och överväga om det ska ändras till 8. (Observera att användaren är synlig strängar kan behöva ändras om programvaran någonsin måste användas på ett annat språk, och det ”är svårt att förutse i förväg.)
- Om numret är svårt att skriva på något sätt. För konstanter som pi är det bättre att ge en definition med maximal precision än att skriva om den på flera ställen, eventuellt felaktigt.
- Om numret förekommer på olika platser. Du behöver inte titta på två användningar av 45 i angränsande funktioner och undra om de betyder samma sak.
- Om innebörden inte är omedelbar igenkännlig. Det är säkert att anta att alla vet vad 3.14159265 … är. Det är inte säkert att anta att alla kommer att känna igen gravitationskonstanten, eller till och med pi / 2. (”Alla” här beror på programvarans karaktär. Systemprogrammerare kan förväntas känna till den oktala representationen av Unix-tillståndsbitar eller liknande. I marin- / marinarkitekturprogramvara, kontrollera Froude-numret på ett föreslaget skrov och hastighet till se om det är 1.1 eller högre kan vara helt självförklarande för alla som borde arbeta med det.)
- Om sammanhanget inte är igenkännbart . Alla vet att det finns 60 minuter på en timme, men att multiplicera eller dela med 60 kan vara oklart om det inte finns några omedelbara indikationer på att kvantiteten är ett tidsvärde eller ett hastighetsvärde .
Detta ger oss kriterier för hårdkodande bokstäver. De ska vara oföränderliga, inte svåra att skriva, förekommer bara på en plats eller i ett sammanhang och med igenkännlig betydelse. Det är ingen mening för att definiera 0 som ARRAY_BEGINNING, till exempel, eller 1 som ARRAY_INCREMENT.
Svar
Som ett tillägg till andra svar. Använd konstanter för strängar när det är möjligt. Naturligtvis vill du inte ha
const string server_var="server_var";
men du borde ha
const string MySelectQuery="select * from mytable;";
(förutsatt att du faktiskt har en fråga där du alltid vill få alla resultat från en specifik tabell)
Förutom det, använd konstanter för valfritt antal än 0 (vanligtvis). en tillståndsbitmask på 255, använd inte
const int 8th_bit=255; //or some other obscure naming scheme that equates to 255.
istället använd
const int AllowGlobalRead=255;
Naturligtvis, tillsammans med konstanter, vet när man ska använda räknare. Ovanstående fall skulle troligen passa bra i ett.
Kommentarer
- typedef enum {state_0 = 0, state_1 = 1, state_2 = 2, .. .} … Don ’ t skratta, jag ’ har sett det gjort. Slå den personen runt huvudet med en våt fisk!
- @ snabbt ja naturligtvis vill du ’ något mer som
typedef enum {init_state=0, parse_state=1, evaluation_state=2, ... }
- THIS_NAMING_CONVENTION_IS_RECOMMENDED_FOR_CONSTANTS
- För strängar vill du inte ’ t bara vill ha konstanter. Du vill sätta alla användarsynliga strängar i någon form av resursfil (detaljer beror på din plattform) så att du enkelt kan byta till ett annat språk.
- Du kanske också vill hålla fast vid affärslogikrelaterat strängar (som SQL-frågor) i en resursfil med någon form av kryptering eller förvirring. Det kommer att hindra ” nyfiken ” användare från att omvandla din logik (eller databasschema).
Svar
Det beror på vad du anser vara hårdkodning. Om du försöker undvika alla hårdkodade saker hamnar du i softcoding territorium och skapar ett system som bara skaparen kan hantera (och det är Ultimate Hardcode)
Massor av saker är hårdkodade i alla rimliga ramar och de fungerar, det vill säga det finns ingen teknisk anledning till att jag inte skulle kunna ändra ingångspunkten för en C # -applikation (statisk ogiltig Main ), men hårdkodning som inte skapar några problem för någon användare (utom enstaka SO fråga )
Tumregeln jag använder är att allt som kan och kommer att förändras, utan att påverka hela systemets tillstånd, ska vara konfugerbart.
Så, IMHO, det är dumt att inte hårddiska saker som aldrig förändras (pi, gravitationskonstant, en konstant i en matematisk formel – tänk volym av en sfär).
Det är också dumt att inte hårddiska saker eller processer som kommer att påverka ditt system som kräver programmering i alla fall, i .e. det är otillräckligt att låta användaren lägga till dynamiska fält i ett formulär, om något tillagt fält skulle kräva att underhållsutvecklaren går in och skriver något skript som får den saken att fungera. Det är också dumt (och jag har sett det några gånger i företagsmiljöer) att skapa ett konfigurationsverktyg, så ingenting är hårt kodat, men det är bara utvecklarna på IT-avdelningen som kan använda det, och det är bara lättare att använda det än att göra det i Visual Studio.
Så, i grund och botten, huruvida en sak ska vara hårdkodad är en funktion av två variabler:
- ändras värdet
- hur kommer en förändring av värdet att påverka systemet
Svar
Är det någonsin en bra idé att skriva in värden i våra applikationer?
I hårddiskvärden endast om värdena är specificerade i specifikationen (på en slutlig version av specifikationen), t.ex. HTTP OK-svaret kommer alltid att vara 200
(såvida det inte ändras i RFC), så du kommer att se (i vissa av mina koder) konstanter som:
public static final int HTTP_OK = 200;
Annars lagrar jag konstanter i egenskapsfilen.
Anledningen till att jag specificerade specifikationer är att ändra konstanter i specifikationer kräver ändringshantering, där, intressenter kommer att granska ändringen och godkänna / ogilla. Det händer aldrig över natten och tar månader / år för godkännande. Glöm inte att många utvecklare använder specifikationer (t.ex. HTTP) så att ändra det innebär att bryta miljontals system.
Svar
- om värdet kan förändras och verkligen kan ändras, mjukkod det när det är möjligt så länge ansträngningen inte överstiger förväntad avkastning
- vissa värden kan inte vara mjukkodad; följ Jonatans riktlinjer i dessa (sällsynta) fall
Svar
Jag har märkt att när som helst du kan extrahera data från din kod förbättras det som finns kvar. Du börjar lägga märke till nya refaktorer och förbättra hela delar av din kod.
Det är bara en bra idé att arbeta för att extrahera konstanter, inte betrakta det som en dum regel, tänk på det som en möjlighet att koda bättre.
Den största fördelen skulle vara hur du kan hitta liknande konstanter som den enda skillnaden i grupper av kod – att abstrahera dem i matriser har hjälpt mig att minska vissa filer med 90% av deras storlek och fixa ganska några kopior & klistra in buggar under tiden.
Jag har ännu inte sett en enda fördel med att inte extrahera data.
Svar
Jag har nyligen kodat en MySQL-funktion för att korrekt beräkna avståndet mellan två lat / långa par. Du kan inte bara göra pythagorus; longitudlinjer kommer närmare varandra när latitud ökar mot polerna, så det är en slags hårig trig involverad. Poängen är att jag var ganska sönder om huruvida jag skulle hårdkoda värdet som representerar jordens radie i mil.
Det slutade med att jag gjorde det, även om faktum är att lat / lng-linjer är mycket närmare varandra, till exempel månen. Och min funktion skulle drastiskt underrapportera avstånd mellan punkter på Jupiter. Jag tänkte att oddsen för att webbplatsen jag bygger en utomjordisk plats kommer in är ganska smal.
Kommentarer
- Ja, förmodligen, men vad om google.com/moon
Svar
Tja, det beror på om ditt språk är kompilerat. Om det inte är kompilerat är det inte en stor sak, du redigerar bara källkoden, även om den är lite känslig för en icke-programmerare.
Om du programmerar med ett sammanställt språk är det helt klart ingen bra idé, för om variablerna ändras måste du kompilera om igen, vilket är ett stort slöseri med tid om du vill justera den här variabeln.
Du behöver inte skapa något skjutreglage eller gränssnitt för att dynamiskt ändra variabeln, men det minsta du kan göra är en textfil.
Till exempel med mitt ogre-projekt använder jag alltid ConfigFile-klassen för att ladda en variabel som jag har skrivit till en konfigurationsfil.
Svar
Två tillfällen där konstanter är (enligt min mening åtminstone) OK:
-
Konstanter som inte har något annat att göra; du kan ändra dessa konstanter när du vill utan att behöva ändra något annat. Exempel: Standardbredden för en rutnätkolumn.
-
Helt oföränderliga, exakta, uppenbara konstanter, som ”antal dagar per vecka”.
days = weeks * 7
Ersättning av7
med en konstantDAYS_PER_WEEK
ger knappast något värde.
Svar
Jag håller helt med Jonathan men som alla regler finns det undantag …
”Magiskt nummer i specifikationen: Magiskt nummer i koden”
I princip anges att alla magiska siffror som finns kvar i specifikationen efter rimliga försök att få beskrivande sammanhang för dem bör återspeglas som sådana i koden. Om magiska siffror finns kvar i koden bör alla ansträngningar göras för att isolera dem och göra dem tydligt kopplade till deras utgångspunkt.
Jag har utfört några gränssnittskontrakt där det är nödvändigt att fylla i meddelanden med värden mappade från databasen. I de flesta fall är kartläggningen ganska rakt fram och skulle passa i Jonatans allmänna riktlinjer men jag har stött på fall där målmeddelandestrukturen var helt enkelt hemsk.Mer än 80% av värdena som var tvungna att överföras i strukturen genomfördes konstanter genom specifikationen för det avlägsna systemet. detta tillsammans med det faktum att meddelandestrukturen var gigantisk gjorde att MÅNGA sådana konstanter måste befolkas. I de flesta fall gav de ingen mening eller anledning, bara sa ”sätt M här” eller ”sätt 4.10.53.10100.889450.4452 här”. Jag försökte inte heller lägga en kommentar bredvid dem alla, det skulle ha gjort den resulterande koden oläslig. Jag såg dock till att kodavsnitten där dessa magiska värden visas är ordentligt isolerade och att deras behållare (klasser, paket) heter korrekt för att peka direkt på specifikationen som verkställer dem.
Som sagt, när du tänker på det … det handlar i stort sett om att göra det uppenbart …
Svar
Om du ”hårdkodar värdet på jordens gravitationskonstant, kommer ingen att bry sig. Om du hårdkodar din proxyservers IP-adress kommer du in för problem.
Kommentarer
- Du kanske behöver mer precision för jorden ’ s gravitationskonstant, så hårdkodning det flera gånger kan leda till problem.
- Peter Noone? Från Herman ’ s Hermits ?
- Gravitationens acceleration på jorden är ganska mycket 9,81 m / s ^ 2 för de flesta breddgrader och höjder (naturligtvis om du ’ du letar efter olja under jord eller att skjuta ICBM över nordpolen, att veta att variationen i gravitation är mycket viktig för mycket mer decimaler), med tyngdacceleration på andra planeter är ett annat antal, men så vitt jag vet är gravitationskonstanten konstant runt om i universum. Det finns mycket fysik som måste ändras om g var variabel.
Svar
Mestadels nej, men jag tycker att det är värt att notera att du wi Jag har flest problem när du börjar duplicera det hårdkodade värdet. Om du inte duplicerar den (t.ex. använder den bara en gång vid implementeringen av en klass) kan det vara okej att inte använda en konstant.
pi
kan ändras …