Slashdot Log In
How to Keep Your Code From Destroying You
Posted by
ScuttleMonkey
on Wed May 30, 2007 02:09 PM
from the i-have-been-sent-here-to-destroy-you dept.
from the i-have-been-sent-here-to-destroy-you dept.
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."
This discussion has been archived.
No new comments can be posted.
The Fine Print: The following comments are owned by whoever posted them. We are not responsible for them in any way.
Full
Abbreviated
Hidden
Loading... please wait.
Damn (Score:5, Funny)
The whole article is -1 redundant. (Score:3, Insightful)
I have. It ain't fun. Not that I'm bragging on myself, but I've now had people from the support group stop me in the hall and compliment me on the quality of the code I've written and deployed.
Re: (Score:3, Informative)
Re: (Score:3, Funny)
That was just terrible... (Score:5, Insightful)
This looks like it was written for (and BY) freshmen CS majors.
Comment your code smartly? No shit?
Use #defines everywhere? Honestly, I find that having a config file (or DB table) is a lot better, as I can change global variables without even a recompile...
I'm not saying its BAD advice, its just advice that anyone in the real world already knows.
How about something new?
1.) Use test driven development
2.) Write complete unit tests, including bad input
3.) If any piece of code is complex enough to require a comment, make it its own function and comment the function. I believe the only thing that REQUIRES comments are classes and methods. Not pieces of code...
I code go on, but I'm not a writer...
And neither is the author of that pile of trash...
It was fine... (Score:5, Insightful)
I'm not sure if it really called for a Slashdot entry, but I've been on a few projects with new coders where a quick read of something like this on their parts would have saved everyone a lot of grief.
Parent
But C doesn't have classes or methods. (Score:5, Funny)
Parent
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.
Parent
Re:That was just terrible... (Score:4, Insightful)
Agreed, but some of the things in this article can be applied conceptually if not literally. Don't want a 2MB config file or header file? Right, me either. But break your program down into smaller pieces and declare stuff at that level and group it together at that level. Conceptually the same as what he is recommending, just done according to your actual implementation.
I too thought the article was very basic, but that doesn't mean that the principles don't apply well to systems larger than a simple game.
Parent
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.
Parent
Re:That was just terrible... (Score:5, Insightful)
As for your advice
1)Thinking about testing early- good. Writing unit tests-good. The test driven development mentality (write tests instead of design, write unit tests before coding)- bad. It leads to a lot of wasted time, completely rewritten test suites, and throw away work. Thinking about testing early is useful, it may cause you to think about corner cases. But writing them first causes 2 problems- you end up writing the code to solve the tests (rather than solving the problem) and/or you end up throwing away half the test suite in the middle when you refactor the design.
3)Disagree. The purpose of comments is to make sure that maintainers know what the code is trying to do. Anything block of code thats more than 5 or 6 lines deserves a comment. Breaking all of those into independent functions leaves you with hundreds of 5 or 6 line functions, which is even harder to understand how they interact. Frequently the correct thing to do is not break it into a function and just write a 1 line comment.
Parent
Re:Comments are a code smell. (Score:4, Insightful)
Parent
Re:That was just terrible... (Score:4, Interesting)
Parent
Re:That was just terrible... (Score:5, Insightful)
That is just hiding your complexety. A massive tree of functions called each one time is as complex as all the code sequencally in one function. Plowing through the massive tree of functions will cost you more time as reading sequentially through your code whit comments at the places you would have created a function.
Nyh
Parent
Re:That was just terrible... (Score:5, Insightful)
Parent
Use a language that checks I/O errors by default (Score:5, Insightful)
C, C++, and Perl are not "safe" in this sense. Python is. Not sure about other common languages.
Re:Use a language that checks I/O errors by defaul (Score:3, Insightful)
Every time you create something, destroy it afterwards.
Assume every action will fail and handle it appropriately.
I have seen 'developers' assume everything will be taken care of, then when the software gets into the users system their usage patterns make it explode.
Simple management needn't make a development time longer or harder and allows you to migrate things to other applications/systems with ease.
Re:Use a language that checks I/O errors by defaul (Score:4, Insightful)
True enough, but this misses my point. The question is: What happens when a programmer fails to properly handle errors?
This happens all the time, either because the programmer is not sufficiently competent, or simply misses a check, or because the program in question is a prototype that got pushed into production without being reworked.
Having the language produce useful error messages by default does not preclude an other strategy regarding error handling, resource deallocation, etc. It wouldn't necessarily even need to be done via exceptions. It just needs to change the default strategy from fail-silently to fail-safe, which is what you really want if you care at all about reliability and correctness.
Parent
Summary: Beginners need tips too. (Score:5, Informative)
1. Comment smartly.
2. Name your constants ("use #defines").
3. Descriptive variable names, but not too long.
4. Handle errors.
5. Avoid premature optimization.
6. Clarity is better than cleverness.
The author may not be a beginning programmer, but it appears that he might be a beginning writer on programming.
Steps for Job Security (Score:3, Funny)
1. Use comment syntax to obfuscate the actual running code
2. Don't indent or "pretty format" your code
3. Use the same variable name over and over, capitalizing different letters to make them unique throughout the program
4. Use variable names that are incredibly offensive in hindu, so any common "outsource" programmer will refuse to work on the code.
You get the point.
Expected Value (Score:5, Funny)
However, what's the probability that the savings actually goes to *you* and not a coworker competing with you for a promotion, or someone who replaced you in a later year? If you work in an office with 100 staff, let's say 1%. So expected savings to you is EV = 1% x 60 minutes = 0.6 minute, less than the minute it takes to write the comment. (Even assuming the payoff is correct, and then helping competing coworkers doesn't do any damage to you.)
This is what I consider to be the "tragedy of the commons" for software engineering jobs. When I was a programmer, the people who did the least documentation were the fastest, and often the only folks who could approach certain parts of code, and so held in the highest esteem by the executives. Now I only write code for my own projects.
Re: (Score:3, Insightful)
Suddenly that "one minute" is a lot of hours spent writing comments that you'll never read, cluttering up your code and getting wronger as you don't maintain them.
If I knew which comment to write, sure, I'd write it. And I do, when I think it's appropriate. There are plenty of time
Mostly agreed (Score:5, Insightful)
Tip 2: Don't use #define. Avoid it as best as you can. Use const int. That's what it's for. It will be typechecked by the compiler, it's much harder to produce bizarre errors, and 99% of the time it's better.
const int NUM_ALIENS_TO_KILL_TO_END_WAVE = 20;
Tip 4: Warning messages don't work. Don't bother with them. Use assert() - if it triggers, your program will crash with a useful error message. Now that's an incentive to make things work!
In my current project, out of 25,000 lines of code, I have almost 1100 asserts. And the first number counts whitespace. Any bugs I have get found and squashed pretty much instantly.
Re: (Score:3, Informative)
I guess if you're forced to use pure C, it could be an issue, but I would personally just compile it as C++ (remember, you don't have to use all the C++ features if you don't want to.)
Re: (Score:3, Insightful)
I mean, unless you're using K&R C, in which case I feel very sorry for you.
Re: (Score:3, Informative)
You're right, though - that's one of the more annoying "features" of assert. Luckily assert() is not a particularly hard thing to rewrite.
Re: (Score:3, Informative)
I suspect they only do this in release mode, of course.
Re:Mostly agreed (Score:4, Insightful)
Parent
I thought #defines were deprecated in C++ (Score:5, Insightful)
I.e. not
#define PIXEL_WIDTH_OF_PLAY_AREA 800
#define PIXEL_HEIGHT_OF_PLAY_AREA 600
but
const int PIXEL_WIDTH_OF_PLAY_AREA=800;
const int PIXEL_HEIGHT_OF_PLAY_AREA=600;
Re: (Score:3, Informative)
Using const int instead of define can save you a whole lot of time when it comes to debugging. When something has gone wrong and you need to step into your code with a debugger, const int will have created a symbol that your debugger can use and inform you of, while define will make the debugger tell you the value of the constan
At this point I am thinking (Score:4, Funny)
Actually (Score:5, Funny)
If I understand correctly (Score:5, Funny)
Obvious and Wrong in One (Score:5, Insightful)
Advice on good comments--great--but really, it's just obvious. Anyone that doesn't get how to comment well doesn't want to comment well. And the above quote made me want to wring his neck. If you don't know the difference between those two operators, you should stick to VB.
Felt I should point out (Score:5, Insightful)
It's not a matter of knowing the difference, it's a matter of the code depending on the difference. If you need to increment beforehand, do it on the previous line. Afterward, do it on the next line. Expressions are like sex: they're better without side-effects.
Parent
Some more redundancy, care of Brian Kernighan (Score:5, Insightful)
Two rules to live by (Score:5, Funny)
But, if you simply MUST, then:
Rule #2: If you have to blow up, arrange it to be in someone else's code.
That way, when you're (say) deep in your file system update locking and you realize that something's gone truly plonkered, you stealthily return something that causes X Windows to blow chunks long after you've returned.
"It's the file system."
"No, it's not. It's the bloody clipping code in X. Remember when release 10.5.08A came out? It's just gotten worse from that. Did I ever tell you about the time that 9.02 was released? Let me just say, you're lucky, man . .
Rule #3: When necessary, distract, distract, distract. Everything is on the table, and "Look, the Goodyear Blimp!" [points excitedly] is just for starters...
Good systems programmers know these tricks, and all the others you haven't learned about yet, which is why they're curmudgeons with level 70 pallies and tier-2 gear and you're shovelling Java and XML around trying to make a rent check.
Cheers!
Tip 3 is crap. (Score:3, Insightful)
#define MAX_ALIENS_ON_SCREEN_AT_ONCE 5
I would almost undoubtedly write:
#define MAX_NUM_ALIENS 5
Any confusion caused by the shorter name would be cleared up very quickly, and the shorter name would lead to much more readable code. "
Cleared up very quickly? no, it can only be cleared up after searching your code to realize it is the max number of aliens on the screen, not the max per level, or per game, or whatever the hell you were thinking 2 years ago when you wrote it.
Bad Bad Bad.
sloppy.
Hungarian Notation (Score:4, Insightful)
I wish he'd included a link to the Wikipedia article on Hungarian notation [wikipedia.org] and specifically referenced "Apps Hungarian". Hungarian notation is essentially a cheap way to create programmer-enforced "types". When these are truly new types ("dirty string", "null-terminated string", etc.) not known to the compiler/interpreter, it might be reasonable; this is "Apps Hungarian". However, prefixing an unsigned int with "ul" (i.e., "Systems Hungarian") is silly; your compiler should warn you/error out if you're trying to do something inappropriate with it, since it knows what an unsigned int is. Hungarian notation will be a useful thing until it's as easy to define new types in common programming languages as it is in, say, Haskell, but it should be used judiciously.
A Note From the Author (Score:5, Informative)
* To those who think it is all so obvious that I shouldn't have written about it:
No. You are wrong. Just wrong. Good programming practices do not just appear in peoples' heads as if by magic.
It's an introductory article. It's sold as an introductory article. And I am far more interested in being Right than I am scared of being Obvious.
* To those who have problems with suggesting using #define instead of const int
Meh. Yeah, you're probably right. But the important thing here is the CONCEPT of having your constants being defined in one central, easy to find place. Once a person has that down, he or she can define them however is desired.
* To those who accuse me of being a (gasp) inexperienced programming writer.
Yeah. So what? I never said I wasn't. I'm a game author. I've written over a dozen games. They all made money. That doesn't mean I am mister programming advice god.
But one, if you have a problem with it, yell at IBM, not me. They're the ones who had me write the piece.
Two. This is kind of ad hominem. Who cares how experienced I am or am not? I'm still right.
* I didn't read the article, but I'll say bad things about you because it means I'm awesome.
R0ck 0n d00d. First post!
* I liked the article. It might tell beginning programmers something actually useful.
If anyone says this, thanks in advance.
Re:Who wrote that article? (Score:5, Informative)
Maybe it was the note at the top of the article that says, "Level: Introductory."
Maybe it was the author's comment at the end that said, "At this point, you may be thinking, 'Wow. That was a big waste of time. All of this stuff is obvious and everyone knows it. Why did anyone write all of this?' I hope this is what you're thinking. Then you're already smart. Good for you."
But somewhere along the course of reading the article, I got the impression that he wasn't writing it for professional developers (at least, smart ones), but for people relatively new to programming.
But then, maybe I'm just stating the obvious, Cap'n...
Parent
Re: (Score:3, Insightful)
Re:Who wrote that article? (Score:5, Insightful)
That's a bit harsh. Apart from writing comments that are a maintenance liability, using C++ macros when constants would be better, mentioning the use of Hungarian notation that is a liability without mentioning the use that can actually be useful, advocating silent failure in the case of failed preconditions, misquoting Knuth and, to add insult to injury, citing a Wikipedia article in support when that article is currently tagged as having dubious citations (I know; I put the tag there a few weeks ago), failing to understand that games development is one of the few areas where early optimisation is basically a fact of life for some genres, and arguing that you shouldn't rely on programmers knowing basic language facilities like the pre- and post-increment operators in the C family, what was wrong with it? :-)
I am, of course, being facetious. As the author himself points out at the end, much of this stuff isn't obvious to newbies, and it's better if someone tells them earlier rather than later, so kudos to him for taking the time to write it up. I do wish people volunteering such material would get some peer review if they can, though, because the only thing worse for inquisitive newbies than no information is bad information.
Parent
Re:Who wrote that article? (Score:4, Informative)
Very little apart from failing to respect scope and not encoding any type information?
Parent
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();
}
Parent
Re:Who wrote that article? (Score:5, Informative)
The indenting in the selected code was not mine. It got screwed up somewhere between my machine and being posted on their site. I'll drop them a not and ask them to fix it.
No, I am not insane.
Parent
Re:Who wrote that article? (Score:5, Funny)
Parent
Re: (Score:3, Informative)
Re:Who wrote that article? (Score:4, Insightful)
Parent
Re:Self documenting code? (Score:5, Funny)
Parent