Prashant is the Oz behind Chronon. Inspired and frustrated by years of breakpoint guesswork in the current debuggers and fumbling with printin() statements and logging frameworks, Prashant set out to find a different way to debug programs. Chronon is the result of his efforts. Prashant has posted 22 posts at DZone. You can read more from them at their website. View Full User Profile

Is the traditional debugger still relevant in 2011?

07.18.2011
| 7348 views |
  • submit to reddit

The traditional debugger as we know it hasn't changed since the dawn of programming; which is to say it has remained pretty much the same since 1970s.  Lets take a deeper look at some of its fundamental design principals and whether they are still relevant in 2011.

Traditional Debugger

Design Principles

The traditional debugger is designed around the idea that :

  1. Programs are single threaded 
  2. Flow of execution is sequential 
  3. Bugs are always reproducible.
  4. Programs run for short periods of time

Implementation

Sequential flow of execution and single threaded-ness

This principle is clearly reflected in the interface of the debugger which has the 'stepping' buttons which allow you to navigate the execution of your program sequentially. There is no well defined semantic for what happens when you say 'step forward' in one thread, with respect to all the other threads.

Dbgr-stepping

Reproducible bugs and short runs of a program

The traditional debugger relies on the 'breakpoint' model which assumes that the person debugging has a well defined and fully reproducible set of actions. It also assumes that the program doesn't run for very long otherwise you would have to set a breakpoint and wait hours for it to hit.

Not multithreaded by design

Although most debuggers can stop and show you the stack frames of all the active threads when you hit a breakpoint, that is more of a evolution of the traditional design of just showing the stack frames of the single sole thread which  the program is assumed to be running on.  The rest of the debugging elements are not designed around the fact that the program flow is not  merely sequential and data is being modified by multiple threads.

But we are in 2011...

None of the assumptions of the traditional debugger hold true anymore in 2011:

  1. Almost all programs are multi threaded
  2. Flow of execution is not 100% sequential. Data can be modified by multiple threads at the same time.
  3. Bugs are becoming increasingly non reproducible due to race conditions and just the increasing complexity of programs.
  4. Programs run for days, months and even years on servers. 

Anybody who has had to debug a multi threaded program knows that merely showing the active stack frames does not help much in detecting race conditions. Not only that, but just breaking the program modifies the execution and timings of various threads leading to the bug becoming non reproducible while debugging.

The 'breakpoint' model is broken since for long running server side programs you can't realistically set a breakpoint and wait for days to hit the breakpoint, only to start all over again once you step over a line you didn't intend to.

And that leads us to Log files...

The failure of the debugger to keep up with programs written in the 21st century has led to the rise of logging and huge log files.

Logging is fundamentally broken by its very nature because :

  1. You are trying to predict the errors in your program, in advance, which you dont even know of. 
  2. Since you usually put a logging statement where, you might think the error would be, you have usually hardened the code around that area already. Thus in real world situations the program usually breaks where there wasn't any log statement at all, because the programmer never thought he might encounter an error in that piece of code.
  3. Long running programs generate enormous log files and you usually have to write another set of programs just to parse through those log files.
  4. Writing logging statements is a distraction from programming and results in clutter of code.

Thus the obsoleteness of the traditional debugger has led to people coding their own custom debugging mechanisms for every program they write.

Chronon - Reinventing the debugger for 2011

When we started designing the Chronon Time Travelling Debugger, we built it with programs of the 21st century in mind. Our assumptions were:

  1. Programs are inherently multi-threaded
  2. Flow of execution not entirely sequential. Data may be changed by other threads. Calls to a method may be interleaved across threads.
  3. Bugs are tough, if not,  impossible to reproduce in a multithreaded world with race conditions.
  4. Programs run for (very) long periods of time.

Implementation

Record everything, no need to reproduce

The Chronon Recorder records the entire execution of the Java program. The recording is then subsequently used to debug the program in the time travelling debugger. This ensures that no bugs need to be reproduced.

No breakpoints, built for long running programs

Chronon does away with the concept of breakpoints entirely. You can jump to any point in time of the execution of your program instantly. Thus you might have a recording that is 5 hrs long and maybe you want to get to an exception that was thrown after 4 hrs. Chronon allows you to jump to the exception instantly with a click of a button, instead of making you wait for 4 hrs like your traditional debugger would.

