Debugging [1d]

When your code does not behave as expected, you can use a debugger statement ("breakpoint") at any point in your code. This statement will open a REPL Show archive.org snapshot ("console") that you can use to inspect the current state of the program and move the control flow ahead manually.

Use debugging tools to find the exact line in the code where your expectation does not match the actual behavior. Since we use open source for everything, we can always find that line. When you ask a colleague for help, they will be able to help you better when you have already located the issue.

Learning to help yourself and ask good questions

Debugging in Ruby

Note

Running your server as part of a single combined terminal with the bin/dev command makes Ruby debugging harder.
To work around this, you should start your web server in a separate terminal as described above. If you are using terminator, bin/term is the easiest way to to achieve this.

  • Include the byebug gem in your Gemfile. This provides debugging for your app.
  • At any line, insert the command byebug or debugger.
  • When you start your app and the Ruby interpreter passes this line, this will open a debugging console. Do this.
    • Note that when your app is a web app, the console running your rails server will pause the server and show the debugging console. Your browser will "hang" while that debugging console is open.
    • Note that the byebug console is not a full irb console, even though it somewhat behaves that way.
  • Use the byebug README Show archive.org snapshot , byebug's help command (check help help for its usage) and our byebug cheatsheet to learn to do the following in the debugging console:
    • Understand your current position in the program
    • Read local variables
    • Call methods that are reachable from the current scope
    • Switch into a full irb console and back to byebug
    • Move the program position one statement ahead
    • Jump into the next method call
    • Jump out of the current method call
    • Exit debugging console and resume program
  • Use a simple raise statement e.g. in controller code and open the corresponding page with your browser
  • If you need to debug code that is part of a gem like rails, just (temporarily) add a puts or debugger statement to its source files. Ruby is an interpreted language after all!
  • You should be in a habit of reviewing your code before committing. Never commit a debugging breakpoint.
  • If you are debugging rspec tests, you can use rspec -b to print the full stack trace.
  • If you encounter problems caused by ActiveRecord and its database mapping, you can run ActiveRecord's query methods in the rails console and it will log the exact database interaction with related sql commands and its result.
  • Before you know where to debug, you will often find yourself staring at logs beforehand - they are your friend at this mission!
    • Use Rails.logger.info() to add your own custom messages to log/<environment>.log
    • Use tail -f log/development.log for a live view of the local Rails server's log
    • ..or tail -f log/test.log to see the same for RSpec tests!

Different debugging libraries

Ruby has always had multiple gems for debugging. When you're working on a customer project you need to check the Gemfile to see which one is used.

All Ruby debugging gems have the same basic functionality:

  • Add a breakpoint
  • Get an IRB-like console when the breakpoint is reached

A debugging gem will also offer commands to step through your program, but their names differ from gem to gem.

Each gem also uses a different expression to set a breakpoint:

Gem Breakpoint
pry Show archive.org snapshot binding.pry
byebug Show archive.org snapshot byebug
debug Show archive.org snapshot binding.break

Debugging in JavaScript

  • At any line, insert the command debugger
  • When a modern browser's JavaScript interpreter passes this line, this will open a debugging console if developer tools are already open. Do this.
    • Note that since JavaScript is single-threaded, you cannot interact with your app's frontend while the debugging console is open.
  • Use the Google DevTools debugging guide Show archive.org snapshot to learn to do the following in the browser's debugging console:
    • Understand your current position in the program
    • Read local variables or this. Observe how Chrome will automatically show the state of local variables in the Sources tab.
    • Call functions that are reachable from the current scope
    • Move the program position one statement ahead
    • Jump into the next method call
    • Jump out of the current method call
    • Exit debugging console and resume program
  • You should be in a habit of reviewing your code before committing (e.g. by using git add -p). Never commit a debugging breakpoint.

Debugging in Cucumber scenarios

  • If you haven't done so already, configure Capybara to open Chrome for scenarios tagged with @javascript.
  • When you use Spreewald Show archive.org snapshot you can open a debugging console at any line in your Cucumber scenario, by saying Then console. Do this.
  • Try this out from a debugging console:
    • Use page.find(...) to inspect the current DOM.
    • In a @javascript scenario, observe the current frontend state in the Selenium-controlled browser. If you run E2E tests in headless Chrome, you may need to re-run the test with a visible Chrome window (NO_HEADLESS=1). Note how you can even use the developer tools in the Selenium-controlled browser to inspect the DOM or run commands on the JavaScript console.
  • When a step fails and you don't know why, it is often a good idea to open a debugging console right before the failing step.
    • You can put debug statements within Ruby code as well.
    • To check the server log, enter tail -f log/test.log in your terminal to print the server log while the test is running.
    • To print the full stack trace you can use cucumber -d ...

Debugging network traffic

  • Your browser DevTools have a Network tab. You can use it to observe outgoing network requests and their responses.
  • Try this with an app like cards:
    • Open developer tools and go to the Network tab
    • Check Preserve log in the tab's settings so the list isn't cleared before a full page load.
    • Switch between a few cards. What requests and responses do you see?
    • Update an existing card. Find your form data ("params") in the the relevant request entry in the Network tab.
    • Find out how to throttle the network traffic in your browser to simulate a slow internet connection
  • You can also use the curl command in your terminal to print the response of a request.

Debugging DOM changes

  • In your browser you can right-click any element and choose Inspect.
  • This will open a tree displaying the current state of the DOM. The tree is live, so it will be updated automatically when your DOM changes.
  • Do this on the large hero photo at https://makandra.com/ Show archive.org snapshot .
    • Can you find the element for the photo?
    • Observe how the DOM changes as the photos are rotated every few seconds.
Henning Koch Over 5 years ago