How to Keep Your Code From Destroying You 486
An anonymous reader writes "IBM DeveloperWorks has a few quick tips on how to write maintainable code that won't leech your most valuable resource — time. These six tips on how to write maintainable code are guaranteed to save you time and frustration: one minute spent writing comments can save you an hour of anguish. Bad code gets written all the time. But it doesn't have to be that way. Its time to ask yourself if its time for you to convert to the clean code religion."
Re:That was just terrible... (Score:5, Interesting)
The real thing is to used named constants where it makes sense. #define is the crudest approximation of that, C can use enums, C++ can use "const" for compile-time values, etc.
In a real project, you have to scope your constants otherwise you'll have a billion of them in "everything.h" and every time you touch it, the world will rebuild. So nix the "centrally located" file theory.
In a real project, your constants will often have interdepedencies on other bits of code, so changing one will frequently affect the others. Heck, maybe changing one will cause it not to compile. This example makes them all trivial to the point of uselessness. Shuttling it off miles away in an #include file, can frequently give the impression this than can be changed with no effect on anything else.
Re:Who wrote that article? (Score:4, Interesting)
Void change_score(short num_points)
{
if (num_points < 0)
{
// maybe some error message
return;
}
score += num_points;
if (num_points > 0)
make_sparkles_on_score();
}
Re:That was just terrible... (Score:4, Interesting)
Re:Who wrote that article? (Score:1, Interesting)
Re:Who wrote that article? (Score:3, Interesting)
On the other hand, I work with many CS degree holders who could greatly benefit from this article. So while to some it's obvious stuff, just because it's obvious advice doesn't mean that it's always followed.
I did kind of cringe though, at the bit about good var naming. I have been known to name vars things like ArthurKingOfTheBritons and IckyIckyIckyPtangZoomBoing when a var is used just once or twice and is declared in close proximity to where it's used, but of course we all know that's bad practice.
Re:That was just terrible... (Score:4, Interesting)
That was my thought, too. When writing C++, you should *avoid* #define like the plague. In fact, avoid using the preprocessor for anything except including (and guarding) headers and, occasionally, conditional compilation. One of the best things about enums is that they create not just values, but *types*. So, if you define:
The compiler will barf if you accidentally type:
... or something equally silly, but perhaps less obviously wrong.
Smart C++ programmers find ways to get the compiler to point out their mistakes. One of the most powerful (and most clever) examples of this is in Barton and Nackman's book on C++ for scientists and engineers. They make use of templates to define types for representing physical values that not only have units attached, but which allow the compiler to statically check the units. Given:
The compiler would take care of all of the unit checking at compile time, and, assuming we got rid of the erroneous line, generate machine code equivalent to:
And if m or g aren't actually used except to calculate f, the compiler will optimize them away completely.
I used the verbose version of their syntax, BTW. You can also write:
which will apply default units to the numeric values. Of course, good code would also define a "const Acceleration g(9.8)" in a header somewhere, etc., rather than using numeric constants directly in the code, and it would use better variable names.
Of course, such usage is well beyond the "Introductory" level of this article, but I think even an introductory article on C++ should recommend using enums to define constants, not #define. More advanced C++ users should devote a little time to writing classes that idiot-proof the code (because we're *all* idiots, at least some of the time), ideally without sacrificing performance.
Re:Felt I should point out (Score:1, Interesting)
I think you're just not familiar with the terminology here. Anything that is observable outside of an expression other than through the returned value is a side effect [wikipedia.org]. If you call puts("foo"), printing foo to stdout is a side effect even though it's the whole point of the function call.
Re:Mostly agreed (Score:3, Interesting)
Re:That was just terrible... (Score:3, Interesting)
This is not to argue against splitting functions where necessary; sometimes you need to split things in odd ways with tricky internal coherence to make other parts of the code much neater, and sometimes it improves separation of concerns (a good thing!) But splitting stuff into ultra-short functions for its own sake is missing the point, and those who do it are making big headaches for the maintainers of that code. I say this from a position of authority; I've had to maintain applications I wrote several years after believing them obsolete and setting them aside (yes, with a total hiatus in-between) and I know for sure that understanding the code is the biggest challenge of all for maintenance. People who deliberately split code up into ravioli, and especially those who advocate that others do so, are "dangerous idiots" precisely because they've lost sight of the fundamental need for comprehensibility and are encouraging others to also stray from The True Path.
Writing good code takes good taste, and any basic technique should be applied judiciously. It's the higher-level things (comprehensibility, separation of concerns, consistency) that are the true goals of the Good Programmer.
[Ye gods! This message is preachy. Serves me right for posting really late...]
Re:Who wrote that article? (Score:3, Interesting)
Re:Who wrote that article? (Score:2, Interesting)
Re:Good ideas, bad execution (Score:2, Interesting)
I tend to put a lot of my consts within a class or function. You can sometimes do this with #define and #undef but it's less clear what you're doing. And even if you do this, you need to be a lot more careful about namespace pollution. C++ will allow the scope to be limitted to a namespace.
Though you do still have to be careful about passing in expressions that have side-effects (because you don't know how many times they will be evaluated), or that are expensive to compute (inefficient for the same reason).
This is a concern as well. But unless you need to use the paste operators, a macro doesn't have any benefit over a function. With a function, it's a lot clearer what the code does.