We even came up with the Chronon Recording Server recently which is specifically designed for long running programs. It takes care of splitting the recording after a pre defined time interval or if the physical size of the recording gets too large.

Embraces multi-threaded, non sequential nature of programs

Although Chronon still has the stepping buttons, including a 'step back' button, to allow examining sequential execution of a single thread, the rest of the interface is designed with multithreaded, non-sequential execution in mind.

Dbgr-stepback All the views like the Exceptions view, Variable History and Method History view show you data independently of threads. You can then proceed to filter them by the thread you want to examine.  1 of 3

Showing data independently of threads and then allowing you to jump to any point in time and examine the sequence that led to that particular state embraces both the multi threaded data manipulation as well as the single threaded sequential nature of the execution of the program.

Conclusion

The traditional debugger as we know it is of not much use in 2011. This is the reason people have resorted to the use of log files and custom debugging mechanisms. With Chronon, we have solved a lot of the issues with the traditional debugger and designed it to debug the way modern programs are written and used.

We believe that in 2011, you should not need to litter your code with logging or any other kind of custom debugging mechanism. Our current product and upcoming enhancements are steps in that direction.

 

From http://eblog.chrononsystems.com/is-the-traditional-debugger-still-relevant-in

Published at DZone with permission of its author, Prashant Deva.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Comments

Fabien Bergeret replied on Mon, 2011/07/18 - 5:04am

Most people do not use the advanced features you can have in Eclipse. Using conditional breakpoints can be VERY usefull, for instance. And expressions you can call in debug mode too.

So, before buying new software, I'd rather suggest using existing software properly ...

Andrew McVeigh replied on Mon, 2011/07/18 - 5:30am

Let me add a further assumption that breaks the traditional debugging model for me in my work -- vast amounts of data where the underlying processing engines use this data to branch at many points. This makes debugging very difficult using traditional means, regardless of any advanced features of any IDE.

Prashant Deva replied on Mon, 2011/07/18 - 7:19am in response to: Fabien Bergeret

Conditional breakpoints are merely an evolution which do not solve the fundamental design issues with the breakpoint model, which is that programs are long running and bugs are not easily reproducible. If your program breaks after running for 4 hours, good luck trying to debug it using conditional breakpoints.

Also if you have used the expressions view in Eclipse, you know if the expressions results in a complex hierarchy of method calls, the expressions view wont evaluate it.

John J. Franey replied on Mon, 2011/07/18 - 7:55am

Short running programs with easily reproducible bugs are very much in use in the 21st century. Long running programs and hard to reproduce bugs can be decomposed to short running programs with easily reproducible bugs. I'm not ready to throw out my debugger.

Fabien Bergeret replied on Wed, 2011/07/20 - 2:46am in response to: John J. Franey

I agree with John. When an odd issue occurs in a long running batch, the first thing I try to do is to shorten the input data to reproduce the issue (with the help of logs), then to run it in the debugger (a classical one, generally using conditional breakpoints).

The only hard to reproduce bugs are the one related with multi-threading (and, yes, they are difficult to find with a classical debugger).

Lund Wolfe replied on Sat, 2011/07/23 - 10:29pm

I realize this is just advertising for the chronon recorder but I do find the regular IDE debugger very useful and easy to use, especially on standalone desktop apps. My experience is that the vast majority of bugs are easily reproduced. The debugger is very helpful in stepping through and identifying the defective code, seeing the stack trace of where the error may have been introduced upstream, and verifying the fix. The debugger is also very useful for validating that your new code works as you have theorized and for learning/understanding how a program actually works when poorly designed and poorly documented. I'm not giving up my regular debugger.

Intermittent bugs are hard to fix but they are hard to find and fix by any method. Sometimes you just have to make an educated guess based on the existing code and try to force it to occur without fundamentally changing the logic. Intermittent bugs are often the result of a poorly conceived (or misapplied) solution (often at a very low level) rather than just slightly defective or incomplete program logic.

Robert Johnson replied on Thu, 2011/09/08 - 10:14pm

Really I cant believe it. patent infringement attorney

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.