Download as docx, pdf, or txt
Download as docx, pdf, or txt
You are on page 1of 28

Name:K.Dhanunjaya Reddy Reg.

No:21BCE5524

All About Debugging

Introduction

What, why, and how to debug

In computer science, debugging is the process when the developer


or programmer attempts to find a source of error, isolate it, and then fix it
or create a way to work around it. The word “debug” first appeared in the
1940s when Grace Hopper was working on the Mark II computer and
observed that it wasn’t functioning correctly. The reason was that a moth
got stuck in the relay of the computer, causing it to malfunction. So back
then, a “bug” was quite a literal term!
Finding and fixing bugs is an essential step in the software
development cycle. Usually, the process of finding a bug or a
scenario where the program doesn’t function properly is part of the
testing phase of developing software.

Why Debug?
Debugging is definitely the most dreadful task for developers. After
all, we like to build things rather than fix bugs! Nevertheless, no one
can deny the importance of debugging. Programs or applications
that work perfectly from the first try are the exceptions and not the
rule.

Debugging can help developers pinpoint various types of errors,


including syntax errors, semantic errors, and logic errors. Although
compilers can help significantly in finding some syntax errors, some
of them — like runtime errors — can depend on the environment
and the dependencies, which means that they will not occur in every
single run of the application.

Oftentimes, testing and debugging software takes a longer time than


writing the software itself. Being able to find and fix bugs is a
valuable skill for any developer because it means that you’re a
creative thinker and a problem-solver. However, this process can be
made more efficient if the company or the team has a set go-to
debugging strategy. Not to mention the financial loss that can be
avoided if a severe bug is found in a product before it is deployed.

How to Debug

There are different debugging approaches that perform different


functionalities. Some approaches reproduce the error conditions
that caused the failure, while others examine the program state at
every step of the application and locate the bugs that caused the
errors. Those techniques can help programmers trace the execution
of the code step by step and halt it wherever an error occurs.
We can categorize debugging techniques into two main categories:

1. Techniques that analyze the program performance by inspecting


the main memory after the program crashed (post-mortem
debugging).

2. Techniques that analyze the program step by step by running it


under a debugger (“dynamic debugging” or “tracing debugging”).

Most applications today contain thousands of lines of code, which


can make the debugging process complicated. Some strategies can
be followed to make debugging easier, such as unit tests, code
reviews, and pair programming.

Unit testing

Sometimes, the location in the code where the error occurred can be
clearly identified. However, that’s not always the case. Most times,
the location of the bug is unclear. Here’s where unit testing can be
helpful. It allows the programmer to run a specific part of the code
with a particular input. Doing so can ease the process of locating the
bug.

Pair programming

An agile software development technique where two programmers


work together on the same codebase, usually in the same physical
location. The two programmers will have different roles. The driver
writes code, while the observer or navigator reviews each line of
code written by the driver. The two programmers switch roles
frequently to increase the efficiency of this approach.
Code reviews

A software quality assurance approach where two or more


programmers systematically check each other’s code for errors and
uncertainties.

Debugging Tools

Debugging tools, or debuggers, are special tools that are built for the
sole use of analyzing programs and finding errors. Some debuggers
analyze a test case and run it to determine which lines of the code
didn’t execute correctly or at all. In contrast, others provide
simulations of the code’s behavior, allowing the programmer to
model how the program will behave on a given software (operating
system) based on specific dependencies.

Testing vs. Debugging

Testing and debugging are two terms that are usually used together,
which may lead to the misunderstanding that they mean the same
thing.

In fact, they are quite different from each other. They do share some
functionality, but they differ in designs, execution, and benefits.
Both testing and debugging are essential stages of software
development and come with a variety of results. That’s why it’s
necessary to properly understand the differences between them to
optimize our software development process.
Although there is no fixed procedure to fix all bugs, there are several
techniques that can reduce your debugging efforts. A significant (if
not the entire) part of this process is spent finding the location of the
bug.

The three most known and used tecniques:

 Trace-based debugging

 Spectrum-based debugging

 Delta debugging

Trace-Based Debugging

Trace-based debugging is traditional and the most common


debugging technique used in most debugging tools today. Trace-
based debugging is predicated on the concept of breakpoints.

A breakpoint is a pausing or stopping point added to the program to


