Is it ever a good idea to hardcode values into our applications? Or is it always the right thing to call these types of values dynamically in case they need to change?
14 Answers
Yes, but do make it obvious.
Do:
- use constants
- use a descriptive variable name
Don't:
- have any magic numbers floating around the code
-
51Which is cleaner,
diameter = 2 * radius
ordiameter = RADIUS_TO_DIAMETER_FACTOR * radius
? There indeed are corner cases where a magic number may be better solution. Apr 14, 2011 at 5:57 -
6I can't agree with this answer enough. I tend to think of programming like being a novelist. You tell your story through the code and if people cannot understand the logic it makes your code worthless in my opinion. That's why well thought out naming conventions are essentially for readability. Also, there is no good reason to use magic numbers. By using magic numbers you remove the "why" from the equation and make it more difficult to understand. For instance: "diameter = 2 * radius" What is the two for? This "diameter = RADIUS_TO_DIAMETER_FACTOR * radius" makes much more sense.– chriswApr 14, 2011 at 12:29
-
12diameter = 2 * radius is straight from high school maths. The reason for not naming the "2" is that for it to have a value of anything else would require a change to the laws of physics or maths, or both. (On the other hand, naming Pi, or Plancks constant is a good move for simple readability). Apr 14, 2011 at 13:32
-
9@Joonas: Pfft. Surely you mean
diameter = radius << 1
? I suppose that could also bediameter = radius << RADIUS_TO_DIAMETER_BITS_TO_SHIFT
.– AntApr 14, 2011 at 14:14 -
6
What I find odd about this Q&A so far is that nobody has actually attempted to clearly define "hard-code" or, more importantly, the alternatives.
tl;dr: Yes, it is sometimes a good idea to hard-code values, but there's no simple rule as to when; it depends completely on context.
The question does narrow it down to values, which I take to mean magic numbers, but the answer to whether or not they're a good idea is relative to what they're actually used for!
Several examples of "hard-coded" values are:
Configuration values
I cringe whenever I see statements like
command.Timeout = 600
. Why 600? Who decided that? Was it timing out before, and someone raised the timeout as a hack instead of fixing the underlying performance issue? Or is it actually some known and documented expectation for processing time?These shouldn't be magic numbers or constants, they should be externalized in a configuration file or database somewhere with a meaningful name, because their optimal value is determined largely or entirely by the environment that the application is running in.
Mathematical formulas
Formulas usually tend to be pretty static, such that the nature of the constant values inside isn't really particularly important. The volume of a pyramid is (1/3)b*h. Do we care where the 1 or 3 came from? Not really. A previous commenter rightly pointed out that
diameter = radius * 2
is probably better thandiameter = radius * RADIUS_TO_DIAMETER_CONVERSION_FACTOR
- but that is a false dichotomy.What you should be doing for this type of scenario is creating a function. I don't need to know how you came up with the formula but I still need to know what it's for. If, instead of any of the nonsense written above, I write
volume = GetVolumeOfPyramid(base, height)
then suddenly everything becomes a lot clearer, and it's perfectly okay to have magic numbers inside the function (return base * height / 3
) because it's obvious that they're just part of the formula.The key here is of course to have short and simple functions. This doesn't work for functions with 10 arguments and 30 lines of calculations. Use function composition or constants in that case.
Domain/business rules
This one is always the gray area because it depends on what exactly the value is. Most of the time, it's these particular magic numbers that are candidates for turning into constants, because that makes the program easier to understand without complicating the program logic. Consider the test
if Age < 19
vs.if Age < LegalDrinkingAge
; you probably can figure out what's going on without the constant, but it's easier with the descriptive title.These may also become candidates for function abstraction, for example
function isLegalDrinkingAge(age) { return age >= 19 }
. The only thing is that often your business logic is a lot more convoluted than that, and it might not make sense to start writing out dozens of functions with 20-30 parameters each. If there isn't a clear abstraction based on objects and/or functions then resorting to constants is OK.The caveat is, if you're working for the tax department, it becomes really, really burdensome and honestly pointless to write
AttachForm(FORM_CODE_FOR_SINGLE_TAXPAYER_FILING_JOINTLY_FOR_DEPRECIATION_ON_ARMPIT_HAIR)
. You're not going to do that, you're going toAttachForm("B-46")
because every single developer who ever has worked or ever will work there is going to know that "B-46" is the form code for a single taxpayer filing blah blah blah - the form codes are part of the domain itself, they never change, so they're not really magic numbers.So you have to use constants sparingly in business logic; basically you have to understand whether or not that "magic number" is actually a magic number or if it's a well-known aspect of the domain. If it's domain, then you don't soft-code it unless there's a really good chance it will change.
Error codes and status flags
These are never okay to hard-code, as any poor bastard who has ever been hit with the
Previous action failed due to error code 46
can tell you. If your language supports it, you should be using an enumeration type. Otherwise, you'll usually have an entire file/module full of constants specifying the valid values for a particular error type.Don't ever let me see
return 42
in an error handler, capiche? No excuses.
I probably left out several scenarios but I think that covers most of them.
So, yeah, it's sometimes acceptable practice to hard code stuff. Just don't be lazy about it; it should be a conscious decision rather than plain old sloppy code.
-
Thanks for the good breakdown! - most people don't think through all the options I would add "Environment Configuration" - I think these should be avoided (not hard-coded), since most data should be put in a config file or database. This follows the principal of "keeping data and logic separate" that is a mainstay of MVC or MVVM. string TestServerVar = "foo"; string ProdServerVal = "bar";– m1m1kMay 7, 2019 at 16:39
There are various reasons for assigning an identifier to a number.
- If the number might change, it should have an identifier. It's much easier to find NUMBER_OF_PLANETS than to search for every instance of 9 and consider whether it should be changed to 8. (Note that user-visible strings might have to change if the software ever has to be used in a different language, and that's a hard thing to predict in advance.)
- If the number is hard to type in any way. For constants like pi, it's better to give one maximum-precision definition than to retype it in several places, possibly inaccurately.
- If the number occurs in different places. You shouldn't have to look at two uses of 45 in adjoining functions and wonder if they mean the same thing.
- If the meaning isn't instantly recognizable. It's safe to assume that everybody knows what 3.14159265... is. It isn't safe to assume that everybody will recognize the gravitational constant, or even pi/2. ("Everybody" here does depend on the nature of the software. Systems programmers can be expected to know the octal representation of Unix permission bits or the like. In naval/marine architecture software, checking the Froude number of a proposed hull and speed to see if it's 1.1 or greater might be perfectly self-explanatory to anybody who should be working on it.)
- If the context isn't recognizable. Everybody knows there are 60 minutes in an hour, but multiplying or dividing by 60 may be unclear if there's no immediate indications that the quantity is a time value or a rate value.
This gives us criteria for hard-coding literals. They should be immutable, not hard to type, occurring in one place or context only, and with recognizable meaning. There's no point in defining 0 as ARRAY_BEGINNING, for example, or 1 as ARRAY_INCREMENT.
As an addition to other answers. Use constants for strings when possible. Of course, you don't want to have
const string server_var="server_var";
but you should have
const string MySelectQuery="select * from mytable;";
(assuming you actually have a query where you want to get all the results from a specific table, always)
Other than that, use constants for any number other than 0 (usually). If you need a permission bitmask of 255, don't use
const int 8th_bit=255; //or some other obscure naming scheme that equates to 255.
instead use
const int AllowGlobalRead=255;
Of course, along with constants, know when to use enumerators. The above case would probably fit well in one.
-
typedef enum {state_0 = 0, state_1 = 1, state_2 = 2, ...}... Don't laugh, I've seen it done. Smack that person around the head with a wet fish! Apr 14, 2011 at 3:04
-
@quickly well of course you'd want something more like
typedef enum {init_state=0, parse_state=1, evaluation_state=2, ... }
– EarlzApr 14, 2011 at 3:10 -
6
-
4For strings, you don't just want constants. You want to put any user-visible strings into some sort of resource file (details will depend on your platform) so you can change to another language easily. Apr 14, 2011 at 13:45
-
You might also want to stick business-logic-related strings (like SQL queries) in a resource file with some kind of encryption or obfuscation. That will prevent "curious" users from reverse-engineering your logic (or database schema).– TMNApr 14, 2011 at 15:09
It depends what you consider hardcoding. If you try to avoid any and all hardcoded things, you end up in softcoding territory, and make a system that only the creator can manage (and that's the ultimate hardcode)
Plenty of things are hardcoded in any reasonable framework and they work. i.e. there's no technical reason why I shouldn't be able to change the entry point of a C# application (static void Main), but hardcoding that does not create any problems for any user (except the occasional SO question)
The rule of thumb I use is that anything that can and will change, without affecting the state of the whole system, should be confugurable.
So, IMHO, it's silly not to hardcode things that are never changing (pi, gravitational constant, a constant in a mathematical formula - think volume of a sphere).
Also it's silly not to hardcode things or processes that will have an impact on your system that will require programming in any instance, i.e. it's wastefull to allow the user to add dynamic fields to a form, if any added field would require the maintenance developer to go in and write some script that will make that thing to work. Also it's stupid (and I've seen it a few times in enterprise environments) to create some configuration tool, so nothing is hardcoded, yet, only the developers in the IT department can use it, and it's only slighty easier to use it than to do it in Visual Studio.
So, bottom line, whether a thing should be hardcoded is a function of two variables:
- will the value change
- how will a change in the value affect the system
Is it ever a good idea to hardcode values into our applications?
I hardcode values only if the values are specified in the Specification (on a final release of the specification), e.g. The HTTP OK response will always be 200
(unless it changes in the RFC), so, you will see (in some of my codes) constants like:
public static final int HTTP_OK = 200;
Otherwise, I store constants in the properties file.
The reason why I specified specifications, is that changing constants in specifications requires change management, in which, the stakeholders will review the change and approve/disapprove. It never happens overnight and takes months/years for an approval. Don't forget that many developers uses specifications (e.g. HTTP) so changing it means breaking millions of systems.
- if the value can change, and indeed might change, then soft-code it whenever possible as long as the effort involved does not exceed the expected return
- some values cannot be soft-coded; follow Jonathan's guidelines in those (rare) cases
I've noticed that any time you can extract data from your code, it improves what's left. You start noticing new refactorings and improving whole sections of your code.
It's just a good idea to work towards extracting constants, don't consider it some stupid rule, think about it as an opportunity to code better.
The biggest advantage would be the way you might find similar constants being the only difference in groups of code--abstracting them into arrays has helped me reduce some files by 90% of their size and fix quite a few copy & paste bugs in the meantime.
I've yet to see a single advantage to not extracting data.
I recently coded a MySQL function to properly calculate the distance between two lat/long pairs. You can't just do pythagorus; longitude lines get closer together as latitude increases toward the poles, so there's some kinda hairy trig involved. Point is, I was pretty torn about whether to hard-code the value representing the earth's radius in miles.
I ended up doing it, even though the fact is, lat/lng lines are much closer together on, say, the moon. And my function would drastically underreport distances between points on Jupiter. I figured the odds of the website I'm building having an extraterrestrial location get entered is pretty slim.
Well it depends if your language is compiled. If it's not compiled, it's not a big deal, you just edit the source code, even if it will be slightly delicate for a non programmer.
If you are programming with a compiled language, this is clearly not a good idea, because if the variables change, you have to recompile, which is a big waste of time if you want to adjust this variable.
You don't need to make some slider or interface to dynamically change his variable, but the least you could do is a text file.
For example with my ogre project, I'm always using the ConfigFile class to load a variable I have written to a config file.
Two occasions where constants are (in my opinion at least) OK:
Constants that relate to nothing else; you can change those constants whenever you like without having to change anything else. Example: The default width of a grid column.
Absolutely immutable, precise, obvious constants, like "number of days per week".
days = weeks * 7
Replacing7
with a constantDAYS_PER_WEEK
hardly provides any value.
I do agree completely with Jonathan but as all rules there are exceptions...
"Magic number in the spec: Magic number in the code"
Basically states that any magic numbers that remains in the spec after reasonable attempts to get descriptive context for them should be reflected as such in the code. If magic numbers remain in the code every efforts should be made to isolate them and make them clearly linked to their point of origin.
I have performed a few interfacing contracts where it is necessary to populate messages with values mapped from the database. In most cases the mapping is fairly straight forward and would fit in Jonathan's general guide lines but I have encountered cases where the target message structure was just plain awful. More than 80% of the values that had to be passed down in the structure were constants enforced by the specification of the distant system. this coupled with the fact that the message structure was gargantuan made that a LOT of such constants had to be populated. In most cases they did not provide a meaning or reason, just said "put M here" or "put 4.10.53.10100.889450.4452 here". I did not attempt either to put a comment next to all of them it would have rendered the resulting code unreadable. I did however make sure the code sections where these magic values appear are properly isolated and that their containers (classes, packages) named appropriately to point directly to the specification enforcing them.
That said, when you think about it... it's pretty much all about making it obvious...
If you're hardcoding the value of the earth's gravitational constant, noone's going to care. If you hardcode the IP address of your proxy server, you're in for trouble.
-
1You might need more precision for earth's gravitational constant, so hardcoding it several times might lead to problems. Apr 14, 2011 at 12:24
-
1
-
The gravitational acceleration on the Earth is pretty much 9.81 m/s^2 for most latitudes and altitudes (of course, if you're searching for oil underground, or shooting ICBMs over the North Pole, knowing the variation in gravity is very important to a lot more decimal places), with the gravitational acceleration on other planets being a different number, but as far as I know, the gravitational constant is constant around the universe. There is a lot of physics that would have to change if g were variable. Apr 14, 2011 at 18:31
Mostly no, but I think that is worth noting that you will have the most problems when you start duplicating the hard-coded value. If you don't duplicate it (ex. use it just once in the implementation of a class) then not using a constant might be alright.
pi
might change...