Debugging
cornerstone of programming
Most important skill
Helps professional programmers work in a non ideal world
It is to see into the execution of a program by examining it.
For fixing the error
For understanding the software which lacks documentation, tests
To get visibility into the execution of a program you must be able to execute the code and observe something about it.
Sometimes this is visible, like what is being displayed on a screen, or the delay between two events.
In many other cases, it involves things that are not meant to be visible, like
the state of some variables inside the code
which lines of code are actually being executed, or
whether certain assertions hold across a complicated data structure.
These hidden things must be revealed.
The common ways of looking into the ‘innards’ of an executing program
Using a debugging tool,
Printlining
Making a temporary modification to the program, typically adding lines that print information out
Logging
Creating a permanent window into the programs execution in the form of a log.
Involves changing code to find out what is going on
safe doing this using existing tests suite and version control
Debuggin: Splitting problem space
IT is a mystery to be solved
You think it should do something, but instead it does something else.
Use divide an conquer to split different areas of code to debug
This can be passed to other members of the teams
Other dimensions of the program, such as
the space of executed lines
the data structure
the memory management
the interaction with foreign code
the code that is risky
the code that is simple
Removing the error
In fixing a bug, you want to make the smallest change that fixes the bug.
You may see other things that need improvement; but don't fix those at the same time.
Attempt to employ the scientific method of changing one thing and only one thing at a time
The best process for this is to be able to easily reproduce the bug, then put your fix in place, and then rerun the program and observe that the bug no longer exists.
Sometimes, there are really several bugs that look like one.
-
Debugging tool
Debugging tools often lag behind language development, so at any point in time they may not be available.
the debugging tool may subtly change the way the program executes it may not always be practical
Using IDE
Break points
Handling loops
Where to place
use stack trace
debugging through streams
Go to breakpoint
next step
go into
Evaluate expression
code fragment
Use print statements
for when app is running in container and cannot debug via IDE
Stack trace
Search for exception message
search for path which involves your code
Debug using Logs
Logging is the practice of writing a system so that it produces a sequence of informative records, called a log
The amount of information that is provided by the log should be configurable, ideally while the program is running
Beneifts of logs
Logs can provide useful information about bugs that are hard to reproduce (such as those that occur in the production environment but that cannot be reproduced in the test environment).
Logs can provide statistics and data relevant to performance, such as the time passing between statements.
When configurable, logs allow general information to be captured in order to debug unanticipated specific problems without having to modify and/or redeploy the code just to deal with those specific problems.
The amount to output into the log is always a compromise between information and brevity. Too much information makes the log expensive and produces scroll blindness, making it hard to find the information you need. Too little information and it may not contain what you need.
Typically, each record in the log will
identify its position in the source code
the thread that executed it if applicable
the precise time of execution,
commonly, an additional useful piece of information, such as the value of some variable, the amount of free memory, the number of data objects, etc.
These log statements are sprinkled throughout the source code, particularly at major functionality points and around risky code
Each statement can be assigned a level and will only output a record if the system is currently configured to output that level.
You should design the log statements to address problems that you anticipate
Debugging performance problems
Even if you understand perfectly precisely the cost of the code you write, your code will make calls into other software systems that you have little control over or visibility into.
Before you try to make your system faster, you must build a mental model of why it is slow.
can use a profiling tool or a good log/metrics to figure out where the time or other resources are really being spent.
Often most of the time is spent in I/O in one way or another. Finding the expensive I/O
There are many dimensions to the performance of a computer system, and many resources consumed.
The first resource to measure is wall-clock time, the total time that passes for the computation.
can inform about unpredictable circumstances that arise in situations where other profiling is impractical
may not always represent the whole picture
Sometimes something that takes a little longer but doesn't burn up so many processor seconds will be much better in the computing environment you actually have to deal with.
memory, network bandwidth, database or other server accesses may, in the end, be far more expensive than processor seconds.
Contention for shared resources that are synchronized can cause deadlock and starvation.
Deadlock is the inability to proceed because of improper synchronization or resource demands.
Starvation is the failure to schedule a component properly
Fixing
Intermittant bugs
This nightmare occurs so rarely that it is hard to observe, yet often enough that it can't be ignored. You can't debug because you can't find it
What makes it hard is that it occurs only under unknown conditions
Try to record the circumstances under which the bug does occur, so that you can guess what the variability really is.
The condition may be related to data values
If that is not the source of variability, the next suspect should be improperly synchronized concurrency.
try to reproduce the bug in a controlled way.
If you can't reproduce it, set a trap for it by building a logging system, a special one if you have to, that can log what you guess you need when it really does occur.
Necssary if bug only found in production
But takes a long time
This can happen in third party code
Debugging while container is up
Debugging after merge
When merging, must make sure that the branch or patch already passes the build
when merged and compliation passes, there will probably be failing tests
especially if patching changes from current system to a new system, as new system may have changed (refactored/deleted code/changed code etc)
Check things which might be affected from the changes made first, this might require using a debugger to find where in code base the flow hits the changed code
Last updated