I often find myself trying to explain what a bug is to people who have less experience with them, so this is an attempt to try and lift the lid.
Bugs are things that do not work as intended. Their name comes from the original bug, which was an insect that got squashed onto a punched card, which meant that the instructions that should have been followed were read incorrectly. In modern times they might be spelling errors in languages that are not strict about declaration, however the tools we use to write code, will normally be looking for this and highlighting where things look wrong.
Some bugs are simple
Simple bugs are things you can usually resolve within a two dimensional context. Everything you need to understand how they go wrong is in one file, you just need to read left to right (or RTL) and top to bottom.
These bugs might be as simple as a check for two things being the same x==y, mistyped so that it becomes a setter x=y.
Some bugs are complicated
As applications grow, they tend to be expressed in ways that make code easier to read, easier to understand, easier to reuse, but not always easier to debug. Code gets spread across multiple files, broken into units where the code in one file is somewhat related to each other. However your application is combining these groups of code together, so the runtime execution jumps around from file to file. When trying to find bugs, you’ve moved from 2D representations where everything is visible, onto 3D where you need to be in the right file to start looking down and right.
One common issue at this level might be where the usage of a function in one file, mismatches the definition in another. For example we create a method that subtracts one number from another Subtract(x,y), and then call it with the arguments the wrong way around Subtract(y,x).
Other bugs might be where we change a value somewhere but never update the original, or conversely update a value that everything expects not to change. Often we are starting to see side effects to our code being the cause of subtle problems.
Some bugs are complex
Even with code that works perfectly in one environment, there are other factors that can make it break in another. The first to consider is time, which counter intuitively is more than one issue.
Code might run where it has the machine to itself and have no issues, then run again later when other things are happening and hit limitations. These might be resource constraints, like running out of memory, or not being connected to the internet. Defining the conditions that caused the problem can often be a bigger challenge than recreating them. It’s very common for your code to be run by people who are less precise in their description of the problem.
Another problem is that often we make our code do more than one thing at once, for performance. The number of things that happen and speed that they happen can vary across systems or even on the same machine. These can mean things happen out of order and your bug is where you are not prepared for these. It becomes a race for which finishes first, hence these bugs are known as race conditions.
The next time related issue is where the version of the environment changes. Your code works perfectly with your current environment, but with older or newer dependencies, it breaks. Conversely someone might be running an old version of your code, so you have to consider what your code would have done previously and what state things might be in now. Did you write a file in an older format, but now your code is the newer version? Did someone use the newer version of your code to write a file and its been sent to a machine with the older version?
At this point we are starting to see that the number of factors to consider is expanding. We don’t just look up and down, left and right, ie. 2D. We don’t only look between files, 3D. We have to think about when it runs 4D, what version of it’s environment its in 5D, and when it’s data was produced 6D.
Talk about n-dimensional chess!