examine the state of program execution up until that point. After
rectifying the current bug, the developer usually sets the next
breakpoint and repeats the same process until all the bugs are
corrected.

Traced-based debugging has four sub-techniques

1. Trace debugging (TD)

2. Omniscient debugging (OD)


3. Algorithmic debugging (AD)

4. Hybrid debugging (HD)

All of these sub-techniques are based around the same concept:


program slicing.

Slicing

Program slicing is a technique used in computer science to simplify


big programs by focusing on a smaller, selected section of them. The
process of slicing deletes parts of the program that have no or little
effect on the aspect being tested or the overall output of the
program. In 1981, Mark Weiser, computer scientist and Chief
Technology Officer at Xerox PARC, defined a program slice as:

“The mental abstraction people make when they


are debugging a program.”

Program slicing is used in many applications in computer science:

1. Debugging.

2. Reverse-engineering a program.

3. Measuring a program’s coverage, overlap, or clustering.

4. To gain a deeper understanding of the inner workings of a


program.
There are several possible approaches to slicing a program, such as
static slicing, dynamic slicing, conditional slicing, and amorphous
slicing.

 Static slicing: Static slices are constructed for a subset of the


program’s variables without any assumptions about the input of
the program. After picking a slice’s variable set, we can construct
one of two types of slices: a backward slice or a forward slice. A
backward slice contains the sections of the program that could
affect the slice’s variables, while a forward slice contains those
sections that are affected by the slice’s variables.

 Dynamic slicing: Dynamic slices are formed based on the


variable set and the point in the code we want to inspect in
addition to the sequence of input values for which the program
produced an error. This information is called the dynamic slicing
criterion.

 Conditional slicing: In static slicing, we provide nothing about


the input. In dynamic slicing, we construct it based on a
specific input. Conditional slicing lays somewhere in the middle.
In a conditional slice, we can provide information to the slicing
tool about the input without being so specific about precise
values.

 Amorphous slicing: All previous slicing discussed so far


represents syntax preserving. These approaches are constructed
by deleting the statements that don’t affect the set of variables in
question. However, amorphous slices are constructed using any
program transformation, which simplifies the program while
preserving the functionality of the overall program.

Among those four types, dynamic slicing is the most used technique
in debugging. That is because when we debug, we have a specific test
case that produced the error, so we can use that test case as an input
to construct our slices.

Trace Debugging
In trace debugging (TD), the debugger can set a breakpoint, and
when a breakpoint is reached during program execution, the
program is suspended. Then, the programmer can examine the
program state by running it line by line. The debugger takes control
over the interpreter only, and hence the scalability of TD is the same
as that of the interpreter. During the process of finding the location
of a bug, if a bug is found before the breakpoint, then the debugging
process needs to restart to catch it.

Omniscient debugging

In omniscient debugging (OD), also known as back-in-time


debugging, the debugger can trace the computations of the program
both backward and forward. In this type of debugging, execution
traces are enormous, and storing them is a challenging task, so the
scalability of OD is quite tricky.

Algorithmic debugging

Algorithmic debugging (AD) is a semi-automatic debugging


technique that produces a dialog between the debugger and the
developer to find bugs. So, there is no need to see the code to
perform the actual debugging. That’s why the level of abstraction of
AD is high. AD is done in two phases: First, it builds the execution
tree of the given program. Then, the execution tree made is explored
in full detail.

Hybrid debugging

Hybrid debugging (HD) is a debugging technique that combines


trace debugging, omniscient debugging, and algorithmic debugging.
First, it uses trace debugging to find out the part of the program
where the error occurs. Then, it uses algorithmic debugging on only
that part of the program and produces its execution tree. Afterward,
it applies omniscient debugging to a single method where
algorithmic debugging identified a bug.

Spectrum-Based Debugging
In spectrum-based debugging, also known as spectrum-based fault
localization (SFL), the debugging process is done by monitoring the
statements included in a particular execution tree. This is achieved
by using the program spectrum to identify the active part of the
program during its run. The program spectrum is a collection of
runtime information that gives a view of the dynamic behavior of
the program. It includes some flags corresponding to different parts
of the program. Different types of program spectra exist, such
as block hit/miss and function hit/miss. These spectra are used to
pinpoint the exact sections of the code running for specific or
abstract input.

