views:

258

answers:

11

Every programmer is taught a basic set of rules for writing good, maintainable code early in their career. These include not using gotos, avoiding copying and pasting, avoiding globals, etc. However, sometimes rules that are only intended to be guidelines or rules of thumb get applied religiously by the more anal-retentive types, to the point where they harm maintainability, readability or performance.

What best-practice rule do you feel is a good idea in general, but is overzealously applied by programmers that fail to realize that rules have exceptions?

+13  A: 

Hard to say...

Single return from a method: Nothing wrong with exiting early if a condition is met.

duffymo
I'd not only say there's nothing wrong with it, I'd say it's highly preferable. It enables dealbreaker conditions to be checked for and gotten out of the way so the meat of the function can happen without being cluttered by them.
chaos
+6  A: 

One exit point per function. I'm happy that I'm seeing more people use guard clauses to get out of functions early, but I still have a few co-workers who are adamant about one exit point per function.

Bill the Lizard
Can you provide an example of such a guard clause you are referring to? Thanks!
cschol
In a recursive factorial with argument x: "if (x <= 1) return 1;"
duffymo
See also the arrow anti-pattern.
Jason
+4  A: 

Always use descriptive variable names. Great rule, but not particularly necessary if the variable in question is a simple loop index.

tvanfosson
Yes, great rule, better exception.
Bill the Lizard
One project of mine actually came to need a style document. A quote from it: "Make for() loop control declarations fit onto one line whenever feasible. If it's not feasible, consider using shorter variable names so it becomes feasible. Everyone knows that i and j are counter variables; trust us."
chaos
A 3rd party developer hired to help with a previous employer's project insisted on naming variables like that. Until I replaced them all with md5 hashes of his original names, that is. I believe he now understands my position, and, as a bonus, has discovered the benefits of version control. Result!
jTresidder
Definitely agree... 'iLoopIndex' (yes, Hungarian notation) seems much more verbose than 'i' :)
Reuben
For some reason I like 'ix' these days, but yeah. I'm of the opinions that people need to not be afraid of doing some typing when naming functions and such, but that's because it has a purpose in the context. But I suppose the whole thread is about rules being overgeneralized.
chaos
+9  A: 

Here's another one: "Comment your code". Not if you do things like this:

// Loop over the array
for (int i = 0; i < n; ++i)
{
    x[i] = i;
} // end of loop over array

These kinds of useless comments make my blood boil. They're more heat than light, more clutter than insight. Make the code comment itself.

duffymo
Agreed... but worse than the comments that are fairly straightforward are the ones that are *entirely* redundant. I've definitely seen comments that say "// Free the buffer" right before a call to "Free(Buffer)".
Reuben
Yes, those crack me up, too.
duffymo
Worse than redundant comments are comments that could be redundant if the code itself was fixed rather than using a comment to cover it.
Tom Hawtin - tackline
+1  A: 

Look, the code has to do two things: express the program you want, and make itself clear to the reader who has to figure it out later. The rules are all there to help you do that. Read Orwell's six rules for writing sometime. The last one is "break all the other rules rather than do something outright barbarous." That's the real goal.

Charlie Martin
+4  A: 

Use design patterns.

I have a quote, from whom I don't know, socked away on the "GoF Gone Wild" topic... "Look, kids, here's a factory-factory creating factory for creating factory-creators for creating factories for creating certain kinds of mud creatures!"

chaos
This made me laugh - so true.
duffymo
People took the GoF design patterns overboard, it's true.
Max
+1  A: 

Don't use functional decomposition.

I use function decomposition when I have a small program that does one thing well. I also use it from the top level to tie my classes together. I use it at the lowest level to implement the methods of my classes.

+1  A: 

Put everything in classes.

Not always; sometimes a good set of (static) functions will do what you want without the overhead of a class.

plinth
A: 

Echoing what duffymo said with an example from the current version of some source code (bare minimum changes to conceal the guilty):

/*
 =========================================================================


Function: int loadmsg (void)

    Inputs: void

    Outputs:

Returned Value:      FUNCSUCC or unknown message number

Purpose: loads text of all messages into menus, strings, and

Description:

    loadmsg() tests if message files can be found and accessed

Notes:

    Functions Called:
            loadstr()
    Called By:
            sys_startup()
    Constants Used:
    Global Variables Referenced:
            iFLAG
    Local Variables:
            cc      return value from rldinit

 ========================================================================
 */

static mint
loadmsg()

{
register mint cc;

if (cc = rldinit())
    return(cc);
return FUNCSUCC;
}

Indentation is accurate (that is, as in the actual code). How to deconstruct?

  • The macro FUNCSUCC is 0.
  • Consequently, the body of the function is equivalent to:

    return rldinit();

  • The leading comments are almost all superfluous.

  • The function loadstr() is not called - it doesn't exist.
  • The variable iFLAG is not referenced.
  • The inputs and outputs are immaterial.
  • In fact, the whole function is called once - so the calling function may as well call rldinit() directly.
  • This function is deleted in my working branch.
  • This was 43 lines between the open comment and end of function - in place of a function call.

I wish it were an isolated instance. No, it isn't a file I work on primarily. It is, however, a file of just over 20,300 lines (and it isn't even the biggest maintained - as opposed to generated - source file in the system). No-one knows all of what's in it - and therefore no-one is responsible for spotting such problems. I do this sort of problem spotting rather consistently, but by accident when I have to look at the code.

(Another bugbear of mine: 900 of the 20,300 lines have trailing blanks on them. I hate that!)

Jonathan Leffler
Ooh, hanging whitespace. Hate that. :1,$s/ *$// ftw.(Supposed to be two spaces in the regex. Silly HTML.)
chaos
20,300 LINES?! Oh, my. There's something else to hate.
duffymo
Anyone who intentionally lets a production source file get over 1000 lines needs to be restrained from computer access, unless it's a single function.
Max
Do you think a 1K line function is a good thing? I don't. If I have to scroll to read it I start thinking that refactoring is an order.
duffymo
@Max: I put the limit at 2000 lines (approx), but I agree. It has grown by accretion over 20 years, and there is a penalty of sorts (lots of extra work) in introducing new files into the system, and breaking up a file complicates maintenance of older versions (we have 5 main versions).
Jonathan Leffler
@duffymo: there are 32 functions in the file with more than 100 lines, and 3 of those are over 1000 lines. The biggest of those is almost a classic switch/case statement (which can sometimes get an exemption). It could and should be refactored. The others have less excuse. 1K functions are BAD!
Jonathan Leffler
And as another FYI: the file has over 600 #ifdef and related conditional compilation lines (and about 50 includes, many conditional). This too is overdone, but compounded by a legacy of working over many divergent platforms. It is depressing at times.
Jonathan Leffler
+2  A: 

I've always been annoyed by "give 'em what they want". Fair enough in theory, but in practice what they ask for is rarely what they want, it's more like the real problem half-solved in the first manner that popped into an untrained head. Deciphering desires from requests is an art in itself but it's a vital part of being a good programmer, IMHO (and at least doubly so in web-dev).

jTresidder
+1  A: 

The single most overzealously-applied rule of thumb I've encountered is never using gotos.

In large applications, occasionally you'll run into a scenario, usually involving nested loops or control structures, where an outlying condition requires special processing. Programmers often use complicated control structures and flags and generally make the code a lot more elaborate than it needs to be rather than simply using a goto. Linus Torvalds made an argument for gotos that I think every serious programmer ought to take into consideration rather than blindly spouting off citations of Dijkstra's paper.

It's not that gotos are bad -- it's that like any programming tool, its mis-application can lead to headaches for yourself and other programmers down the line.

Max