Wednesday, October 17, 2007

Debugger Support Considered Harmful

Jim Weirich made a great point today at the Pragmatic Studio's TDD with Rails workshop. He said that when he first discovered Ruby, people asked him about the inadequacies of the debugger, and his response was, "What debugger?"

He was unfamiliar with the debugger because he had been writing tests.

Asking why Ruby has weak debugger support is like asking why a dolphin doesn't have gills. Ruby has weak debugger support because Ruby programmers shouldn't be using a debugger. Ruby supports TDD and BDD better than any other language except possibly Smalltalk. Debugger support is for languages that you can't run tests against gracefully.

Debugger support is like nail-biting support, or farting-in-public support. Its absence is a feature. You want to avoid supporting bad habits. If programmers have to break their bad habits, that's a good thing.

It's also like asking why Lisp doesn't have design patterns. There are definitely design patterns which are only necessary in the absence of particular language features. If you're used to a crutch, you think you need it. Ruby lacks debugger support because it's not limping.

Update: Comments are now closed. I deleted several rude comments and several comments about deleting rude comments. Many comments on this post were aggressive and/or rude. Even the most lucid response I've seen on another blog calls me crazy. Apparently this is a more emotional subject than I realized.

One deleted comment stated that tests were for finding out when things went wrong, and debuggers were for fixing them. I cannot emphasize enough how totally and completely I disagree. Tests have absolutely nothing to do with checking to see if something went wrong. The mere fact that anybody could even think so in 2007 shows the strength of the Sapir-Whorf effect which is the primary argument for referring to tests as specifications rather than tests. Tests are absolutely not for checking to see if things went wrong. They are for articulating what code should do, and proving that code does it.

Another deleted comment referened an excellent screencast on the Smalltalk debugger, custom-created for the sake of this discussion, which I had to delete. Please understand, if your comments are rude, I will delete them, no matter how well-reasoned they are, no matter how polished their presentation, no matter how much I might respect you. Rude discussion doesn't belong here.

For a quick summary, the screencast demonstrated that the Smalltalk debugger works with TDD. Although this was a very cool demo, anyone with any knowledge of Smalltalk's history or the history of TDD knows that, since TDD originated with Smalltalk, and the Smalltalk debugger is famous. So my opinion persists that debuggers work backwards.

Debuggers are based on the idea that the code base has enough places bugs could happen that the work of locating the bug is involved enough to justify machine assistance. This is not true of well-tested code. It is not true of code you understand, either. More importantly, the whole point of [T|B]DD is that you identify the bugs before you write the code. As tools which track down bugs in existing code, debuggers presume and encourage a workflow which is exactly backwards.

It is my opinion that clean, well-tested code renders debuggers unnecessary, and that debuggers arose in the historical conditions which predated [T|B]DD. In that context, debuggers were a useful tool. In the context of well-tested code, specification of the system's behavior can be very atomic, to the point where a debugger is no longer necessary. It was and is my opinion that debuggers are a historical relic of C, and specifically of C pointer mechanics. It was and is my opinion that this historical relic belongs in history books, museums, and Wikipedia screenshots, and that adding a debugger to Ruby would be actively counter-productive to Ruby in the same way that adding C pointer mechanics and re-introducing goto would be.

I think the most important points here are:

1. Debuggers encourage a backwards workflow2. Debuggers are a historical artifact of C pointer mechanics and primitive flow control

I definitely still consider debuggers harmful. Sorry about the closed comments, and the comments deleted for rudeness, but how much time am I supposed to have? I don't need people stressing me out. I got angry and lost sleep last night. That's absurd overkill. One way or the other, it's just a technique. It's not as if I was talking about your mom or something.

4 comments:

It's an urban myth that Lisp doesn't have design patterns. It comes from Peter Norvig's talk where he proclaims that, in Lisp, the _GoF_ Design Patterns are either invisible or much simpler. People played a game of telephone with this quote until it became: "Lisp doesn't need design patterns" and then backfilled a theory to come up with why.

You can live without a debugger - until you have to deal with someone else's ("legacy") code :)

But 'Ruby doesn't have a debugger' is old hat - check out the latest release of NetBeans - the integrated debugger is solid and doesn't take much work at all to get running with existing (non-NetBeans) projects.