Explore different ways to identify, search for, and remove errors from software, including splitting, hypothesizing, experimentation, and rubber ducking.
- [Instructor] Nobody wants their application to fail. In the last chapter, we focused on ways to record activity and errors consistently. Knowing about problems is important, but that's only part of the challenge. In this chapter, we'll focus on ways to debug Node.js software and eliminate errors we've identified. We'll start by exploring different ways to locate problems in an application. Then we'll use Node's built in debugger to take complete control over a Node.js process to see what's happening and how.
We'll compare three different debugging techniques, starting with Node's built in debugging, then Chrome's DevTools debugging, and finally, Visual Studio Code's debugging. Let's start with a holistic look at debugging, which isn't just logging. What does debug actually mean? The term debug means to identify and remove errors from software. We've covered some of the identification already, but clearly there's more to debugging than just logging. Debugging is a combination of many things. Logging helps by including a record of an error and hopefully some context.
In order to fix a problem, we need steps for reproducing the problem. That way, we can verify that we have the correct solution. Knowing what is working is also important, as it narrows down the possibilities of what is malfunctioning. Finally, debugging includes the act of finding where the problem is occurring, and why. The last part can be difficult, so how can we approach it? There are a number of different approaches to locating bugs, and we'll discuss each in turn. They include splitting, which is also known as binary search, hypothesizing, experimentation, and rubber ducking.
That last one isn't a joke. Let's start with splitting. Splitting is a technique that helps speed up the search process. The goal is to find a midpoint between two locations where the problem can be occurring. Then we experiment by adding logging or other indicators that will check the results. If it's not in the first half, it's in the second half. This technique is also known as binary search, which is a fundamental computer science algorithm. It's not the most efficient, but it's effective. Hypothesizing is a more nuanced approach than just splitting up the code.
In short, we'd use our knowledge of the system to rule out sections where the problem doesn't exist. Then we'd choose a hypothesis about where a problem could be. Finally, we'd run an experiment to test the hypothesis. A less formal way to explain hypothesizing is, I think the problem is here because, then testing to see if that's really the case. Another way to search for the problem is through experimentation and observation of the system. This can include trying different test cases, to see if the problem still exists.
We can also add more logging in places where we think the problem is happening. Finally, we can use a debugger to control program execution to see exactly what the program is doing. We'll discuss the use of a debugger in the next video. Finally, there's rubber ducking. It's name is a reference to a story in the book The Pragmatic Programmer. Basically, a programmer would carry around a rubber duck and explain their program line by line to the duck. The act of explaining the problem to someone else in describing what the code should and shouldn't be doing often reveals problems, and a deeper understanding of what the program is doing.
By talking to something inanimate, like a rubber duck, you don't have to bother or interrupt anyone who's busy. There's no one way to debug software, and often it takes a combination of several of these techniques to locate the source of a problem. I mentioned the use of a debugger just a moment ago, and Node has one built in. Let's learn how to use it.
- Building a troubleshooting mindset
- Why measure performance?
- What's a microservice architecture?
- Managing microservices with PM2
- Effective logging strategies
- Debugging Node.js applications
- Benchmarking performance
- Profiling code execution
- Knowing what to optimize