This article is all about writing code that doesn't fail. But, if it does, having an acceptable way to figuring out what is wrong is a must.
The title of this article is something I heard at Google, and to me, it represents a lot of what is wrong with the company. In the particular situation, we were trying to figure out what was happening, as we just had logs of "crashes" in the wild, with no extra information. And when I asked if we had actual debugger tools, I was told that we don't need debuggers if the code is well-written, by good developers, well-documented, well-reviewed and with good unit-tests. Yet, that answer completely lost sight of the real problem: We had a bug that no-one knew about and all the "good this and that" didn't avoid it from happening.
Debuggers, Why We Need Them?
So, this short article is all about why we need debuggers.
Debuggers are great to understand what is happening with the code during its execution. Their name might imply they are good "just to find a bug", but they are more than that. You can learn a lot of what an application (or just a function) is doing just by debugging it line-by-line and maybe messing up with the variables a little to see what happens.
In any case, I would say they are a must to find "unexpected problems". It is not that it is impossible to find bugs using other techniques (in fact, that's what I needed to do at Google in the project I was working at the time)... yet a debugger would probably make an entire day of adding logs, reviewing logs, modifying code, running everything again, into a 5 minute step-into, see the state of variables, maybe change some of them, find the bug.
So, debuggers are a great way to find real problems with ease.
What are Real Problems?
When talking about programming, the real problems I am talking about are "unseen or undetected bugs". I mean, while developing, everything seemed fine. Yet, on the "wild" (that is, when the product was released to the world), some bugs were noticed. This is the worst (and somewhat most common) scenario: When things get released to the world, we don't have just a couple of developers testing all the possibilities they can think about. We might possibly have an entire world of people using the app and doing everything that was unplanned and/or unexpected.
How Good Developers Help?
So, going back to the title of this article, good developers help in avoiding any situation that needs debugging. In that sense, the idea that if we have good developers we don't need debuggers is right. As long as the developers never make a mistake, we will never need to debug anything. But, if we do have mistakes, what should we do?
I even have a story where I was talking with a friend about good programming, and he told me that in a 'perfect world', all code will have good unit tests. To which I answered that in such a perfect world, no developer would ever make a mistake, to need a unit test.
Even if I somewhat contradict myself, the entire idea is: If you are 100% sure your code will never cause an error (and actually right about that belief), maybe having good unit tests will not help. Everything is perfect already. But, if unit tests didn't avoid the problem, at least make your code "debugger friendly"... and I hope your project can deal with a debugger.
Debuggers, Which Ones Are Good?
I can't really answer this question for all languages and in all situations but, to me, a good debugger needs to:
- allow me to put breakpoints anywhere I want (and good code does just one thing at a time/line, so I can put a breakpoint really where I want)... that is avoid calls like
a(b(), c(), d(e(), f()));
- allow me to see all variables (including return values, before the method returns);
- allow me to change variable values so I can play with possible different situations;
- allow the basic step-by-step, step-into, step-out actions.
Well... there are probably a lot of other things to take into consideration, but those are the things I really use and help me a lot. And no, unit-tests never helped me solve a new bug. They are great at avoiding a previous bug to resurface (and possibly to ever exist if well planned), but they don't help in solving existing bugs.
What About Existing Bugs That Were Avoided?
Oh... my text might be too harsh. Unit tests do avoid real bugs from appearing and I am not saying we don't need them. I am just saying unit tests are about bugs "known to (possibly) happen" and, even if it is possible to deal with different cases (with better developers), they rarely solve "existing bugs" or completely "unexpected ones"... which is all about debuggers (or in some cases, major refactors when something is already "smelling").
Don't Have a Debugger?
I am sorry if you deal with this. Try to insert "debug" statements, "puts()", "Console.WriteLine()" and similar in your code. I hope you get a good debugger but, if you don't, you need to go "old-school" (or just 'almost resourceless')".
- 5th January, 2020: Initial version