This is a serious question because in 5+ years of programming I have never used a debuggers. The only time I used a debugger was when I was learning to program and to trace out for loops.
Now I just use print statements and read code to figure out what’s going on.
Yes, absolutely, it's an indispensable tool - and I've been doing this software gig since 1990. Some languages, like JS and Python which are quickly interpreted, are amenable to printf debugging, while others, like C++, C, Go, really benefit from debugging. A debugger is your best bet at debugging multiple threads, for example, especially since you can pause them at strategic locations to recreate a race condition. This is really difficult with printfs.
The world of JS development has tremendously powerful live runtimes/debuggers in the browser developer tools, those are a fine example of what a debugger can be.
I write go using Goland by JetBrains, which uses Delve under the covers as a debugger. Compared to dbx (which was amazing), gdb, etc, it's deficient, but better than nothing.
How do you know how you got to that point in the code without a debugger? What's the call stack like?
How could you debug a call in a DLL that is being loaded by your program if you do not use a debugger?
It might be alright for tiny programs but it's essential for "big" applications.
printf'ing isn't going to help with 2 million+ lines of code or where there's a leak somewhere in that code (eg. someone else wrote some bad code or bad reference counting and didn't release when they should, eg. in COM wrappers in Windows), or someone is double-freeing some memory or trampling on memory and you need a hardware breakpoint to know what is modifying that memory at any given point.
I step through almost every line of code I write in a debugger. I'm pretty visual based, and that combined with the action of clicking through forces me to slow down and really think about what my code is doing. Whenever I open the debugger, I find bugs that I can fix! :P
I've heard it said that there are two types of programmers: those that stare at their text editor all day, and those that stare at their debugger all day.
I often find myself working on a legacy codebase. The application will enter a state that I don't think should be possible. The debugger can usually help me figure out how that happened.
It's worth mentioning that debuggers are less essential in languages like Go where the control flow is purposefully very straightforward. I often debug Python and end up being totally surprised to see the execution jump somewhere else because of a decorator.
It's as if you didn't read the comment I wrote and started foaming at the mouth at the chance to say RTFA as is HN tradition. (Or didn't read the article closely enough yourself)
He said explicitly, he used a debugger.
He came to understand the value of having a proper mental model of your code, but the comment I replied to said they had never used a debugger.
My comment was about the difference between knowing how to problem solve without a debugger, and straight up never having used it
There's nothing wrong with having more tools in your toolbox
> This is a serious question because in 5+ years of programming I have never used a debuggers. The only time I used a debugger was when I was learning to program and to trace out for loops.
They're saying it themselves, "yeah technically once I used it when I was figuring out how for loops work".
I wouldn't say I've ever written a Brainfuck program even though once I messed around with a hello world on an online interpreter
Leave it to people here to say a comment doesn't say literally the exact words it says
-
The spirit of multiple replies, not just mine is debuggers are an option you should at least be familiar with before tossing aside, even if you do end up not needing them
It's the preference of the people referenced by Person B.
Person A the word _never_, the definition of absolutism.
You're literally making my point, a preference towards not using debugger not a limitation, an absolutist approach of never having used one professionally could be.
It's not like I said "OMG go use one right now or your career will fail" either before you latch onto that too. I said even those guys with a preference away from them, have used them professionally
Didn't think I'd be spelling out 1st grade reading comprehension on HN but here we are.
Why this sudden increase who think turning off their critical thinking skills to go "gotcha" because you didn't write out your comment like a thesis is something positive?
To give an opposite metric, on one of the C++ software I develop the "add printf, compile, and run" takes in average 1/2s while it take sometimes up to a minute to load it in gdb or lldb. Which sucks because a lot of things are incredibly easier with a debugger.
That's very unusual, is it an embedded environment? I'm used to C++ taking much longer than other languages to compile, which in turn discourages printf debugging.
not at all, standard Qt desktop software - when split correctly into object files and shared libraries the incremental build time in C++ can be very fast (also, being on linux and using lld as a linker helps tremendously, building on windows is on average 3-5 times slower for me, and lld links in the bat of an eye compared to bfd (GNU ld) and gold)
You're right. But you need to have been exposed to a good debugger before you understand this. Preferably you also have had a colleague that was proficient in it to get you started.
> Now I just use print statements and read code to figure out what’s going on.
Print is worse and more work. You should set one (or several) breakpoints and then debug, which replaces possibly many run/debug loops at once. You also have no chance of accidentally committing a print statement.
Hearing that people don't use debuggers feels like hearing that someone uses a screwdriver instead of a drill that someone gave them for free and is just sitting in the garage, untouched.
There are literally no drawbacks to switching to a debugger.
> You also have no chance of accidentally committing a print statement.
Debuggers are ephemeral---unless they are "reversible", which is a subject of ongoing research. You can't replace logging with debuggers, and some print statements used for debugging are in fact better described as post-hoc logging. On the other hands, print statements do change your program and can mask some other problems especially in multi-threaded programs.
> There are literally no drawbacks to switching to a debugger.
Only for properly prepared environments. In some environments enabling a debugger itself can be annoying or even close to impossible (for example, some non-native socket-based debuggers tended to be fragile). I use debuggers when I can, but being able to not rely on debuggers is useful from time to time.
You seem to have inferred two straw-man arguments from my comment: 1) that people should stop logging, and 2) that debuggers can be used in 100% of cases.
> You can't replace logging with debuggers
I never suggested this. I only discussed whether to use printing or debuggers for debugging.
> Only for properly prepared environments
Of course, but these are the vast majority. Most devs are working with Java, Python, C#, TS/JS, Visual Basic, Go, or some combo. All have debuggers.
While I meant not to fully refute but rather to build upon your statements, some clarification seems necessary:
> I never suggested this. I only discussed whether to use printing or debuggers for debugging.
Yes, but I specifically mentioned some usefulness of printing for debugging ("post-hoc logging"). Printing can be used both for debugging and for logging simultaneously, and many debugging prints can be readily converted to actual logging. As far as I know there are no widespread equivalents in debuggers---but please let me know if any, I'm genuinely curious.
> Of course, but these are the vast majority. Most devs are working with Java, Python, C#, TS/JS, Visual Basic, Go, or some combo. All have debuggers.
Their quality wildly varies though, and they are especially fragile when multiple languages or environments are in play. In my recent case, Visual Studio 2017 froze when debugging mixed C++ & C# codebase. I tried a lot, but eventually I didn't want to investigate further and decided to use print debugging for the moment. It was finally fixed when I and my team upgraded to VS 2019, I still don't know why it didn't work and it fixed itself.
Then probably I was talking about something else. I meant persistent logging for later inspection, not ephemeral logging for one-off debugging (yes, it is confusing...).
My impression has been that developers way too often rely on the subsequent use of the debugger when writing code. It’s like, “I don’t really know what I’m doing, but the debugger will help me understand my code... Oh, what a piece of crap I wrote! Let me start over...” Looks almost like people are debugging themselves.
They're much more useful in maintenance environments where people have already written a million lines of code before you got there. Of course you have no idea what they've done. After a few years they probably have no idea either. You can go grepping in the codebase, but the sheer speed of asking the debugger "how did I get here?" is hard to beat.
They're also useful in layered environments. Sometimes it's a bug in other people's code and you need to get in there to find out what's happening. When all you have is disassembly, and can't readily insert print statements, the debugger is absolutely invaluable. One of my own "debugger greatest hits" was finding a bug in Windows CE stack unwinding this way.
It's simpler to click a few lines of code, get the entire program state or a selected subset, and then get a perfectly line by line granular understanding if desired, then to write a bunch of print statements. The only reason printlns would seems easier is because it takes s bit more time investment to learn debugging tools.
In my ide I can see all threads, I can freeze and unfreeze threads as I want, I can run a threads to the same point. All while inspecting the variables in use.
Or pausing code and seeing the whole call stack, having it navigable by just clicking.
This is a hard question to answer easily, IMO. I find that Java folks tend to overuse the debugger, spending 20 mins stepping through something that a simple value print would have solved.
That said, some code -really- needs a debugger. You can theoretically spend hours adding prints everywhere, but even that pales in comparison.
In short, I find that the need for a debugger is rare, but when you do need it, it's irreplaceable.
There's literally no difference between a print and a breakpoint except that the print you actually have to write code while a breakpoint not only do you don't have to write code... you can see the entire program state.
There is literally no argument here. Debugging with breakpoints is categorically less work.
When you see people stepping through code it's because they don't know where the error occurred. It's the equivalent of putting print statements everywhere. You tell me which one is better.... littering your code with print statements? or breakpoints?
A debugger is not just useful to debug. I've found it a joy to actually be able to step through every step and see e.g. a request being transformed through the different libraries and middlewares. In Goland, you can even step into the stdlib!
I will admit there a few "blind spots" but 99% of the time, a debugger is a super fun way to understand your code rather than inserting print statements everywhere.
Yes. Especially if the debuggers are easy to use and aren’t just gab-style shells.
I can definitely lived without a debugger, I’ve done it before and you get used that after awhile. But given the choice between a programming experience with a good graphical debugger and one without, the former will almost always win out.
As with many other perennial programming debates, I think we underestimate the diversity of our experiences when having this debate. There are codebases that debuggers don't really help that much on, perhaps because they're technically very difficult to get running, or perhaps because they were written in such a way as to not really need them very often.
There are other code bases where debuggers are a necessity.
Some of those considerations are not even strictly speaking in the code themselves, but related to the code + developer; for instance, I really love debuggers for codebases I don't understand because I just came to them. You can read the code all you like, but until you watch it run, you don't realize that this one if clause that you kind of skimmed over actually invokes an entire chunk of code you didn't even know existed, etc. Whereas someone intimately familiar with that code may not need the debugger so much. Any sort of recursive data (parsing, HTML nodes, etc.) is a pain to deal with in printf debugging too because you either fail to dump out enough context to understand where you really are, or because you dump out so much context that you drown in it.
My call is that A: they're absolutely indispensable tools that you should have in your toolbelt so that you don't hesitate to use it when you need it, but at the same time B: you should try to avoid depending on them, because a codebase that you can't handle without a debugger is a code base that you can't understand, and that's bad.
I very deliberately say "should try", because it's not always practical; maybe you're just visiting this code base and have no reason to understand it, or maybe it's just intrinsically too darned large to understand, etc. But you should still strive to not need debuggers to follow subtle, complicated code, but make your code do what it says it does and no more. (e.g., stop using globals, don't write code that tries to figure out what lies to tell to other bits of code to make them coincidentally do what you want, etc.) I also say avoid "depending" on them, because if you don't depend on them, you can use it freely. I've only used a Go debugger a handful of times, but each time it saved me a ton of time. But the codebase in question remains comprehensible and straightforward, because I don't make skilled use of a debugger a prerequisite for following it. (I've inherited other code bases which do.)
> As with many other perennial programming debates, I think we underestimate the diversity of our experiences when having this debate. There are codebases that debuggers don't really help that much on, perhaps because they're technically very difficult to get running, or perhaps because they were written in such a way as to not really need them very often. There are other code bases where debuggers are a necessity.
This is absolutely true and very wise; there are a lot of strange kinds of programming environment out there, and we need to be aware of the full spectrum of tooling possibilities. And failure possibilities.
The worst environment I ever had to deal with was a strange embedded one where my code ran as a subprocess of a 3G module. There was a single-step debugger but not a proper JTAG one - so if it crashed, the device reset rather than dropping you to a debug prompt. Printf was sort of possible, but over buffered USB - and if the device crashed, it lost the last few lines in the buffer which would have told you what the crash was. I ended up leaving a breadcrumb trail in bits of memory that were known not to be zeroed on boot.
I don't usually use debuggers in functional programming languages. Since it's mostly expressions I usually use REPLs.
But for imperative languages like Go, a fast and good debugger can boost up productivity a lot if properly used, it's basically a REPL for imperative languages - since imperative languages mess with the ordering and the environments much more than functional languages.
Instead of inferring how to code would be executed, you would debug at reasonable places, know how it executes and play with it directly with some expressions. It's more about the feedback speed.
Only using print it's not sufficient because there are a lot of data structures that are too large to serialize. Or like functions that are not serializable at all, you have to reference it in the debugger or it doesn't really help.
It depends on the language. I've used debuggers in java, much less in c++, and hardly in go. I feel there is not much of a need in go for debugging, writing good tests and the occasional log/print statement do fine.
Java, often having more complicated structures and layers (more due to the culture, one could write more go-like simpler java as well) is more reliant on debugging. More dynamic (less predictable) languages such as python even more.
My debugger usage pattern varies between languages. For C# I rely heavily on the debugger because it is just so easy and pleasant to do so. For Go using GoLand I use the debugger regularly, but I expect that it won't be quite as versatile as debugging C#. For Python or JS I find it easiest and most intuitive to just print-debug for everything.
Especially on JVM, conditional breakpoints are really nice for this. (And at least most classic Java-Webservers are really compatible with this approach)
Agreed, debuggers can be nice to have but they are mostly a crutch.... Write modular code with unit tests and you find your need for debuggers is really a rarity
Absolutely; everything from libraries, language development, even in REPL languages like J and R, I use debuggers all the damn time, native J/R/whatever, GDB, the whole lot. If you deal with hairy issues, there's no way of solving the problem with print statements, and if you're used to them, they're a lot more productive. You just have to pay the toll of learning the debugger.
I haven't uncorked any golang in a long time (~5 years), but I do remember thinking WTF regarding the debugger. I think the idea is to write enough unit tests you don't need the debugger so much. Seems questionable, but what do I know; Google would never hire me. Otherwise I liked golang a lot as a very pragmatic language and ecosystem. I had wished the GC was optional somehow to replace C/C++ tier "systems" stuff, but whatever; it's a fine successor to Java type things.
This is a serious question because in 5+ years of programming I have never used a debuggers. The only time I used a debugger was when I was learning to program and to trace out for loops.
Now I just use print statements and read code to figure out what’s going on.