Dear new developer,
When you are fixing a bug in a program you are working on, a key thing to do is to get an understanding of the state of the system. This can include user input, stored values from a persistent data store, and non recurring information like the current time. But the most important piece of state is that of the program in memory. What function or procedure is executing when the bug appears, and what did all the variables look like at that moment?
And that’s how a lot of debugging happens–printing out log statements to a file. You can solve many problems that way, it’s extremely portable and customizable, and it gives you some insight into program state.
However, a far better solution is to use a real debugger. They’ve been around since the 80s, at least, and give you far more insight into a program’s state than log statements. You can see the state of any variable. You can run commands interactively. You can stop anywhere, and restart the program. If you pair an interactive debugger with an automated test, you can have an extremely tight feedback loop that will help you zero in on the issue at hand.
Most of the major languages have such interactive debuggers (in fact, that’s one way to decide to avoid a language; a development language without a real debugger is likely to have other language level issues, like a poor dependency management story). Some languages even have standard protocols where you can connect to remote servers with a debugger. If you ever have to debug a production issue and can enable that, it’s going to be super helpful.
Debuggers are often integrated with an IDE, but some are runnable on the command line. Whatever your language, just google for “<language> debugger” and find out more about this valuable resource.