How to Keep Your Code From Destroying You
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."
Captain Obvious?
Damn, that game looks sweet. Anyone know what it is?
-- www.globaltics.net
Political discussion for a new world
Comments, clarity, constants. If you're not doing this in your daily coding exertions, you deserve to have to maintain your own stuff 10 years from now.
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.
Mit der Dummheit kämpfen Götter selbst vergebens.
That has to be the worst written article on cleaning up your code I've ever read.
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...
Good quote, too many chars. Seriously, the slashdot 120 char limit sucks!
C, C++, and Perl are not "safe" in this sense. Python is. Not sure about other common languages.
"Not an actor, but he plays one on TV."
The article is suited for beginning programmers, I guess. Here is the summary of the tips.
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.
In Soviet Russia, code destroys YOU!
"One minute spent writing comments can save you an hour of anguish."
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.
We know where leadership by an anti-intellectual "strongman" who scapegoats minorities and likes boisterous rallies goes
I thought I'd make two comments on things that I think he got a bit wrong.
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.
Breaking Into the Industry - A development log about starting a game studio.
Not that I don't use them a lot myself, but I thought that in C++ you were supposed to try to avoid the use of macros altogether, and in particular were supposed to use consts for, well, defining constants.
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;
"How to Do Nothing," kids activities, back in print!
The comments I like best are correctness invariants or induction hypotheses. Like the ones you'd use to prove that your algorithm is correct. For example:
// Invariant: if an object is ReadOnly, then everything that points to it is ReadOnly
// Invariant: if an object is writeable, then everything it points to is writeable
// Invariant: when you call CopyOnWrite(), you get back a writeable object
// Invariant: The ReadOnly flag starts false, and will change to true during the object's lifetime, but can never change back to false.
The correctness invariants for a data structure can also be embodied in a "sanity_check()" function for that data structure, and also in test cases. But the correctness invariants for an algorithm are rarely embodied in any code anywhere. But they're the ones that give you the programmer an assurance that your code is correct. That's why they're so important.
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?
Actually, it's not necessarily a bad thing for your code to destroy you. Just make sure you don't dereference any old pointers to you afterwards.
People who are just starting their careers as programmers are allowed to read articles too. Just because something is aimed at a population less experienced than you doesn't mean that it's crap!
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.
It has functions...
Best Slashdot Co
Relying on the environment to do all cleanup leads to bad code.
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.
liqbase
To keep my code from destroying me, I shouldn't #define MAX_ALIENS_ON_SCREEN_AT_ONCE to equal 100. That's way too many aliens to survive.
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.
<xml><I><am><so><damn>Web 2.0</damn></so></am></I></xml>
Ok, yeah, it's redundant. But is there anything wrong with going back to the basics? Look at sports figures ( and I chose sports for an analogy because most pro sports are very good at filtering out all but the best, and the very best get to the top by proving that they are better than the second best in head to heah competition, something that programmers almost never do. ) The best often are known for continually going back to basics.
Lombardi was known for his comment that if you block and tackle better than the other guy you win.
Magic Johnson was known for being on the court an hour earlier than the other pros and practicing shot after shot.
And Bobby Fisher's guide for beginners is still the best because he knew the basics like nobody else.
Yep, no you need to include the "Back To School" basic programming techniques, like Rodney Dangerfield might include.
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.
except friday.. I want to go home. I'll clean it up on monday.
-- 'The' Lord and Master Bitman On High, Master Of All
In Soviet Russia, Code comments YOU!
... if your C code requires you to know the difference between i++ and ++i, it is too complicated
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.
If other reasons we do lack, we swear no one will die when we attack
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." - Brian W. Kernighan
"The Devil does not know a lot because He's the Devil, He knows a lot because he's old." -- unknown
Rule #1 of Systems Programming: Never check for an error you don't know how to handle.
."
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!
Any sufficiently advanced technology is insufficiently documented.
" For example, in real life, I probably wouldn't give constants names as long as I did in the previous section. I just did that so that you, the reader, would totally understand what they meant without any context. In the context of the program itself, instead of:
#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.
The Kruger Dunning explains most post on
Don't deploy your code to the ED-209.
I'm trying to teach myself to set people on fire with my mind... Is it hot in here?
First of all. Don't write a program called MCP. Second, don't work for a company called Skynet.
I wish he'd included a link to the Wikipedia article on Hungarian notation 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.
It may be a dead horse to good coders but it is essential that the accounting staff know such things. Such articles can be used to educate them. The articles can also be used to train the newbies they hire.
Unfortunately, there are organizations where the bean counters and CEOs want results NOW and don't want the staff to 'waste' their time on documentation and good coding practices. If you can get your quick and dirty code completed for that 'one time' application up and running really fast, they will love you for it and the effect it has on the bottom line. If you insist that documentation and special good coding refinements are needed and it will take half a day longer, they'll tell you not to waste your time.
Then, a month or a quarter or a year later, they will ask you to take that 'one time' application and modify it for slightly different parameters. And because you did it before, they will expect it to be done in a fraction of the time.
It is an endless treadmill with some organizations. While doing the right thing usually costs less in the long run, getting the results NOW often overrules doing the right thing.
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.
"Not an actor, but he plays one on TV."
As the person who actually wrote the article in question, I'd like to thank you for your comments and respond with a few of my own.
* 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.
- Jeff Vogel
Spiderweb Software
Fantasy RPGs for Mac and Windows.
http://www.spiderwebsoftware.com
Refactoring code to make things as clear and obvious as possible is, of course, a good idea. But it is no substitute for actually stating your intentions in the form of comments or contracts. A maintainer coming to search for a bug in code that is clear but uncommented can only discern what the code actually does as opposed to what it was intended to do. Thus if the bug is a result of a gap between intended functionality and what got implemented (as happens often enough to matter) it makes things a lot harder to track down. If you an state clearly and simply what a block of code is intended to do, do it -- it gives a maintainerr something to verify against.
Craft Beer Programming T-shirts
No, this has to come from no less than Field Marshall Obvious.
"Comment like a smart person."
Let's all "program like good programmers" while we're at it, or, even better, "invest like lucky investors", "dance like a professional", "socilize like an extrovert", "copulate like leporids", "wield power like a super-villan", and "fly like Superman".
Besides, nice idea in principle, but based on two grievously flawed assumptions: the programmer is a smart person, or at least knows what one is like, and the next programmer reading it will be a smart person.
I've tried this both ways over the years, and in my experience, separating large functions into small, well-named ones with clearly delineated inputs and outputs is a big net win for maintainability. It makes it much easier to see what is going on, because it doesn't force someone reading the code to have to confront the whole mess at once. They can dig deeper into only the subfunctions that are relevant to the problem that they are trying to solve, without worrying that some non-local effect of a prior block of code will confuse the issue.
Re. file scope: if you can figure out where to put function prototypes and const definitions such that they'll be visible in the right places, how is appropriate placement of macro definitions any harder? They go in the same place.
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.