The First Rule of Programming: It's Always Your Fault

Apparently you have never used any of borland’s tools. Access violations run ramped, restarts are required. Hell, one time it wasn’t calling the deconstructors for statically instantiated class variables. Yes, most of the time it is the programmers fault, sometimes it really isn’t.

Whenever I get stuck on a really annoying bug, something that seems to be really obvious but I just can’t see, I just ask someone else to take a look.

I take a few minutes to explain the problem, and the bug. Usually, just explaining it to someone else is enough for me to ‘see it’. If it is not enough, they usually find it. If they don’t find it, we usually find the problem together.

This reminds me of this entry, which deals with the same topic.
http://whatiseeinit.blogspot.com/2008/02/bad-worker.html
I always enjoy reading your entries. =)

scenario: The user saves data, exits the program, and shuts off the computer. On next use, the data file is messed up.

Question: Is it a defect not to use FILE_FLAG_NO_BUFFERING, FILE_FLAG_WRITE_THROUGH, nor to invoke FlushFileBuffers before closing the files?

Abdication of responsibility.

You see it more and more, especially with this ‘new’ generation.
It’s like your first example; the programmer could not believe that it was his code causing the select problem because he could not believe that HE was responsible for the problem.

Remember, always take responsibility for what you have done, both the good and the bad.

If you are wrong admit it and fix it. You earn far more respect with that approach than any other.

Oh yea, by the way, most of the time even if it is the OS, framework, compiler, the blond in the cube down the isle fault; there is usually a work around to get around the problem. So, even if it is the above mentioned fault then it’s still YOUR FAULT for not finding the work around.

TAKE RESPONSIBILITY, in the long run you will be glad you did.

By the way Jeff, how is your venture going? Well I hope…

Regards,
John McPherson, Senior Software Developer

There are exceptions however COUGHSharePointCOUGH

To those who say Jeff is saying the problem is always in your code:
“Start with your code, and investigate further and further outward until you have definitive evidence of where the problem lies.”

One only needs to read.

To those who imply the article is wrong, because one time the bug wasn’t your code:
The plural of anecdote is not data.

What if you’re cleaning up other people’s code and you found out that that they code worse than you…then after the clean-up, the enhanced code (with your fingerprint) is failing while the “junky” original code you started with works?

Talk about hang-ups.

It depends…

Once upon a time, we have a website that don’t work or Firefox 1.0. Basically all buttons have no response when be clicked.

It was later revealed that before Firefox v1.0.0.3, they forgotten to add the click handler for image buttons (“input” tags with type=“image”) so the click events won’t fire.

It’s almost always better to check for known defects after the first round of search for bugs but before starting the next round. In this way you can make sure “it’s your fault for this bug” and no excuse.

I’m agreeing with the general consensus. Use the following algorithm:

while ((developer.desparationLevel() MADNESS)
(! problem.solved()))
{
if (developer.getYearsExperience() = 5) {
debugger.use();
} else {
tweakFrameWork();
}
}

Seriously, todays platforms and frameworks have so many moving parts with potential incompatibilities that you can’t take anything for granted. Although I still blame myself first… habit.

At my first full time programming job, I was writing C code using a library written by another developer. Being a rookie, I made silly off by one errors, blew up the stack and screwed up memory. Sometimes it would crash in my code, but sometimes the library would crash. For example, I called a routine that required a preallocated memory block that wasn’t allocate to the size I told the library it was. Crash.

I can still remember the argument now.
“Your library’s got a bug”.
“No, your code’s got a bug”.
“But it crashes here”.
“Yes, because you’ve passed it garbage here and here and this handle is uninitialized.”
“Oh, yeah, let me fix that … oh it works now - thanks!”

Since then I’ve assumed all bugs are my fault, even when they’re not.

Now maybe the library should have been more defensive and not simply crashed. But, maybe it was actually the right thing to do. It forced my client code to call it in the way it was designed, rather than just silently failing and involving much hair tearing out.

I get the same thing when I mess up with STL - you get thrown into a line of source code that looks uncanningly like line noise. At that point, I’m praying that the bug’s in my code, cause I’ve got more of a chance of reading that!

