We know from my last installments, that there are some people here
that go around telling "there is no stack in C", because the word
"stack" doesn't appear in the C standard.
Apparently, more or less the same people, start telling that
it is enough to read the code to be able to debug a program,
without using such low level tools like a debugger.
I chimed in on a recent thread to say that the C abstract machine
clearly describes a LIFO structure which is known in Computer Science
circles as a "stack," and that to claim "there is no stack in C"
without recognizing this is unhelpful. On the other hand, I rarely
use a debugger. So maybe I have a perspective on this that you would
find worth thinking about ;-)
As an aside, I thought about posting in the thread you mentioned, but
there seems to be so much *heat* on this topic that I thought better
of it. But now I see below that you are sort of calling *me* a liar
by proxy, so, *without heat*, I just want to say a few things.
Now, question for the people that keep a small part of common
sense here:
Is *reading* a program the *same* as *DEBUGGING* a program?
If you mean by "reading," "reading with understanding," then I'd
guess I'd have to answer "yes" to this. When I read code and can't
understand why something is done or why something is done the way it
is, I've oftern found a problematic section of code which contains
bugs. I basically execute the code mentally as I read it. If you
mean to ask whether you can debug a program just by reading the
source code, the answer is also (obviously) yes. I have often found
that an algorithm was incorrectly implemented, just by looking at the
source code of the implementation.
Are serious people here willing to believe this stories of people
debugging huge code bases without a debugger?
The code base I work on has on the order of 800,000 SLOC, which I
think is pretty "huge" for one person. And I repeat, I *rarely* use
a debugger. I'm not some super programmer, and I don't claim to be.
But I learn from my mistakes, and since I've made so many over the
years, I've learned a great deal! (And I try not to use an IDE
either!) Please don't call me a liar. Just read on.
I stay by my position:
A code base bigger than 1500 lines is no longer debuggable in an
abstract sense just by reading code. It needs a debugger.
Well, this isn't easy to address squarely. I said the code base I
work on has about 800,000 source lines of code, but I don't try to
debug it all at once! In fact, the way I program, I would say I try
not to address more than 1500 lines at a time. I modularize
*ruthlessly*, and 1500 lines is a pretty good target for the maximum
size of a module. So I keep the target code small. I also write
pretty thorough module tests so that my assurance of module
correctness can be pretty high, once it passes all the tests. I'm
also very careful about module coupling. I like to keep modules as
independent as possible so that they can be tested in isolation. And
I maintain pretty severe abstraction barriers between modules, so
that one module may depend on another, but never on the internal
details of another. So I have a large body of thoroughly tested code
which is built into libraries that can be used over and over again.
If there's a problem in a program that uses a linked list, I know
it's not inside my linked list module. It may be in the way the
linked list API is used, but not inside the module itself. This is
an enormous advantage in locating where in the code a bug is hiding.
I often just don't have far to look!
I could go on about my coding habits and the tricks I've picked up
over the years (defensive programming, anyone?), but the only real
point I'm making is that I *have* picked up a lot of tricks over the
years and I have a certain discipline I follow to compensate for
myown shortcomings. I know the common mistakes and take extra care
not to make them. Test twice, commit once. And I'm almost obsessive
in coding for clarity, above all else. I know I'm not smart enogh to
debug clever code. So I don't write clever code!
Again, I do all this, not because I am a super programmer, but
because I know I'm not. I know my own limitations, and I have
developed coping strategies. In particular, I have to keep things
simple so that I can understand them fully. I have a pretty keen
sense of when code is "too clever by half," and I avoid writing code
like that. KISS. DRY. Test, test, test. There are lots of things
you can do which keep any given debugging task to managable
proportions.
Note that we suppose a real-time, event-driven code execution,
where you can have faulty libraries, faulty interrupts servicing
programs, etc. ANYTHING.
I write lots of low level code including device drivers, networking
code including protocol stacks with state machines, GUI code (event
driven), multithreaded code, and code of all sorts for embedded
systems. I routinely write code in a portable subset of C which
compiles cleanly and runs correctly on Win32, Linux, Solaris and on
the open source RTOS called eCos, both user space and kernel code
(and yes, that includes writing ISRs). In fact, I think the variety
of platforms and environments I work in is one reason I don't use a
debugger very often. I would have to learn to use a half dozen of
them and then remember which is which and how to what in each. It's
just beyond me to master so many different, complex tools!
But here's the thing I've found about debugging in my own case. When
I don't reflexively reach for a tool when something "bad" happens
with my code, I can often figure out exactly what the problem is
without even looking at the code, if I really understand the code in
the first place. What did it do? What did I expect it to do? If
what it did was not what I expected, why would it do that? Oh... It
doesn't have to be code I wrote, but that certainly helps ;-) If
it's code someone else wrote, I have to start by trying to understand
it. And for me, that means *reading* the code, not stepping through
it in a debugger. When I was just learning to program, I found that
helpful. Now that I know how to read code, I just don't.
Now please be clear that I am not saying anything bad about
debuggers! I'm willing to accept that it's a limitation of some kind
on my part that I don't have the patience to use them. In the 3
cases I remember where my "bug" was caused by incorrect code
generation by a compiler, I was eventually only able to isolate the
problem with a debugger, in one case using SoftICE deep inside the
Windows NT kernel. So I'm not against debuggers! Extreme cases call
for extreme measures! Thank heavens for debuggers! When you *need*
one, you *really* need one! But because my first thought is not to
reach for a debugger, I rarely find it necessary to do so.
The standard disclaimers apply. Your mileage obviously varies.
Dave