Talks

Lightning Talk: Adding byebug to the Professional Puts Debugger Tool Set

Lightning Talk: Adding byebug to the Professional Puts Debugger Tool Set

by Zhi Ren Guoy

In this lightning talk at Euruko 2021, Zhi Ren Guoy provides an insightful introduction to adding Byebug to the professional Ruby debugger toolset, emphasizing its role in improving debugging practices.

Key points discussed throughout the presentation include:

- Introduction to Byebug: Byebug is a Ruby debugger gem that enhances the debugging experience for Ruby programs, specifically supporting MRI 2.5 and above. It allows developers to debug without modifying the code.

- Transition from traditional debugging: Guoy highlights the limitations of traditional debugging methods, such as using ‘puts’ statements for tracking execution paths, which can become unwieldy. Byebug offers a more structured approach.

- Basic Commands: A brief overview of essential Byebug commands:

- help: Displays all available commands.

- list: Shows the lines of source code surrounding the current execution point.

- break: Sets breakpoints in the code to pause execution.

- continue: Resumes execution until reaching the next breakpoint.

- next: Executes the next line and allows for line-by-line tracking.

  • Conditional Breakpoints: Byebug supports conditional breakpoints, which allow the debugger to stop execution under certain conditions, improving debugging efficiency.
  • Variable Inspection and Mutation: Using Byebug, developers can inspect and change variable values as the program runs, which aids in understanding and correcting errors.
  • Viewing Variable Scope: The debugger helps in identifying variable scopes (global, instance, or local) which can clarify issues related to value changes.
  • Debugging Third-party Gems: Guoy outlines that Byebug's step command enables developers to investigate issues within third-party gems, which is challenging when using only traditional methods.
  • Integration with Rails: Since Rails version 4.2, the Byebug gem is included by default, simplifying initiation of debugging sessions within Rails applications. A simple invocation of the 'byebug' method begins the debugging process at that line.

Throughout the talk, Guoy intersperses humor with practical guidance, making the technical content accessible and engaging. The presentation wraps up with references for further learning about Byebug and debugging practices in Ruby, encouraging attendees to explore the tools discussed.

The main takeaway is that Byebug provides a robust framework for debugging Ruby applications, facilitating error identification and correction far beyond what traditional debugging methods can offer.