Delta Debugging
The process of delta debugging (DD) is to minimize automated test
cases. It takes test cases that may cause the error and prepares an
error report. From that error report, minimal test cases are selected
based on their high probability of producing the error. The
minimum test cases will regenerate the same error and thus help the
developer locate the bug behind it.

All About Debugging: Advanced Topics


What comes after standard debuggers?

“Programming allows you to think about thinking,


and while debugging you learn learning.”
— Nicholas Negroponte

When developing software, a specific set of steps is followed until


the final product is reached:

 Setting and analysing the requirements of the goal application.

 Designing the software.

 Testing the code.

 Debugging and fixing bugs.

 Maintaining the codebase.


These steps form the life cycle of a software project. Undoubtedly,
the testing and debugging stages are the most time-consuming
stages. In most projects, developers spend 50% of their time on most
of these steps and the other 50% on debugging alone. Debugging
time can be reduced significantly by writing simple, clear code from
the start.

“Debugging is twice as hard as writing the code


in the first place. Therefore, if you write the code
as cleverly as possible, you are, by definition,
not smart enough to debug it.” — Brian
Kernighan

There are different traditional methodologies for debugging, such as


trace-based debugging, delta debugging, or spectrum-based
debugging. These approaches are best used when the bug we are
trying to locate exists in a codebase that is stored locally and
maintained regularly. For special systems such as embedded
systems, distributed systems, and parallel systems, special
debugging techniques are followed.

There are some advanced topics and questions about the process of
debugging that are either unanswered or take the idea of debugging
to a new level. In this article, we will go through some of these
topics:

1. Anti-debugging techniques
2. Visual debuggers

3. Quantum computing debugging

4. Research questions in debugging

Anti-Debugging Techniques

Anti-debugging is a set of techniques that is added to the code of an


application to detect and prevent the process of debugging it. One of
the main applications of anti-debugging is malware applications. A
malware analyst — also called a reverse engineer — is a person
whose job is to reverse-engineer threats such as worms, bots, and
viruses. A malware analyst will run the malware step by step,
changing some variables to inject changes in the way the application
interacts with the memory.

In other words, the analyst uses some debugging techniques to


understand the behavior of the malware. Once that is done, the
analyst can take action to reverse-engineer the malware, which is
something the creator of this malware wouldn’t want to happen.
Anti-debugging techniques are meant to prevent the program from
running in a debugging mode. These techniques are made to slow
down the process of debugging malware. However, if the analyst is
good enough, they can overcome this, analyze the behavior of the
malware, and reverse-engineer it after all. Anti-debugging requires
an in-depth knowledge of the environment the application is meant
to operate in and fluency in assembly language.

There are several ways to implement anti-debugging properties in


an application. Let’s talk about the top three.

1. API-based anti-debugging

In this approach, the malware designer embeds some checks that


detect when the malware is being debugged. If it is, it will exit the
program. The most commonly used flags are:

 IsDebuggerPresent —This is probably the most straightforward


flag that detects when the malware is running in debugging
mode.

 FindWindow —This is used to detect the existence of specific


debuggers on the machine.

2. Flag-based anti-debugging

Using this approach, the malware will contain flags that detect
several behaviors indicating whether a debugging process has been
initiated.

 Trap flag — This controls the tracing of a program.


 ProcessHeap — This is used to detect the memory heap that is
created when a process gets in debugging mode.

3. Exception-based anti-debugging

This approach checks directly when a breakpoint is added to the


software. If it is, it exits the software.

Visual Debuggers
What makes debugging quite a challenging task is the difficulty of
understanding the abstract level behind the code. It is complicated
for our brains to follow the trace of the instructions behind our code.

Here is where visual debuggers come in.

The notion of visualizing the different steps of an algorithm can be


used to help developers better understand the mechanisms of their
code. The core of any visual debugger is a technique called
program/software visualization. The term software visualization is
used because it is more general and includes both programs and
algorithms. A visualizer will display the data structure represented
in the program step by step as well as the algorithm animation.

Many researchers are aiming to create visual debuggers that ease the
process of debugging for many of the most used programming
languages and developing environments. One of the approaches
used to increase the efficiency of visual debuggers — and at the same
time make designing them easier — is to build application-specific
visual debuggers. Visual debuggers operate by performing some
graph mining of the execution tree to analyze and obtain a plan with
the concrete execution steps of a program for a given input.

Visual debuggers are still an ongoing research effort, with most of


