When something goes wrong when executing our programs’ source code, we commonly say that they have some bug. The term bug got pretty familiar in the programming world. However, what a bug means in technical terms?
From a historical perspective, the term “bug” emerged in the context of hardware engineering. In this context, a bug describes little problems or difficulties in building or using a piece of equipment. Many years later, the term bug became popular in computing and software development.
In this tutorial, we’ll study the most modern concept of bugs in programming. We’ll first understand what exactly a bug is and which are the different categories of them. Then, we’ll explore the debugging process, investigating how to detect and solve programming bugs.
2. Understanding Bugs
We can assume that bugs are coding errors in our source code. In summary, we can say that bugs are human-made and generally created due to the implementation difficulties of complex routines.
At best, we find all the programming bugs during the software testing stages. Thus, the programmers can correct them still in the software development process.
But, it is not unusual for bugs to be detected in the beta testing stages of software or only after its release. In such cases, users should avoid buggy operations until the programmers prepare a correction patch for the software.
It is relevant to highlight that there are different categories of bugs. Furthermore, each bug can be more or less severe regarding the impact it causes on the overall software and the final users: it can be low to critical.
Another potential problem related to bugs consists of inadvertently creating backdoors. Malicious entities can exploit particular categories of bugs to invade and take control of an entire computing system.
There exist several categories of bugs. Some categories refer to, for example, the technical type of a specific bug. Other categories refer to how we perceive the bug (from the user’s point of view). Furthermore, there are categories defined considering the impact of a bug in the system and where it occurs.
Taking into account all the described scenarios until now, in the subsections next, we’ll specifically explore different bug categories. These categories are summarized in the following figure:
2.1. Categories Regarding Technicalities of Bugs
Considering the technical aspects of a bug, we have five different categories of them:
- Arithmetic: category of bugs that includes the ones caused due to a calculation problem in the system. In short, we can see these bugs as a software malfunction caused by, for instance, loss of precision, arithmetic overflow or underflow, and invalid arithmetic operations
- Interface: bugs in the interface category happen when there are communication problems in the system. Such problems may relate to software and hardware. Examples are errors caused by incorrect usage of an API, taking invalid assumptions to the system, and doing an incomplete implementation of a protocol
- Logic: the category that embraces bugs in the control flow of a software program. These bugs lead the program to invalid outputs (such as on executing incorrect or invalid comparisons) or to no output (such as when infinite loops or recursions occur)
- Syntax: these are bugs caused by employing incorrect tokens to execute an operation. These are usually mainly when the programmers work with multiple languages concurrently, making it easy to be confused by their different syntaxes. A frequent example of a syntax bug is using the “=” token for comparing values in languages such as C or Python
- Teamwork: category of bugs that regards miscommunication problems in the programming team. Some examples are the existence of inconsistencies among the software project, product and documentation, and unpropagated updates
2.2. Categories Regarding How We Perceive Bugs
We have two categories that approach bugs in terms of the user’s perception of them:
- Functional: bugs that make the program work differently from the expected (or not work); for example, a “Start” button that resets the program when clicked or a “Save” button that does not save anything
- Visual: bugs that do not present operational impacts (the program works well in functional terms), but something looks wrong in the user interface. For example, the interface gets messy in particular screen configurations
2.3. Categories Regarding the Impact of Bugs
By analyzing how many problems a bug can cause for the users of a software, we can consider three categories:
- Low: bugs that cause minor problems for the users. These bugs reduce the quality of experience, but the software is still functional
- High: bugs that limit the use of the software. The user gets limited in functional terms by the bug, but the software is still usable
- Critical: bugs that make software useless. These bugs have adverse effects on the main functionalities of a program, making it execute invalid processes and returning wrong results
2.4. Categories Regarding Where Bugs Occur
- Unit-level: bugs present in a single unit of work of a program. Since they are isolated in the source code, these bugs are typically easy to solve
- System-level: bugs regarding the integration of multiple units in a program. Usually, they are much more complex to solve than unit bugs
- Out-of-bound: bugs caused by interactions of users with the program. Most out-of-bounds bugs are originated from unexpected and untreated interactions. Malicious entities frequently use this category of bugs to exploit software and find, for example, backdoors and other vulnerabilities in it
3. Finding and Solving Bugs
The first step to solving bugs in a software program is finding them. Currently, the most relevant process to find bugs consists of executing different software testing routines. We can highlight three categories of tests usually employed to detect potential bugs:
- Functional: routines that test the core functionalities of a software program
- Exploratory: routines to test a software program in different and unusual conditions than the expected normal one
- Regression: routines that check if a change in a software program caused some undesirable collateral effect on it
In addition to executing the previously presented test routines, we can use benchmarks to find bugs that harm the performance of a software program. Benchmarks, in short, are tests to evaluate (mainly) the responsiveness and speed of a software program under different conditions and workloads. Among the most common benchmarks categories, we have:
- Load: benchmarks that submit a particular workload for the software program to evaluate its behavior
- Spike: benchmarks to evaluate software under an immediate and unexpected increase in workload
- Breakpoint: a benchmark applied to a specific fragment of code, pushing it to the limit until it crashes
Once we find a bug, we must now solve it. The process of solving bugs is called debugging. We’ll discuss this process in detail in the following subsection.
3.1. The Debbuging Process
The main idea around the debugging process is correcting a bug or finding ways to isolate it, making the software never activate the bug. Thus, debugging is a critical stage of the software development lifecycle, avoiding multiple after-releasing problems.
We can summarize the debugging process into three steps:
- Bug isolation: finding the module, function, or code fragment in which the bug happens
- Root cause detection: determining the specific circumstances and triggers that activate the bug
- Bug fixing: applying a bug correction package to the program to remove the bug or making it unactivatable
Some debugging processes are simple, and we can solve the bugs fast and efficiently. However, other ones are very complex, requiring much effort to solve a single bug.
Some scenarios that make a bug complex to deal with are when it has an unclear cause or presents a stochastic behavior, thus making it hard to reproduce and solve in the debugging process.
The development team can adopt tools to make the debugging process more efficient. Some debuggers are language-dependent, and others handle multiple languages. Furthermore, we have standalone debuggers and IDE-coupled ones. Examples of popular debuggers are the GNU Debugger (GDB), the Eclipse Debugger API, and Valgrind.
In this article, we studied bugs and the debugging process. At first, we investigated the concept of a bug and its different categories. Thus, we analyzed how to find bugs and solve them through debugging.
We can conclude that bugs represent a relevant challenge during the development and release of a software program. The general idea is: as soon we find and solve bugs, the better. Thus, the development team should keep an eye on that, frequently executing testing routines and debugging processes.