5 things to remember for better debugging of your code

Naren Yellavula
Dev bits
Published in
8 min readMar 29, 2017

--

PC. ajmexico (flickr)

Namaste, everyone. A software development engineer always thinks her software works fine and firmly believes her logic is unbreakable. But the reality is quite hard-boiled(any software crashes). No software is perfect. In a huge software codebase, the probability of bugs creeping in raises significantly with the addition of thousands of lines of new code covering tons of features. If you were a part of a large system, you should exactly know where to begin and where to end.

There are two major kinds of bugs we usually see at work:

  • Corner cases & rare use cases which are not fixed due to delivery deadlines
  • Enhancements, regressions which are created by your fellow developers or yourself

The second point is notable here. When you are trying to fix a bug from the recently quit developer or from your colleague who is working on another project, you may feel like cleaning the junk created by others. If it is done by yourself you loose motivation of working dedicatedly on bugs because you can work on something more exciting. Fixing regressions is like extending the past work for more time. So in order to reduce the bugs and make your debugging skill sharper, here, I mention few tips.

1) Getting complete information from the tester or bug finder

Always don’t jump into the fixing of the bug. You should analyze few things before writing down the fixing code:

  • Go to the tester. If he is geographically not in your office, try to schedule a Skype call or a phone call
  • Ask him exactly what is the context of the bug.
  • Ask him to attach the screenshot of bug for more visibility.
  • After fixing the bug, make sure that tester agrees on the behavior of software before marking it as fixed.

I saw a lot of developers playing ball throwing game from one end to another end. Technically they can use tools like JIRA but email communication is pretty slower than direct communication. Commenting on the bug and waiting for more info should happen in the worst case. There is a notable mention about this point in the book “The Pragmatic Programmer” by Andrew Hunt & David Thomas.

There is a graphic programmer who wrote code for GUI painting application. Tester filed a bug saying the program is crashing when he tries to draw something. Programmer reckoned that “I painted and everything worked fine on my machine. What more I can do?”. They pushed the ball to each others court all the time. On one fine day, the manager called both of them into a meeting room and asked. “Now test it”. Tester reproduced the bug and programmer stunned. Then programmer explained the reason “I always tested it by drawing a line from top left to the bottom right”. In this case, tester tried to do the reverse. “Paint from right top to the left bottom”. Then the manager said, “why both of you didn’t communicate before itself?”

Really if developer asked tester to give more information when it is happening, this confusion would never occur and developer might have fixed the bug long before(maybe some co-ordinate geometry logic got screwed up)

That is the reason communication plays a vital role in debugging.

Communication is the starting point of debugging. While trying to solve a problem, you should collect all the relevant data(context & route cause)

2) Overcoming the development Myopia: Holy grail of debugging

Developers usually have the development myopia(fixing things by looking at a shorter section in the code). I faced a serious problem in the beginning of my career with this weakness. My manager(a great person) used to shout at me for my laziness in fixing things which caused many regressions. Developers are usually lazy enough to thoroughly test things end to end. Instead, they(including me) assume things rather than proving them. “I am quite sure it will work without testing end to end after fixing a bug”. It gives a huge chance of erring. Even though you changed one line of code, there is a chance of breaking an entire system. Let me tell you how

You changed the signature of a function in a file. You thought that function is used in the same file. You changed the function call too and thought the bug is fixed. You don’t know that function is imported in many other files and being used there. So when you run the software all other features will break.

There is a nice strategy to handle the bad effects of myopia

Ruthless Testing

Thanks to anonymous

Ruthless testing is all about developers doing absolutely everything in their power to ensure that their software is as heavily tested as it can be before the software reaches people, both QA and customers.

In simple words, it is this. “Instead of being lazy, try to do all a tester will do. It means to do a functionality test end to end before handing it to the testing department. Otherwise, the bug is not truly fixed. We need proofs not assumptions”

