Skip to content

In Successful Search of Bug

February 23, 2010
tags: ,

I have always enjoyed debugging rather than coding. This post is about some of the troubleshooting methods that I came across while debugging.

Debugging is locating the defects. In the book Debugging, David Agans formulates nine rules of debugging for successful search of a bug.

Understand the system.

Make it fail.

Quit thinking and look.

Divide and Conquer.

Change one thing at a time.

Keep an audit trail.

Check the plug.

Get a fresh view.

If you don’t fix it , it ain’t fixed.

You cannot locate the defects unless you are familiar with the system. Though it takes most of your time, it is worth doing it. You need the understanding of the finer details.

Reduce the problem to its essence. Determine the smallest input that will cause the bug. The simpler the data or path to the bug, the more easily you can deduce or track down the problem.

You must change the conditions of the test to see if your bug disappears. If you correct the bug with a change, that change might tell you what the problem is, or at least give you a big hint about what is going on. You form hypotheses with your logic and deductive reasoning skills and then filter them by experimentation and observation. For example, by experimentation, we concluded that the specific argument caused the problem. Finally, we narrowed it down (by using some experience) to the equals as escape problem.

Experience helps in the debugging process in two ways: first, you hone your ability to execute the previous four elements; and second, you might have seen a similar bug or just plain know more about a particular problem.

Designing for debugging by Andreas Zeller:

When it comes to testing and debugging, a model-view-controller architecture has several benefits.  For testing, one can build and add new controllers that invoke services of the model—for instance, controllers that automate execution of these services. For debugging, one can register special views that automatically log all changes to the model. Finally,every observer and model can be examined and tested in isolation, thus reducing complexity.

Debugging sessions:

Java bytecode – using system.out.println. Java Pitfalls by Michael C. Daconta shares a useful technique for applying the println() method. Daconta suggests creating a DebugManager() class that allows you to set a debug flag based on certain classes or applications.

Using comments – comment out larger part of code and narrow down the search.

Remote debugging -running an application on one computer and debugging it on another computer.

Debugging on demand -you open a debugging session whenever an unhandled exception or other unrecoverable error occurs in your program.

Compilation or syntactical errors are the first that you will encounter and the easiest to debug. They are usually the result of typing errors.

Logic errors are different from run-time errors because there are no exceptions thrown, but the output still does not appear as it should. These errors can range from buffer overflows to memory leaks.

Run-time errors occur during the execution of the program and typically generate Java exceptions.

Threading errors are the most difficult to replicate and track down.

Preparation for debugging:

If you use the javac compiler to build your code for debugging, use the -g compiler option.  You can still set breakpoints and step through your code if you do not compile your classes with the -g option; however, you will not be able to inspect variables. The -g option lets you include debugging information in compiled code. This is useful if you want to be able to run the java debugger (jdb).

Keep in mind that if you compile with the -O option that optimizes your code, you will not be able to debug your classes. Optimization will remove all debugging information from the class.

You can manually force the generation of a stack trace using either the following statements.

* Throwable().printStackTrace() to generate a trace of the method’s code at a single point in time. The trace will show the method’s calls across threads.

* Thread.currentThread.dumpStack() to generate a snapshot of the current thread only.

Diagnostic methods:

The Java language provides methods from the Runtime() class to trace the calls you make to the Java virtual machine.

Turn on tracing will produce a list of every method call your program makes:

traceMethodCalls(true)

Turn off tracing by adding the following line to your source code:

traceMethodCalls(false)

Of the all, log files are the best sources of debugging. If you practice debugging through logs, its of much useful in troubleshooting production issues where you are provided with none other than logs. Logging statements serve no other purpose than debugging,they do not help us in understanding the code.The main message a logging statement conveys is that the procedure in question was in need of debugging. Therefore, logging is to be done with specific code locations, events and data. For performance reasons,output is typically buffered before actually being written to the output device. In the event of a program crash,this buffered output is lost. Using ordinary (buffered) output for logging thus hides what happened in the last few events before the crash. One can either use an unbuffered channel for logging (introducing a slowdown,as described previously) or make sure that the program flushes its buffered logs in case of a crash.

Advertisements
No comments yet

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: