This post at Worse Than Failure made its rounds today on the
Yahoo pragprog group and
CFCDev mailing list, and I had a response to one of the emails that I also thought was worth blogging. On pragprog, the discussion was turning into the question, "where do you draw the line on knowing when to eliminate literals?" (not a direct quote) Someone brought up the idea to use YAGNI and DRY as guiding factors: "If you need the number in just one place, just use the number there.
YAGNI," and "If you find the number being repeated so that you would have to change
it in several places, then externalise it so that I change in just one place is needed.
DRY."
Initially, that struck me as an idea worth exploring, since those are two of my most-used, favorite, and life-saving principles (I mean, try violating them over and over for years and see if you don't feel like dying!). In fact, I use them a lot in determining when to create a new method (I use other heuristics as well, such as readability, which is often the most important reason I create a function ... more
here about some reasons for creating methods). But, I thought about it some and came to this conclusion I posted to the pragprog group (which I changed a bit for here to make more sense):
In essence, I'm not comfortable with either of those definitions (DRY or YAGNI) as lines for determining when you are soft or hard coding. Suppose the
following (generalizing to your pleasure -- since I'm having trouble writing it, I'm sure others will have trouble understanding it, as no one would ever (I think) write an application this way)
- it always costs the same to ship each item: 5.00 (units of currency)
- the company only needs to worry about one tax rate: 5%
- the product costs 100 dollars each, and there is only one product.
- customers can buy a variable quantity of this item (called "quantity" below)
- there is a handling charge of 3.14 (units of currency) for each item.
Then your
total_cost = (100+5+3.14)*(1.0+5/100)*quantity
.
We see 100 twice here. Do we pull it out? What do we name it?
oneHundred
? That is the only one that makes sense for both cases. Or we
could change it to to get rid of calculating the percentage:
total_cost = (100+5+3.14)*(1.05)*quantity
.
I'm not even confident I've got the right formula - and I'm the one
making this up. What happens down the line if the state changes the sales
tax? Am I sure I know which number to manipulate? Here, it may look
clear, but it may not be the case in other situations. And then when I
need to do a
circleOperation
with
crappyApproximationOfPi = 3.14
(the
product is cylindrical, and we need to know about how much ribbon we
need to wrap the package when someone selects the gift wrapping option), who gets
the naming rights?
If there is a line that should be drawn (and I'm not convinced there is),
and there exists a place to put it, I don't think the DRY or YAGNI principles have
anything to do with its placement. Readability is the key for me, and
I don't know to what degree that can be quantified.
One in particular I dislike is when people have uncommented literals
like 0x0032aBlahBlahBlah in the code. How (and why) on Earth would you
expect anyone to know what that referred to? Will you remember the next
time you look at it? I wouldn't, but my brain may just be a sieve.
Your thoughts on where to draw the line? (Or not draw it?... Or tell me I'm wrong?)
Hey! Why don't you make your life easier and subscribe to the full post
or short blurb RSS feed? I'm so confident you'll love my smelly pasta plate
wisdom that I'm offering a no-strings-attached, lifetime money back guarantee!
Leave a comment
surely
total_cost = (product_cost+postage+handling)*(tax)*quantity
you never need to worry about remembering what 5, 3.14 and 1.05 actually are
Posted by duncan
on Apr 13, 2007 at 06:03 AM UTC - 6 hrs
Of course, that's how /I/ would do it! (in fact, I would have assumed that most people would do it that way) =)
But, if I were to be pedantic, I might rename "tax" as "taxrate" and spell out the calculation a bit more (since even taxrate does not quite describe taxRate+1 and what its putpose is).. Or I might come up with some other name for it (I don't like "tax" alone because to me, it implies the amount of the tax, not its rate.
Posted by
Sam
on Apr 13, 2007 at 07:02 AM UTC - 6 hrs
Although I've never spent long hours pondering it, I suppose I work on a common sense basis.
General Rules:
1. If I need to use it more than once, make it a variable.
2. If I can foresee any plausible condition where the value might change, I'll pull it out - even if I'm only using it once. It's just easier to find and change that way.
3. If I can foresee any plausible condition where I might need to use the value in another location all together, I'll also pull it out. that way I don't have to do it later. This is merely an attempt to avoid the pain later on.
Acceptable violations:
1. If I need it more than once and the other two rules don't come into play, but all of the uses are highly localized, it may be okay to hard code it.
Any variables I "soft code" simply for the sake of not hard coding are initialized in a group at the top of of the file, function, etc. I know where they are and can access them quickly if I need to make any changes.
Posted by
Rob Wilkerson
on Apr 13, 2007 at 07:22 AM UTC - 6 hrs
I guess I like "encapsulate what changes". Of course, this makes for a judgment call. Most of those individual values seem subject to change. The formula for them may not be.
Then again, DRY comes into play the second time you type the same formula - maybe time to make it a function.
I find that a good test is copy/paste. If I find myself tempted to copy and paste some code, it is time to figure out why I want to do that (may still be a good idea, but still worth considering).
Posted by
Steve Bryant
on Apr 13, 2007 at 10:56 AM UTC - 6 hrs
Leave a comment