 Good afternoon, everyone. Welcome to debugging effectively. My name is Colin O'Dell, and today I'll be teaching you why debugging is important and how to do that effectively. This talk is geared more towards beginner to intermediate level programmers, but I think developers of all skill levels will find something useful and something interesting to take away from this talk. So first about me, again, my name is Colin O'Dell and I am the lead web developer at Unleashed Technologies. We're a web and hosting firm based out of Maryland in the US. I've been a PHP developer for about 14 years now. I've dabbled in other technologies like Java, C-sharp, JavaScript, recently some C, but I really love working in PHP. And even though we are at DrupalCon and we're talking about Drupal and we're talking about PHP, a lot of these skills will be transferable to other languages and technologies. You might know me from some of my PHP League projects. I currently maintain the PHP League's common mark parser as well as the HTML to mark down converter. You might also know me from my PHP 7 Upgrade Guide ebook. And I thought I had another bullet line up list, but apparently I don't. It was gonna be my Twitter handle, which is down here. I'm at Colin O'Dell. If you have any questions, I'll try and answer them at the end. If I'm unable to answer those questions, feel free to come up to me, ask me questions or tweet me, whatever works best for you. So a brief overview of what we'll be discussing today. First, we're going to talk about the importance of debugging. Why is it important? Why are we spending an hour here today talking about it? From there, I'll go into a debugging process and how we actually go from identifying the bug to resolving it. I'll also touch on some really useful tools and techniques you can use when debugging issues. And then lastly, if we have time, I'll open it up for some questions and answers. So when you think about debugging, what word would you use to describe debugging? You might say, debugging is difficult or debugging is time consuming, debugging is annoying. I hate debugging or if you're like me, you might say debugging is a really fun challenge. Personally, I love puzzles, I love challenges, I love critical thinking. So trying to debug a really difficult issue is really fun for me. But more than anything, I think that debugging is important. In fact, I'd argue that debugging is the single most important skill in programming. Now, that is kind of a bold statement. So why would I say something like that? Well, let's think about how much time as developers we actually spend coding and debugging and planning and all of these things. You might think, okay, I spent about a third of my time planning that might be meeting with shareholders, triaging tickets, responding to email, messaging people on Slack, going to meetings. And then the other two thirds of the time you're sitting there at your keyboard furiously typing away, implementing that cool new feature. So do we really spend two thirds of our time coding new features? According to the Mythical Man month, we actually spend up to half of our time testing and debugging. And only one sixth of our time actually implementing new code. Now, testing and debugging does cover things like figuring out issues that are reported by users or shareholders. It includes automated testing, manual testing, debugging problems, trying to figure out how to implement something. All of that takes up about half of our time. So if we're spending half of our time testing and debugging things, then surely that's something that would be good to become efficient and effective at. Now, to put a definition to the word debugging, I really like this one from Wikipedia. And it says that debugging is the process of finding and resolving bugs or defects that prevent correct operation of computer software or a system. And I really highlight the word process here because the process of debugging is so important to the art of debugging. Process really is the foundation of effective debugging. Process includes things like identifying what the issue is, knowing how to go from taking the issue to identifying it to resolving it, that entire process in the middle that is really the foundation of debugging. And as you go through your debugging process more and more and more, you're going to start to gain experience. You're going to gain experience with how to debug an issue. You're going to gain experience with the platform you're working on. So you're going to learn more and more about how the internals of Drupal works. You're also going to gain experience with your tools. So you're debuggers with networking. You're going to learn these technologies and get more and more experience with those. And then as you gain more and more experience in your career, you'll start to develop what I like to call a sixth sense. Some people like to use the word intuition. Basically what I'm talking about here is the ability to see an issue and immediately know what kind of issue you're dealing with. So you see this error and it looks like a MySQL error and you immediately know that SQL syntax is invalid or there's a firewall up and that's why I'm getting this connection timed out error. Now the reason I don't like to use the word intuition is because intuition sort of implies that there's this mythical quality involved. Like there's some external magical force out there that causes this thought to bubble up. But really I'm talking about building up this mental library of heuristics. So the more and more you debug networking issues, the easier it'll be for you to identify when a network issue arises and then your mind will immediately jump to that as the most logical explanation for that issue. And as you debug more and more of different types of issues, again you're building up that mental model of, okay, this behavior probably means this issue here. So in order to develop that sixth sense and become an effective debugger, you really just need to focus on the process. And as you get that process down, the experience will come and so will the development of that sixth sense. So let's talk about that process and what that process looks like. And let's start by talking about the process that most new developers go through when they start programming. So when a junior developer encounters an issue, what are the usual steps that they're going to take? Well, maybe they're gonna try and clear the Drupal cache. Hopefully not on production because that might cause the white screen of death. But the reason they're gonna do that is because it's helped fix issues before. And so they're just gonna say, well, it worked on this other thing, so maybe I'll try it out and see what happens. Or maybe they delete all the dependencies and reinstall them. Or maybe they chmod everything to 777, which is a really bad idea. But again, it solved the permissions issue for them in the past and they don't really know that they're dealing with permissions issue. So they just kind of blindly try it and hope for the best. Now I'm not saying these are invalid solutions. There are certainly valid use cases for at least two of them. But if you're a junior developer, I challenge you to really think through the problem. Don't just clear the cache or reinstall your dependencies. See that it works and move on with your day. Really understand why did clearing the cache solve this issue? Was there some bad value in my cache? Did the cache get invalidated at some point or did it get corrupted? What's going on here? So really think through why that answer was the correct one. Something else that junior developers will typically do is to Google the error. They'll come up with 10 posts from Stack Overflow or Twitter or GitHub or wherever and they're gonna try every single solution. They're gonna try solution one. If it doesn't work, they're gonna move on and try solution two. If that doesn't work, they'll go to the third post, try that, see that it works and they'll commit their changes and move on with their day. Now again, it's totally fine to Google the error and to try different things. But again, remember that debugging isn't just blindly applying different fixes and moving on. Debugging is a process and you really need to understand why it is that solution three worked when solutions one and two didn't. What was the logic behind that? What types of issues were solutions one and two addressing that solution three didn't address? A junior developer will also immediately go and ask someone else. So maybe they've never encountered this issue before. They'll go ask a colleague, they'll go on Twitter, they'll go on the forums and they'll ask, hey, I'm seeing this error, I don't know what to do. And that's totally fine. Again, it's fine to ask for help but when you get that answer, don't just apply it and move on with your day. Understand why that answer was the correct answer. And then unfortunately, I think sometimes newer developers tend to give up if they can't figure out an issue. I don't really, I'm not fond of when people give up because I think that there is always an explanation and there is always a solution if you're persistent enough to find it. And as I'll touch on later, when you are persistent, 95% of the time you will find the issue if you stick with it. And that other 5%, you will learn something even if you couldn't solve that issue. Another trap that I think newer developers and even intermediate developers fall into sometimes is what's known as the XY problem. So they're faced with some issue or some task they need to implement. And they say, okay, I need to do X. How do I go about doing X? And maybe they can't find the right solution and the right implementation for X. So they say, well, I can't figure this out but you know what, I think solution Y might work. I think this other work around hack type thing might work. So then they'll go ask, how do I do Y? They'll go ask on Stack Overflow. They'll ask their colleague on the next desk over. But the problem with asking how do I do Y is that you're not learning how to solve the problem correctly. You're giving up on finding that proper approach and instead you're resorting to a workaround. And when you apply a workaround instead that could lead to some issues to forever along the road. Now at this point I would like to share our personal anecdote from when I was a junior developer and I fell prey to this XY problem. So one of my first big projects as a new developer at an agency was to build this awesome new Magento website. And this website was for a restaurant that ships seafood out overnight. And so they needed us to build this custom integration with the shipping carrier so that we could send all the data to the carrier about how much the package weighed, where it's going, who's paying for it. And then the carrier was sent back the shipping labels and all the rate information on how much that shipment was going to cost. And I was able to implement that as a junior developer and I was really proud of that. And everything has worked fine since then. It's been about six years and that code is still running great. But then one day it stopped working. It was really bizarre. These PDF of the PDF files of the shipping labels were working fine. We didn't touch the code in six years and then it just broke. I was really confused about that. And I checked in GitLab and the history confirmed my suspicions that we never touched that code. So the PDFs were corrupted. I figured, okay, why are they corrupted? Let me fire up my text editor and just look at the plain text of this PDF. And when I did, I saw a bunch of base 65 encoded text like I had expected to see. And then right in the middle of that base 65 encoded text was an HTML tag which you can see up here. And I thought, wow, that's really bizarre. Why is there HTML in my PDFs? So what I did is I grepped for this exact string because it had to be coming from somewhere. And as a result, I found this beautiful piece of code. What this code is doing is it's using a regular expression. So look for a head tag. And then when it finds a head tag in any response body, it's going to replace that regular, it's going to look for the head tag and at the very end is going to append this HTML tag. I looked through the history to figure out why this code was in there. And it was because the backend of Magento didn't support IE9. And so I needed to tell IE9 to behave like IE8. And I didn't know the correct way to get this HTML into there as a junior developer. So I had the brilliant idea, let's use a regular expression to look at the response output for every single HTTP response and just do this regex replace. And why did this affect the PDFs? Well, it turns out that base 65 encoding can contain a less than sign H-E-A-D. So if you can learn two things from this story, number one, don't parse HTML with regex. It's a terrible idea. But more importantly, solve problems the right way. Because when you resort to these types of workarounds, it can bite you later on and cause more issues for you later on. Now I think there are some other pitfalls that we as developers sometimes fall into, especially when we're new to the craft of programming. We sometimes fall prey to the sort of magical thinking where we say things like, I don't know why my website's behaving like this or for some reason it's doing X and I thought it would do Y or this behavior just doesn't make any sense to me. I don't like this kind of magical thinking because it assumes that computers are magical and that they're sentient and they do their own things on their own, which is simply not true. Computers are logical machines. They run on zeros and ones, on, off, true, false, yes, no. The code that the computer runs is also very logical. And if a bug is an issue in our code, if a bug is a piece of code, then by definition, that bug must be logical. Now I really like this quote here from Nick Parlanti in Debugging Zen. And he says that the bug is not moving around in your code trying to trick or evade you. It is just sitting in one place doing the wrong thing in the same way every time. When you fire up your debugger to figure out what's going on, that piece of code isn't jumping from one file into the next file and hiding behind this class. You know, it's not running around, it's there. The code that has an issue is right in front of you and it is a logical piece of code that has a logical explanation. You just need to be really persistent in finding it and not give up on trying to find it. Now when I debug issues, I always assume that my code is the problem because let's think about it. Well let's say your Drupal site suddenly starts experiencing an issue. What are the chances that the issue is caused by code that one person wrote versus code that's in a module that tens of thousands of people wrote? Or code that's in core that hundreds of thousands of people might use on a daily basis? The chances are extremely high that the bug is in your code. So before you start spending your time debugging Drupal core or the module, what I like to do is always assume that my code has the problem and actually validate whether or not my code does indeed have that problem because 95% of the time it's in my code. And that other 5% of the time, maybe it is in the other module but at least I know that my code is correct and I'm not going to waste time in 95% of the cases looking in places where there is no issue. Now if you're helping other people solve their issues and investigate those issues, I think it's safe to assume that their code is the problem. I'm not saying go and blame them and say, hey, your code sucks, you messed up. But when you start the debugging process, focus on their code first and validate that their code is indeed correct before you move on to looking at contributed code. Now in terms of the process that we use when debugging, I've kind of developed this five step process that I use on a daily basis. And I've never really written it down until I started creating this presentation as well as just been something that's evolved over time and that I've just kind of learned to go with and it's worked really well for me. So if you don't have a really solid debugging process, I think these five steps make it really easy to go from identifying an issue to resolving it. So I'd like to share these five steps with you today. The first thing that you should do when you encounter an issue is to gather as much information about it as possible. So first define what is the expected behavior versus the actual behavior? So I expect when I submit this form that it takes me to this confirmation page. The actual behavior as I submit the form, I see a big right error message, I have these entries in watchdog. Once you've defined that behavior, then go ahead and look for more information about it. Go look for error messages or better yet find stack traces. The nice thing about stack traces is they tell you exactly which line of code caused the issue to occur and every line of code that ended up calling that. And if you can't get to stack traces, all you can get is an error message that's still really valuable because error messages aren't these randomly defined strings that your code just decides to spit out on its own that it made up. Those error messages live in the code somewhere. And so you can search your code for that error message. You can search Google, Stack Overflow, Project Forms for that error message and you'll get a lot of really good information about what's going on. Now if the issue is occurring on the front end of the website, it can be really helpful to take a screenshot. And if it's the end user that's experiencing the issue, you can of course ask them to take the screenshot. I've found that even the most inexperienced computer illiterate users are really good about taking screenshots. They know how to do it. And if they don't, you can point them to an article and they'll gladly take that screenshot for you. Now you might get it as a fax, you might get it pasted in a Word document in a zip file or some other bizarre way, but you'll still get that screenshot and that's gonna provide you a lot of really good information. You can see what URL they were on, what the date and time is if that shows in the corner of their system. You can see what the form input is. You can get all this really good valuable information just by asking for that screenshot. You can also get the browser and operating system from that screenshot. And if you need more information about the particular version, you can just ask them to go to the about menu and get that information. It's also really useful to get the date and time that the issue occurred because then you can use that to compare it to your logs to figure out where in the logs was that happening? What was the error message that occurred at that time? Were there any errors that came immediately before it or immediately after that to try and trace that solution? Once you've gotten all the information you need about the issue, now you can go ahead and try to replicate the issue. Try and identify which steps do I need to take to make this issue occur. And when you try to replicate the issue, you really wanna figure out exactly which steps make that issue occur 100% of the time. And it's really important that you're able to replicate it with 100% certainty. Let's say you can only replicate the issue 50% of the time. You go through your steps and only half the time the issue comes up. Well, later on, when you think you solved it and you run through those steps again and you see that everything is fine, how do you know that it's fine because you fix it or just fine because it was that lucky 50% of the time? So you really need to replicate the issue with 100% certainty so that later on, you can positively confirm that your solution is valid. Once you're able to replicate the issue, now you can go into the code and start to identify what the culprit is, figure out what line of code is causing the issue. What is the configuration or misconfiguration that's causing that issue? And when you go to identify the culprit, you want to be really methodical about how you go about looking through the code and finding issues. You don't wanna just jump every which way, looking in that file, looking over there, looking in the database, looking in your cache. Really try and think through what is the problem? What are the symptoms? Where might this bug be located? And kind of go from there. And as you go through this process, I think it's really important to make no assumptions. Don't assume that your code works because you wrote it. Don't assume that the code works because the senior person at your company wrote it. Really try and, if you have any assumptions, validate them, don't just accept them blindly. If someone says it works, just go double check it just to make sure. I can't tell you the number of times that I've thought, oh yeah, that's not a problem. I know I wrote that correctly. And two hours later, I look at that code again and I say, crap, I messed up. So really make sure that you're not making assumptions. And if you think you're making one, just double check it, be 100% sure before you move on. And then lastly, really take time to understand the bug once you identify it. Understand the fundamental nature of why it behaves the way it does and not the way you expected it to. Because again, that's going to help build up your knowledge and experience about how different parts of the system work, about how the code works, about how the web works. You're going to gain that knowledge and build that level of experience that you need to gain that intuition or six cents. Now once you're able to identify the culprit, now we can go ahead and fix it. What we wanna do is we wanna fix it and then retest. So attempt to replicate the issue again using those few steps that we identify that we know with 100% certainty does demonstrate that problem. And when we run through those steps and see that the problem has gone away, we can be 100% confident that we fix the issue. Now when we go to fix it, we wanna be sure to avoid that XY problem. And we want to avoid any type of temporary workarounds because temporary workarounds are not temporary. First of all, in the short term, they're going to add technical debt to the system. You're adding this hacky, buggy, potentially buggy code to your system, but it's going to have to be maintained at least in the short term. And that could introduce other issues as I demonstrated with my story about that Magenta website. And as I mentioned, temporary workarounds are not necessarily temporary. They could stay in your code base forever and never get replaced. Think about it. Let's say that your shareholder comes to you with an issue. You implement this temporary workaround. They see everything works and they're happy. Do you think they want to spend time or money later on down the road to replace that with something else that works when your system seems to work just fine today? They're probably not going to wanna do that. So if at all possible, try and avoid those temporary workarounds. And once you're able to completely fix that issue, the last thing you wanna do is to mitigate future occurrences. So maybe you wanna add an automated test. And if you're doing TDD, hopefully you've implemented that test beforehand. And if not, that's totally fine. You don't have to be a test-driven development developer in order to implement an automated test. You can certainly add it afterwards. That's fine. But automated tests are really nice because they only take a few minutes to write. And then in the future, you can run them a million times and they take microseconds, milliseconds. They're so cheap to run. And so I think it's a really good idea to back up your solution with an automated test. But mitigating future occurrences goes beyond just making sure that your code works. It also means making sure that other people will avoid those same kind of mistakes. So go ahead and share the knowledge that you've gained from debugging that issue. If it was due to some weird quirk with how the system or your project works, go put that in the documentation. If you've learned something really interesting about how the internals of Drupal works, go write a blog post about it. Write about the issue you found and how you resolved it and why that issue worked. And chances are if someone else has a similar issue in the future, when they go on to Google and search for that, they'll come across your blog post and they'll learn from what you learned and you've helped someone else out. And if you ask the question on Stack Overflow, you are more than welcome to go back and answer your own question. It's totally fine. I'm sure we've all experienced issues where we Google this really cryptic error, we find this one post and the person answers, never mind, I fixed it. Okay, I need to fix it now. How did you fix it? I believe there's an XKCD comic about this where he's like, what did you see? So really just try and help other people get through those issues and share your knowledge with them. And if the issue wasn't an upstream project like a contributed module or Drupal core, feel free to submit that patch upstream. And if you're not comfortable writing a patch, just describe what you found and what you did to fix it or you think might work because that's still really helpful to others. So to briefly recap that five step process, number one, gather information about the issue, get as much useful information as you can. Once you have that information, go ahead and try and replicate the issue. Do that with 100% certainty that you know that those few steps will cause the bug to appear. Once you do that, you can go ahead, identify the issue, fix it, retest it and then share that knowledge with others and make sure that it doesn't happen again in your project or help other people to avoid that problem as well. And I think that doing a process like this really does have some really good long-term results. First of all, you're going to gain experience. You're going to gain experience with the debugging process, with the platform you're using, with your debugging tools. You're just going to gain a lot of experience as a developer. And you're going to learn how the system works. Like I mentioned before, even if only 95% of the time your persistence pays off, that other 5%, even though you couldn't solve the issue, you still learn something. You still learned about how this module worked or how Drupal's caching layer worked. So it was still beneficial. And you're going to build up that mental library of heuristics. You're going to understand after solving five network connection failed errors that there might be a firewall issue. You're going to kind of immediately be able to jump to that explanation the next time you experience that issue. And then lastly, it's going to boost your confidence as a developer. Because if you have this solid process in place, you can be thrown into a completely random project. Maybe you've never worked with Symphony or Magento or Joomla before. But if you have this process down and you know what kind of tools to use and what to look for, you can still kind of figure out what's going on and be able to solve that issue even though you're unfamiliar with that platform. So now that I've talked through the process, I would like to share some different tools and techniques you can use while going through that debugging process. Now personally, I think there are two essential tools that every developer should have. And as a lead developer at my company, I make sure every new developer that comes in gets these two tools and learns how to use them. Number one, a good IDE. And number two, an interactive debugger. Now I know some people are going to say, oh, I don't need a good IDE. I'm very comfortable with Vim. I love Vim. I love Emacs. I love Nanna, whatever the case may be. And that's totally fine if you're a seasoned developer. But I think for newer developers, it's really important to have these tools to assist them with the debugging development process. Now when it comes to a good IDE, I think it should have these features at a minimum. It should have syntax highlighting so that if you forget your semicolon or you forget to close your function, you can see that immediate little red indicator when you know that there's a syntax error. You don't have to rerun your code or click through the pages to find that. A good IDE will also have auto-completion so you don't accidentally mistype a core function. Or you'll know, okay, is this PHP array function? Is it needle haystack or haystack needle? It'll tell you right there in the IDE so you don't have to look that up. A good IDE will also allow you to jump through your code quickly. My personal preference is PHPStorm. I'm not endorsing them. I know they're a sponsor, but I just really love how easy it is to get around the code. And I'm sure other IDEs make it easy as well where you can just click on a class name and jump there or hit a special shortcut and type in a partial file name and jump right to that file on that specific line number. And that really makes it easy to debug your code and work your way through it quickly and effectively. And of course, I think a good IDE should also have an interactive debugger. Now, an interactive debugger for those of you who may not be familiar with it, it allows you to pause live code execution. So as you're running code, as you're testing out in your own environment, you can say, okay, PHP, I want you to stop in this file on this line and just take a time out. Just take a breath, stop. Let me look around and see what's going on. You can set breakpoints and say, always stop on line 200. Or you can say, only stop on line 200 if this condition is true. And then once you're stopped, you can step through the execution and say, okay, this line looks good. Let me run the next line. Let me run the next one. You can examine variables and see what they're set to. You can explore the call stack to see what led up to that line of code being run. Now, as a quick little demonstration here, I do have an example of using PHPStorm and XDebug to debug an issue. So here I'm stopped inside of my open source CommonMark parser on line 38 of this file. And I just set a breakpoint, ran the code and PHP just stopped here. And I can take a look and see, okay, what files and what lines of code were called that led up to new line parser line 38 being run. And I can see all the variables here. And maybe I will see, okay, everything looks fine. Let me jump to the next line, run that. Still looks good. Let's run the next line and the next line and the next line. Okay, I don't really know what Git content is doing. Let's step into that function and see what's going on. Oh, okay, it's just returning this variable. And here's what it's set to. All right, looks pretty straightforward. Let me jump back out. And I can also expand these variables here and see what does this object contain? What are these variables set to? And if I want to, I can also jump up this call stack and say, okay, what caused new line parser line 44 to run? Oh, it was called from here. Where was that called? Oh, that was called from here. And that was called from here and so on. And as you jump up these different levels, you can expand those variables too and see what were the variables set to at those points in time. So again, having a good IDE with a good interactive bugger, I think is really critical to being able to debug effectively. And then here I just have a quick screenshot of doing conditional breakpoints and grouping them. So if I'm trying to debug a new line parsing bug, I can say, okay, these breakpoints deal with new line parsing. And when I'm done with that, I can just uncheck this and I won't lose my place. So if I have to come back to this later, I can just recheck that box and go through that process again. And then over here, just an example of using a conditional breakpoint. So I'm saying, only stop here on line 47. If this spaces variable is greater than two. So it's a really powerful tool. If you haven't checked it out, I'd highly recommend you look into that. Now let's talk about some techniques you can use when trying to identify the culprit and figure out the issue. There are several different ways you can go about tackling an issue depending on what sort of issue it is and what sort of information you have. So I'd like to walk through some of these briefly right now. The first one I'd like to share is tracing backwards. So you want to use this technique when you know where the error is coming from. You know that this file on line 28 is failing. And so you fire up your interactive debugger, set your breakpoint there. And then what you want to do is establish the context of what's going on, figure out what's going on on that line right before the failure, and then trace your way backwards. So let's say that this is a diagram of your code. You have function A, which called function B, which called C, which called D, and D is erroring out. Well, we know that the code ran this way. So let's set a breakpoint here, stop on that line of code, and then kind of mentally work our way backwards. Let's see, okay, we're in D, why did D get called? Let me look inside a function C, see what was going on there that led up to D being called. Let's look in B to see what caused C to be called, and so on. Now there is an alternate technique you can use, which is the trace forward. So just working in the opposite direction. Generally you do this if you don't know what line of code is causing the issue. So again, use a debugger, use logging, basically figure out, okay, my code starts off here, and then I know A is gonna call B, and then I see that it calls C, and I see that it calls a D. The problem with this approach is that it can be really inefficient if you don't know where the issue is in your code. Let's say you're having a block that's not outputting correctly. You probably don't wanna spend your time going through the entire bootstrap routine line by line going into every single method. That's just gonna be a waste of time. So what you'd wanna do instead is probably do a divide and conquer type strategy to try and narrow down what code or what part of the code base you wanna focus on. So you start by identifying the different sections of your code and grouping all the functions together, and figure out what are the boundaries between these pieces of code? Where does the code leave this module and then go over to this module or this class or this library? And then once you find which block of code is causing the issue, then you can isolate the issue down to that. So quick diagram, let's say this is a diagram of our system, and what these boxes and lines represent isn't really that important. But what I want you to focus on is that there are these four different groups of code. So there's this blue section here where it pretty much just talks to itself, but then there are these boundaries where the code runs off to these other sections. So in order to divide and conquer, what we do is we set breakpoints at each of these boundaries, run the code, and just see which boundaries get hit and see which breakpoints the code stops on. Maybe we see that these are the only two breakpoints that get hit. And this tells us that that yellow section of code doesn't get run at all because PHP didn't stop here and it didn't stop here. So this was never run. All right, so we've crossed that off and then we can focus on this area. So let's set those breakpoints again and see what's going on. So when the code goes from this blue section to the red section, we can stop and look at those variables and see what's going on. And maybe we'll see that everything looks fine. Everything is exactly how we expected it to be. Things look good there. But at the next boundary, maybe things look wrong. Something's off. Something isn't quite right. And so now we know the issue is somewhere in this section. And now we can go ahead and use that trace forward methodology where we start here and then validate each step of the process to figure out where the issue is. Now there are a lot of really good tools you can use as you're debugging. I've got a few listed up here. And what I'd like to do is briefly touch on each one and describe what it is and how you can use it. So number one, dumping out variables. Sometimes we just don't wanna fire up the debugger. Sometimes it's too much effort. Maybe you're trying to work on your buddy's system and he or she doesn't have XDebug installed or you can't connect. Just dump out the variable. You can use dump in twig. You can use kint. You can use DPM. Whatever the case may be, sometimes it's just really useful to just dump out a variable or two on the screen. Don't do it in production. You can do it in development, that's fine. Sometimes it's just useful to do that approach. You can also use a debug toolbar. I know the develop module has the, I believe it's called web profiler toolbar. It's based on the toolbar that Symfony uses and has a lot of really great information about what's going on with that page request. So we can see, okay, we're using Drupal 8.12. We can see the HTTP response code was 200. We used 45.5 megabytes of RAM. It took this long to execute. Here are how many database queries were run. And you can click on each of these to get more information about what was happening. So if you're experiencing some kind of SQL error or your query is taking too long, just click on this guy here and you can find out more information about that. Another really useful tool is a console utility. Now a lot of platforms do ship with them and some have community built ones. So in Drupal we have Drush and triple console. Symfony comes with the bin slash console built in. I know Magento has a third party tool called N98 Majron and Laravel has Artisan. At the end of the day, they're all very similar. It's a command line tool that gives you debug information unless you do things like clear the cache, reset a user's password, dump out the routes, find that important information. Now sometimes the issues we're experiencing aren't necessarily bugs where something crashes. Sometimes it's a performance issue and you're not really going to be able to use a debugger to find that. So in these cases, you want to use a performance profiling tool and that's going to help you identify slowness. Whether that's a bottleneck somewhere or a really slow query or something's hogging resources or a really inefficient algorithm, they'll let you pinpoint exactly what parts of your code are running slow and why that is. And there are a lot of really great tools out there. My personal two favorites are Blackfire and New Relic. Again, I know their sponsors here. I'm not being paid to push these products. I just really enjoy them. I think they're pretty good. And I do believe they do have free trials. So if you want to check that out, that's cool. And if you're really into just using open source and you don't want to go the commercial route, there are other projects out there like XHPROF that do very similar things. Now one really cool tool that I like to use that isn't that well known is Git bisect. So quick show of hands, how many people are familiar with Git itself and use Git regularly? All right, how many of you have used Git bisect before? All right, a few, that's good. I like to see that. So most of you are familiar with how Git works. It has this history of commits. So we know that this commit was based on this one, which is based on this one and so forth. And we can use a Git bisect to run a binary search across commits to figure out which commit first introduced an issue. So let me explain. Let's say this is a diagram of our repository. And we know that version 1.7 of our project worked great. There were no issues, everything was fine. Fast forward sometime later and our most recent commit on master has a bug. We don't know where exactly the bug is located. We don't know where it was introduced. We just know that there's an issue. So we can use Git bisect to figure out which one of these commits introduced the issue. And because it's a binary search, you don't have to try every single commit one at a time. Git will intelligently find that commit for you. So the first thing you wanna do is tell Git, okay, version 1.7 was good and my head here, the latest commit is bad. Now I'm not gonna run through the exact commands, but you can sort of look them up. There's a lot of good tutorials out there. And once you've identified the good commit and the bad commit, you will automatically check out the one in the middle for you. And it'll ask you, hey, how do things look at this point in time? Is the issue still here? Is it good or bad at this point? And you might say, it's bad. There's still an issue here at this point in time. So if there's an issue here and the issue is still present here, we can automatically cross these commits off the list because the issue wasn't introduced in the future. It was introduced sometime in the past. So you tell Git, this one is bad and then it'll check out what's in the middle again. And then you tell Git, okay, this one's good. Everything was working fine at this point in time. All right, so this one here must also be good. So here's the commit that introduced the issue. And that only took what three, four commands to do that even though there are eight, nine different commits in here. And what's really nice about it being a binary search is that it scales logarithmically. Now I'm not a comp-side major, so I did have to Google what that meant. But basically every time the number of commits goes up by 10, a 10-fold, the number of commands you have to run only goes up by two. So I believe if you have nine commits, you need a test. So nine commits takes four tests. 90 commits takes eight. 900 commits takes 16 tests. So even if you have a lot of commits you have to go through, this scales really well and it's still really efficient and really effective at finding those types of issues. Now another really nice tool that I like to use when debugging specifically network issues is Netcat. Netcat is a really nice UNIX tool that lets you test a TCP connection to some IP address and some port. So we can see here in the first example, I'm just running the Netcat command with a couple of flags and I'm just testing if my computer connects to local hosts on port 80. And I see that the connection succeeded. So I know that if there's a networking issue, I can see whether or not it's caused at that TCP layer. So in this case, if I see connection succeeded, I know there's a web server there on port 80 and it's responding to things. So if I'm seeing some type of issue and I think it's Apache related, I at least know that Apache is running and is responding to connections. Now let's say you're trying to diagnose some issue connecting to some third party service or maybe you just wanna see if Google has SSH open. You can pop that in. You can say, okay, try connecting to Google on port 22 or try connecting to my database on 3306 or connect to this API on port 443. And you can see right away if the reason you're having the bug is a networking issue or not. If you see something like connection timed out, there's probably a firewall up in the way. So if you're debugging the issue connecting to my SQL server, you don't have to focus on whether the SQL syntax is valid or not. That doesn't matter here because it couldn't even connect to that SQL box. So again, just a really nice tool to help diagnose those kinds of issues. Another nice tool you can use is Curl. Curl is a command line HTTP client. And if you pass in the dash i flag here in the URL, it'll show you all of the HTTP headers. Now, of course, you can see these in Chrome's DevTools, but maybe you don't have access to that. Maybe you don't want to fire up Chrome. You just want to type something out quick. Curl is a really nice way to get that kind of information about the HTTP request. And the final tool I'd like to share with you is this tool called Strace. Strace allows you to attach to any running process on a box and see what sort of system calls are being made. Now I mentioned back at the beginning of the introduction that I'm just getting started and see development. I don't know what most of these things do. I'll be totally honest with you. But just looking at it, I can kind of figure out what's going on. So let's say I have this PHP process, which is doing, I don't know what, but I need to figure out what it's doing and why it's doing it. I can pull this up and I can see some things that kind of make sense to me. So here we have something being written, set names, UTF-8. So something's going on with UTF-8 encoding. Down here, I see that a file is being opened. A file called crypt.class.php. So my PHP code is probably doing something with cryptography. It's probably requiring this at some point. Down here, I see what looks like a SQL query, selects star from accesses. And then down here, I see that dev random is being opened. So even though this might seem like a bunch of gibberish, even though I might not know exactly what my process is doing, I can kind of get a vague idea that it's doing something with cryptography. It's doing something with the SQL query. So maybe I should look in that part of the code to figure out what's going on. So that kind of wraps up the tool section and we're getting close to the end here. The last technique I'd like to share with you is getting help. Sometimes, no matter how hard you try, you just can't figure it out on your own. So we'll get some assistance. The first thing I think you should do is go read the fantastic manual. Go read the fantastic documentation. Some developers somewhere spent their time to write out information about common issues and how to do certain things. So go check that and see if there's any useful information there. Maybe go check the project forms or an issue queue. See if someone else reported that issue. And if not, you can report it and go ahead and maybe someone else will check later and respond to you. You can of course post elsewhere in places that aren't specific to Drupal. You can go on Stack Overflow, IRC, Twitter, anywhere that developers congregate. If you work with others, go ask a colleague. Maybe you're struggling with this really hard Drupal question and there's a Drupal expert sitting right next to you. Go ask them. And if you don't really have that expert or they don't know either, just go find any senior developer even if they don't work with Drupal, even if they don't work in PHP. Because chances are they're familiar with caching technologies and how HTTP requests work and all these different types of topics that they may not be specific to your project but they still know something that can help you out. And then the last technique you can use is rubber ducking. Basically you take a rubber duck, put it on your desk and if you have a problem, talk to the duck. Tell the duck what you're doing. Say, okay, duck, I'm having this weird issue. I'm trying to log into the website and I'm seeing this really bizarre error. I tried doing this, I got this instead. Just kind of talk out that problem or if you're trying to implement something you're not sure how to do it. Talk out what you're trying to do to the duck. Yes, you may look silly but the idea here is that it's kind of jogging your mind and by saying it, you're forced to say all of the thoughts and assumptions that you're making. Maybe you're making invalid assumption and you'll catch that as you're speaking it. And then finally, sometimes you just need to take a break. Clear your mind, start fresh, come back to it later on that day or the next day. That's going to help you forget those invalid assumptions you may have made and it's going to give you a chance to recharge your batteries and let your subconscious work on it. Now, we're at the end of the talk here but there are four things I would like you to walk away from this talk with. Point number one, computers aren't random and neither are bugs. There is always going to be a logical explanation for what's going on. You just need to be persistent enough to find it and that persistence will always pay off. You'll either fix the issue or you'll learn something new that'll help you out in the future. Don't be afraid to dive deep into the code base. Maybe you haven't gone at the Drupal core before. Maybe you're not familiar with how caching works but jump in there anyway. You'll learn something and the more you jump in there the more and more you'll learn and become an expert quicker. And then lastly, don't make assumptions or take things for granted. Challenge everything. Now unfortunately, we're right up against the time limit so I don't think I really have time to answer questions but if you have any feel free to come up to me afterwards I'd be happy to help answer them. I do have a few resources here on debugging and doing effectively. I'll post these out on Twitter. Here's my Twitter handle right here at Colin O'Dell. So if you're interested in that just keep an eye out for that. And thank you guys. Thanks for your time.