Clarity over brevity in variable and method names
37signals.com
37signals.com
For example, I might call a function in a geometry library gradient_of_line, but within a line module in that library, I'd probably just call it gradient.
In mathematical code where there is a common notation that happens to be very concise, I'm quite happy writing code that uses it, like
y = m * x + c,
as long as the terminology/notation is standardised or well understood. I don't think writing dependent_variable = gradient * independent_variable + crossing_point
is an improvement in this sort of case.By a similar argument, I have no problem with giving abstract loop control variables like counters a short name like i or n, since they are only used within a small area of the code. However, if the variable represents some more meaningful concept, then I would probably name it accordingly.
It's absolutely an art, not a science. But it shouldn't go to either extreme -- names that are too short (var xi_a) are too confusing for clarity, but names that are too long provide too much visual noise to be clear.
In my opinion, "make_person_an_outside_subscriber_if_all_accesses_revoked" just takes too long to read. Much better would be something like this:
// If all accesses have been revoked, then make the person an outside subscriber
def updateOutsideSubscriber
...
end
The function name is short and gets straight to the point of what it does. Someone coming across the code for the first time can instantly figure out roughly what the function is, and then decide if it's worth their time to read further, or if they should just skip over it.Then, a comment explains in further detail what it is for, and why it is used. You only need to read it if it seems important to your task at hand.
Good variable naming strategy goes hand-in-hand with good commenting strategy.
The end goal should always be maximum clarity, but remember that too much information, or too much information presented upfront, can reduce clarity.
37signals says "clarity over brevity". I'd say "clarity over extremes".
In it he makes the argument that it's a good goal to make each line of code understandable with as little other context as possible.
Your `makeOutsideSubscriber` is fine when your in that module. But when someone else is using the module.
import subcribe
...
def SomeFunction
subscribe.makeOutsideSubscriber(...)
And then 3 months later someone comes and reads the code above using your module it sure would be nice if they didn't have to go dig through the source of your module and read the comments to figure out that it really means "make person an outside subscriber if all accesses revoked"It seems to me that "make_person_an_outside_subscriber_if_all_accesses_revoked" just sounds like an internal module function. If something outside the module is calling it, it just smells like the whole thing is organized wrong.
But sure, if the function is being used in a "global" way like that, then the full, long version is probably better...
What if new requirements dictate that if the same thing should happen given a different condition (if all access is revoked or if the user is set to be disabled), would the method name then become make_person_an_outside_subscribe_if_all_access_revoked_or_user_is_set_to_disabled ?
The function as described means that the only time this method is to ever be used is if all access is revoked... if that's the case why even make it into a function? Or to put it another way:
//make_person_an_outside_subscriber_if_all_accesses_revoked
function revokeAccess(user) {
user.clearSubscriptions();
user.addSubscription(new OutsideSubscription());
//other revoky stuff goes here...
}
//shift_records_upward_starting_at
function shiftRecords(startPosition, amount) {
//up or down. to go down supply a negative amount
}
...or somethingThe original function appears to have two responsibilities: it performs a test on the accesses, and then it also converts the person in some cases. The long name follows from that complexity. Unless there was a good reason not to, I would prefer to separate those responsibilities into their own functions with one job each, and then the naming problem takes care of itself:
if all_accesses_revoked(john):
convert_to_outside_subscriber(john) var allAccessesRevoked = items.All( areRevoked);
if( allAccessesRevoked)
person.makeOutsiedSubscriber;
but sometimes, the programmer hasn't discovered a good refactoring. def update_outside_subscriber
...
end
Surely? I hope I'm not being pedantic, it just looks really odd to me. It sticks out like a sore thumb in an otherwise excellent point.A few years after I left that job, I briefly ended up back at that company on a contract assignment - for a different project, under a new development manager. At one point, I had to pull some data from the database, and had no problem finding the information I needed, or how to connect it together.
The dev manager joked about the long table names (not knowing I was the source of them). But when I asked him if any of his current developers had trouble finding the information they needed, or understanding the relations, he said, "No, they just get tired of typing them."
That's just one anecdote, but I'm going to stick with long, descriptive names.
The only way DescriptiveVariableName could me made for meaningful is if DescriptiveVariableNameUser declare s DescriltiveVariableName's type (DescriptiveVariable) every time DesriptiveVariableNameUser accesses (DescriptiveVariable) DescrptiveVariableName.
Also, the names used in the article show a very poor aesthetic sense. Names like that are screaming out as needing a refactor. Having a condition in your method name is a code smell. Your methods (read: api) should be abstracted as discreet actions, and the code that calls it should perform control flow.
On the other hand, in long variable names, the excess of characters provides redundancy, which makes it easier to error-correct. The parent post is riddled with errors that would halt a compiler, but many humans would not even notice them.
I don't buy that short variable names are necessarily less clear. I think the ideal is to find variable names that are terse and clear. And I'm strongly in the camp that believes that brevity aids clarity.
It's not so much "screw readability" as "long names are ugly and annoying to type, and if you can't figure out what 'i' and 'x' and 'dx' and 'j' mean in this context, then you lack intelligence and that's your problem, because it's obvious, duh. Real programmers are efficient, not verbose."
I've worked with quite a number of programmers who seem to have a very hard time putting themselves in the shoes of someone who will have to read/maintain their code later. Good variable names are all about communication, and there are certainly programmers out there who don't have communication as one of their strong suits.
We all do that. How many times have you looked at something, went "What asshole wrote this?" Only to find out from git that it was you?
if someone really smart says they use terse variable names, you don't tell them they're wrong, you try to understand them. There exist styles of writing high quality code that don't need naming style like `someone_else_just_finished_writing?`. there are styles that use it. if you're only accustomed to the long way, you'd be well served to go join a successful team that uses the short way, instead of blindly saying that they're wrong. some of the clearest code i've ever seen was Haskell, for which i think most people find you don't need long names.
me, when i find myself needing long names, i try to refactor until i don't need them any more. its not always possible given time constraints, backwards compat, trying not to change fragile code etc, but i mostly chalk that up to a personal or team failing.
Like the Scheme and Haskell communities, respectively.
Haskellers completely avoid introducting entities (like function arguments) where they aren't needed.
Utilize, upward, starting at, finished writing
vs.
Use, up, from, wrote
So:
def shift_records_upward_starting_at(position)
could be: def shift_records_up_from(position)
and: def someone_else_just_finished_writing?(document)
could be: def other_user_just_wrote?(document)
I don't think the shorter versions are any less clear.For me, clear and concise method names have always help me understand code that I'm reading, as well as understand a stack trace.
I'd settle for six months.
<rant class='mini'> When I talk with friends in other industries (e.g.: civil engineering), they have a very specific way of doing things. These fundamental activities do not change very often because they're based on decades of experience (and, I assume, because bugs in their process could kill people). That doesn't mean things don't change: concrete mixtures and such are always improving and sometimes it sounds like the IT industry with all the new tech coming out, but that's just materials technology, not how specs and processes are written. </rant>
If you spend a lot of time writing math, the opposite is true: shorter variable and function names are better for clarity, to the point that arbitrary operator overloading is essential -- as anyone who's suffered through matrix.transpose().multiply(matrix2.inverse()).multiply(vector.multiply(scalar)) . . . would tell you!
You can also print them. My co-workers sometimes print code. Please don't laugh, some people do not have good vision (and one day, you will be that person too).
"Comments are generally only needed when you failed to be clear enough in naming. Treat them as a code smell." ...but only in simpler applications, such as self-describing CRUD type web applications?
I think I agree with the quote within some web apps, however remember some code may take weeks/months to appreciate the complexities of. For example, a TCP stack is a complicated thing, born and refined through much research for several decades. Notes of various design choices and optimisations need to be documented, and long comments are sometimes the most convenient way to do so.
I've read far too many comments above functions that simply restate exactly what the code is doing or explain what the stupid abbreviated variables mean.
Comments are a tool that should be used sparingly. They definitely have their place and can be used helpfully. I've found that they're easy to screw up though and I try to avoid them.
I think since I started programming professionally I've stuck to expressive names (not necessarily long names), mostly for code self-documentation. It's nice, most editors/IDEs tend to have name completion, even if it's only document bound, so you only need to type it in full once.
someone_else_just_finished_writing?(document)
someone_else.just_finished_writing?(document)
Especially when using underscores, it's too easy to miss a period or a subtraction.And when you have several lines using such long names, it becomes a wall of text and have you to read everything out loud to understand what's happening.
My eyes never need to drift to the right side of the page/screen. Everything is justified at the left. Keep indentation to a minimum. Alas, this is not a popular idea when people write code.
Books, newpapers and magazines often adopt multi-column formats. Why? Does anyone know?
Columns also allow room for comments. Columned class notes are a great example. You can even leave the whole right side of the page clear for adding comments later.
Unconvential perhaps. But very useful.
Anyway, names are arbitrary. They are inherently ambiguous. The truth is that computers work via numbers, not names. As such, naming will always be a subjective affair, to some extent.
(Of course, this assumes that you distribute your executable instead of keeping it inaccessible to others, for example by running it on a Web server.)
It is not that big of a deal though. On platforms like Java or .NET, you can run an obfuscator to strip out names and leave confusing looking strings.
But it only increases reverse engineering complication very slightly. If you're trying to protect a small secret (like a key validation or special algorithm), you're out of luck, even if you strip symbol names. If you're trying to prevent wholesale ripoff of your app, legal action is more effective.
Making your code "worse" is a terrible tradeoff for approximately zero gain.
In some others (e.g. C), the executable that's distributed pretty much talks the language of the underlying machine, so the original code structure and naming are not preserved.
This creates at least two problems:
1) You need to remember to update every inlined use of that logic at bug fixing time. Experience says you'll inevitably miss at least one, the first time around.
2) You've created a Multiple Points of "Truth" maintenance burden. When you hand the code off to somebody else for maintenance, and there's some bug around "updating user records to mark them as outside subscribers if all accesses are revoked", they have to figure out whether or not the fact its being done different ways in different locations is intentional or accidental, and if accidental, which way is in fact correct. This is always an enormous pain in the ass.
def make_person_an_outside_subscriber_if_all_accesses_revoked
person.update_attribute(:outside_subscriber, true) if person.reload.accesses.blank?
end
I prefer camel case