00:00:00.080 Welcome everyone! It’s time to learn some tricks in this lightning talk. My name is Zhi Ren Guoy, and I will be discussing how to add Byebug to the professional debugger toolset. I’m a software engineer at Fave, where I typically work with Ruby on Rails. I am an agilist at heart, always keen on exploring ways to work better by adopting a lean and agile mindset. Additionally, I tinker with operations and infrastructure, focusing on improving continuous integration and deployment. Today, we will have a 15-minute crash course on getting started with the Byebug debugger.
00:00:21.680 Before I start, I’d like to give a quick shout out to everyone involved in organizing Euruko 2021. Thank you for all the time, effort, and work that went into this event. Here’s a general reminder for everyone to follow the code of conduct. A little about myself: I’m currently a Ruby on Rails engineer who makes terrible memes and bad puns—I’ll share a few throughout this talk. I also co-host a monthly podcast about software development. Most of the time, I appear on social media as 'ghost eat human', a pun on my name—don't worry, I don't actually eat people. I assume many of us, in our day-to-day jobs, ship working bugs—oh, sorry, I meant features! As part of our work, we write tests to ensure our code functions correctly. However, what do we do when we find something wrong with the program and can’t quite pinpoint the issue? Usually, we read through the code line by line, examining the logic, hoping to decipher why it isn’t working. Maybe we can figure out the issue just by reading the code. If reading the code alone doesn’t resolve the issue, we often resort to using 'puts' statements to track the code execution. You know how it is: puts here, puts there, puts everywhere! Hopefully, we can find out where the bug occurs. However, what if puts isn’t enough? Another approach is to use a debugger, which is an application that allows us to run the program under controlled conditions.
00:03:02.800 Let’s take a look at a terrible example. In this example, we have a function that takes a user ID and a hash called 'referred'. If it’s the first time a user gets referred, and they are not in the hash, they get a discount. However, if they have been referred before and are already in the referred hash, they don’t get a discount. Naming things can be difficult, and I had a hard time coming up with a good name for this example. This code is intentionally flawed for a reason. At the end of this program, I send a message for user ID 1 and an empty hash, expecting to get a discount. However, when I run it, it returns zero. Now, let's examine the professional Byebug way. To see how it features a certain line of code, we use puts to help mark the execution path. Since we didn’t see any similar puts statements in the output, we know that the code did not pass through that line. Buying byebug is a Ruby debugger gem that supports MRI 2.5 and above; it does not support other implementations such as JRuby or Truffle Ruby. We can run Byebug from the command line to debug a Ruby program without editing the code. Running Byebug on the program displays the file content, and the left playback shows the number of lines along with which line the debugger is currently on. At the bottom, there is a prompt where we can input commands. The first thing we need to know is what commands we can input. What better way to find out than calling the help command? The help command provides a list of all available commands. Rest assured, we will quickly go through some of them. By the way, quitting Byebug is much easier than quitting Vim!
00:05:06.160 Next, let’s discuss the 'list' command. Using the list command shows all the lines of source code, along with the line of code you’re currently pointing at. In this case, it’s line 1. Now, let’s talk about the 'break' and 'continue' commands. The break command sets breakpoints in the source code, and Byebug will stop execution when it reaches a breakpoint. The continue command resumes the program execution until it hits the next breakpoint or reaches the end of the program. Based on the code logic, the program should stop at line 5. We want to stop at line 5, so we need to set a breakpoint there. The continue command will then execute until it reaches the next breakpoint or the end of the program. However, we see that execution returned 0 at line 3 instead of stopping at the breakpoint at line 5. The next command is like the continue command but proceeds to the next line instead of the next breakpoint or the end of the program. We know that the program returns at line 3, and we can confirm this by using the next command to perform a line-by-line execution. Byebug also supports conditional breakpoints. We can set breakpoints based on specific conditions. For example, I can create a breakpoint at line 3 if a user has been referred before. Let's say we want to know the values of some variables. As professional Byebug users, we can print the values of variables using puts. In Byebug, we can type the variable name in the console, and it will show the value of the variable at the line being executed. At line 3, we can check that user ID has a value of 1. Furthermore, using Byebug allows us to mutate variables on the fly. Here’s another example program that prints the value of 'a'. Initially, 'a' is set to 1. We can use the next command to move the code execution to the next line and then set 'a' to 42. As a result, at the end of the program, 'a' will have the value of 42.
00:07:06.960 We can also utilize Byebug to understand the scope of variables. This capability helps us determine which variables are global, instance, or local. For example, there are scenarios where we want to track when the value of a variable changes. In the case of a professional debugger, we might have puts statements all over the place to track variable values. Byebug provides another option: we can use the 'display' command to show the value of variables every time the debugger stops. The 'set' command modifies Byebug settings, and the 'set trace' command enables line execution tracing. With these two commands, we can monitor the value of a variable at every line of code execution. Now we’ve found out where the issue is! The truth is, we all write programs that depend on gems, and this is where I feel we hit the limits of being a professional puts debugger. For instance, if we’re using a third-party gem, like a QR code generator, there’s no way to debug it using puts unless we have access to the source code itself. Even if we do, it may be a hassle to clone the repository and scatter puts all over the code. In such cases, we can use Byebug’s step command to delve into gem methods. By doing so, we can step into the gem’s code and see what’s going wrong. However, if we realize we’re lost in a rabbit hole of code, we can simply ask Byebug where we are, and it will indicate our place in the execution path. Lastly, when using Byebug in Rails, know that the Byebug gem is included in Rails by default since version 4.2. In the code, call the 'byebug' method to initiate debugging, and the debugger will start at the line following the byebug method call. That concludes my talk. Here are all the references I used to prepare for this presentation. I hope you all learned something today. Thank you!