One of the skills that you'll always need to get better at is debugging. Today, we're getting extremely practical and talking about how debugging is an incredibly complex thing that developers have to do and how we can get better.
Create simple virtual private servers in seconds at www.SkySilk.com. Choose from over 40 Linux OS Distros and Software Applications for fast, simple cloud hosting.
If you have questions about today's episode, want to start a conversation about today's topic or just want to let us know if you found this episode valuable I encourage you to join the conversation or start your own on our community platform Spectrum.chat/specfm/developer-tea
If you're enjoying the show and want to support the content head over to iTunes and leave a review! It helps other developers discover the show and keep us focused on what matters to you.
Transcript (Generated by OpenAI Whisper)
One of the skills that you will always need to get better at is debugging. No matter how good of a programmer you are, the most difficult bugs that you face will always be your biggest learning opportunities as developer. And in today's episode we're going to talk about some strategies for debugging stubborn bugs. This particular episode is actually inspired by a few debugging sessions that I've had recently. And I realized that I was doing a few things instinctively that I've learned over the years that I feel like are worth kind of formalizing in today's episode. My name is Jonathan Cutrell, you're listening to Developer Tea. My goal on the show is to help driven developers connect to their career purpose and help them do better work so they can have a positive influence on the people around them. And in today's episode we're getting extremely practical. We're talking about debugging, it doesn't get much more hands on than that. Of course this show is not always about hard skills. For example, in the last episode of Developer Teawe talked about thinking about the future and thinking about your place in the future and your purpose and how it took you to that place into the future. And I encourage you to go listen to that episode but we're kind of doing a 180 in terms of style today. So I'm really excited to talk about this because I think that debugging is really an incredibly complex thing that developers do. And we don't realize how complex it is until we look back on it or if we take a few minutes and we think about all of the information that we're having to process, when we create something we expect it to work almost of the time it doesn't but we expect our code to work otherwise we wouldn't have created that and created it that way, right? But unfortunately when we're writing code we often have blind spots. Not only do we have blind spots but we have an old code that we may not be considering. There's a regression problems that we may face. Those are a totally different kind of bug. And so it doesn't really help us to think about debugging as just a mistake that we make. And a lot of the time it is a misunderstanding, a blind spot or it's some kind of consequence that we weren't able to fully evaluate. So it's not so much about writing bag code. Actually it's about investigating how your reasonably formed OK code is causing a problem. Now of course that's not to say that we don't make silly mistakes. Like for example I was writing some code yesterday and I made a spelling error. And of course that caused all of the entire application to fail. And these things happen. You're going to miss a semicolon here or a comma, a trailing comma and some JSON somewhere and it'll break the whole system or it'll break half of the system and you have to go and find that. So there are things that can help us with those kinds of mistakes. But a lot of the time the mistakes that we make as developers have less to do with syntax and more to do with some kind of information flow. So we're going to talk about how we can debug these things. And sometimes by the way those bugs also, and this is driven by a recent experience I had, those bugs are also because of an interaction with an external system. Your internal system may be written perfectly fine, but because of some interaction with an external system, something goes wrong. So we're going to talk about two specific strategies and they're really complimentary strategies. You kind of do one and then you do the other. We're going to talk about those in today's episode. But before we do that, we're going to talk about today's sponsor, SkySill Cloud Services. SkySill is a new cloud hosting platform looking to shake up how businesses and developers approach cloud computing. You can spend up a virtual private server in just a few seconds. You can choose between popular Linux operating systems like Ubuntu, CentOS and DBN, as well as 40 different software applications like WordPress, Magento, and MySQL among many others. You can create and host your own website. You can have a blog or an application or script. All of this is super simple with SkySill. They're currently beta testing their new cloud platform, which means that everything is completely free of charge in exchange for feedback and testing. So it's a great time to get in on the ground floor and try out their brand new service. One of the really interesting things about SkySill is that they offer a rewards point system. Now, this sounds like something from a totally different industry, but as it turns out, when you sign up and use their platform, you can use the points that you accrue with a SkySill account credit. So in other words, you can pay for your SkySill services with your points, or you can redeem them for real rewards like Visa Pre-Pay gift cards, for example, or Amazon gift cards. And they have more reward options coming soon. Developer T-Listenders can use the code T-Time, all one word, all caps, T-Time to redeem 1000 Sky points, which is equivalent to $10 cashback or account credit, available for redemption when the SkySill platform goes live later this summer. Head over to skysoaks.com to sign up for the free beta. That's totally free. And use the code T-Time. That's all one word, all caps, T-Time to redeem those 1000 Sky points. Thank you again to SkySill for sponsoring today's episode of Developer Tea. So we're talking about two strategies, two real quick strategies to use when you're debugging. And since some people may be listening to this and you need to get to the debugging session, we're going to keep this episode short today. The two strategies, and they go back to back, you're going to do one before you do the other. Number one, isolate your problem. Isolate your problem. This is something that very often developers wait far too long to do. If you have a bug in a system, if you can isolate whatever is creating that bug, or if you can take the code that you believe is responsible for the bug and remove it from the system, or delete the other code around it somehow. Typically you can spin up a quick instance, maybe an interpreter of some kind, or if you're doing something like a React project, for example. Have a test React project that you can delete all the components except for the one that is causing you trouble. Once you pull out the code, if you can isolate the problem and it still exists, then now you have a little bit more of a clean space to actually work on the problem, to figure out what exactly is causing that problem. And typically when you pull the problem out of its context, you either change the problem, in other words, the problem is either no longer there, or it's different in some way, or you find that the code that you thought was responsible for the problem wasn't actually responsible for the problem. So this helps you take another step towards the code that actually is responsible. And once you find the code that is responsible, I still believe you should pull that out and isolate it. Now, if you're an experienced developer, then you know that this can be hard sometimes. But what this will require you to do, and this is a good thing, this will require you to write your code, to design your code in such a way that you can pull pieces of that code out. You can take a component, for example, and plug it into another place. If you're developing your code in a sufficiently modular way, such that your classes or your components or your functions or whatever it is that you're writing, whatever style you're writing in, if you're developing your code modularly enough, you should be able to take that piece of code out of your code base and put it into a test scenario. If your code is too reliant upon other pieces of your system, then this process of debugging will necessarily require some refactoring. And again, this is a good thing because very often in the process of refactoring, you uncover what the bug was. So once again, the first strategy, the first step that you need to take is to isolate the bug, isolate the bug. Now at this point, you're going to walk down the normal strategies that you typically would use to debug. For example, duck debugging. You can talk through your code, explain exactly what it's doing, walk through every step. If there's a loop, count how many times that loop happens. If there's a conditional, explain that conditional in as clear language as you can, and don't take anything for granted in this process, use your normal debugging skills. If you have a Linter, use a Linter. So we're not going to talk about all of the specifics of the isolated debugging that you'll do, although there's plenty of really cool strategies that you can use. But if you pull that code out, and you see that the system that you've pulled that code out from works when that code is gone, and in your isolated scenario, the bug is gone, then something about the interaction between that code and your system, the rest of the code, something about that interaction is causing a bug. So the next strategy is integration, integrating your code back in from the isolated scenario, integrating whatever that solution is back into your original code base. And quite often what will happen is instead of integrating it all at once, all wholesale, you can use a strategy like a piecemail integration, so integrate one piece at a time, or if you're like me, you can use kind of a dividing conquer method. So first, start with the whole thing. If that doesn't work, then try the first half, the first half of the code. And if that doesn't work, try the second half of the code. Of course, keep in mind that you can't put in half of a method, and you can't cut a class in half and expect that to work. So that's not what we're talking about. When I say divide and conquer, what I mean by this is taking the logical pieces that can run sequentially, that don't have dependencies above it, and integrate those. Integrate the pieces that work so that you can isolate. Further isolate the pieces that don't work. This strategy is particularly useful when you're working with external platforms that are causing bugs, and you can't seem to track them down. Unexpected sources of bugs, for example, you may find a bug in a library, or an interaction between two libraries. This is a very common scenario. You have one library that is doing some work, then you have another library that does some work. And when you put them together, there's a naming conflict, or some kind of interaction, some system level conflict. And unless you were particularly familiar with that conflict, it may be very difficult to find that bug. So quite literally deleting code out until you don't have the bug, and then reintroducing that code back again in piecemeal parts, or in small half sections, until you find the piece of the code that is causing the bug. Of course, this totally ignores the opportunity of using debugging tools to help you along the way. There are plenty of excellent tools that could help you along the way, or give you warnings, for example, when you're using two libraries that aren't necessarily compatible, that have known compatibility issues, especially. But really, this process is not only about debugging, but it's also about software design. If you think about all of your software in terms of its modularity, if you can make a piece of code work on its own in an isolated environment, and then plug it back in. In other words, now that it works on its own in an isolated environment, you can put it into your code base with much more confidence. And if you do this for all of your code, if you pull out most of the pieces of your code and make them so that they are modular, so that they can be composed together, then you're much more likely to be able to isolate and fix the bugs that you encounter. All of this is based on the same principle that we talked about over and over again on Developer Tea, and that is, when you have a problem, try to break it down into the smallest version or smallest pieces of that problem, the subproblems, the smaller the problem, the more easy it will be to solve, and the more powerful the solution will be in the long run. So when in doubt, make things smaller. Make things smaller. Thank you so much for listening to today's episode of Developer Tea. Thank you again to SkySulk for sponsoring today's episode head over to skysilk.com. Don't forget the coupon code TTime for the 1000 Sky Points that are redeemable whenever they're full service launches later this summer. Thank you so much for listening. And if you haven't subscribed yet in whatever podcasting app you're using, then it's very possible that you will miss out on future episodes. And I don't want that to happen. Hopefully you don't want that to happen either. Go ahead and subscribe so you don't miss out. Thanks so much for listening. And until next time, enjoy your tea.