Forgive me, but I disagree somewhat with this idea that “a good carpenter doesn’t blame his tools”. A good carpenter recognizes his mistakes it is true, but he also recognizes how his tools allowed him to make those mistakes and seeks to improve the tools. Perhaps the straightedge is off, or the nails weak, or the wood warped. Tools and materials need to be resilient to cope with any reasonable carpenter.

You can’t create quality products when the tools are working against you.

Sometimes the problem is indeed in the system rather than your own code. Back in the 80s I was translating some astronomical utilities into S-Basic to run on a Kaypro 10. One of the programs used the greatest integer function int(x) extensively, and when I ran some test cases the program would sometimes give right answers and sometimes give wrong answers with no apparent rhyme or reason. I couldn’t find anything wrong with the implementation of the formulas, so I inserted a number of print statements to print out intermediate results as the program ran. I finally determined that the int(x) function as implemented on the system would return wrong results if the floating-point number x was exactly a negative integer, e.g., if x was -3.0000…, int(x) would return -4 instead of the correct answer of -3. So I fixed it with the kludge of writing a function to use in place of int(x) which tested the argument to see if it was a negative integer, and if so added “1” to the result of calling the system function, otherwise returned the result of the system function . . .

Great article Jeff.

Does it really matter that much? Programmers can just swallow a little pride and say, “Hey it’s my fualt.” Yeah I know that you might have spent HOURS AND DAYS on that stupid code but still, its just courtesy to do so.

lession 1.
don’t outsource your code to developing countries!
lession 2.
cheaper code cost more down the road.
lession 3.
write in the language of the code, i.e. ENGLISH

Actually, being a Mac developer, I can assure you, I had issues like you described in the first sentence all the time. But believe it or not, I wrote more than a dozen of bug reports to Apple and in the majority of all cases, they said “Yes, we can reproduce it and yes, this is a bug WE must fix”. Before Apple admitted that, I ran through all the stages of anger, wanting to throw that damn machine right out of the window, sadness, why doesn’t it work ::sniff::, to desperation, no it will never work, I can’t ever make it work, it’s hopeless. It really brightens your day if you then finally find out “Thanks God! It’s not my fault! :D”

Hey T.E.D., looking at your code, looks like you flipped the input pipes, was that the bug?

In response to:
Heh. Rather timely.

I spent the better part of yesterday trying to figure out why the child process in a CreateProcess wasn’t reading from its input handle. The output handles it was writing to fine, but no matter what I did it wouldn’t read from the input one.

Below is the chunk of code I found the problem in. See if you can see it too. :slight_smile:

// Make the shell’s input pipe
if (!CreatePipe(si.hStdInput,Shell_Input,sa,0))
throw std::string(CreatePipe failed because ) + Error_Message();
ZeroMemory(si,sizeof(STARTUPINFO));
si.cb = sizeof(si);
si.dwFlags = STARTF_USESTDHANDLES;
si.hStdOutput = GetStdHandle (STD_OUTPUT_HANDLE);
si.hStdError = GetStdHandle (STD_ERROR_HANDLE);

Of course originally the ZeroMemory call wasn’t in there, but I found that CreateProcess did nasty things without it. Doh!
T.E.D. on March 21, 2008 06:13 AM

I’m finding the level of defensiveness to this post not only humorous, but indicative of how true Jeff’s ultimate point is.

At any given moment, you’re either part of the problem or part of the solution. Pointing fingers and dishing blame is being part of the problem. Taking immediate ownership, regardless of whose fault it really is, instantly takes you a step toward the solution.

Great post, Jeff.

This reminds me of two rules of software:

  1. Statistically speaking, a bug is more likely to be in code higher on the stack than lower.

  2. The problem is between the chair and the screen.

One of the joys of software development is what we live in a very predictable world, one where once you understand what the code is doing, everything makes perfect sense: there really are no “ifs” or “maybes”. You can spend days debugging a problem, convinced that the world is indeed flat, or that gravity is no longer in force, only to find the bug, which when fixed, makes you feel that harmony has once more been restored to the world. And it is this what makes you feel like a software superhero.