Como su nombre indica, la depuración significa "depurar" (¿Qué?) La aplicación. Es un proceso en el que los problemas de marco y otros errores lógicos se retiran de los errores.
Por lo general hay tres tipos de errores:
Error de sintaxis y errores de tiempo de ejecución son dos tipos de errores en donde sólo se tiene que comprobar lo que salió mal y cómo arreglarlo usando un compilador. Sin embargo, el tercer tipo de error no puede ser revisado por un compilador. La lógica es algo que te inventas. Tienes que escribir el algoritmo correcto para hacer que funcione. Si hay algún tipo de problema, tienes que comprobar su algoritmo, una vez más para asegurarte de que es el algoritmo correcto. Los errores lógicos no generan ningún error al compilar el código fuente. Tampoco notifican al usuario acerca de resultados erróneos. Un ejemplo común sería:
// Proporcionado b no es cero
La depuración nos ayuda en la búsqueda de este tipo de errores y resolverlos para obtener la respuesta y la solución correcta.
Punto a destacar aquí es que la depuración no sólo es útil en la solución de los errores lógicos. A veces también es útil mientras se quita los errores de tiempo de ejecución como el más famoso "NullReferenceException"
En todos los IDE, la opción para establecer algunos puntos de interrupción está incluida. Los puntos de interrupción son algunos pasos en su código donde IDE le avisa cuando la ejecución de código llega a ese lugar (o punto). A continuación, se le permite comprobar el consumo de memoria de la aplicación, las variables (incluyendo sus "en ese momento" valores). En esta etapa, se puede ver lo que es el estado de la aplicación y cómo debe comportarse. También puede comprobar qué tipo de variables (con valor) son enviados a este bloque y cómo están siendo utilizados o manipulados. Esto te guiará aún más para solucionar el problema.
La depuración de errores en tiempo de ejecución
Por ejemplo, si tropiezas con DivideByZeroException, entonces puedes agregar un punto de interrupción a esta función y ejecutar paso a paso, uno a uno cada declaración y buscar la forma en que su código obtiene una variable con cero y así sucesivamente. Esta es la depuración de errores en tiempo de ejecución. DivideByZeroExceptions son generados en tiempo de ejecución cuando se ejecuta el código. Es por eso que por lo general se genera este error mientras se ejecuta la aplicación.
Este tipo de depuración es algo fácil, ya que no requiere una gran cantidad de búsqueda de error. El marco que está utilizando lanzaría una excepción y que fácilmente sabran lo que elprograma está diciendo para solucionar este problema en ese lugar. Y entonces puedes agregar fácilmente el parche para solucionar el problema.
La depuración de errores lógicos
Depuración de un error lógico es una tarea un tanto difícil, ya que no se pueden encontrar fácilmente. Tienes que correr a través de todos y cada declaración y comprobar donde realmente está el lio? A veces puede tomar 5 - 10 minutos, a veces puede tardar una hora, dependiendo de la complejidad de la lógica o como el algoritmo está diseñando.
Ejemplo de un algoritmo "calcular la edad".
// Suponga fechaDeNacimiento proviene de usuario que tiene la expresión fechaHora válida
edad var = (DateTime.Now - fechaDeNacimiento) .Days / 365;
La variable edad mantendría la información correcta, sólo si la lógica se aplica correctamente. Sabemos que 365 son el número de días en un año... Pero lo que no sabemos es el número de horas en un año bisiesto después de 4 años. Así que si se ejecuta el código anterior, no se garantiza que pueda dar la respuesta correcta. Podría tener al menos 10% de error. Al correr la herramienta de depuración, puedes encontrar que se usa 365.25 como divisor, este es el camino correcto para encontrar la edad de una persona utilizando el objeto DateTime. Ahora, el siguiente código se ejecuta correctamente y no tiene tantas posibilidades de error como el código anterior (todavía podría tener posibilidades de error!)
edad var = (DateTime.Now - fechaDeNacimiento) .Days / 365,25;
Los errores lógicos toman más tiempo. Debido a que dependen de la complejidad de la lógica para ser resueltos. Pueden ser removidos sólo si el algoritmo se entiende completamente.
Tabla de códigos de assembler
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.
There are usually three types of errors.
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) { // provided b is not zero 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.
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”
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:
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.
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.
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.
// Assume dateOfBirth is coming from user having valid dateTime expression 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).
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.
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.
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.