Skip to main content

5 things to do when you cannot trace a bug

Programming today, is more about fixing existing code than writing new. In most of the cases, bugs are easy to trace, especially when you are using a modern IDEs like Eclipse or Visual Studio. However, it is very likely that you get trapped in situations like a specific button not doing anything, application crashing randomly, or a record not updating for a specific ID. Here are some tips you may find lifesavers if you get jammed too often when debugging your code:

Catching random errors

Remember, there are no random errors unless you are calling a random function. The code is always consistent, if a function calculates compound interest of an amount over a certain period of time -- within an allowed range -- correctly, it will never do it wrong as long as the parameter values are in range. So, the code is consistent. Data, however, may not be. Here is an example:

public boolean saveRecordInDB (int id, String name, float height, float weight) {
// Do something
}

Test:
saveRecordInDB (1, "Owais", 5.6, 52);
saveRecordInDB (1, "Ahmed", 6.2, 78);

If the first method worked fine and the other didn't, it is very clear that this is something to do with the data in arguments. When you'll dig in deep, you might find that the id that goes into database is Primary key-indexed and is therefore throwing back duplication error. Same is true with NULL, values out of range, etc.

Reading stack trace

Stack trace that -- lines and lines of activities that the runtime environment (JRE, CLR, etc.) is generating -- mainly comprises of methods being called from your code and the libraries you're using, writes all activities on console. Whenever there is an uncaught exception, the whole trace is displayed and programmers are often reluctant to read it. However, stack traces -- scary as they look -- are only to help identify the main source of problem. Always start looking from bottom, your eyes should be scanning the words like "Exception", "Error", "Failed". Once you spot an Exception, now you'll read from top to bottom, look for the classes and methods "you" have written, not for the libraries and APIs you're using.
The better your exception handling in your code, the easier the stack traces are to read. Target NullPointerException, IndexOutOfBoundException, IllegalArgumentException and ClassCastException - the most frequently thrown exceptions, and often uncaught.

There are smart ways to avoid these exceptions without the trouble of writing try/catch block (Java):
- To handle NullPointerException
public int getInteger(Object obj) {
 if (obj == null)
  return;
 Integer i = Integer.parseInt (obj);
 return i.intValue ();
}

public boolean isStringEmpty(String str) {
 return ("".equals(str)); // Avoid writing str.equals("")
}

- To handle ClassCastException
public MyClass objToMyClass (Object obj) {
 if (obj instanceof MyClass)
  return (MyClass) obj;
 return null;
}

In cases when you find yourself completely out of luck, search the web for the exception you doubt, is causing the issues. But copy-paste the exception is not always a good idea; if you see an exception like:

Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.util.ArrayList at MyClass.main(MyClass.java:34)

Remove "MyClass" part from the search query. Search only for Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.util.ArrayList at. Because there are strong chances that someone has already encountered similar problem and posted on some developers' forum, but their class and method names will be different. Thus, the search engine may not return any results.

Pinpoint the location

Identify the origination of the bug. Start with which tier it occurs in, the Client (Java/VB script, applet), Presentation (Servlet, JSP, ASP, JavaBean), Controller (Server, Implementation classes, Factories), Data (SQL Engine, Cloud, No-SQL Database). Next is the module or package, is the error generating from client code, a utility, server-side implementation classes, or another libarary? Once you figure this out, then looking for the specific method and line is just a matter of time.

Explain the code to someone else

This is very handy. Explaining your code to some other programmer requires you to go into details and specific, which you probably would've skipped assuming "Oh! That works, I know. Let's move forward". It is then when you find that the bug was actually in the part you overlooked. This has worked for me countless times.

Take a break

Here, you're going to play with your brain's short-term memory. Think of it as cache that gets cleared whenever not in use for long time. When you are writing code, you have a lot in your short-term memory, which tells you "Hey! This part's okay", "Oh! That line's fine. I remember". You cannot debug with so many assumptions about your code's correctness. So in order to clear your short-term memory. Take a break. Read an article in your to-read list. Check your emails, play a game. Don't even throw a glance at your code unless you forget completely about what you were debugging, how is the method call hierarchy, etc.


In the end, bug tracing and fixing is a skill that furnishes with experience and there are no rules of thumb for dealing with bugs. Whenever you feel hopeless, ask for help, there are thousands of professionals on on line forums like StackOverFlow and XDA-Developers.

Please feel free to leave your comments, pointing mistakes and enhancements.

Happy fixing.

Comments

  1. Quite a helpful post ! Thanks for sharing :)
    It precisely, well explains true facts about bug tracing which can drive a coder crazy :D

    ReplyDelete

Post a Comment

Popular posts from this blog

Executing MapReduce Applications on Hadoop (Single-node Cluster) - Part 1

Okay. You just set up Hadoop on a single node on a VM and now wondering what comes next. Of course, you’ll run something on it, and what could be better than your own piece of code? But before we move to that, let’s first try to run an existing program to make sure things are well set on our Hadoop cluster.
Power up your Ubuntu with Hadoop on it and on Terminal (Ctrl+Alt+T) run the following command: $ start-all.sh
Provide the password whenever asked and when all the jobs have started, execute the following command to make sure all the jobs are running: $ jps
Note: The “jps” utility is available only in Oracle JDK, not Open JDK. See, there are reasons it was recommended in the first place.
You should be able to see the following services: NameNode SecondaryNameNode DataNode JobTracker TaskTracker Jps


We'll take a minute to very briefly define these services first.
NameNode: a component of HDFS (Hadoop File System) that manages all the file system metadata, links, trees, directory structure, etc…

A faster, Non-recursive Algorithm to compute all Combinations of a String

Imagine you're me, and you studied Permutations and Combinations in your high school maths and after so many years, you happen to know that to solve a certain problem, you need to apply Combinations.

You do your revision and confidently open your favourite IDE to code; after typing some usual lines, you pause and think, then you do the next best thing - search on Internet. You find out a nice recursive solution, which does the job well. Like the following:

import java.util.ArrayList;
import java.util.Date;

public class Combination {
   public ArrayList<ArrayList<String>> compute (ArrayList<String> restOfVals) {
      if (restOfVals.size () < 2) {
         ArrayList<ArrayList<String>> c = new ArrayList<ArrayList<String>> ();
         c.add (restOfVals);
         return c;
      }
      else {
         ArrayList<ArrayList<String>> newList = new ArrayList<ArrayList<String>> ();
         for (String o : restOfVals) {
            A…

Titanic: A case study for predictive analysis on R (Part 4)

Working with titanic data set picked from Kaggle.com's competition, we predicted the passenger survivals with 79.426% accuracy in our previous attempt. This time, we will try to learn the missing values instead of setting trying mean or median. Let's start with Age.

Looking at the available data, we can hypothetically correlate Age with attributes like Title, Sex, Fare and HasCabin. Also note that we previous created variable AgePredicted; we will use it here to identify which records were filled previously.

> age_train <- dataset[dataset$AgePredicted == 0, c("Age","Title","Sex","Fare","HasCabin")]
>age_test <- dataset[dataset$AgePredicted == 1, c("Title","Sex","Fare","HasCabin")]
>formula <- Age ~ Title + Sex + Fare + HasCabin
>rp_fit <- rpart(formula, data=age_train, method="class")
>PredAge <- predict(rp_fit, newdata=age_test, type="vector")
&…