We get exceptions mostly, it is best to always test your applications before submitting it to markets or other platforms for users. Debugging is one of those options to test your applications. As the name suggests, Debugging means “to debug” (What?) the application. It is a process in which framework problems and other logical errors are removed from the errors.
As a software developer, you might know that there are usually three types of errors.
- Syntax error
- Run-time error
- Logical error
Syntax error and run-time error are two types of errors that can be shown to the developer by the framework or compiler (first one). So, the developer just has to check what went wrong and how to fix it. However, the third type of error cannot be checked by a compiler. Logic is something you make up. You have to write the correct algorithm to make it work. If there is some kind of problem, you have to check your algorithm once again to make sure that it is the correct algorithm. Logical errors do not generate any error while compiling the source code. They also don’t notify the user about wrong results. A common example would be:
int Remainder(int a, int b) {
return a / b;
}
Indeed, the developer wanted to get the remainder, but used division operator. Source code would compile and would give results… Wrong results.
Debugging helps us in finding such errors and solving them to get the correct answer and solution. This option is provided in every IDE (Visual Studio, Android Studio, Eclipse… others that you have tried) for developers to debug their applications.
How to Debug
Now you might also want to know how to debug your applications. Well, that is pretty simple. I have also mentioned above that (almost) all of the IDEs provide tools to debug your application. I have used Eclipse, Visual Studio, Android Studio… They have all provided me with (similar) tools to debug the applications and see how things are done.
The thing, “How things are done” is helpful when solving the logical error. Point to note here is that debugging is not only helpful in solving the logical errors. It is also sometimes helpful while removing the run-time errors such as the most famous “NullReferenceException
” (For more on NullReferenceException
, you can read this other post of mine to understand what it is?… why it is generated!… and how to solve it?). Syntax errors need to be resolved before the object-code can even be generated. So that leaves the debugging method applicable to run-time and logical errors only.
The steps to debugging processes generally depend on the type of error you are trying to debug. So let me clarify the two types of debugging process. However, the actual process is similar. You start and end up in the same way. It is just your internal process that is different for both:
- Run-time error
- Logical error
Process
In every IDE, option to set up some Breakpoints is included. Breakpoints are a few steps in your code where IDE notifies you when the code execution reaches that place (or point). You are then allowed to check the application’s memory consumption, variables (including their “at that time” values). At this stage, you can see what is the state of application and how it should behave. You can also check what type of variables (with value) are sent to this block and how they are being used or manipulated. This would further guide you in fixing the problem.
Run-time error debugging
For example, if you stumbled upon DivideByZeroException
, then you can add a Breakpoint to your function and execute step by step, one by one each statement and look into how your code gets a variable with zero (or is the user passing the value to be zero) and so on. This type is the Run-time error debugging. DivideByZeroExceptions
are generated at run-time when the code executes. That is why you usually would face this error while running the application only.
This type of debugging is somewhat easy, because it doesn’t require a lot of searching for error. The framework that you are using would throw an exception and you (if having more than beginner level experience) would easily know that the program is telling you to fix this problem at this location. And then you can easily add the patch to fix the problem.
Logical error debugging
Debugging a logical error is a somewhat tough task because they cannot be found easily. You have to run through each and every statement and check for where actually do things mess up? Sometimes it can take 5 – 10 minutes, sometimes it can take an hour depending on the complexity of the logic or algorithm being designed.
Let us take an example of an “Age calculating” algorithm. Take a look at the following C# code.
var age = (DateTime.Now - dateOfBirth).Days / 365;
age
variable would hold the correct data only if the logic is applied correctly. We know that our logic is correct. Which is not! We know 365 are the number of days in a year… But what we don’t know is that we round up the overhead number of hours in the Leap year after 4 years. So if the above code is run, it is not guaranteed to give the correct answer to every input. It might have at least >10% of errors chances. If processed under debugging tools, we would find that using 365.25 as divisor is the correct way to find the age of a user using DateTime
object. So now, the following code would run correctly and would not have as much error ratio as the above code had (still might have error chances!)
var age = (DateTime.Now - dateOfBirth).Days / 365.25;
Now when you would use it, it would display correct for the provided input.
Note: The above example has a physical significance, I wrote the age calculation algorithm which gave me my age to be 20 years (while I was 19.5 or something years old).
Points of Interest
Now let us wind things up. A few things mentioned in this post are:
- Debugging is a process in which bugs (mainly logical or run-time) are removed from the application.
- (Almost) every IDE supports debugging tools.
- Breakpoints.
- Debugger (in which application runs… vshost.exe can be an example for Visual Studio geeks).
- Profiling tools, memory management, variable information and other tools required to alter the state of application and to check what is going on under the hood.
- Run-time errors are easily understandable and solvable because the underlying framework tells the developer what went wrong. So (if the developer has some understanding of the framework then) he can remove the chances of problem occurring again.
- Logical errors take more time. Because they depend on the complexity of the logic being solved. They can be removed only if the algorithm is fully understood and how it should be written in the language.
See the examples above for more.
That’s all for now folks! :-) I hope it helped some of you…