My manager Chandrashekar, a distinguished engineer always stressed the need of ruthless testing. He says “It is developers duty to test functional aspects of software due to the code change. Tester’s job is just to find out more advanced corner cases”.

If you want to know more about this visit this wonderful resource

Test your bug fix against the whole system and overcome development myopia

3) Using debugging tools

Even though you are fine with sprinkling print statements all over the place, try to use debugging tools like GDB(C) or PDB(Python) or Chrome developer tools(JavaScript). It pauses the execution flow and will give access to you to inspect the variable’s data. It shows you what is predicted behavior and what is actually happening. You just need to set the breakpoint and then step through each line.

There are three kind of gdb/pdb operations you can choose when the program stops at a break point. They are continuing until the next break point, stepping in, or stepping over the next program lines.

  • c or continue: Debugger will continue to the next break point.
  • n or next: Debugger will execute the next line as a single instruction.
  • s or step: Same as next, but does not treats function as a single instruction, instead, goes into the function and executes it line by line.

Personally from my experience, the bugs creep in due to following reasons in Python/JavaScript applications:

  • Unintended data entering into a variable
  • Asynchronous execution of code & no exception handling

So never hesitate to use these tools whenever required. Sometimes jumping(stepping) into third party library functions can make you find some bugs.

Use debugging tools whenever possible

4) A bug is a puzzle to solve, not a lame excuse to blame others

Debugging is a process which consists of emotions and egoistic implications curled with each other for a developer. People treat it as spending energy and time for cleaning a dirty plate that others ate their dinner. Instead, we can have a mindset of solving a puzzle(unknown problem) with an enthusiasm. All bugs are puzzles. Let us go after them with a full attack. This is our opportunity to overcome the panic of fixing bugs.

Some of us have this habit of blaming others for each and every things. It might save you from a hot situation temporarily, but damages your style of working in the longer term. It makes you an irresponsible person in the eyes of your colleagues.

The motivation of solving bugs may not be comparable to the joy of beginning something from scratch and owning everything. But still, it has the business impact. You are not a single one. You are part of a team. Deliverables of a team matters in a larger context. Reducing the troubles of your customer by taking extra care while taking bugs can make you happy too.

Be motivated while debugging. Jump into the customer’s shoes.

5) Logging should be self-explanatory but not a crossword puzzle

Logging is a passive debugging mechanism. Logging is used in any software system for following reasons:

  • For checking the health of system
  • To report any crashes back to the developers
  • If it is a web app, developers can analyze the logs for debugging

How should a perfect logging system be?

It should be in a way that for example in a web application, it should show the Lifecycle of the request coming from the client to response delivered back along with data. By looking at logs in this way,

$ tailf /var/log/app/main.log

we should be able to tell what a request has undergone in its journey from URL router to middleware and then database.

Logs also tell us about the errors which are occurred in between. It is a best practice to separate your logs into multiple categories.

  • Access logs — main log
  • Error logs — errors & crashes

If your logging system is like a crossword puzzle, you are like the Alice in the wonderland running here and there. So it is your duty to maintain a sane logging system so that debugging becomes easier by looking at events.

Leaving the log file as it is can cause disk space problem. To check that, use log rotation or override old logs.

Mongo DB 3.0 uses a concept called capped collections which automatically overrides the space occupied by the older content of the file with new content.

Use logging as an effective debugging helper

A bonus tip:

Always keep track of the bugs you encountered and fixed. If they caused regressions what reasons have caused them?. Try to be proactive in adding the value to your company. Debugging is an art according to Norman Matloff, professor and author of a book on software debugging.

Try to be a good artist. Leave ego and fear behind

Hope you enjoyed the article. Any queries reply to me https://twitter.com/Narenarya3

Resources & Useful Links

--

--

Naren Yellavula
Dev bits

When I immerse myself in passionate writing, time, hunger, and sleep fade away. Only absolute joy remains! Isn't this what some call "Nirvana"?