What is RPA?

To thrive in this continuously evolving technological and economic change, organizations need to focus on two main objectives: automation & digital transformation. Businesses these days are operating…

Smartphone

独家优惠奖金 100% 高达 1 BTC + 180 免费旋转




Debug Your Go Code Without 100 Extra Printlns

A lot of people use Println debugging.

That is: When your program doesn’t work, add a ton of Printlns everywhere so you know whether things are going the way you planned as your code runs.

Take the following code — and yes, there’s a bug in it:

The idea is to listen for connections, and simultaneously send a GET request to that listener. The listener should reply with Howdy!, and the output should be: The webserver said: Howdy!

Instead, it just hangs without printing my message. In attempting to debug this, you’ll typically see something like:

You’d then add all sorts of variables to these Printlns, track how they change, and so on.

I’m not a fan of this approach, but surprisingly it is the main debugging technique of so many amazing developers.

It’s not ideal though: Your code gets really messy, you forget to delete them afterwards, and often they don’t really provide the information you need.

Luckily, there’s a better way.

A debugger is a tool that breaks down the execution of your code, allowing you to step through it line by line, or dive inside every function call, or just stop at specific points of your code so you can see what’s going on.

To learn how a debugger works, let’s assume you’re a newbie developer and you’re trying to figure out why the code in the excerpt above hangs instead of giving you the expected response.

We’ll learn the main debugging commands you need to be familiar with: break, continue, next, step, restart, breakpoints, clear, and locals.

To start debugging, go into the folder where your code is, and type dlv debug. This will build your project, run it, and attach the debugger to the process. It doesn’t output much:

The first thing you’ll need to do is tell Delve where to stop. You don’t want it to just run through your whole program, you want it to stop somewhere so you can analyse things. These stopping spots are called breakpoints.

Since we don’t really know where the problem lies, just that the program hangs, let’s start with func main(). We can do that with either break or just b.

You’ve set your first breakpoint. Let’s start our program and see what happens.

For that, use continue, or just c. It runs the code until it hits the next breakpoint.

Now our program is running, and it has stopped on line 10.

Let’s go to the next line by typing next, or n.

If we just press enter, it’ll repeat the previous command, and go to the next line.

You can do that a couple more times, but once you try to get past line 12, it will hang.

That’s our http.ListenAndServe() call. So there’s probably something weird going on there.

Let’s CTRL-C out of it, and type restart or r to start our program again.

Before we keep going, let’s move our breakpoint to line 12, and clear the previous main.main breakpoint.

Let’s go to our new breakpoint with continue, or c, and then step inside that function call to see what’s going on in there. We can do that with step, or s.

Now we’re peeking into code from the net/http library. Nothing critical there except for calling server.ListenAndServe(). Let’s next or n until we get to line 3004 there, and then step or s into it once more.

I can’t see anything that would cause my code to hang there, so let’s keep hitting next or n until something fishy pops up.

Line 2764 looks suspicious… Let’s add a breakpoint here, just in case, and delete the previous one.

Alright! I’m ready for the next step! I’m going in!

Hitting next or n a few times, we find the culprit. There’s an infinite loop there, which is what Serve() uses to keep listening to new connections indefinitely.

This means that our call to ListenAndServe(), waaaaay back at the beginning, blocks the control flow.

So if we want to get to the next line while still listening for incoming connections, we’ll need to run these in separate goroutines. An easy fix:

Now when we run our program:

Perfect!

We can also use the debugger to check the value of variables in our program. Let’s take the fixed version of our exercise and run it again.

Take note of the locals command, which lists out the local variables, and the print command, which we’re using to show the value of one of those variables.

This is of course just a little example to show you how to use Delve.

Ideally you would read the documentation to find that ListenAndServe() calls block, as opposed to digging down a few layers deep to figure out what’s going on.

I hope this was helpful in showing you how debuggers work though, and that it’ll inspire you to delve deeper into the subject.

Add a comment

Related posts:

What are the differences between Chemical and Physical changes?

Is crushing a can an example of a physical or chemical change? A physical change is a change that affects the form of a substance, but not its chemical composition. A chemical change is a change of a…

How to Be Successful in the US as an Immigrant Entrepreneur and Live the American Dream

Confianz Global is a software solutions company that deals with ERP implementation and one of the top three partners for Odoo ERP in North America, they also develop custom applications and products…

Can I cash this car insurance check?

I got into a car accident the other day, and it was the other driver s fault. My insurance company closed the claim because I don t have collision on my policy. A claim was then filed under the other…