the work restricted to academic use only. However, one software
visualization tool that I find interesting is called Python Tutor, which
is used to visualize the programming learning process. It also
supports other languages such as JavaScript and C++.
Quantum Computing Debugging
Debugging quantum computers is one of the biggest challenges of
developing and building a fully functional quantum computer. It is
even more of a problem for quantum computers than it is for
classical computers. The reason behind this is the way quantum
computers operate.

Quantum computers use aspects of quantum mechanics to perform


computations. The two main principles that quantum computers use
is quantum entanglement and superposition. By nature, quantum
computing is anti-debugging. If we try to sneak a peek at an
intermediate step in the execution, the entanglement and
superposition will break and we will not be able to continue
executing the program.

One way to get around this is by simulating the program and then
using the simulation as a debugging tool. Margaret Martonosi, a
professor of Computer Science at Princeton, pointed out three ways
we can tackle debugging a quantum computer:

1. Debug quantum algorithms based only on the information about


the collapsed quantum state, which is the state the algorithm
shows to be the wrong answer.

2. Use chi-square statistics and probability theory to estimate the


states representing the correct answer.
3. Find patterns within the algorithm that could help the
programmer detect problems.
Under Research in Debugging
Technology is forever ongoing research. There are a lot of advances
to be made in all fields, and debugging is no exception. Current
research questions in debugging — well, aside from quantum
debugging — are:

 Debugging concurrent applications

 Remote debugging

 Debugging machine learning

 Artificial intelligence algorithms

Even existing debugging tools have room for improvement. Can we


make them easier to learn? Can we add visualization and code
performance analysis to them?

If you’ve thought about it, the sky is the limit.

Literature Review
Debugging Backwards in Time
Author Bil Lewis analyses that Over the past forty years there has
been little change in way commercial programme debuggers work.In
1961 a debugger called “DDT” existed on Digital machines which
allowed the programmer to examine,deposit,set breaks,set trace
points,igle step,etc.And the most important question is that “What
information will help the programmer most?”.He describes about
omniscient debugging that it works by collecting events at every
stage change and every method call in a program and he also
mentions about the interesting things about it. The ODB is an
implementation in pure Java which collects information by
instrumenting the byte of the target’s program as it’s loaded.We
want to be able to “revert” the program to any previous
state.Effectively this means that every change in every accessible
object or local variable constitutes aseperate state and must be
recorded.We”ll need to record each assignment in each thread and
define an ordering on them.Every object,variable,I/O stream,etc will
have a known value at each time stamp.The ODB supplies a print
format showing the class name and an index number.Every ,method
call that is recorded will be displayed in a “method trace” pane.The
format of the trace line will be <Object>.methodName(arg0,arg1)-
>retutnValue.Selecting a line in the threads pane reverts the
debugger to the nearest event in tne thread.Modelled after
EMACS,the ODB has a minibuffer which is used to execute extended
commands.The programmer may do an incremental text search
through the “trace:pane,or an event-analysis search through all
events,forwards or backwards.
We have to find “The Snake In The Grass”.For reducing the size
consumed by the bugs the ways to attack to attck this problem are
“garbage collect”old events and throw them away,instrument fewer
methods,record for a shorter time.Grabage Collection is bad that it’s
not throwing garbage away but just older events which might be an
important.By requesting that these methods not be instrumented,a
great deal of uninteresting events can be eliminated,that is “Safe
Code”.If the programmer suspects that a certain known event always
occurs before the bug,then recording could be turned on at that
point and turned off after the bug.
For large number of bugs,the ODB is highly effective.Problems that
took hours with the break point took minutes.In practice,it has
proven to be quiet easy to make bugs fit into 10 million events and
debugging even highly complex program has not been a problem.In
addition to finding the bug,the ODB allows the programmer to
confirm exactly why it is occurred.

Debugging reinvented: asking and


answering why and why not questions
about program behavior

Authors Amy J.Ko,Brad A Myers shares their experience when


software developers want to understand the reason for a program's
behavior, they must translate their questions about the behavior into
a series of questions about code, speculating about the causes in the
process. The Whyline is a new kind of debugging tool that avoids
such speculation by instead enabling developers to select a question
about program output from a set of why did and why didn't
questions derived from the program's code and execution. The tool
then finds one or more possible explanations for the output in
question, using a combination of static and dynamic slicing, precise
call graphs, and new algorithms for determining potential sources of
values and explanations for why a line of code was not reached.
Evaluations of the tool on one task showed that novice programmers
with the Whyline were twice as fast as expert programmers without
it. The tool has the potential to simplify debugging in many software
development contexts.
Debugging: a review of the literature from an educational
perspective

