Ocaml’s Debugger

I haven’t thrown chum in the water for weeks. With that in mind, I wanted to do a quick, off the cuff discussion of this articlefrom Files Bowkett, basically saying that one of the nice features of Ruby is the lack of a debugger.

Ocaml has a debugger. I think I used it once. I have vague memories of a debugger that made gdb look polished.

Strong static typing and unit tests are two ways to detect bugs in your code, neither of which need a debugger. But I want to mention a couple of other techniques (which also don’t require debuggers) to help improve the quality of your code.

Technique number one is documenting. This is actually one of my favorite debugging practices- if a peice of code isn’t work, I start explaining, into comments, what it is (or at least) should be doing. It’s amazing how often the problem with my code when I comment it- as I’m writting that comment that say “this next block of code is doing X”, I notice that the next block of code, in fact, doesn’t do X. Or that I need to do Y before I do X. Or whatever. If you can’t explain what the code is doing in English (or whatever your native natural language is), with all of the ambiguity and imprecision available to you there, then you don’t understand how the code works- and it’s a sure bet that the code isn’t doing what you want to it do, or what you expect it to do. And the advantage of doing this is that the next person comming along gets the advantage of your “knowledge tracks”, the trail of bread crumbs you’ve left behind in the forest of code as to why things are the way they are (instead of just what they are).

Side comment: there are those who would argue against comments, saying that code should be obvious enough without them. Well, by definition, if you have a bug and it’s not immediately obvious what the bug is, so you have to go looking for it, then the code isn’t obvious, even to the person who wrote the code, probably just a couple of minutes ago. What hope does somebody else, coming into the code cold, have of understanding the code, if you yourself don’t even understand it? And personally I’d put the bar for obviousness much lower than that. My basic rule is that if I have to stop and think about something, write a comment about my conclusions. And bugs are a sign that I should have thought about that code much more closely.

Other people argue against comments, saying that they other people won’t maintain them. These other people (and it’s always other people) will change the code, but not the comment. In my experience, these people are the ones most likely to do this. I am unsympathetic to either the claim or the claimants- the comments are right there, only a few lines distant from the code, in the same file, and generally even on the same screen. All you have to do is up arrow a couple of lines and change the comment. I have somewhat more sympathy when the document is in some other format, in some other file, and requiring you to use some user-hostile word processor and get sign off approval from three managers to change. But comment? ‘Cmon. If you not willing to change the comments which are right there, what other stuff are you not maintaining? Not to put too fine a point on it, what other stuff are you breaking and not fixing by changing that code?

Dragging this rant back on topic, the other big debugging technique I’d like to bring up is simplicity. There are two ways to write code: write code so simple there are obviously no bugs in it, or write code so complex that there are no obvious bugs in it. Of the two, one actually works to prevent bugs, the other to protect them from your debugging efforts. Guess which one I prefer?

In an odd way, Ruby’s poor performance is an advantage here, and Ocaml’s good performance a hiderance. In Ruby, the performance of your code is going to suck anyways, so you might as well make it simple and easy to maintain. With Ocaml, there is a temptation to try to push the performance envelope. To be worried about clock cycles. To corrupt the code in the name of performance It’s a weird psycological effect- but one I think may actually be happening. Complicating code for performance is always a bad idea- if it turns out that performance is important, and the clean code isn’t performant enough, you can go back and corrupt the code later- code can always be screwed up, it’s generally hard to unscrewup code, however. Which is sad, in a way, as Ocaml has a number of really nice features to simplify and generalize code that only impose a minor performance penalty. But these features are routinely ignored by newbie programmers in the name of performance.

Functions should be short- a screen full, two at most (with a screen being defined as 25 lines of 80 characters)- and as independent of everything else as possible. The functional ideal is very much the ideal to be shooting for- the function is dependent only upon it’s arguments. Objects and modules should (in general) be short. If the functions have interdependent behaviors (for example, shared object-level state), they should be as few as possible, with as little shared state as possible. Build more complicated behaviors out of simple behaviors. A complex system that works has invariably evolved out of a simple system that works. Do one thing, only one thing, and do it right.

A design like this is easy to debug- in fact, it’s easy for the bugs to just jump out at you. Everything dependent upon this peice of state is all together, and easy to fit into your head all at once, so none of of it falls out. The bug can’t hide, it’s got no where to hide in. And it’s easy to track down which small peice the bug is in. This design is also easy to test. This is one of the big advantages unit testing brings, as it strongly encourages this sort of simple design.

Many years ago, I had a programming teacher who used to ask, whenever I was wresstling with some particularly annoying bug, why I wrote it to have that bug in the first place? This really deeply annoyed me at the time, and my protestations that I didn’t write it to do that, that it was misbehaving just to spite me, were met with just a smile. But I’m begining to see the wisdom of the question: by far the easiest way to debug a program is to simply not write a buggy program in the first place. So that’s my rant. Much better than any debugger, is a language that helps me keep the bugs out.

No related posts.

This entry was posted in To Be Categorized and tagged . Bookmark the permalink. Post a comment or leave a trackback: Trackback URL.
  • Brian

    Jeesh. I went through that entire rant, and never even mentioned my favorite Pogoism: “We have met the enemy, and he is us.”

  • http://www.linkedin.com/in/robertfischer Robert Fischer

    A design like this is easy to debug- in fact, it’s easy for the bugs to just jump out at you.

    …or to jump out at the compiler. If the foo function returns a variant type of A or B, and you only handle the A case (possibly because B was invented after foo), then it’s a compile-time error, and you can never get to the point where you release buggy code.

  • Dude

    I’m sorry, but this is moronic. You emulate debugger in your head by writing comments. I’m glad I don’t have a compiler – when I verify machine code that segfaulted I notice lots of optimisations that I wouldn’t notice otherwise. And I’m also glad that I don’t have a cpu – i’m much more careful about overflow than I would be if I had a chip running my code for me.

  • Categories