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 has some good pointers. But what if you not the one who wrote the code (Developer hired to finish another developers work)? What can I do to minimize the nightmare of work required to deal with tightly coupled, non documented, and hard to read code? It would be nice if there was an article that could help with that.
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.
Um... well, duh.
But aside from simply commenting, *updating* comments is also important, and possibly more so. Looking at the history of the TCP/IP source in OSX, for example, you see wonderful instances of complex code that's been updated as new operating systems have been built on top of it, but comments reflect the old behavior rather than the new.
A good programmer writes code to be executed efficiently by a machine.
A master writes code to be read efficiently by human beings.
That is all.
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!
In his "player_bullet::move_it()" example he should have moved all of his "[Small chunk of code.]" sections into a new function. Then, he could have called a function named "Calculate_bullets_new_position". This way, he is using the code to comment. It is much cleaner and easier to understand. Functions should rarely, if ever, have comments in them.
A unique way to learn a language: http://languageloom.com
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.
What about structured coding? I mean really, this stuff is so obvious, and then to not even mention structured coding?
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?
which, for me at least, takes more time away from trying to figure out what the goddamn code actually says.
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.
So where can I download "Kill Bad Aliens"?
It is notable that Tip 1, "Comment like a smart person", and Tip 2, "Do error checking. You make errors. Yes, you" can be sensibly combined into "Use contracts". Sure, you'll still need some extra comments to describe the function, but any comments about the parameters a function recieves and what it returns can be usefully written as contracts which provide both documentation and error checking. It also helps you to think about exactly what you intend a function to do, and assists greatly down the line when re-using code by providing clear testable constraints on what a function can and cannot do so you don't accidentally go misusing it.
Craft Beer Programming T-shirts
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>
Just wondering... because, offhand, I can't think of any other obvious reason to remain anonymous.
Just as I always wonder whether the people who find those amazing Easter eggs in programs were able to find them because they put them there themselves...
Use java
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.
error: 'I' undeclared (first use in this function)
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.
Additional to this, if the 'nice' language features give the user an error message and bails, what happens to the intermediate steps you were performing?
Not everything fits inside a nice transaction and sometimes things need cleaning up.
It might be the final step in a long list of sequential actions, or it might just be a few easy steps but you can be sure of one thing:
If your program keeps kicking them totally out of the system (no matter how 'nice' the message) for a stupid simple handleable errors they will be pissed off.
liqbase
/* insert meaningful and descriptive comment here */
An Indian-American Hindu committed to non-violent thought/speech/action alarmed by the global explosion of radical Islam
In Soviet Russia, Code comments YOU!
the foremost concern of any programmer used to be time. CPU time. How many cycles for this operation, versus how many cycles for that one. Now it seems like we have shifted our time concerns to programming time - the programmers' salary, the time to market, etc. Funny though how this tends to result in bloated, sluggish, bug-ridden programs that need at LEAST a patch or two before they even reasonably deliver what was promised on the box.
I guess we are lucky that the software "consumer" (and I use that word with the greatest contempt) has been "educated" to EXPECT a certain amount of crashes and bugs, and even DEMAND that the latest software come on 3 or 4 CDs instead of just one. I mean WOW, more is better, right? I wonder, however, which other industry (apart from maybe Hollywood) can get away with this? But sheep are sheep, and they will continue to eat what we feed them.
Seven puppies were harmed during the making of this post.
???????????
Reason: Your comment looks too much like ascii art.
Reason: Your comment looks too much like ascii art.
Reason: Your comment looks too much like ascii art.
... 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
Probably shouldn't. But possibly will be. And this hypothetical person won't be alone :(
"The Devil does not know a lot because He's the Devil, He knows a lot because he's old." -- unknown
"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
C, C++, and Perl are not "safe" in this sense. Python is. Not sure about other common languages.
Please check your errors. I see far too many projects coded in Python that just barf stacktraces to the console if anything unexpected happens.
Java has the advantage that it *makes* you handle your errors, even if you choose to do so poorly.
My God, it's Full of Source!
OUTSIDE_IP=$(dig +short my.ip @outsideip.net)
Several other tips may be added to those in the article. Some off the top of my head:
1. Each parameter to a function on a different line, for example
void foo(parm1,
parm2)
{
bar(parm1,
parm2,
parm3);
}
2. Put {} in an if stmt even if there's only one stmt. That is
if(condition)
{
action();
}
instead of
if(condition)
action();
3. Decouple
Avoid (note the word is avoid, not don't at all)
(stolen from a book, probably Writing Solid Code)
if (pizza type is this)
{
bake this kind of pizza
}
else if(pizza type is that)
{
bake that kind of pizza
}
else if(pizza type is the other)
{
bake the other kind of pizza
}
Instead do this:
if (pizza type is this)
{
create a pizza object of type this
}
else if(pizza type is that)
{
create a pizza object of type that
}
else if(pizza type is the other)
{
create a pizza object of type the other
}
pizzaObject.Bake();
4. If you want to use stmts like
if(5 == z)
{
}
think whether you also want to carry them all the way to
if(5 less than z) instead of if(z greater than 5) for the sake of consistency.
IOW, decide what you want: consistency or ease of understanding in your code. Sometimes they aren't compatible.
5. Always check boundary conditions.
6. Always check arguments to functions for valid values.
Why does the author use code that won't compile in the documentation?
Void change_score(short num_points)
I totally agree with TIP #2 though, #define should not have been dropped from some modern C derivatives though.
Why UNIX?
Its amazing how many people buy into this nonsense. I bet you think java stack traces are in any way useful to the end user as well? They must be a heck of a lot smarter than me cause I can't make heads or tails about what I should do as an end-user to address exceptions that are simply punted to the top.
In reality just the opposite is true. By buying into exception handling and just expecting things to be handled by passing responsibility up the stack what you are really doing is loosing control and ownership the system along with the ability to systematically verify that *ALL* possible conditions are handled acceptably well.
Its very easy to audit code and find all cases where return codes are not checked. Can you say the same for exceptions? How do you systematically know weather its ok for a particular exception to be punted or even what exceptions can possibly be generated by black boxes under you?
In some areas this may very well be an acceptable response. However trading off programmer laziness for lower levels of reliability especially in server codes is a rediculous tradeoff.
Using a language that ensures reasonable "islands of sanity" can be maintained (sections of code that can't fail unless the CPU does) is absolutly essential. Interpreted languages that do everything for you scare me sometimes however they are very useful for a wide range of purposes.
Perl has it.
-- Trinity in high heels carrying a whip: The donimatrix - there is no spoonerism
This relates to my biggest gripe about VB.Net. Any function can throw any exception, and you have no way of knowing, apart from looking at source code or documentation what kind of errors any specific function might throw. So basically all errors become runtime errors. This is one place where I wish VB.Net would copy from Java. If the function is going to throw an exception, it should be an compilation error if you aren't catching it. Also, related to this, when using ASP.Net, the debugger never breaks on uncaught exceptions, because effectively they are all caught at some level by the web server, so you have to break on all errors which causes a lot of wasted time as it breaks on internal errors in the .Net framework that are caught internally.
Anthropic principle: We see the universe the way it is because if it were different we would not be here to see it.
Trust me, you don't want to see what it was like before he realized this (say ten years ago). We're talking numerical constants galore. Pages and pages with no comments, just string constants peppered here and there. Lotsa externs. At the same time, he made great games which I loved to play. There were some bugs, but it was pretty good overall, so who cares, right? It's debatable as to whether I'd have done any better at the time. :-)
Ultimately it's a headache for him more than us, and I'm glad to see he's improved his practices. I hope he develops even more over time. Buy his games, they're fun and have a good storyline.
No.
No.
No, and you can't really know whre a cache miss will happen unless you know exactly what computer will run that code.
Your compiler knows that a const is constant, and won't throw memory (and lookup time) away with it. Unless, of course, you want to debug. And you shouldn't be thinking about cache size while targeting the (quite heterogeneous) PC.
Rethinking email
When possible, the comments should be written before the code, describing the flow of data, the steps performed, etc. This helps not only the poor slob looking at the code months or years later trying to figure out wtf is going on, but also helps the initial author write the code correctly the first time, and debug it more efficiently the next two or three or sixteen times.
In my years as a C coder, I found this to be a very helpful technique. It really helped me visualize what I was trying to do before doing it, and saved hours of debug time. And of course its always easier said than done, but it is a good goal to strive for.
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.
Comments should be used in one situation and one situation only, and that's where a piece of code cannot be refactored to clearly reveal its intent witout resorting to comments. For everything else, refactor to reveal intent.
Good example cases for comments are pieces of code that simply MUST do weird things that a developer wouldn't expect, often when dealing with crufty libraries that cannot be replaced and that require odd workarounds ala "// we have to call the open method twice because only a second call will completely open the connection". You simply cannot refactor around that kind of problem and as such a comment is the only option (short of replacing the underlying offending code.)
Again: For everything else, refactor to reveal intent.
" 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
These are ok for intro tips. Though if the goal is maintainable code I don't know if I'd be doing trivial stuff in C++.
Saying use "#define" everywhere is pretty much like saying use globals everywhere. It's better than using constants, but sometimes not by much. Keeping variables scoped as tightly as possible can help save some pain; globals can add salt to the wound.
Although java centric one must include information on how to write UNmaintainable code as well. The original unmaintainable code site (AFAIK)
I'm sorry, I'm to tired to be witty at the moment so this message will have to do.
So your fine with assuming that the other developers variable names accurately show the intent of the function? Not me.
And I will always take verbose over none.
The Kruger Dunning explains most post on
1. Commenting code makes sense. But the trick is to write the comments first. Then code.
2. Don't use #define! It has file scope, and something like "#define SQUARE(x) x*x" will mess up if you give it "SQUARE(1+1)". Use const instead. Use functions insead of macros. The optimiser will inline simple stuff like that.
3. Don't add redundancy to names. "MAX_NUM_ALIENS"? If it's a max it must be a number.
4. It's more efficient to add the input testing code in debug only. You tend to have nice things like assert macros to help test as well.
5. Don't be dogmatic about it. Just because Donald Knuth said it doesn't mean it's always true. Make sure your basic algorithms are efficient. You don't need a profiler to tell you that an array is going to be better for random access than a linked list.
6. Quite true.
Are you writing a quick tool or an application? For a quick tool, sure, you want a nice explanatory error message. But for an application, you might want to do something different. You might want to ignore the message or do your own error handling.
My favorite part is where he says: "if your C code requires you to know the difference between i++ and ++i, it is too complicated," because it makes me remember that being covered in my very first programming course, and that all code should perforce be understandable to someone who has finished maybe 1/3 semester of intro programming.
Especially the people I work with.
What is the point in following any of the rules when no one else on the team does?
"you deserve to have to maintain your own stuff 10 years from now."
I've heard people say they explicitly _don't_ follow the rules so they _will_ be the ones who maintain it 10 years from now.
"I've now had people from the support group stop me in the hall and compliment me."
And I've had people stop and say: "Who gives a sh*t? I know what I'm doing, I have to maintain it. If I leave a mess, it's not MY problem."
But if you do do all this, you could be laid off and replaced with someone who'll maintain your code more cheaply.
Can you be Even More Awesome?!
...it only takes one person on a team to not follow any of these guidelines to submarine the whole thing (if they aren't held accountable by management -- which all too often doesn't care).
Everyone else starts to think "what is the point? Bob is not following the guidelines and he got the same raise I did last year, why bust my ass when all we need to do is make sure it works?"
"Bob" doesn't care because he is the type who only cares that it works (or possibly not), and doesn't care if there is a mess because "I know the code; if I leave, it's not my problem anymore."
The article isn't redundant because the % of "Bobs" is high.
The behaviour of the code is not implementation dependent. It's actually undefined. (The C standard makes a huge distinction between the two types of behaviour). Not only is a C compiler allowed to return one of the 24 possibilities you thought of, but it's also allowed to return ALL 24 of them, go back in time, return another 9 that are physically impossible, have sex with your mother, and start World War 3 as a side effect. There is no limit on what can happen when you invoke undefined behaviour. Beware the wrath of standard C.
And it's saved me and others countless time, I'm certain. When it comes to C code I comment similarly to how the article suggests. It's fairly obvious. For example, consider this code. There's some tricky stuff involved in correctly emulating the controller inputs for the Intellivision, and the bulk of the comments revolve around explaining the trickiness.
That said, when I code assembly language, I tend to comment nearly every line. Why? Unlike C code, most assembly statements aren't very descriptive. For instance, "MVI@ R4, R0" means "read whatever R4 points to into R0." Ok, but what might R4 be pointing to? What kind of thing are you reading? What are you trying to accomplish? Imagine if you wrote your C code so that all pointers were named p and q, and all other variables were named i, j, k, a, b, and c. That's what assembly's often like. So, I use short per-line comments (or sometimes per group-of-lines comments) to add that missing information. Here's an example from Space Patrol. (In this particular example I also was counting cycles, due to the performance critical nature of the code. That's an entirely different story.)
All I can say is that comments like these have saved my ass more than once.
--JoeProgram Intellivision!
Having been a part of a mostly support team (read: virtually no new development) for the past year and a half I can tell you that each extra minute you spend tweaking those variable names into something meaningful, encapsulating logic into methods, writing good comments that are meaningful to someone who's never seen the code before - and generally, writing good, commented code will save you man-months in the future.
I can't emphasize this strongly enough. Spend the time right now to write it so damn well you never have to see it again, or waste man-weeks fixing it later.
If it's short and terse, it's fucking wrong.
If it's clever and creative, it's fucking wrong.
If it's convenient and "more compact" to write it all on one with ternaries or lots of nested or chained operations on one line rather than a method, it's fucking wrong.
They say that brevity is the soul of wit. But in code, brevity is the soul of insanity.
Write it well the first time and subsequent changes are easy. Writing it poorly the first time leads to buildings full of maintenance programmers. You don't want your code to be that bad do you?
Question everything
And no, it's not about wearing face paint when you're coding, smartalec! It's "Keep It Simple, Stupid!"
While a lot of the points in the article are painfully obvious (note however several people here criticizing the use of any comments in code. Arrrgh!), the last one covers my biggest gripe when fixing someone else's code. I call it "Gee, Mom, look what I can do" code. Spare me, please, the people who code to impress. And it's not just C and C++ that are susceptible to this (my particular "favorite" is crap like "if(a=14)". It's wrong on so many levels, even if it does work as intended -- note the single equal sign instead of a double one). Object Pascal, Basic, every language I've worked with has its own delightful way of letting you obfuscate the hell out of things, and shooting the *next* guy in the foot. Even raw assembler has a nice trick or two up its sleeve (anyone remember unimplemented opcodes?).
The only thing that impresses me is code that is simple (no huge, miles-long functions that run hundreds or thousands of lines), obvious, and works.
"My country, right or wrong; if right, to be kept right; and if wrong, to be set right." --Senator Carl Schurz (1872)
Where have you learnt C++? If you use iostream you can set them to throw exceptions: Exception Mask. It isn't done by default, because a failing IO-operation is hardly a big surprise (incorrect rights, nonexisiting file, out of data). I find exceptions overrated, they make it awkward to check the state and should be reserved where you really need to unwind the stack not for simple state checks.
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?
> if your C code requires you to know the difference between i++ and ++i, it is too complicated.
WTF??? If you don't know the difference between i++ and ++i you have no damn business messing with my code!
The second to the last paragraph of the article touches on the fact that it is obvious. And that paragraph expressed the hope that people were thinking that when they were reading the article.
The last paragraph mentioned that methods of writing maintainable code that may be obvious to you may not be obvious to everybody.
People get into programming through many routes and encounter many programming standards (or lack of them). They also, over time, change how they do things, especially when encountering unreasonable deadlines and corporate standards. Having occasional reminders of good programming practices helps.
Note that the 'References' section of the article has links to other tips on writing maintainable code.
I mean, someone should at least talk to ken and see if he is still a jackass, and reset the bool accordingly.
The creator of this post (Jacob Smith) hereby releases it, and all of his other posts, into the public domain.
Disclaimer: I have not RTA.
From the blurb: one minute spent writing comments can save you an hour of anguish
Ummm... Ok. We've seen this tidbit of good advice over and over again. Why is it that we keep pounding away at it? From where I sit, good coders will have good coding practices without having to have it tattooed into their foreheads. A good coder takes interest in being (tada!) a good coder. People who need these type of simple coding tips beat into their heads are not interested in being good coders. It's that simple yet we see it repeated again and again.
Maybe we just need bad coders to be kicked to the curb. There are plenty of us who are willing to follow the basic standards of good coding because we want our code to be understandable by others. We don't see commenting code as drudgery. We don't need it beaten into us.
Let the deadwood go, for once and for all.
I know it seems like a rant but I'm always looking for these good coding practices articles and they all end up saying the same 6 or 8 things. It's becoming as tedious as reading some gaming sites top 10 FPSs... again. We know everyone loves UT and HalfLife. Enough already!
Dedicated Cthulhu Cultist since 4523 BC.
It isn't done by default, because a failing IO-operation is hardly a big surprise...
Well, not really... it isn't done by default because the original iostream library was created before exceptions were added to C++, and changing the interface would have broken legacy code.
What is obvious to you may not be obvious to everybody. And the author admits that in the last two paragraphs.
Note that 'everybody' may know it but not everybody may practice it. Also note that not all organizations train people the same way. There are still those people who come up through the ranks and are not formally trained.
no, I've been coding for a whikle and apparently only I know this..grumble stupid old code...stupid cantractor..grumble grumble.
The Kruger Dunning explains most post on
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.
Unfortunately, this doesn't address the problem I was speaking of, for two reasons:
Still, if this were enabled by default, it'd be an improvement.
"Not an actor, but he plays one on TV."
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."
Structured coding would be for the more advanced programmers, especially in organizations that use it.
Some organizations don't have the support needed for structured coding and related practices. They often have legacy code that works and just needs tweaked to handle new conditions. Applying structured code would often require rewriting large parts of applications that may have been running for decades.
Of course, structured code could be brought in for the handful of 'clean sheet' projects that sometimes appear. And it could come into play IF the IT staff can convince the bean counters that a critical application needs to be rewritten to be more efficient and provide enhanced abilities.
*p++ = a;
*p++ = b;
*p++ = c;
vs.
*p = a;
p++;
*p = b;
p++;
*p = c;
p++;
The former is idiomatic use, the latter what a VB coder would do.
Looks good--I wish it were enabled by default.
"Not an actor, but he plays one on TV."
These points should be drilled into everybody who is learning how to program with an eye to doing it professinally. While the effort to do things right may seem like a waste of time now, it will prove invaluable later. (They may also want to improve their command of the English language so that the documentation is understandable, at least in those places where English is the language of choice.)
My biggest complaint about programming and software development classes is that they tend to focus on what I call 'clean sheet' programming. You start with nothing and end up with a series of programs that meet the needs of the class. The documentation you put in the programs meets the requirements of the teacher as specified in the class requirements. Then you put the programs aside and never revisit them again.
Unfortunately, the real world isn't like this. There are legions of SUPPORT programmers that will eventually have to maintain 'clean sheet' programs.
With this in mind, I would challenge any educational organization to have classes on how to do SUPPORT programming, especially for poor code. The students would NOT be permitted to rewrite things unless they can guarantee that EVERYTHING would still work after it is rewritten. And the results would need to have better documentation than the original.
Would be programmers might learn to do things right after experiencing what happens when they are done wrong. Or they might decide that accounting or truck driving is a better profession.
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
Don't write meaningless comments into your code, but instead share them with us.
What is also green are those people who think they should const or #define sequential sets. Use enum folks! Enums allow you to auto-increment/decrement your set, or re-order without having to re-type a bunch of numbers. Also, it doesn't hurt to add an end reference to your set for future use, eg:
// Do something.
... // Do something.
enum EFruits {APPLES = 0, BANANAS, CLAMENTINES, DURIAN, EGGPLANT, GUAVA, ELAST_FRUIT};
Then later in your code you can run over the enumeration as follows:
int dxFruit;
for(dxFruit = 0; dxFruit ELAST_FRUIT; dxFruit++)
{
}
The advantages are if you go back and add FIGS to the list, you don't have to hunt down every instance you ever used the fruit set to ensure your count is right, and you don't have to re-number GUAVA. I really hate seeing:
#define APPLES 1
#define BANANAS 2
#define CLAMENTINES 3
#define DURIAN 4
#define EGGPLANT 5
#define GUAVA 6
for(i = 0; i 7; i++)
{
}
Another advantage is to eliminate the referencing of "magic numbers". I just want to flog the person who write:
if (myFruit == 3)
{
}
I shouldn't have to spent a fortnight looking up what the hell 3 means!
Does Slashdot have a section for developers in training? If so, then the article should be there. If not, then having it here is useful for the newbies.
Heck, having it available as a reminder for the experienced developers makes it worth having here. People can get sloppy over time.
Of course, there are developers that are not well trained in certain areas. They may be able to crank out highly functional code ten times as fast as everybody else, but the maintenance cost of that code may be sky high. That is where these articles can come in handy IF the person is willing to learn.
Do you know any 'super programmer' whose code requires another 'super programmer' to understand, much less maintain? They may be the one that needs to see this article. (And they may also be the one least likely to view it.)
Perhaps the compiler should force you to write a short summary of each function's purpose, parameters, and return type. Otherwise you have no way of knowing, apart from looking at source code or documentation, what the function might do.
Seriously, if a compiler were capable of informing you that you haven't handled an exception properly, that would be great, but that's not what Java does. It merely looks to see if you appear to be handling it or that you've passed it up the call chain. For most GUI applications, 90% of the exceptions should be handled at the "top", so you have to add boiler-plate code all over the place to keep the compiler happy. Then if Sun adds or removes an exception from an existing library, all the code that is in the call chain is broken.
It's also very likely wrong, since the function will almost certainly be called (NUM_BULLET_MOVES_PER_SECOND*num_active_bullets) each second. This doesn't compile (unless you've done something stupid with the preprocessor). Lesson: Don't use winword to write C++. Again with the editing code with a word-processor! It's 'void', not 'Void'.
And you think that in the event that num points is -ve you should MAYBE throw up an error? Seriously? Because it's a bug in the caller and not the function, it's not the function's problem right? So it's best to ignore it right?
And what's with all the shorts? You realise that shorts suck on every x86 since the PPro, right? I could understand using them in a size-critical struct, but as loop counters? Bizarre.
Teaching the basics is great, I'm all for it. But this article stinks.
Most of the arguments for in depth comments are actually tell tale signs that code needs to be refactored. I don't think this article gives too good examples on how to comment you code, and it seems the author doesn't have too much experience in team programming with a fluid code base.
Some code will always require a comment, but if you can write code that doesn't require one, then IMO that's better than masking unnecessary code complexities with comments.
for (short i = 0; I < MAX_NUM_ALIENS; i++)
if (aliens[i].exists())
aliens[i].move_it();
I realize that for the game he's currently got, a short may be sufficient. But it's not hard to imagine a later version supporting swarms of aliens, with individually animated tentacles (each of which might count as an alien in that array), etc etc.
Personally, when dealing with code written in a statically typed language, I like to make sure I #define every single type I'm using, even if it's something simple like a short, because you never know when you'll have to change it. Probably makes it easier to go 64-bit clean, too, but in any case, it's something I learned from the Linux kernel, and it seems to just make a lot of sense.
He also didn't seem to be using a particularly object-oriented style, for a so-called C++ programmer:
Void change_score(short num_points)
{
score += num_points;
make_sparkles_on_score();
}
As others have pointed out, that's a damned weird coding style. But whatever.
The point is, as he says:And of course, what he's likely missing here is, we probably don't want the score to ever be updated without making the screen flash with pretty colors, either. So where is that function? Looks global, but it's been awhile since I've done C++. But if it is global, that implies that something else, somewhere else, might update the score for no apparent reason, and neglect to call make_sparkles_on_score().
And also: What else might we want to do with the score? Is the score the only thing we want to display and change, anyway? (Maybe we want to implement health later, or some other statistic that should be up there and flash some animation when updated.)
It seems to me, the obvious thing to do here is create a class for score, and override the relevant mathematical operators. (One of the few legitimate uses for operator overloading, but I digress...) Maybe it's just me, but saying change_score(10) seems a lot less intuitive than score+=10.
It would also solve the problem of that explicit short. I don't suppose anyone would ever want to change the score by more than 65,535? Wait, it's a signed short, so half that.
I admit some of these are a matter of taste -- some people don't like object-oriented programming. But I do think some of them are fairly obvious, almost instinctive for me.
Don't thank God, thank a doctor!
Six ways to create proper spread sheets!
Step 1: Color-code
Step 2: Reference other cells for static numbers in functions
???
Profit!
FTFA: // move all the aliens // this alien currently exist?
for (short i = 0; I MAX_NUM_ALIENS; i++)
if (aliens[i].exists())
aliens[i].move_it();
Note that this is an infinite loop.
Should be "i MAX_NUM_ALIENS;", not "I MAX_NUM_ALIENS;"
Kevin Smith on Prince
I don't want to be annoying, but: error handling is for handling errors, and finally is for finalization whatever else happened.
ie if something needed cleaning up, I trust a finally clause way more than any if (h_res==0) {clean;} I can ever write, and if it is handleable (is that e really necessary), well, handle it in the catch clause!
if you are a writer, write simple, stupid, clear, short, structured, descriptive, idiomatic codes
if you are a reader, read the code. if the code is a piece of crap to read, its comments are more likely so.
if you are a PM/architect or whatever your company calls those useless nannies, please, either your men are too stupid and none of your beautiful processes will change that, or your men are a little bit more intelligent than you and all your crappy cliches are nothing but insults
the title and the first two points are figuratively speaking, people with common sense will get it.
- refactor instead of rebuild: learn how to build slim and trim apis, optimizations rolled in over time
- take the time to do it right (when appropriate): spend the time to predict how the code might be used. If it's a hack for the current problem, and you know it, do it right.
- maintain it: keep libraries compiling and working together. Much less work in the long run.
- prioritize api bug squashing: get rid of own api level problems that happen over and over. Come up with a solution which will prevent the problem from ever occuring again.
- cache late: caching is a bane. Cache for speed when it works, not before. Avoid other types of sync issues (auto gen once at startup instead of caching on fs, etc)
- lessen test time: decrease the amount of time it takes to see if a problem occurs. Run, puke, fix, repeat... as quickly as possible.
- time spent is time gained: take the time to do it right and you get better at doing it right. Hack the dirty and you'll get better at dirty.
- gain instinct: code lots. you'll get to the point that you'll do it right even when on autopilot.
- lots of logs: log everything, and turn off the logging for deployment, wrap in if's to not affect speed.
- count on cpu juice and lots of memory: boxes are much faster now, don't worry about each byte, atleast not at first.
- allow yourself to make misteaks: you'll find out the reasons were valid in the first place.
It's a big field, made up of little simple. Get good at the simple, be good at the big.
the problem is how to fail safely.
VB (classic VB at least) defaults to fail=>terminate application. Turbo pascal for dos does the same. This was effective at preventing errors spiraling but can cause the user to lose a lot of work.
Delphi defaults to fail=>leave event handler and give user a criticial stop message box. This means the user has a chance to recover thier work but depending on the failure things may be left in a very bad inconsistant state.
neither solves the root problem which is going from deep in a nested tree of functions that touch data back to a state where the data is consistant while throwing away the minimum information possible.
Checked exceptions are a possibility but i susepect few programmers would tollerate having every exception checked and it takes very strong discipline to write good catch blocks for every exception.
Fail=>rollback is an option (this is what database servers tend to do) but it requires a lot of infrastructure to handle the rollbacks. This can be done at the OS level the compiler level or the application level but either way it is a LOT of overhead.
note: i'm known as plugwash most places but i screwd up registering that here somehow in the past and now can't register
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.
Found a bug in the author's code. This snippet will fail if it's in C. Otherwise, it's plain sloppy... // move all the aliens // this alien currently exist?
for (short i = 0; I MAX_NUM_ALIENS; i++)
if (aliens[i].exists())
aliens[i].move_it();
Also, repeat after me: DON'T WRITE VARIANTS ON THE SAME ROUTINE. While we're at it, take advantage of inheritance in subclassing!
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.
There are probably only a few ways to invite a can of geek whoopass more than to write a flawed introductory coding article and post it to slashdot.
... you know the list.
1) Claim evolution is false and/or use the oxymoron "christian science" seriously
2) Say, imply, or imply by omission that linux sux.
3) Get a portion of a formula wrong
4) Diss an MMORPG
5) Misunderstand something and write about it.
6)
The biggest flaw in this guys discussion of C++ code was that it was a C discussion, and partially incorrect or misleading. C++ should follow some format of OO software engineering principles. Use case narratives, swim lanes, class diagrams, etc before the first line of code is written. Make everything autonomous, make it accept fuzzy inputs, make it do what it does and do it well even if widget A is v 2.0 and widget B is 1.8. Use stubs etc etc. Treat each class like a separate piece of software you may use later and plan on it being (hopefully attemptedly) misused by some dumbass 3,000 miles away you've never met.
I think the biggest revelation for me as a beginning programmer was that before you code, you plan the code. It seems like a really simple idea. However, it seems that most people start with a loosely defined handfull of use case scenarios and just hammer that crap into existence. Then they're bought out by conglomerate X and vanish, money in hand.
I just comment out the following function calls before rolling out to production:
e _id);
stab_programmer($employee_id);
shoot_programmer($employee_id);
drown_programmer($employee_id);
strangle_programmer_while_sleeping($employee_id);
frame_programmer_4_embezzlement($employee_id, $expense_fund_handler);
mangle_programmer_with_factory_machinery($employe
insert_cyanide($employee_coffee_cup_id);
break_nerve_gas_capsule($employee_cubicle_id);
illegally_download_music($employee_computer_id);
hide_bodies();
I've already been fired twice from a Furby and an Aibo factory, but the Recall Process was efficiently quick.
Solomon
"Twice half-assed makes an ass whole." --Solomon K. Chang
The idea that comments add to code maintainability is arguable at best.
As a programmer who has worked with hobbyist, private sector, government initiative and open source projects I can tell you that like the code itself, comments are not made equal.
A prime example is when a given function F allocates, but does not free memory on the heap in say C/C++ it would be wisest to document this with relation to the function. However comments which appear in source code are not necessarily the best documentation format, hence the scale of the project and the logistics of contractual obligations are the most common likely driving forces in systems documentation.
There are of course sloppy programmers, documenters, managers and executives in nearly all information technology organizations, so if you have lots of options with respect to your career, have a good look at the environment the software is being maintained in before committing to a project.
Personally the best case situation is where documentation is relative to version and off board in an appropriate file format which when displayed, allowing you to see documentation and associated source module in an agreeable visual and ergonomic format. Where if you make a change to source code you MUST update the documentation when relative line numbers change in order to keep the documentation in synch. (No, adding a blank line just shouldn't make it as a new version... "you cause it, you fix it" rule)
As far as religions go, I'll stick to the following.
John 14:6, John 14:28, Genesis 3:24
Thank you and have a nice day,
AS A : Systems Analyst
pragmatic programmer says that your code already says what it does, and if it doesn't then you haven't used reasonable variable and function names. Commenting it is repeating it, and fails DRY!
Comment why code needs to do certain things, it makes more sense and may help people.
Heh, I wish strict and warnings were enabled by default too :)
Trouble with using Fatal though is it confuses people who are good at catching their exceptions, because it just looks plain wrong. eg:
The exception handling is there, but because every open you see in good code is followed by an exception handler, it's hard to resist the urge to "fix" it.
I've used it in personal stuff, but not in any production code...
-- Trinity in high heels carrying a whip: The donimatrix - there is no spoonerism
Junior to mid-level programmers (those in the field less than five years)... please do yourself a huge favor -- check your ego and read the book "Code Complete" by Steve McConnell. (Hell, *all* programmers should do it).
That single book will teach you to write maintainable, understandable, and clean code. It has examples in C, Pascal, and Ada, but the concepts contained within are applicable to all programming languages (except for maybe brainfuck and whitespace). It will also teach you what bad code looks like (coding horrors).
Make no mistake. This book is the definitive work on how to write good code.
If it was hard to write it should be hard to read.
/* doFoo() : This function explicitly turns on the foo flag and does foo. */
def doFoo() {
foo = FALSE;
stopDoingFoo = TRUE;
}
Oops... forgot to change the comment didn't ya? A TEST would have made a better comment. A test that would FAIL when it's no longer TRUE.
IBM is evil
"Mit der Dummheit kämpfen selbst Götter vergebens." would be the grammatically correct version of the sentence.
For example right now I have to work with a code made by other people, with there own lousy implementation of a regular expression parser. Crazy. not only it is probably full of bugs, but it also makes me waste my time having to learn there API that I will never use again.
Someone mentioned this earlier in the thread, but it's really important. All good programmers I know use assertions liberally throughout their code. It will not only catch errors, but also serves to document the code as it makes the underlying assumptions clear to anyone looking at the code. Asserts are the C way of specifying preconditions, postconditions and invariants... Or to put it more simply, every time you think 'this pointer better not be NULL when entering this function' you do
assert(pointer != NULL && "You're a moron for calling this function with a NULL pointer!");
The && "comment" is a nice trick for having additional information when your assert fails...
The interactive way to Go -- http://www.playgo.to/iwtg/en/
I can't help but wonder if those who expressed difficulty with the parallel programming subject were in the non-CS crowd.
If this is your first exposure to writing maintainable code, then odds are you shouldn't be programming for a living. Also, consider how bad IBM's code must be maintenance-wise if this is considered news! DOH!
What's really news is that you could not do any of these maintainable code options and easily have a long career of programming. All your projects will be crap, but unless you seriously break something, it's unlikely you'll be fired just for being inefficient.
stuff |
Apologies, this is all "code",
// You should never get here, unless you have a funny definition of short and long
Considering
for (short i = 0; i < MAX_NUM_ALIENS; i++)
(N.B. corrected case of "i")
There are even more nasty problems that could occur if down the line they decide that the maximum number could be very large and forget to change the types of the counter, consider the following, where we are "good" and use "typedefs".
#include <iostream>
/**
* A warning to all on mixing short and long.
*/
int main(void) {
typedef short counter_type;
typedef long limit_type;
limit_type max_counts=65537;
counter_type i=0;
std::cout << "max_counts=" << max_counts << std::endl;
for (i=0; i<max_counts; ++i) {
if (i%128 == 0) std::cout << i << std::endl;
}
std::cout << "i=" << i << std::endl;
return 0;
}
Do you (or other people out there) make use of compile time asserts, or numerical traits to avoid this type of problem? Failing that do you have any solid tricks to avoid the above, apart from the obvious e.g. making sure the types of counters and limits are the same?
A common problem I see with C++ is that you can do things in a very solid manner (e.g. type_traits, algorithm for_each) however at the potential expense of obfuscation - there's something comforting in a simple for loop... maybe that's just me.
Any comments?
Be nice to people on the way up. You will meet them again on your way down!
missing chances or catching them what makes billionaries of this sort.
Read radical news here
I've met people that can write some pretty ideal code, but the problem is these are usually very difficult people to work with. Idealism is a nice start, but when you get into the gray area of people and personalities it's not a good fit. Why? Because everyone has a different idea of what is "right". There needs to be enough flexibility on a team for people to accept this or projects go tits up. When they do, the Idealists always stand around for a couple days bitching about it while everyone else slops things together to get them out the door.
Clue: At this point, nobody really cares hearing about the "right" way to do it. We just want to get the damn thing done. Standing around, pissing-and-moaning, is like putting and anchor on a sinking ship.
boycott slashdot February 10th - 17th check out: altSlashdot.org
You, sir, are a legend. The Exile games rule. I bow to your greatness.
Maybe I just don't remember correctly, but I remember that java supported the "throws" keyword, which when put after the method, let the compiler know that your method was capable of throwing an exception. Also, when that method was called, it would require that you catch the error, and do something about it. Or at least continue throwing it up the chain. I would like to know when changes are made to the API such that an exception would be thrown so that I could at least handle it correctly. As it stands with VB, you have no way of knowing which exceptions are to be thrown, and therefore you can catch everything at the GUI level, but if you don't know what types of errors to expect, then it's hard to handle them properly. Also, it stops you from doing any proper clean-up in the immediate area where the error occured.
Anthropic principle: We see the universe the way it is because if it were different we would not be here to see it.
It's certainly an unfortunate reality that there is much material about programming on-line, but relatively little of it is really good, and it's by definition impossible for someone new to a given area to work out for themselves which is which. Indeed, it's might be that the best technical content isn't the best written, and that the wonderfully easy-to-read stuff is littered with dangerous misconceptions and technical errors.
If you've got the patience, I've written a few fairly detailed posts here in the past with good starting points for those learning various aspects of programming: on-line resources you can usually trust, book lists, that sort of thing. Google seems to do a reasonable job of handling Slashdot's archives, so go ahead and browse. Just ignore me when I'm ranting on some political subject. :-)
If there's one piece of general advice I'd give for those looking to learn on-line, it's learn to use Usenet. Unlike your average programming web site, programmers who frequent the various language newsgroups tend to be pretty competent. More to the point, their replies to questions tend to be effectively and constructively peer reviewed, making them more accurate and often more insightful than any most people's personal web sites. There are newsgroups for most popular programming languages, as well as for many specialised programming areas, programming for different operating systems, using different programming tools, etc. You can access these using services like Google Groups if your ISP doesn't have a Usenet server. Look for the comp.* hierarchy, particularly comp.lang.* for different languages (and alt.comp.lang.learn.c-c++ if you're learning either C or C++).
Most of these groups have a decent FAQ that you should read before starting, to determine the best place to ask your questions. For instance, questions about particular operating system APIs or development tools are often off-topic in the generic programming language newsgroups, since they will only apply to people using that language with the specific OS or tool, but the same question might be perfectly reasonable in another group. The FAQs also tend to have good lists of books and tutorial/reference web sites you can trust. If you start from those, then for the most part, things they link to will also be fairly trustworthy. Just don't go and put something like "Java tutorial" or "learn Python" into Google and expect the top ten hits to be great, because most of them will probably be hobbyist sites written by enthusiastic but not terribly well-informed or experienced people.
If you disagree, post your argument. (-1, Overrated) isn't your personal censorship tool for views you don't like.
Can you really write code so cleanly that doesn't need comments?
When writing code for a real system (and not a theoretical one) you come across situations (boundary cases, platform limitations, etc) where you try something and realize that it doesn't work. Negative knowledge is valuable to preserve and the best way to do it is using comments. Whether you can write cleanly or not is completely irrelevant in these cases.
Using his example:
Instead, use:
advance_bullet_position();
find_bullet_collisions();
check_bullet_path_end();
it's got me send he
Patriotism is a virtue of the vicious
I would say that the first mistake is using C++ at all for "Kill Bad Aliens". Even coding it in Ruby would probably be fast enough for most machines, though I'd probably use Python or something.
The second problem here is, why would you have a separate type for counter_type and limit_type? I guess I can imagine something like this happening in a larger context, but it seems like the above should probably be the same type.
As for what I'd do to prevent the above, I'd use unit tests. That way, I'd know exactly where the infinite loop was, as soon as I changed the type of either limit_type or counter_type, and it probably would not take me very long to figure it out from there.
I understand that a simple "for" loop may be comforting, I grew up with them too. But most of the time, there's no reason for it, and you'd be better served with a Ruby-like iterator. Something like:
max_counts=65537
max_counts.times { |i|
puts i if (i%128 == 0)
}
That's assuming you actually need to count to 65537 and have i in the first place. Usually, you have a for loop because you need to iterate over something, which means you'd be better served with something like a foreach loop:
my_stuff = ['one', 'two', 3, 0.4, SomeObject foo, somevar, and, so, on]
my_stuff.each { |x|
puts x
}
Of course, the especially cool part about Ruby is that I'm ignoring types here entirely in the values I'm printing. In general, all I need to be able to print an object is for it to have a to_s method, allowing it to be implicitly converted to a string -- which I think is a lot nicer than overloading bitwise operators, the way iostream does.
But you can see here, even if I was concerned about integer types in Ruby -- and I'm not, Ruby seems to automatically flip over to the BigNum library as needed -- the latter form avoids even needing a counter, or assuming that what I'm iterating over looks like an array at all. It's usually much more efficient to implement one "each" method than to overload [] for strange types. Consider something like a parser:
xml = new SomeParser('hithere')
xml.each_token( |x|
do_something_with(x)
}
I'd say the majority of problems match much better onto something like that, where it can simply walk through the string, parsing as you go, than something like this:
for (i=0; i
In that example, it now has to parse xml's string entirely at least once to get the number of tokens, and it'd really be better off just caching it as an array, since we could theoretically want random access to it.
Now, there's nothing stopping you from implementing all of the above, and more, including the traditional way to do it:
while (defined(t = xml.next_token))
do_something_with(t)
end
But there's another disadvantage for simply asking for next_token. You now have to remember to reset it somehow, otherwise the next thing to want to iterate through is going to get a big fat NULL.
Also, you've lost something else: "each" is generic. There are standard library functions, and certainly user libraries, which know how to use each. Even if you can't think of a use for that, it helps that you already know how to use foo.each, even if it's something weird like foo.each_token. And maybe it's just me, but it looks a LOT clearer than certain other libraries I've used which pass around callbacks, even if it's effectively doing the exact same thing.
Despite the fact that most of my examples are in Ruby, I really don't like Ruby. I think it's like Perl, but with even more emphasis on strings, and it looks like it will be dog-slow for a very long time. But it does make for very quick hacks, and it's certainly sufficient for a Kill Bad Aliens game.
Don't thank God, thank a doctor!
Erm... One of those examples had xml, and I forgot to escape it for the web... that should be
/><c>hi<d>there</d></c></a>')
xml = new SomeParser('<a><b
Also, the example's a bit contrived, given that real XML parsing in Ruby is usually handled by REXML, which does do all the parsing upfront (as far as I know; there's enough abstraction that it might not), and stores it in not just arrays, but recursive object structures that more closely reflect what XML looks like.
Don't thank God, thank a doctor!
"I would like to know when changes are made to the API such that an exception would be thrown so that I could at least handle it correctly."
And you think getting a compile errors is the way to figure that out?
"As it stands with VB, you have no way of knowing which exceptions are to be thrown.."
Of course you can, it's documented. How do you know what any method does if you're not checking the documentation?
Is this guy kidding me? In the intro he claims to be using C++, and then the HEADLINE of one of his points is to use #define? WTF. Get this guy out of here
1. Get paid to write code (Mine). 2. Get paid overtime to fix code (Mostly other people's). 3. ??? 4. Profit! In this case "???" consists of a manager asking me politely to comment my code once a year, while simultaneously offering me a nice pay increase. Having said that, the only code that I've come accross that I simply couldn't figure out what was potting was usually my own, and usually as a result of "We told the client this will take a week to develop, but they need it tomorrow. Here's some money, make it so." Hey, if it works and the client is happy, I'm happy.
1. It was written for those that are just starting out with programming----that's obvious. But all of you would rather point out how obvious the "tips" are, while missing this VERY obvious point.
2. Who cares if the code actually works or not? Are you going to copy his game? Are you going to use his work on your resume? NO....and if you do......lol. It's written to show a point, just like any beginner tips.
3. The point in generalizing with things like teaching tips to people new to programming, isn't the code. Its how its written. And while I cringe at the idea of languages that don't follow set way to....say indent, you can't say his exammple's wouldn't prove useful to someone that's never programmed before. Personally I wouldn't have used a game to show it, but anything that can catch the attention of anyone new to the religion is good, so I can see why he did.
Some of you are acting like when you first sat down and typed in "Hello World!" you ALREADY knew where and when to comment, damn I bet most of you C programmers that taught yourself how to program started out saying shit like (of course out loutd) cowt gets "Hello World" instead of saying c out gets "Hello world!". For most of you I bet it was some time before you even had your first "away from desk" coding experience, you know what I'm talking about....that last block you couldn't get right while you were at your desk, now your in Burger King writting down ideas on a napkin during your lunch break.Now, 2 years after you start writing code that's worth a shit you wanna pick apart the work of anyone that tries to help the guy you used to be.
This is Slashdot! Give me the latest gadget, bug, or OS project! This ain't english class so don't confuse the two!
How not to get sued by Atari for a Bazillion bucks.
Comment removed based on user account deletion
What's wrong with MoveImmediately rather than MVI?
Deleted
Umm.. Hiding complexity is a GOOD THING. Think about this, internalize it, and embrace it.
Most of the time, if confronted with a function that makes a peanut butter sandwich, say called make_pb_and_j() then we expect to find simple high level instructions on how to make a pb_and_j, something like:
We don't want to find instructions on how to go to the grocery store and buy the bread, or AI on how to earn money with which to buy the bread, or instructions on how to grow the wheat or till the field, or even to make the bread. ( or peanuts or the strawberries for the jelly, or how to fire clay into a plate or smelt ore into steel to make the knife etc )
All those complex actions are necessary in order to make a peanut butter and jelly sandwich, but I don't need to know about them to make a pb and j because in the above example this complexity was nicely hidden in the get_xxx_from_xxx functions. Given a get_fluff() function, then if I want to make a fluffernutter, then I need only change a few lines.
What too often happens is that someone is given a make_pb_and_j function and they need to make it into a make_peanut_sandwich( -topping ) function that can either make a fluffernutter or a pb_and_j. Instead of creating a get_fluff function, since fluff is pretty simple to make, they lazily add the logic of what would have been a get_fluff function inside an if block: ( I had to delete the example because of the lameness filter )
That expanding out all the steps into if-blocks makes for hard to read code is obvious. They teach programmers not to do this in CS 101, but that course is hardly necessary to appreciate the common sense fact that information hiding is a good idea.
Now if a programmer wants to be able to maintain their code, then they follow common sense good practices, but in a group, this falls apart. The goal of a programmer is usually not to create maintainable code. It is to collect another paycheck without getting fired. Writing good, or maintainable code is bad for one's career. Writing good, elegant, maintainable code and working efficiently are only good goals when you yourself reap the benefits and suffer the consequences resulting from the quality of the code - i.e. you are your own boss.
Consider what happens to the 'good programmer' who insists on writing good code, in a group of 'bad programmers' who don't insist on any such thing:
Someone, a 'good programmer' who takes the time to produce easy to read, maintainable code takes on the extra work entailed by producing quality product. But they are measured against 'bad programmers' who just add another nested if statement to whatever 20 page long pile of crap method they are coding..
Now every bit of 'good code' that the 'good programmer' produces is MUCH easier to read and work on than the crap everyone else produces. Everyone who has the pleasure of being assigned to work on it gets their project done either ahead of schedule or with time to fart around on slashdot. Working on good code makes you look good.
But working on bad code makes you look bad because you have to read and understand horribly byzantine piles of interconnected, pasted and unfactored crap to m
...