This paper reviews the literature related to the learning and teaching
of debugging computer programs. Debugging is an important skill
that continues to be both difficult for novice programmers to learn
and challenging for computer science educators to teach. These
challenges persist despite a wealth of important research on the
subject dating back as far as the mid 1970s. Although the tools and
languages novices use for writing programs today are notably
different from those employed decades earlier, the basic problem-
solving and pragmatic skills necessary to debug them effectively are
largely similar. Hence, an understanding of the previous work on
debugging can offer computer science educators insights into how to
improve contemporary learning and teaching of debugging and may
suggest directions for future research into this important area. This
overview of the debugging literature is organized around four
questions relevant to computer science educators and education
researchers: What causes bugs to occur? What types of bugs occur?
What is the debugging process? How can we improve the learning
and teaching of debugging? We conclude with suggestions on using
the existing literature both to facilitate pedagogical improvements to
debugging education and to offer guidance for future research.

Debugging concurrent programs


Authors Charles E.Mc Dowell,David P.Helmbold shares their views
that the main problems associated with debugging concurrent
programs are increased complexity, the "probe effect,"
nonrepeatability, and the lack of a synchronized global clock. The
probe effect refers to the fact that any attempt to observe the
behavior of a distributed system may change the behavior of that
system. For some parallel programs, different executions with the
same data will result in different results even without any attempt to
observe the behavior. Even when the behavior can be observed, in
many systems the lack of a synchronized global clock makes the
results of the observation difficult to interpret. This paper discusses
these and other problems related to debugging concurrent programs
and presents a survey of current techniques used in debugging
concurrent programs. Systems using three general techniques are
described: traditional or breakpoint style debuggers, event
monitoring systems, and static analysis systems. In addition,
techniques for limiting, organizing, and displaying a large amount of
data produced by the debugging systems are discussed
Designing the whyline: a debugging
interface for asking questions about
program behavior
Debugging is still among the most common and costly of
programming activities. One reason is that current debugging tools
do not directly support the inquisitive nature of the activity.
Interrogative Debugging is a new debugging paradigm in which
programmers can ask why did and even why didn't questions
directly about their program's runtime failures. The Whyline is a
prototype Interrogative Debugging interface for the Alice
programming environment that visualizes answers in terms of
runtime events directly relevant to a programmer's question.
Comparisons of identical debugging scenarios from user tests with
and without the Whyline showed that the Whyline reduced
debugging time by nearly a factor of 8, and helped programmers
complete 40% more tasks.
Programmers use slices when
debugging
Authors Mark Weiser explores that Computer programmers break
apart large programs into smaller coherent pieces. Each of these
pieces: functions, subroutines, modules, or abstract datatypes, is
usually a contiguous piece of program text. The experiment reported
here shows that programmers also routinely break programs into
one kind of coherent piece which is not coniguous. When debugging
unfamiliar programs programmers use program pieces called slices
which are sets of statements related by their flow of data. The
statements in a slice are not necessarily textually contiguous, but
may be scattered through a program.

Debugging Inputs
Authors Lukas Kirschner,Ezekiel Soremekun,Andreas Zeller When a
program fails to process an input, it need not be the program code
that is at fault. It can also be that the input data is faulty, for instance
as result of data corruption. To get the data processed, one then has
to debug the input data-that is, (1) identify which parts of the input
data prevent processing, and (2) recover as much of the (valuable)
input data as possible. In this paper, we present a general-purpose
algorithm called ddmax that addresses these problems
automatically. Through experiments, ddmax maximizes the subset
of the input that can still be processed by the program, thus
recovering and repairing as much data as possible; the difference
between the original failing input and the “maximized” passing
input includes all input fragments that could not be processed. To
the best of our knowledge, ddmax is the first approach that fixes
faults in the input data without requiring program analysis. In our
evaluation, ddmax repaired about 69% of input files and recovered
about 78% of data within one minute per input.
Debugging optimized code with
dynamic deoptimization
Authors Urs Holze,Craig Chambers,David Ungar shares that SELF's
debugging system provides complete source-level debugging
(expected behavior) with globally optimized code. It shields the
debugger from optimizations performed by the compiler by
dynamically deoptimizing code on demand. Deoptimization only
affects the procedure activations that are actively being debugged;
all other code runs at full speed. Deoptimization requires the
compiler to supply debugging information at discrete interrupt
points; the compiler can still perform extensive optimizations
between interrupt points without affecting debuggability. At the
same time, the inability to interrupt between interrupt points is
invisible to the user. Our debugging system also handles
programming changes during debugging. Again, the system provides
expected behavior: it is possible to change a running program and
immediately observe the effects of the change. Dynamic
deoptimization transforms old compiled code (which may contain
inlined copies of the old version of the changed procedure) into new
versions reflecting the current source-level state. To the best of our
knowledge, SELF is the first practical system providing full expected
behavior with globally optimized code.

