Guest post originally posted on the Rookout blog by Noa Goldman

Since the beginning of time, back to before humans invented fire, there were two traditional ways to debug applications: one way -after having invented hieroglyphics, of course – was by reading log lines and the other was by using the common debuggers that surrounded a cave dev’s cave.

It’s safe to say that society has progressed since then and, luckily, so too has traditional debugging. In order to get a clear understanding of how much we R&D team members have evolved, we’ll have to go back in time for a little while to see what it meant to debug traditionally.  

Writing the logs on your cave walls

Let’s review the most prehistoric of debugging methods: logging. The prehistoric developer did this by adding log statements in key paths of the code. Then these logs were printed to a local file or a remote logging server in a distant cave. After, the issue had to be reproduced in the application itself so that the log lines would be printed according to the relevant bug they were trying to fix.

Thankfully, the process of debugging with logs has evolved. In recent years, debugging with logs has grown and matured into what we now call ‘tracing’, in which context has been added to log statements in order to allow developers to analyze the behavior of complex, cloud-native, service-based systems.

Log debugging, especially when used nowadays, has many advantages. The most important one is that the application continues to run as it is without having to stop. When working with cloud-native, distributed systems, logging works well.

However, debugging using logs comes with a few disadvantages. The first is that the logs themselves have to be printed, and as such it isn’t always easy to read through them and understand what they mean, even for the developer who originally wrote them. And this is made even worse by what has been dubbed ‘Logging FOMO’, which is the need a developer feels to add log lines anywhere and everywhere, in the hopes that doing so will give them more insight into their code. The second major disadvantage is the fact that in order to add logs and be able to get the information, lines of code have to be added. It’s not just about writing new code, it’s also about having to wait for the new code to be deployed in order to see the new logs.And, to add salt into an open wound, the overhead for printing the logs and the storage costs for storing them are significant. Suffice to say, the difficulties of log writing today are unavoidable.

Confused Gandalf meme saying "This code... written last month... I have no memory of this place"

We invented the wheel and an IDE

Now that you know all about debugging with logs, let’s continue with our debugging overview and introduce you to: The Traditional Debugger. 

At this point, we’ve jumped way beyond caveman years. With society’s evolution, the traditional debugger was introduced. You modern devs may know what it is, but for those of you who are still stuck in prehistoric times, it’s a debugging tool that allows developers to run the application in a visual debugger, sometimes as part of an IDE, where the code is also written, edited, and version controlled. The visual debugger has breakpoints, snapshot view, intellisense, and other such pretty visual enhancements.

However, much like debugging using log lines, or discovering that there’s a lion outside your cave, there are disadvantages here as well. A major challenge when using a debugger is that the application has to run in debug mode. Usually, this means stopping your applications, which means you’re not really reproducing the behavior of a multi-threaded, multi-service, or cloud-native distributed system. Another significant challenge is that it’s difficult to practice debugging when using remote servers. Attach to process challenges are definitely something to consider when using a debugger.

Less time fixing bugs, more time to for coffee

Lucky for us, in our modern society, alongside inventions such as iced coffee and Zoom calls, new debugging solutions were introduced to the world. These are solutions that attempt to generate a best-of-breed approach, by mixing the two approaches above to get the best of both worlds.

These tools allow managers to enhance their team’s debugging process, reduce overhead costs, and save time and money. For developers, these tools means spending a great deal less time on bug fixing (which can be extremely frustrating at the best of times) by allowing them to, well, log less.

Let’s look at the future called Non-Breaking Breakpoints together and examine what it means and why these tools are necessary in modern times.

Meme showing a gentleman wearing blue shirt holding a cup of coffee saying "Critical bug? Coffee first!"

So, What Are Non-Breaking Breakpoints?

Tools that offer tracepoints, log points, snappoints or Non-Breaking Breakpoints are all tools that are offering methods for modern debugging. Modern debugging provides an easy way to investigate issues using relevant data. The use of modern debuggers allows developers to keep searching for proper bug solutions without having to stop the application from running. These tools usually offer a visual, code-focused interface, where fetching the additional data is done simply by clicking on the relevant line of code.

Such tools allow both developers who know each line of their code and managers who are not as familiar with it to dynamically add a data collection point that once hit will send a log line, trace line, or full snapshot of all local variables, stack trace, and much more.

This modern debugging implementation makes the traditional practice of log debugging and step-by-step debugging possible in several cases which were considered impossible before, such as:

Back to the future of debugging

Now that we’ve crawled out of our caves and into the future, let’s understand how modern debugging tools actually work. In this day and age, modern debugging allows users to fetch snapshots from any desired location in the code. These snapshots are being fetched by placing things called: tracepoints, log points, or Non-Breaking Breakpoints.

A Non-Breaking Breakpoint can be set in any line of code, remotely, in any desired environment, and at any time. Once it is set, the Non-Breaking Breakpoint is able to fetch data, messages, or snapshots which include all local variables being collected from the application in that specific location in the code. It has no effect on the running application or its performance and includes a protection mechanism to make sure there are no overheads while data is being fetched.

Changes are scary. Modern times can bring a lot of uncertainties and confusion. I mean, no one thought that the cronut would actually be tasty back in the day, remember? But don’t worry. Using the new technology of modern debugging is much easier than inventing fire. Don’t believe me? Setting Non-Breaking Breakpoints is so fast and easy, here’s all that needs to be done:

  1.  Attach the correct SDK to your code. It’s a one liner that when added in will allow data to be fetched instantly, remotely, and at any time.
  2. Once the SDK is installed and the IDE is open with the current repository of the running application, you simply set a Non-Breaking Breakpoint and make sure the running application will execute that chosen line. Once it’s done – snapshots will be coming right at you. Easier than inventing fire, right?

New technology can be scary sometimes and you may think that what you’ve been working with so far is enough. And maybe it is, but why put in the extra work when there are tools and technologies out there that will make your life so much easier? Why continue to stay a cave dev, when you can be a modern dev? Embrace change and move forward. And if you don’t do it for the sake of your tech, do it for that extra coffee time you’ll be freeing up.