An introduction to debugging code


#1

Recently while helping someone make improvements to an SVG shape editor being developed on JSFiddle, we were setting the currently active shape with a thicker stroke. That worked when one of the Stroke input fields was active, but when selecting one of the Shape input fields that Active stroke on the element was being removed.

Using the debugger I easily found the cause of the problem, but just giving the answer of how to fix it isn't all that useful, as nothing much is learned.

What follows is a breakdown of how the debugging process occurs, and aims to be a useful guide for others attempting similar debugging work as well.

Reliably causing the problem

When debugging code, it's very useful to have a reliable way to cause the problem to occur. This allows us to easily experience the problem, and acts as a confirmation afterwards that the problem has been fixed.

In this case, when a shape is selected, such as the green line, clicking on a line field like Y1 results in the thickened stroke around the active green line going away. That is the bad behaviour that we want to prevent from happening.

Investigating the issue

That thick green line is controlled by an attribute on the SVG shape called stroke-width. We want to find out when that stroke-width changes, to help us further understand what is causing the problem.

The person I was helping uses Firefox, but since Firefox 52 the debugger has been revamped, and doesn't support all of the features that it used to.

It is possible to still investigate the code using Firefox, but it can be tricker, by:

  • manually setting breakpoints,
  • or by searching for text such as "stroke-width" and setting breakpoints

So in the meantime, because it's not as easy to debug code with Firefox as it is with Chrome (or I just don't have the right tools for Firefox), I'm going to use Chrome to demonstrate how to debug the code.

Breakpoints

Because the problem seems to be that the stroke-width is changing to an inappropriate value, I can set up a debugging breakpoint that triggers whenever an attribute on the green element is changed.

In Chrome, I want to get things ready for when I click on the Y1 input field to trigger the problem.

With the green line selected in the dropdown box:

  • Right-click on the image and select Inspect.
  • Find that green line in the displayed HTML code.
  • Right-click on that line, then Break on -> attribute modifications.

That way, when I click on one of the line fields such as Y1, the debugger will watch for any changes to the attributes on the green line, and break in to the code when those changes occur.

Stepping through the code

Clicking on the Y1 line field results in the debugger breaking into the code at the following line, where the line coordinate is being updated.

shape.setAttribute(input.id, input.value);

Hovering my mouse over id I see that the id is "y1", and hovering over value I see that it's the same number from the input field. That's good and expected, for that sets the y1 coordinate of the SVG line. We can press the Resume script execution button to continue on.

The next breakpoint occurs at the start of the showSVGCode function, where the stroke-width is removed. That's why stroke-width is being removed. But I do see at the end of the function that the it is added back again. I can press the Resume script execution button and expect that the next breakpoint will occur at the end of the function.

The breakpoint now occurs at the end of the showSVGCode function which is entirely expected. This is where we add the stroke-width back on to the element, and it feels like a likely cause of the problem, so let's step closely over this code.

getActiveShape().setAttribute("stroke-width", document.getElementById("active"));

Pressing the Step over next function call button I observe that the green active line doesn't appear back on the screen, as would be expected. Why doesn't it appear?

Going back to the Elements panel I see that the green line now has a stroke-width that contains a value of "[object HTMLInputElement]".

We have now found the cause of the problem, so what went wrong?

Exposing the problem

It is easier to see what's causing the problem when the value being set to the attribute is assigned to a variable. This will also beneficially reduce the size of that long line of code, making it easier for us to understand what it's doing.

We can use an Extract Variable technique for the active id to achieve this.

We need to get out of the paused script before we can change the JSFiddle code. Pressing the resume script execution button again gets us out of the paused script, and the jsfiddle code can now be edited.

To extract the active variable, we create a variable that is assigned the same thing that's being set to the attribute:

var active = document.getElementById("active");

This allows us to then use that active variable in the next line of code:

var active = document.getElementById("active");
getActiveShape().setAttribute("stroke-width", active);

I now think that I can tell what is causing the problem, but we can use the debugger tools to help confirm that suspicion. The good news is that I don't have to repeat all of the debugging process from before.

Instead, I can:

  • run the JSFiddle code and select the green line,
  • go over to the Sources tab in the Developer Tools area,
  • in the (index) tab, I can scroll down to the showSVGCode function,
  • find that var active line that I added, and
  • click on the line number to set a breakpoint there.

Selecting the green line and clicking on the Y1 line input field results in triggering that breakpoint on the var active line. I can then use the step over next function call button to execute that line, and I can now more closely examine the contents of that variable.

Determining a solution

Investigating that active variable, I see that it's a reference to input#active which leads to the insight that using active.value will lead to success. I can confirm that by scrolling down through the list of properties that the debugger shows me for input#active, and down at value I see that it has a value of "6"

The reason why the stroke-width isn't turning up is because we are trying to assign the input field as a whole object, when we need to instead assign the value of that input field.

Fixing the problem

We are now in a good place to fix the cause of the problem by giving setAttribute the value of the active input field.

// getActiveShape().setAttribute("stroke-width", active);
getActiveShape().setAttribute("stroke-width", active.value);

Testing the code by selecting the green line and clicking on the Y1 input field, now results in the active stroke-width no longer being removed from the line, and this problem is now fixed.

We can now click on the line number of that var active line to turn off the debugger, and close the developer tools panel.

Now that the problem is fixed, we can delete the commented out line of code from above.

Improving the code

With the code now in a better working state, this is a good time to think about how we can reduce the likelihood of this type of problem from happening again.

In this case, we have a separate applyStrokes() function that can be used instead. So, the code that we had before can be entirely replaced:

// var active = document.getElementById("active");
// getActiveShape().setAttribute("stroke-width", active.value);
applyStrokes();

The problem no longer occurs, and we have reduced the opportunity for similar problems to occur.

Conclusion

Sometimes it feels like only trial and error can be used to experiment with problems.

This post helps to explore some of the tools that are available to you, that can help you to shine a light in the dark.


Please someone help me with my snake game, can't get a good answer
pinned #2

closed #4

This topic was automatically closed 91 days after the last reply. New replies are no longer allowed.