References

Atwood, M.E. and Ramsey, H.R. Cognitive structures in the comprehension and memory of

computer programs: An investigation of computer program debugging. TR-78-A21, U.S. Army

Research Institute for the Behavioral and Social Sciences, Alexandria, Virginia, August, 1978.

Chase, W.G. and Simon, H.A. Perception in chess. Cognitive Psychology 5, 4, Oct 1973, 55-81

ABKP86ALLEN, R., BAUMGARTNER, D., KEN- NEDY, K., AND PORTERFIELD, A. 1986.

Ptooh A semiautomatic parallel programming assistant. In Proceedings of the International

Conference on Parallel Processing. IEEE, pp. 164-170

Cha87.David Chase. Garbage Collection and Other Optimizations, Ph.D. dissertation, Computer

Science Department, Rice University, 1987

Cha92.Craig Chambers. The Design and Implementation of the SELF Compiler, an

Optimizing Compiler for Object- Oriented Programming Languages. Ph.D. dissertation,

Computer Science Department, Stanford University. March 1992. Google ScholarDigital

Library

CMR88.Deborah S. Coutant, Sue Meloy, and Michelle Ruscetta. DOC: A Practical Approach

to Source-Level Debugging of Globally Optimized Code. in Proceedings of the SIGPLAN

'88 Conference on Programming Language Design and Implementation, pp. 125-134. Google

ScholarDigital Library

[Bal69] B. Balzer. EXDAMS–Extendible Debugging and Monitoring System. In ACM

Spring Joint Computer Conference, 1969. [BdK00] M. Ronsse K. De Bosschere and J. de


Kergommeaux. Execution Replay and Debugging. In Automated and Algorithmic

Debugging, 2000. [CC77] J. Cohen and N. Carpenter. A Language for Inquiring about the

Runtime Behaviour of Progaams. In Software–Practice and Experience, 7, 1977.

Disscussion
We discussed anti-debugging techniques, visual debuggers,
debugging quantum computers, and some unanswered questions in
the field of debugging that are currently under research.

Debugging will always remain an essential step in software


development, and although new advances will probably appear in
the future, knowing the history and the basics of debugging is a must
for every developer — regardless of their experience level.

There are a number of other strategies that can be used to help the
developer locate bugs existing in the code. As a developer, I always
remind myself of a few things:

 The bug may not be where you’re looking for it. Sometimes when
a developer looks for a bug, they spend a long time inspecting a
specific section of the code just to find out that the bug is
elsewhere.

 Looking at the problem from another angle gives a different


perspective. And by pointing out the parts of the code that are
bug-free, we can reveal where the bug really is.

 Inspect the input data and test details. Sometimes, the test case
may be broken. So, it’s always a good idea to go through it and
make sure everything is on point.
All of the above are techniques used to locate bugs errors, but then
what?

Once a bug has been identified, errors must be corrected. In some


cases, this can be trivial. At other times, it’s going to be
straightforward. Developers must think thoroughly about how a
specific fix is going to affect the remainder of the code. They need to
ensure that the repair will not cause other parts of the code to break.
Bugs that represent conceptual errors in the code are without a
doubt the most difficult to fix. That’s why developers must rethink
not just the fix but also the logic of the program.

Conclusion

Debugging is a central part of what we do as developers. Because


of this, I think it's a good idea to think about it and do it in an
efficient way, instead of just reacting to bugs as they happen.

As we've seen, there're plenty of things we can do, both from a


mental and from a technical point of view, to become better
debuggers

You might also like