I love talking about naming conventions. Probably because I’ve spent so many years working on them, and I’ve come up with what works well for me, and I’m so friggin sure they’re so awesome, that I just love talking about them. What makes it even more fun is that my conventions aren’t all that conventional… gives me pretty good grounds for babbling on about them. <grin>
I’m not going to go into too much detail on my whole scheme, but there’s one in particular that I’ve been using for some time now, and I love it so much I’m here to share it with whoever’s lucky enough to be reading this.
Yep, that’s it. I’m not sure exactly how many people use this, but I think it’s quite few. In fact, I don’t think I’ve ever seen it “in the wild”, and of the group of MVPs that I blab to a bunch, I think maybe only one or two – if that – use it as well (but I’m working on changing that). So, in 10+ years of programming and listening to however many hundreds of thousands of people talking in forums, I’m going to guess that the usage rate for this is well below 1%.
But anyway, it wouldn’t be much of a blog post if I didn’t try to convince you why it’s so great.
Here’s the thing: any time that a programmer spends thinking about anything other than the immediate task at hand is simply wasted time. Worse even than direct wasted time, this “off thinking” takes us out of whatever zone we might happen to be in, which takes direct wasted time and adds a whole boatload of indirect wasted time, because we have to momentarily leave our train of thought, then try to jump back onto the thing when we’re done. If anyone’s ever tried to jump onto a train, you’ll know it’s a lot harder than jumping off it. Not convinced? Sure, no problem… just go read Armen Stein’s Code of Silence, then go pick up a copy of Peopleware and read that. If you’re still not convinced, don’t bother – you’re not going to gain anything from the rest of this.
So, if you’re still here, I’ll assume you can understand – and can even come to have great respect for, if you don’t already (and you should) – the fact that getting bumped out of a zone is detrimental to productivity.
Next factor: active memory. Not computer memory, but human memory. If you haven’t already, I strongly advise to go pick up a copy of Code Complete (it’s only the best book ever written about software construction). You’ll find that a recurring theme within the book – in fact, you might say it’s the whole point of the book – is that the key to good software construction is reducing complexity.
The more complex things are, the more stuff we have to try and hold in our heads at once. This doesn’t really work well, being that software is very complex, and we simply can’t keep it all in our heads and actually attempt to get work done at the same time (you’ll note, being in the zone effectively removes any thought consciousness except that which is directly related to your zone).
In numerous contexts within Code Complete, it’s stated that studies have shown that 7 tends to be a magical number: the one that, give or take, is the limit to what programmers can remember at any given time about any given thing. If a procedure has more than 7 arguments, try to refactor. If you have to remember more than 7 variables within a routine, refactor. If you have an interface that has more than 7 methods? Refactor. I haven’t specifically tested this myself, by Steve McConnell sure has hell seems to know what he’s talking about, and it makes enough sense to me where I’ll take it as a given. So let’s say that if we have more than 7 things we need to keep in our active memory at a given time, we’re in danger of being kicked out of a zone because we have to force our brains to pull up some other piece of information… sound good? Good.
Wait – we were talking about module names, right? Right.
Class names aren’t much for this discussion… you get an object variable and can only access their properties and methods through the variable, so by default you pretty much have to code this way with classes anyway. Standard modules however…
Not too many people give a whole ton of thought to standard module names beyond: a) picking something that has at least a slight resemblance to what code it contains, b) making sure it doesn’t interfere with an existing module name, and c) making sure that it doesn’t interfere with an existing public procedure name. That pretty much sums up most people’s criteria for naming a module. More so, once that module is named, it’s almost never used again except to pick it out of the left hand list in the VBE.
Let’s talk about procedure names for a minute also… naturally, we tend to name our procedures so that they don’t interfere with other procedures. We don’t worry about it all that much for private procs, because we don’t really care much outside of the context of the current module. Public procedures though, these tend to get a bit more thought. Sometimes we’ll even find ourselves fighting to come up with a good name for them: one that doesn’t interfere with other public proc names, because that’d cause an ambiguation problem.
As a result, we often end up with procedure names that may not be all the semantic (and I’ll take a second to point out that ALL of my naming conventions are heavily based on semantics, because semantics are what ultimately keep us from having to think of things too much, and in turn keep us in the zone: anti-semantics are EVIL. Programming is a language, and we as developers should be able to – without extraneous thought – convey what’s in our heads, what we need to do directly into a flowing computer language. In fact, this transfer should happen without thinking. We’ll think about what we need to do for the task at hand, we’ll think about the environment and the platform and the framework, but we’ll NOT think about how to convey that information into the language of the program itself: that should be done automatically, without thought (7 things adds up fast, this one is entirely unnecessary after a few months working with a given languages (as long as the language doesn’t suck, like PHP (I wonder how many nested side thoughts I can come up with??)))).
Anyway, we come up with these ridiculous function names that aren’t a direct representation of what we need to tell the computer to do. They’re a direct obstacle to something we shouldn’t at all have to actually think about. Hmmm… is that fGetOSUserName or GetOSUserName. That kind of stuff doesn’t do you much good when what you’re really needing to think about is what needs to be done with the user name, not how to get the stupid thing – like flying a plane: always be ahead of it. Writing code in the zone? You’re thinking ahead of it, not stuck on what you named that function.
A theoretical story, then, to FINALLY start talking about why these module names are so important…
Some time back, I was writing code. Let’s say it was a project where I had to perform a number of custom import routines from varying other systems. The kind that aren’t close enough where you can wrap them up into one routine with (7 or less) parameters to define the behavior. Naturally, each of these entirely different import code bases goes into separate modules.
Now, I’m sitting there writing code… or trying to anyway, but what I’m actually doing instead is trying to remember the name of that function that I call to perform the import. You know, if I was smart, I’d just name it ImportFile or something, because that’s exactly what it does… but we can’t have a bunch of ImportFile public functions laying around, right? So, like most people, I end up with: ImportMedentDailyVisitReport, ImportWebPTBillingReport, ImportBlahThisThatWhoCaresTheseNamesSuckBalls.
So there I am, wasting so freaking much time trying to remember the name of this module (“so freaking much time” is like more than 2 seconds to me… doesn’t take much to get kicked off a train). What do I do so I can remember the name? Go to the module, open it, look at the top of the module in the first proc or two where my entry points and public stuff usually is? While that’s a pretty retarded way to do things… why go through that trouble. Now I’m WELL beyond my two seconds: I’m rolling the dirty coughing on dust watching my train go somewhere else without me.
I type in the module name and hit period. Know why? Because this gives me intellisense and shows me exactly what public functions and properties the module has, so I just have to glance in the list, highlight it, CTRL+Left once or twice (with a shift in there) to highlight the module name and dele…
STOP. RIGHT. THERE. (don’t worry, the train’s long gone anyway)
“Self, wtf is this… why are you going to delete that module name?”
“Well, that’s what we do… nobody codes with module names in front of their functions all the time.”
“Self… why not?”
“Idunno, what if I change it later? My code will break!”
“Dumbass! Listen up… how many times do you go changing table names on a whim? How many times have you looked at a project three months later and said ‘hey, screw that field, I’m changing ya!’ Hm?”
“Ummm is right, you don’t know. Pick a halfway decent module name to begin with and you won’t have to change it later. Probably the only reason you’d ever consider changing it anyway is just because you can.”
“Idunno man… that’s like… not normal.”
“Listen dope, you just spend how much time trying to remember a function name? Just got your ass kicked off your train of thought that you owned, and now it’s going to take you how long to find the thing again, let alone get back on it? Because you want to retain the right to change a module name?!?! Here’s what you do: you take yourself outside, slap yourself as many times as necessary then come back in and prove to me that you’re not a hopeless imbecile.”
Somebody give me one good reason that we can’t use a module name as a prefix to fully qualify our function calls.
Protip. You can’t.
SEMANTICS! REDUCTION OF COMPLEXITY!!!! Now you can name every freaking import procedure “ImportFile” and it doesn’t matter! You’re going to qualify it with the module name! Now instead of ImportMedentDailyVisitReport() and ImportWebPTBillingReport() and ImportBlagThisThatWhoCares, we have things that MAKE SENSE! MedentDVR.ImportFile(), WebPTBilling.ImportFile(), ICare.ImportFile() (ok, bad example on the last one, capital I means too much as a prefix for anything, but you get the idea.)
Still doesn’t sound like much though, does it? So, let’s go alllll the way back up to the top (ok, don’t, I’ll do it for you), and take a look at some of what we previously discussed:
- Getting bumped out of the zone causes major holdups in real, productive work
- Having to think about too many things at once causes us to get bumped out of the zone
- Having any sort of block between what we need to convey to the language and how to implement that need within the language is dangerous to the zone
Those are the main points. Let’s see how not fully qualifying procedure calls with module names interferes with those points:
- When we have to stop and think of a function name for more than a fraction of time, we’re bumped from the zone
- When we have to stop and think of a function name, we’re almost always running a mental scan of the application in an attempt to try and trigger something that’ll give it to us. That’s usually a LOT more than 7 things, so your train is gone. No helping it.
- We can’t think ahead of ourselves and code productively because we need to stop and think about function names.
And finally, let’s see how a fully qualified ModuleName.FunctionName helps with those points:
- Semantic. Your procedure names make sense and your modules are cake to remember. Here’s why: your module names come in two flavors: common, reusable code like DateTime.IsWeekday() or ODBCUtil.ExecutePT(), and task-specific code like WebPTBilling.ImportFile() Now you don’t have to think about 7 things or more – you don’t even have to think outside of the scope of your current task! The common module names you’ll have so memorized in short order that you don’t need to think of it (and intellisense is amazing for quick-picking functions within a module), and the “task at hand” type module names are already part of your allowed 7 memory items because they’re… guess what? Tasks at hand! Brilliant!
- No longer need to run mental scans of the modules within the app in hopes to trigger what that function name was. No longer try to type it three times before you give up and go look for it. No need to jot it down on a piece of paper so it’s in front of you five minutes later. Just type the module name!
- And finally, the whole point of this rather lengthy and ridiculous post: you don’t need to stop doing anything to tell your programming language what to do. What you need is conveyed to what you type without having to make a conscious translation! Just keep plugging away without mundane interruptions… SEMANTICS!
There you have it kids. Use fully qualified module names. It’s for the good of you, eh?
So go turn on some Dead and have fun ridin’ that train (however, I’d heed Cash’s advice and leave that cocaine be).
In all seriousness though, I can’t convey enough how much of an impact this tiny little change from the norm has had for me in terms of coding productivity. Simply amazing. You’d never think that such a little thing could make such a difference.
There is one caveat, and it’s very small: if you’re writing function names that are ambiguous across your project’s modules, you will not be able to use them within the Expression Service (eg, queries, control expressions, etc.) because the ES doesn’t allow you to qualify a function name with a module name. This is of very, very little consequence though… the types of functions that tend to have ambiguous names across modules are the types that fit into the second category of modules, the “task at hand” type modules like WebPTBilling.ImportFile() stuff which you’d never call through ES anyway. The common ones don’t end up with the same name due to semantics, but you have the huge added benefit of intellisense support for them now. Win. Win.
I can’t advocate this one enough!
(if you liked this article, thank Patrick Wood – he’s the reason it was written)