00:00:00.000
Our next speakers are a dynamic pair. One of them, Stanislav, is quite young but has several impressive projects to his name. Let's give him a round of applause because, as I mentioned, this is his first time speaking at a conference. He has worked mainly on desktop projects using C and C++, but he is also using Ruby for some smaller projects. Franz is also quite young—he looks even younger, so you can ask him about his age later. The interesting thing about him is that he is an automation expert and part of the team that records this conference. He was introduced to Ruby last year at this very event, which is pretty cool. In a stroke of fate, a few months later, they both started working at the same company where they began using Ruby in their projects. Today, they are here to tell us about their project called CodeTracer, a new way to debug. Let's give them a warm welcome!
00:01:17.720
Hello everybody! Today, we're going to talk about CodeTracer, which is a revolutionary time-traveling debugger for Ruby programs. First, we will explain what a time travel debugger is and show you a quick demo of how it works. After that, we will delve into some technical details about how it functions behind the scenes. Then, we will share the history of the project and what remains to be done. Lastly, we'll discuss how you can contribute to our open-source project.
00:02:03.159
Before we dive deeper, Stanislav has some questions for you all. Hi everyone! How do you feel when you're debugging? Do you sometimes feel sad when you can't resolve a bug in time? Are you sometimes disappointed in your skills, or do you feel frustrated with the programming environment? Do you get angry at yourself, your colleagues, or the technologies you use? Have you ever felt so desperate while debugging that you considered reinstalling your operating system just to see if it would fix the issue?
00:02:10.640
Do you debug for so long that you feel like you might be losing your mind? Do you hear voices in your head? As seasoned developers say, sometimes bugs can feel overwhelming. But what if I told you that we have a solution to these frustrations—or at least a partial one? Introducing CodeTracer! CodeTracer is a time-traveling debugger that records the execution of a program into a self-contained trace file. You can think of the trace file like a video recording of your program, allowing you to skip ahead, rewind, and explore any moment of the program's execution repeatedly in order to find bugs.
00:02:39.360
Let's look at what we can see on the screen here. As you would expect from any debugger, we can jump forwards in the code, set breakpoints, and navigate to those breakpoints at will. What makes CodeTracer remarkable is that you can do all of these steps in reverse. You can jump back to a previous breakpoint or navigate backward to another previous line of code. In the top right part of the screen, we have what we call a code trace. The code trace is essentially a list of every function call that will happen throughout the execution of the code. If we collapse the two functions at the top level, we can see how they correspond to the code in our simple test program.
00:04:06.720
Let’s take a closer look at the iterate asteroids function, which we are calling multiple times. This allows us to use the code trace to quickly navigate to each function call. Now that we’re in the iterate aster oh wait... sorry for the momentary switch. As we navigate, we’ll see the features of CodeTracer, including omniscient loop controls. We can move through each step of the loop and navigate in reverse as well. Let’s zoom in a bit—this upper panel shows the values of each variable in real-time as the program executes.
00:05:34.560
You will notice that as I move the slider, the displayed variable values update accordingly. Additionally, in the bottom right part of the screen, we see the event log. The event log lists every interaction your program has with the outside world, including non-deterministic events that could lead to errors or unpredictability, such as network events or file interactions. Each time a relevant event occurs, a snapshot of the program is taken, so we can reconstruct the history of what has happened each time.
00:06:58.000
At the top of the screen, we also have the state panel, which provides an overview of what the current line of code can access in terms of local variables. Here, you can see a list of all the local variables that line 15 has access to. Because CodeTracer is omniscient, it also records the history of each variable. For instance, the damage variable was initially unassigned, then assigned 0, followed by -20,000 and so forth.
00:08:11.680
Another impressive feature of CodeTracer is the trace lock, which allows you to inject code into your recorded program as you debug. For example, I can log the damage variable and see a list of every instance where the program passed through that line of code, along with the exact value of the variable at each instance. Furthermore, I can log the iterator, which will allow us to visualize the process better. As we see here, when the iteration equals zero, we know we've gone through this function for the second time.
00:09:21.760
This feature helps you pinpoint bugs more easily. We also have the scratch pad feature, which allows you to set aside specific variables for later inspection. This is particularly useful when dealing with objects containing many properties, allowing you to focus on just the parts you're interested in without needing to navigate through everything. In the future, CodeTracer will support loading multiple projects at once, making this feature even more beneficial.
00:10:36.720
Now, how do we actually use this debugger in a typical debugging session? I've prepared a simple example program called SpaceShip, which could be a part of a video game. In this example, a spaceship with a shield is navigating through an asteroid field, where collisions are inevitable. As the shields deplete, their efficiency deteriorates drastically—the damage taken when shields are at 50% would be 50 times greater. Let's see how this program behaves. We have two arrays of test cases, and right off the bat, we notice something odd in the event log: the initial reported damage is zero when it should not be.
00:12:04.000
In CodeTracer, if you observe something suspicious, you simply click on it, which brings you to the status report function. It’s common in many projects that error reporting occurs far from where the bug is located, but since CodeTracer allows for time travel debugging, we can step back into where the actual problem resides. When we examine the loop again, it's clear that the function for calculating damage is returning zero, indicating something is amiss. As we investigate further, we find that while the mass is set to 100 and the remaining shield is also set to 100, the calculation being performed is incorrect since it multiplies the mass by 100 minus the remaining shield, which would yield zero.
00:13:28.000
Unfortunately, someone forgot to add an if statement in the calculation, which caused the first calculation to fail—spoiler alert, that someone was me! As I continue observing the event log, I see another issue where the calculated damage in subsequent iterations becomes a negative number. To understand why this is happening, I can step backwards in the same manner we did before, now observing the second iteration of the loop.
00:14:52.640
Once again in the calculation function, we see that damage is returning an odd negative value. The issue is due to the shield exceeding 100% during the execution flow. As a developer, I recognize the need to rectify this, and with some quick editing, I can fix the identified issues. Now, let's advance to the next iteration where I've implemented the necessary corrections.
00:16:59.840
With the adjustments made, at 100% shields, the damage inflicted by the first asteroid should indeed be 100, just as we initially predicted. However, scrolling down, we can see that the final result shows that the test has failed. According to the logs, we expected the spaceship to be destroyed during the negative test case, but it survived. In such scenarios, it's beneficial to have access to a variable history to gain insight into what transpired.
00:18:40.480
Therefore, we navigate back to the function where the core logic resides. As I inspect the various values, nothing appears to be amiss with the damage output. However, examining the remaining shields also yields no immediate concerns. When stuck on a problem, we can lock multiple variables simultaneously to reveal new information. As we progress through the iterations, we discover a moment where the remaining shield dips to -670, a critical situation that wasn't immediately evident just from the logs and status panel.
00:20:42.720
This realization highlights the program's response during debugging without needing additional logging or restarting the program. It’s a simple yet effective demonstration of how CodeTracer's features can significantly streamline the debugging process. Now, let's touch upon how you can contribute to CodeTracer, as there are still some inefficiencies that need to be addressed for larger projects. These stem primarily from limitations in the Ruby trace API and the interpreter itself, which means we need your support to rectify these issues.
00:22:58.320
The community's interest and involvement would signal to us that there are capable developers ready to help enhance CodeTracer’s functionality. Despite the current limitations, it works well for smaller projects. As Stanislav mentioned earlier, I first encountered Ruby last year at this conference, and within just two months, we were able to add Ruby support to CodeTracer.
00:25:12.640
Acknowledging the potential for improvements, we aim to enhance the product. In our GitHub repository, you can explore the source code and view details of how CodeTracer has been implemented, particularly the Ruby backend, which is a small application that's quite accessible to understand.
00:26:17.840
Moreover, we have dedicated documentation to help new users learn how to contribute or develop for CodeTracer. Additionally, through our open collective, supporters can gain early access to forthcoming backends. Although the development of the RR backend is complex and time-consuming, we aim to integrate it into CodeTracer soon.
00:28:27.200
In the meantime, if you or anyone you know in the industry is looking to invest in the project—a development in system programming languages for instance—do encourage them to reach out to us. We also have a Discord server for feedback, and CodeTracer is available for download from GitHub, with set repositories for various Linux distributions launching shortly.
00:29:00.000
Thank you all for your attention! We hope to see you again next year at the same presentations to discuss all the changes that will have taken place by then!