Hi and welcome back to Weekly Dev Tips. I’m your host Steve Smith, aka Ardalis.
This is episode 37, in which I'll talk a bit about how I debug problems I find in my code.
If you’re enjoying these tips, please leave a comment or rating in your podcast app, tell a friend about the podcast, or follow us on twitter and retweet our episode announcements. All these things help increase the reach of this podcast, so more people can benefit from these tips.
This week's tip is by request via twitter from Bernard FitzGerald (@bernimfitz) who wrote "How about an episode devoted to effective debugging? I think that would be interesting to hear your methodology of tracking down a bug." Well, Bernard, this bug's for you. Sorry, lame beer commercial joke. On that note, here's a commercial...
Sponsor - devBetter Group Career Coaching for Developers
If you're not advancing as quickly in your career as you'd like, you may find value in joining a semi-formal career and technical coaching program like devBetter.com. I launched devBetter a few months ago and so far we have a small group of motivated developers meeting every week or two. I answer questions, review code, suggest areas in which to improve, and occasionally assign homework. Interested? Learn more at devBetter.com.
Show Notes / Transcript
Let's talk a bit about debugging. Let me start off with a couple of personal observations. First, I think debuggers are amazing. Having the ability to magically stop time in the middle of your application anywhere you want and see exactly what the state of everything is there is like a super power. It far outstrips using console output and checking a log file or terminal window for logged output like "got here" and "got here 2". Those were dark days.
And second, despite how amazing they are, I almost never use the debugger. One tip I give all the time to students in my workshops is that they learn to use ctrl-F5 instead of F5 to launch their applications because it's so much faster. In my experience, 90% or more of the time you're not actually debugging when you launch your application, and in a recent experiment I ran it took about a second to launch an ASP.NET Core app without the debugger and about 10 seconds to do so with it (running on my somewhat old laptop). Those seconds add up, especially when you remember that after a few seconds you're likely to get distracted and go look at your phone or open a browser and start checking email or twitter or something. Not using the debugger helps keep you in the zone and productive.
So why not use the debugger to, like, actually debug problems? I do sometimes. But more often I'll write tests. If it's my own application, I probably already have a bunch of tests. If there's some weird behavior going on and no existing test is catching it, I'll try to write a new one that fails because of the bug I'm looking for. Going through this exercise forces me to analyze what the program is doing, what classes are collaborating and how, and in general to have a better understanding of what's going on.
If I can't easily write a test to isolate the issue I'm having, then I'll use the debugger. I might even debug from a test, since that's often an easy way to jump right to a particular place in my code that I know is being called with known inputs. From there I'll look at the values of all the relevant variables and arguments and usually that will identify where something isn't set the way I'd thought or assumed it was.
Another approach I take is to use some kind of diagnostic tool within the app framework I'm using to provide me with as much data as possible about how the system is working. That might be using a tool like ELMAH for older ASP.NET apps, or an MVC route debugger middleware that shows me every route and how it's configured. I have some middleware for ASP.NET Core on GitHub that will format and render all of the services the application has registered. Things like this can often help provide additional context and information that can eventually help find the source of a problem.
Tests aren't the only thing that helps avoid the need for a debugger. Using custom exceptions like I described in episode 7 helps make it obvious what went wrong so you don't need to debug in order to figure out that
NullReferenceException. Writing short, simple methods with low complexity, perhaps with the help of Guard Clauses that I described in episode 4 is helpful, too. I actually revisited both of these topics in the previous episode, too. When your code is kept simple and small, problems are generally easily detected. If you're writing 1000 line long methods that require multiple levels of nested regions in them to be comprehensible, I can see how you might need the debugger to sort out what the heck is going on when something doesn't work.
What are some other things I'm doing while troubleshooting? I'm not wasting hours focused on finding the problem mano a mano. I'm harnessing the power of a billion people on the Internet to help me. I can record another entire episode just on how to minimize how much time you waste blocked by some problem, and I've written an article on my ardalis.com site called Working Through Roadblocks - A Guide for New Programmers that goes into this as well.
Show Resources and Links
- ASP.NET MVC Route Debugger
- List all ASP.NET Core Services
- Working Through Roadblocks - A Guide for New Programmers
That’s it for this week. If you want to hear more from me, go to ardalis.com/tips to sign up for a free tip in your inbox every Wednesday. I'm also streaming programming topics on twitch.tv/ardalis now. Thank you for subscribing to Weekly Dev Tips, and we’ll see you next week with another great developer tip.