[HN Gopher] The unreasonable effectiveness of print debugging
       ___________________________________________________________________
        
       The unreasonable effectiveness of print debugging
        
       Author : pcr910303
       Score  : 232 points
       Date   : 2021-04-24 15:28 UTC (7 hours ago)
        
 (HTM) web link (buttondown.email)
 (TXT) w3m dump (buttondown.email)
        
       | SinParadise wrote:
       | The limitation of print incentivizes me to write smaller
       | functions and code that are generally free of mutations, so
       | traces doesn't get stale fast.
       | 
       | Debugging on the otherhand, well.. I've just been told by my
       | senior to write bigger functions, because the line-by-line
       | debugging tool jumps around too much when moving between
       | functions to functions.
        
       | two_handfuls wrote:
       | I agree with the point about time travel debugging. I find it so
       | intriguing that I've been playing with it for a little tool to
       | make VR games. Anecdotally, it has helped me a lot with
       | debugging.
        
       | api wrote:
       | Print debugging is basically variable watch points, but IMHO
       | easier.
       | 
       | The only time to really beware is embedded and real time systems
       | where printing can throw timing way off or cause other side
       | effects.
       | 
       | I heard of a case once where printing via JTAG caused an issue
       | due to the power draw of sending all the extra data out. But that
       | was trying to debug a novel board design and its software at
       | once.
       | 
       | You won't hit that kind of thing on normal computers like
       | desktop, mobile, or cloud unless you are writing drivers.
        
       | gdubs wrote:
       | GPU equivalent: putting stuff into vertex buffers so you can
       | inspect the buffer and see if the expected values are there.
        
       | utopcell wrote:
       | > I do want to point out that print debugging has one critical
       | feature that most step-based debuggers don't have: you can see
       | program state from multiple time steps all at once.
       | 
       | At Google, we have time-traveling debuggers neatly integrated
       | into our cloud IDE: You can step forwards and backwards, you can
       | inspect variables for all the values they've had or will have
       | until program termination, and you can also see all invocations
       | of methods (along with their parameters) that have happened or
       | will happen.
       | 
       | I still use logging for debugging. Cool tech aside, I think what
       | you really need, above everything else, is the fastest possible
       | iteration cycles.
        
       | LudwigNagasena wrote:
       | I can just write print(whatever) and get the job done, I don't
       | want to put breakpoints and search for a data structure I need.
       | Why can't I write something like this: breakpoint { debug(var) }
       | 
       | ?
        
         | Groxx wrote:
         | Assuming you mean something like "leverage the debugger to
         | print, so I don't have to do it in code": you can, in most
         | debuggers. This is effectively a "log breakpoint", or a
         | "conditional breakpoint" where your condition is
         | "print(thing)".
         | 
         | I use debuggers even for print-debugging for this kind of
         | reason. No need to re-compile between changing prints, just re-
         | run - the debugger session will hold them from previous runs,
         | you can temporarily disable them with a single click, etc. It's
         | _FAR_ faster and more flexible.
        
       | rubyist5eva wrote:
       | Print debugging is great but you'll pry the IntelliJ debugger
       | from my cold dead hands.
        
         | mistahenry wrote:
         | Completely agree. When implementing new functionality in my
         | Kotlin Spring Boot apps, I find the debugger crucial for fixing
         | any exception that isn't immediately clear. I'll simply rerun
         | my test with a breakpoint on the failing line, peruse the
         | values of local variables (often spelunking deep into nested
         | objects), and test theories with the window that lets my
         | evaluate arbitrary expressions. Occasionally, I'll change the
         | value of a local variable and let the program continue to see
         | if that value would fix the issue.
         | 
         | It's a workflow that makes "Wait, why did that happen" such an
         | easy question to answer.
        
       | njharman wrote:
       | I think it has most to do with way user thinks.
       | 
       | I need to see big picture, whole state, all the stuff and rapidly
       | jump back and forth. I also, supposidely, have ability to keep a
       | lot of state / scope/ abstraction in my head. So I find print
       | debugging sufficient and fast. Rarely encounter situation I feel
       | need for "stronger" tool.
       | 
       | Where other people focus on one thing, all that simultaneous
       | output is just noise and distraction to them. And based on the
       | continued use and popularity of step-based debuggers, these
       | people are much more productive (and happier) using those type of
       | tools.
       | 
       | It's very important to understand neither system is inherently
       | superior. Although one or the other is superior to each
       | individual. [btw over 35yrs of tech industry / software
       | development I've found this true, that tools/paradigms are not
       | universally superior but are superior based on individual) for
       | many subjects. All the ones that have internal debates in
       | techdom]
        
       | [deleted]
        
       | sunstone wrote:
       | I learned early on with an expensive microprocessor emulator,
       | just have the code raise the voltage on an IO pin as a print
       | debugger rather than spend days debugging the emulator.
        
       | praptak wrote:
       | You call it print debugging, I call it a powerful experimental
       | framework for testing hypotheses about the behaviour of the
       | program.
        
       | CJefferson wrote:
       | Personally, I think my biggest reason for using print debugging
       | is.. it works.
       | 
       | In C++ I often find the debugger doesn't find symbols on projects
       | built with configure/Make. If I have a Java Gradle project I have
       | no idea how to get it into a debugger. Python debuggers always
       | seem fragile. Rust requires I install and use a "rust-gdb" script
       | -- except on my current machine that doesn't work and I don't
       | know why.
       | 
       | I'm sure in each case I'm sure I could get a debugger working
       | given enough time, but the only error I've ever had in print
       | debugging is failing to flush output before a crash, and it's
       | never been hard to search for "how to flush output" in whatever
       | language I'm current using.
        
         | mschuster91 wrote:
         | Worst thing with Java is, especially when taking over a project
         | or extending some open source thing: finding where that goddamn
         | log4j config is. Is it in web-inf, in tomcat/glassfish config,
         | somewhere entirely else (e.g. specified in the run config), or
         | is it configured in one of the five wrapper layers.
         | 
         | And _then_ you have to figure out the syntax... does it want
         | package names, class names, or (hello Intellij plugins!) need a
         | fucking # at the beginning to be recognized.
         | 
         | And _then_ you have stuff like a  "helpful" IDE that by default
         | only shows WARN and above levels without telling you somewhere
         | "there might be stuff you don't see" like Chrome does.
         | 
         | For actual debuggers, shit is worse, across the board. Running
         | in Docker is always a recipe for issues, not to mention many
         | applications actively messing around with stuff like ports.
         | 
         | A system.out.println always ends up somewhere sane.
        
         | fighterpilot wrote:
         | Part of the reason it works is it forces you to reason about
         | the code, otherwise you won't know where to put the print
         | statements.
        
         | zamfi wrote:
         | Print debugging always works, but also: it lets the programmer
         | _customize their view_ of the program's (very, very large)
         | hidden state in any way imaginable. Step debuggers are the "no-
         | code" equivalent: extremely useful for the purposes for which
         | they were designed--and often the better choice there--but
         | inherently limited.
         | 
         | Geoff's not wrong in invoking Bret Victor's Learnable
         | Programming argument that being able to track state over time
         | is critical to debugging, and Geoff's right that print
         | debugging makes this easier than almost any existing step-
         | debugger.
         | 
         | Bret's deeper point, though, is that a major challenge in
         | debugging is _hidden state in general_ , and that variable
         | state changing over time is just one example.
         | 
         | Not only is there a _ton_ of hidden state in the execution of a
         | program--the full execution trace PLUS state of every variable
         | at each point in that trace--but there is also a ton of
         | _interpretation_ of that state that the programmer needs to do
         | while debugging: "what does this sequence of events imply?" -
         | "why is this pointer pointing here?" - etc.
         | 
         | Doing that interpretation is much easier when the programmer
         | gets to _selectively view_ that (again, HUGE amount of) hidden
         | state. Print debugging gives the programmer complete control
         | over what state is shown. No other debugger does that: they all
         | show a ton of data and context (often useful!) and make certain
         | operations easy (inspecting single variables! viewing call
         | stack snapshot!), and these are often just the right things.
         | 
         | But sometimes they're not. And often, when you start debugging,
         | you don't know if the fancy debuggers will be too much or not
         | enough.
         | 
         | Print debugging gives you the power to _write code_ to
         | selectively view the (again, HUGE!) hidden state of your
         | program, and this scales from the smallest code-tracing bug to
         | the largest distributed systems.
         | 
         | Step debuggers, on the other hand, are essentially "no-code"
         | debuggers -- extremely useful for the purpose for which they
         | are designed, still useful for adjacent purposes, and a great
         | place to start if you know the tool well, but ultimately not as
         | powerful if your needs exceed their capacities.
         | 
         | A good programmer will know how to use all these tools for what
         | they're best at!
        
           | vvanders wrote:
           | If you've chased heap corruption printf doesn't really help
           | you much but a data breakpoint is a godsend.
           | 
           | Same thing with watch windows, memory views and the like.
           | There are classes of problems that do well with printf but
           | calling them "no-code" is vastly underselling them.
        
             | zamfi wrote:
             | I'm not sure when no-code became a pejorative, but that
             | wasn't my intent! Only that most of these tools, unlike
             | print, are special-purpose, exceptional for that purpose,
             | and often even useful in other circumstances.
             | 
             | A data breakpoint is a great example of something useful
             | that print doesn't do well.
        
               | vvanders wrote:
               | You seemed to be drawing a parallel between no-code ->
               | "not as powerful", in my experience they're different
               | tools for different use cases.
               | 
               | I also don't think they're nearly as no-code as you call
               | out. VS' watch window has very few limitations compared
               | to printf back when I was working on win32 things.
               | 
               | Also important to consider iteration time. I once worked
               | on a system where adding a printf was a 20 minute process
               | due to the need to heavily optimize for a memory
               | constrained platform(scripting fit in 400kb block with
               | the asset bake step).
        
               | zamfi wrote:
               | > in my experience they're different tools for different
               | use cases
               | 
               | Exactly!
               | 
               | Debuggers are very useful tools, and typically not as
               | general-purpose as print. I don't view "not as powerful"
               | as a meaningful distinction, because it requires that you
               | ask "powerful at what?" ---
               | 
               | VS' watch window is great but (I assume) doesn't work
               | across distributed systems, etc. -- as a general
               | technique, print is universal in the sense that there are
               | very few problems that can't be diagnosed by modifying
               | your code and printing some (possibly a manipulation!) of
               | the hidden state. This is going to be harder than using a
               | special-purpose tool designed for exactly your problem.
               | 
               | In the same way, "no-code" tools are typically better
               | and/or easier than writing code to solve the same
               | problem, but special-purpose.
        
               | vvanders wrote:
               | > typically not as general-purpose as print
               | 
               | In my domain which doesn't usually cover distributed
               | systems printf can be worse because it introduces
               | synchronization primitives that have caused race
               | conditions to disappear(and that race condition causes
               | second order heap corruption or the like). On one
               | platform system memory was so small(8mb total) that each
               | output to stdout went over the serial link slowing
               | performance down to 1/20th of a realtime process under
               | any real logging.
               | 
               | Like I said, different tools for different uses, and
               | really depends on the context. If there was one size fits
               | all then we'd just use that but the diversity of
               | debugging tools I think shows that you need a variety of
               | techniques to approach the problems we encounter.
        
               | zamfi wrote:
               | > Like I said, different tools for different uses, and
               | really depends on the context
               | 
               | We totally agree, and I'm not sure what we're arguing
               | about--perhaps you can fill me in.
               | 
               | I'm arguing that print is almost always worse than any
               | specialized tool. (After all, who would use a specialized
               | tool worse than print?) There is not a one-size-fits-all
               | tool, and print is not a one-size-fits-all tool.
               | 
               | Indeed almost every seasoned developer has a story about
               | print failing. Whether it's the mysterious "Heisenbug"
               | that disappears when you measure it (like the sync issues
               | you mention) -- my personal story is when I was trying to
               | debug a (class project) kernel scheduler. Printing to the
               | console was so slow that by the time I'd printed
               | anything, the scheduler had moved on to the next time
               | slice!
               | 
               | It's worth nothing that "print debugging" is not
               | literally just using the "print" function; it's a style
               | of debugging that involves logging specific information
               | using some logging function (usually, but not always,
               | print) and then analyzing it after the fact (usually, but
               | not always, by reading the printed output).
               | 
               | This strategy of "get data out, then analyze it" is the
               | general form of print debugging, and in the small-memory
               | case, or the sync Heisenbug case, this often means
               | collecting data in the appropriate variables before
               | outputting it to be visible. Isn't this still print
               | debugging, even though it doesn't use a "print" function?
        
               | vvanders wrote:
               | I think we're mostly arguing about how useful the various
               | approaches are. At least for me print debugging is a
               | measure of last resort unless I want to extract some
               | historical data out and I know it won't influence the
               | timing of the issue I'm trying to chase down.
               | 
               | With print debugging your inserting the whole build +
               | deploy + repro setup loop into your debugging, if that's
               | a long time(say 20 minutes in one job I had with
               | production hardware) you're in for a world of pain. I
               | find that just about any other tool usually is an order
               | of magnitude more efficient.
               | 
               | Also even the "step debugger" tools do the same thing
               | you'd do with a print. LLVM for instance uses the IR JIT
               | API to generate watch/eval values:
               | https://releases.llvm.org/9.0.0/docs/ORCv2.html#use-cases
               | 
               | IMO you should relentlessly optimize your iteration
               | times, that's the inner loop of development speed and
               | print debugging fares pretty poorly in that area for all
               | the reasons above.
        
           | tomcam wrote:
           | > it lets the programmer customize their view of the
           | program's (very, very large) hidden state in any way
           | imaginable.
           | 
           | I've been trying to articulate this to myself for a long
           | time. Thank you.
        
           | jayd16 wrote:
           | This is a lot of words but I wonder if you've ever worked
           | with a debugger with watchable variables or immediate mode
           | code execution. I find it odd you say print debugging is more
           | flexible.
        
             | gerdesj wrote:
             | Using a debugger is largely _passive_ - it shows you what
             | is actually happening.
             | 
             | Debugging via print allows you to step outside and peer in
             | ie it is _active_.
             | 
             | Print debugging can be prone to bugs within itself which
             | may cause additional ignorance about the potential bugs
             | being diagnosed. How meta can you get? 8) There's also the
             | effect of the effort of actually looking - that may or may
             | not have an effect.
             | 
             | Anyway, the discussion here is largely ignorant of language
             | and function. At the moment I spend time fiddling up Python
             | and OpenSCAD scripts if I dig out a programming language.
             | For me, print is really handy. For a Linux low level
             | latency sensitive driver in highly optimised ASM n C I
             | suspect this matter is moot.
        
         | tgsovlerkhgsel wrote:
         | Especially when you need to run your code on a remote server as
         | part of a bigger platform like some Cloud or Serverless system.
         | 
         | These systems likely already have a way to get logs, but good
         | luck getting a debugger to work there.
        
         | le-mark wrote:
         | I'm sorry but this is just ignorance, learning to use the
         | debugger for the platform at hand is a basic skill every
         | developer should master. So many times have seen developers use
         | the debugger to troubleshoot and fixed issues and been
         | perceived as a "ninja" (despise that term but that was the
         | effect) because they knew how to use the debugger. I mean yeah
         | keep printing lines, and keep being out performed by your
         | debugger using peers. That's the choice.
         | 
         | Yes I am dieing on this hill.
        
           | CJefferson wrote:
           | I do use debuggers when I have a hard core problem, I've
           | found some horrible memory corruptions using RR and gdb for
           | reverse debugging. However, sometimes someone throws a
           | horrible gradle java project at you and asks for help, and
           | figuring out how to debug is a pain.
           | 
           | I'd throw your comment back -- maybe all languages should be
           | "debug first", make it as easy to get code into a debugger as
           | it is to just build and run it.
        
           | d0mine wrote:
           | You are missing out on the important point: printing forces
           | you to formulate a hypothesis: what you expect and to compare
           | with what you actually get. Debugging encourages less
           | modeling and more trying random stuff until something sticks.
           | 
           | It is an exaggeration. In practice, it is useful to apply
           | both. Novices can get some insight using debugging, more
           | experienced with code base people should exercise their
           | understanding of the code and use well picked prints.
        
             | SAI_Peregrinus wrote:
             | You can also do print debugging with a debugger. Just have
             | a breakpoint that doesn't halt, but instead simply prints
             | the values of interest to the debugger console. This is
             | particularly nice for things like debugging interrupt
             | handlers where the time taken to print output normally is
             | too much to accept.
        
               | toxik wrote:
               | Watched variables they were called once upon a time.
               | 
               | Also, I think what you suggest to do here is way harder
               | to learn than printing.
        
               | saagarjha wrote:
               | Perhaps, but that lends credence to the theory that
               | people using print debugging may just not have learned
               | how to effectively use a debugger yet.
        
           | axaxs wrote:
           | OK. And I've also cringed watching ninjas step through code
           | slowly, reading everything, spending 20 mins catching
           | something 2 print statements would have achieved.
           | 
           | Debuggers aren't bad. But neither is printing. Knowing when
           | to reach for them is probably a bit more key.
        
             | mmazing wrote:
             | Tools in a toolbox.
             | 
             | The worst developers I've ever known always have their
             | "this is the best way to do everything" hill they die on.
        
             | dragonwriter wrote:
             | > And I've also cringed watching ninjas step through code
             | slowly, reading everything, spending 20 mins catching
             | something 2 print statements would have achieved.
             | 
             | The problem is that the two print statements will only
             | catch the bug if they are the right two, based on a correct
             | hypothesis of what the bug is. Which, with a debugger,
             | won't require stepping, but setting two breakpoints, doing
             | a run-to-breakpoint, and inspecting values.
             | 
             | Stepping is required when you are exploring behavior
             | because you _don't_ have an easily testable hypothesis
             | about the source of the bug.
        
               | cratermoon wrote:
               | But with print statements if the first place I put them
               | doesn't work, I can start doing bisects and quickly find
               | the right place to print.
               | 
               | As you note, debugger breakpoints aren't magically better
               | than print statements when I'm investigating a hypothesis
               | - I'm no more likely to put them the right place than I
               | would have put print statements.
               | 
               | And then there's a class of problems that neither
               | debugger nor print statements will help: many years ago a
               | very junior co-worker was wondering why his C code was
               | giving the wrong answer for some math. It took me
               | pointing out that one of the numeric types he was using
               | in his code was different from the rest (I think it was
               | #defined elsewhere, in some library, as an integer type).
               | When the compiler did the math it had to do some type
               | coercing.
        
               | jacques_chester wrote:
               | > _But with print statements if the first place I put
               | them doesn 't work, I can start doing bisects and quickly
               | find the right place to print._
               | 
               | Can't I also bisect with breakpoints?
        
               | cratermoon wrote:
               | You can, but the comment was talking specifically about
               | stepping through the code line-by-line.
        
               | dragonwriter wrote:
               | > And then there's a class of problems that neither
               | debugger nor print statements will help: many years ago a
               | very junior co-worker was wondering why his C code was
               | giving the wrong answer for some math. It took me
               | pointing out that one of the numeric types he was using
               | in his code was different from the rest
               | 
               | A debugger and watches on the values of concern
               | _absolutely will_ help with that (so will properly placed
               | print statements), so its a really bad example. (Of
               | course, strong typing helps even more with that
               | particular case.)
        
               | cratermoon wrote:
               | No, my co-worker was so junior he didn't understand why
               | that was happening. It took me a moment to glance at the
               | types in the source and point out the problem, no
               | debugger needed.
        
             | pjmlp wrote:
             | They weren't ninjas, otherwise they would have used
             | breakpoint actions for doing those print statements without
             | modifying the source code.
        
               | majjgepolja wrote:
               | What's breakpoint action? Is it like inserting printf
               | before breakpoint?
        
               | formerly_proven wrote:
               | Breaking is just the default behavior when a breakpoint
               | is hit, you can generally attach whatever behavior /
               | conditions you want using the debugger's scripting
               | language.
        
               | edoceo wrote:
               | maybe this is sometimes called assert()? or in some
               | debuggers you set a watch on a var and the BP triggers
               | only on the watch-condition so the BP don't trigger each
               | loop, only when x=7
        
               | pjmlp wrote:
               | It maps breakpoints to debugger actions that are
               | triggered instead of actually stopping execution, like
               | formatted output of whatever variables are in scope.
        
           | zeta0134 wrote:
           | I've used print debugging extensively doing embedded
           | development, when I could reasonably hook up a serial port to
           | capture the output, or put a crude console on a tiny screen.
           | These systems can't always be debugged in the traditional
           | sense, and if you're troubleshooting some bug that happens on
           | hardware but not in your simulator, then you use the tools
           | you have available.
        
           | xondono wrote:
           | I'm also willing to bet you live way up the stack.
           | 
           | Try debugging something in the embedded world, and you'll see
           | why a lot of bare metal programmers use printfs. Turns out
           | timing is critical most of the time, so using a debugger
           | hides a LOT of bugs from your eyes.
           | 
           | Debuggers are very useful, but so are prints, there just
           | different tools, they have different purposes.
        
         | christophilus wrote:
         | Agreed. Also certain classes of bugs (such as bugs in
         | parallelism) are easier to debug via print than using a
         | debugger.
        
         | pugworthy wrote:
         | I agree with this sentiment. Print debugging is essentially
         | universal. The same goes for compiler directives or simple
         | constant driven conditionals to toggle it (in a brute force
         | way) on and off.
        
         | wmichelin wrote:
         | Python easily has the best debugger I've ever seen in a
         | language.
         | 
         | ``` import pdb; pdb.set_trace() ```
         | 
         | that's literally all you have to do at any point in your code.
         | Run your code in the foreground of a terminal, and boom you
         | have a debugger exactly where you want it.
        
           | anarazel wrote:
           | Fwiw, it's not too hard to approximate that in c/c++. Print
           | out the pid (I often print out "gdb -p %d") and then sleep
           | (and perhaps send SIGSTOP to other processes in more
           | complicated scenarios).
        
           | gmfawcett wrote:
           | In recent Python, it's even easier -- just put `breakpoint()`
           | in your code.
        
         | 1337shadow wrote:
         | What Python debuggers you are talking about? have you tried the
         | built-in CLI debugger? Just drop breakpoint() in your code and
         | you're in. Have been using it daily for over a decade and
         | really happy with it - it's actually one of my favorite
         | features of the language, amongst the many super useful
         | features that Python and its excellent stdlib have to offer.
        
           | zmmmmm wrote:
           | Only thing I hate about this .... regular point of code
           | review: remove the debugger breakpoint you left in your code!
           | 
           | We haven't had one hit production yet, but it came close.
           | Print statement is a lot more harmless.
        
             | [deleted]
        
           | CJefferson wrote:
           | Honestly, I didn't know that and I'll try it. Last time I had
           | to debug I remember adding "-m pdb" (as at the start of
           | https://docs.python.org/3/library/pdb.html , first result in
           | Google), but for some reason that immediately threw an error
           | instead of starting the program, so I just chucked some
           | prints in instead.
        
             | 1337shadow wrote:
             | I just tried python -m pdb and it works for me
             | https://dpaste.org/9EQo#L26 but I really always use
             | breakpoint(). You can even configure it to use other
             | debuggers with an environment variable, ie.:
             | PYTHONBREAKPOINT=ipdb.set_trace
        
               | CJefferson wrote:
               | I just quickly went any checked the program I was trying
               | to debug. I was running 'python3 package --arguments',
               | where 'package' is the name of a directory which contains
               | a package I was working on. 'python -m pdb package
               | --arguments' just complains that 'package' is a
               | directory.
               | 
               | Adding a 'breakpoint()' at the start of the program does
               | get me into the debugger. I'll remember that for future
               | (but, it's not easy to find by googling if you don't
               | already know what you are looking for!)
        
             | montecarl wrote:
             | I have mapped a key to insert "import pdb;pdb.set_trace()"
             | in my editor. Also use it daily, and not just for
             | debugging. It is useful when working on a new project and
             | you just want to interrogate some object you got back from
             | a library to see what valid operations you can do with it.
             | Or to double check some math operations.
        
           | kbd wrote:
           | Never felt that Python debugging was "fragile". BTW if you're
           | not using pudb you're missing out.
        
         | bakatubas wrote:
         | As a counter-point, I think there's an argument that folks
         | don't spend enough time in the debugger. But there's a lot of
         | value there and in fact one could use a debugger environment to
         | unit test as even native debuggers have scripting environments.
         | 
         | Personally, I think folks should master the debugger _first_
         | and during all steps learning a programming language.
         | 
         | But similar to test-driven-development it's a different way of
         | thinking, and most books scarcely discuss the debuggers.
         | 
         | That being said, I do use print-debugging a lot too--in C++ a
         | lot of functionality can be compiled-out, allowing one to, for
         | instance, print hex dumps of serialized data going to the
         | network.
         | 
         | On that note, there is a distinction between trace debugging
         | that is part of the source code and general print statements
         | that are hacked in and removed.
        
           | foobarian wrote:
           | The problem is that it's not just a matter of "learning the
           | debugger for Java." In practice there are many different
           | projects that configure debugging many different ways, and it
           | doesn't matter that you know which keys to press in IntelliJ
           | if it will take you an hour to figure out how to attach it to
           | the project. This speaks to OP's point, where it's hard to
           | use a real debugger to casually investigate random projects.
           | 
           | Having said that, it is absolutely a requirement when working
           | on a project for any length of time (especially
           | professionally) to set up and figure out a debugging
           | environment, because it is significantly more productive than
           | printing. But the startup cost is certainly there.
        
             | zmmmmm wrote:
             | The java case is actually pretty universal ... you run the
             | JVM with debugging enabled (fixed string of flags) and then
             | tell your IDE to attach to the JVM on the port you gave it.
             | You don't need compileable source, can be on a remote
             | server, different OS etc - if you have just the source for
             | the bit you want to debug you can set a breakpoint in it
             | and it'll stop there.
             | 
             | Being able to debug third party code in remote / hostile
             | environments (even when its mixed with proprietary vendor
             | code) is one of the things I like about Java.
        
             | eitland wrote:
             | > The problem is that it's not just a matter of "learning
             | the debugger for Java."
             | 
             | In the Java case, for stanalone projects (i.e. not
             | something deployed on a server) an if it is your own
             | project and you don't do anything unreasonable it is mostly
             | just set a breakpoint and hit "run with debugging".
             | 
             | Probably the least painful debugging experience I know.
             | 
             | Doing it for Tomcat/Tomee was slightly more advanced IMO
             | but still utterly trivial compared to wrangling css or js
             | ;-)
             | 
             | There are reasons why we "old folks" like Java so much
             | despite its verboseness.
        
           | throwaway894345 wrote:
           | I can believe there is value in learning a debugger, but
           | debuggers could stand to improve significantly. Debugger UX
           | is almost universally awful and per the parent it's often
           | difficult to get one up and running. Moreover, if you do your
           | "print debugging" with log statements of the appropriate
           | level, they can be useful in production which is perhaps the
           | biggest value.
        
             | corty wrote:
             | Also, in almost all languages debuggers are an
             | afterthought. Take e.g. the situation with Golang, Haskell
             | or Python. Either there is no useful debugger or there is
             | one, but it came late and still cannot debug everything the
             | language does.
        
               | hawkice wrote:
               | Print debugging not (really) working is haskell is...
               | Non-idea, and a bad pairing for bad real debugging. But
               | test cases are usually easier to figure out. Presumably
               | there's a balance discovered by people in big projects
               | but it never seemed as good as normal approaches to me.
        
               | corty wrote:
               | Haskell debugging by testing is great for small functions
               | where you can use quickcheck. But larger tests for the
               | more complicated stuff don't work in quickcheck and there
               | isn't much else that one can easily do.
        
               | slaymaker1907 wrote:
               | I haven't actually used quickcheck in Haskell, but I've
               | used it for very complicated tests in other languages
               | including Racket, TypeScript, Rust, and Java. The nicest
               | thing about quickcheck is that it lets you easily create
               | test data without imposing too many constraints on it.
               | Regular fuzzing or randomized testing is almost as good,
               | but the narrowing done by quickcheck is sometimes nice
               | for understanding test failures.
        
               | Quekid5 wrote:
               | Not sure what you mean, there's e.g. Tasty for non-QC
               | testing. It can do all sorts of variations of test, e.g.
               | traditional unit tests, "golden" tests, etc.
        
               | kaba0 wrote:
               | On the other hand, it is reall great in case of the JVM
        
           | klyrs wrote:
           | In a world with perfect optimizing compilers that never
           | introduce bugs, we should never "need" print debugging. But
           | that's not where I live, so I'll keep using print debugging.
           | 
           | On the other hand... adding print statements can also
           | invalidate certain optimizations (an excellent source of
           | heisenbugs), so I'll never stop using debuggers either
        
             | toast0 wrote:
             | Print debugging is essential in distributed systems.
             | Sitting in the debugger waiting for human input often leads
             | to timeouts and not covering the case you want. Of course,
             | sometimes adding the prints, or even just collecting values
             | to be printed later also changes execution flow, but like
             | do the best you can.
        
               | [deleted]
        
         | rufus_foreman wrote:
         | >> If I have a Java Gradle project I have no idea how to get it
         | into a debugger
         | 
         | You download Intellij IDEA, run it, choose File->Open and
         | select the build.gradle file, right click the main class and
         | there's a Debug option.
        
           | [deleted]
        
       | timzaman wrote:
       | This is pretty much the only way I debug;
       | 
       | - cross language/platform
       | 
       | - forces you to come up with hypothesis up front, then test these
       | very systematically
       | 
       | - you know what you are doing
       | 
       | - debugger doesnt interfere
       | 
       | - works across threads and processes
        
       | lisper wrote:
       | Print debugging is useful for the same reason backtraces are
       | useful: both allow you to see what happened in the past, which is
       | usually where the problem you're trying to fix actually happened.
        
       | georgewsinger wrote:
       | I recently discovered a Linux debugger & tool which allowed me to
       | solve problems 10x faster than print statements: pernos.co (which
       | is layered over Mozilla's rr time-tracking debugger).
       | 
       | Pernosco's tool is described pretty well on their website, but
       | basically it allows you to view a program inside and out,
       | forwards /and/ backwards, with zero replay lag. Everything from
       | stack traces to variable displays (at any point in time in your
       | code execution) is extremely easy to view and understand. The
       | best part is the lightning fast search functionality (again: zero
       | lag).
       | 
       | On top of this: extraordinary customer service if anything breaks
       | (in my experience, they fix bugs within 24 hours and are highly
       | communicative).
       | 
       | If you value your time I _highly_ recommend you check out this
       | tool.
        
       | NoZZz wrote:
       | If you've ever used visual studio to debug c/c++ code you just
       | know why the linux crowd mentally works around it.
        
       | breck wrote:
       | I hate coding in an environment that does not easily support
       | step-wise debugging. And yet, I use printf 10x-100x more
       | frequently. Printf is actually causing you to do some thinking,
       | and writing a little bit of code to conduct an experiment that
       | hopefully will tell you in one shot what the problem is on a
       | simple run. Step-wise debugging instead forces you to think about
       | the problem, but then go through carefully and run a lot of
       | mental load at each "next step" push to figure it out.
       | 
       | That being said, there's almost no good reason for a platform to
       | not support step-wise debugging, so it's a big code smell that
       | you're going to have a bad time in general there (even if in
       | practice you'd largely use printf anyway).
        
         | varispeed wrote:
         | There are environments where printf is not possible - e.g. MCU
         | development. For instance, if the code breaks before the serial
         | port is setup for printf to work.
        
           | mark-r wrote:
           | You can always just send the output to a block of memory that
           | is reserved for debugging, and dump out that block when
           | necessary.
        
       | marco_craveiro wrote:
       | I disagree slightly with the emphasis on "print debugging". I
       | think what is missing is a body of theory around logging as a
       | methodology. When I write code, I like to be able to look at the
       | log file and "see" what the code is doing, when on DEBUG or
       | higher. I think logging is a difficult but very important skill,
       | and one which we are losing over time. If anyone is aware of any
       | good books on logging (even if very old), do let me know. Seems
       | like "logging theory" is a missing subject in Software
       | Engineering.
       | 
       | I also don't see any contradiction between liking good logs and
       | using the debugger when needed.
        
         | strikhedonia_ wrote:
         | Absolutely.
         | 
         | When people say they use 'print statements,' are they talking
         | about log points (a debugger construct), logging or something
         | else?
         | 
         | I should hope that, in most cases, they're not literally
         | modifying their source code to achieve this. While there are a
         | handful of scenarios in which this is necessary, on the whole
         | it strikes me as inefficient, time-consuming and error-prone.
         | In most environments, there are better ways to make this data
         | observable.
        
       | diegocg wrote:
       | I have never spent much time learning debuggers honestly. I'm not
       | sure if what I want exists:
       | 
       | I would love to have a debugger that offers a partial text editor
       | experience, eg. it shows my code, I move the cursor to some
       | statement, then I press some key binding and the debugger starts
       | printing (in another window) all the state changes in that
       | statement. Another key binding prints all the state changes in
       | the entire function, etc. All of this while the program is
       | running.
       | 
       | Are there debuggers that can do this? I have used gdb in the
       | past, but having to set up breakpoints by hand and remembering
       | names makes it too tedious.
        
         | Agingcoder wrote:
         | Yes, it's called pernosco, and it's quite remarkable. However,
         | it works from a recording of your program.
         | 
         | https://www.pernos.co
        
       | chromanoid wrote:
       | I usually only do print debugging when I encounter a Heisenbug. I
       | mainly develop in Java, maybe my choice is related to its really
       | really great debugging tooling.
        
         | ben509 wrote:
         | The worst is when you put print statements in and a bug goes
         | away, and you realize there's some kind of instruction
         | reordering bullshit at work.
        
           | chromanoid wrote:
           | A simple toString() with side effects can be insidious when
           | mixed with other bugs...
        
       | dmitryminkovsky wrote:
       | Whenever this comes up, I think of this quote from _The Practice
       | of Programming_ by Brian W. Kernighan and Rob Pike [0]:
       | 
       | > As personal choice, we tend not to use debuggers beyond getting
       | a stack trace or the value of a variable or two. One reason is
       | that it is easy to get lost in details of complicated data
       | structures and control flow; we find stepping through a program
       | less productive than thinking harder and adding output statements
       | and self-checking code at critical places. Clicking over
       | statements takes longer than scanning the output of judiciously-
       | placed displays. It takes less time to decide where to put print
       | statements than to single-step to the critical section of code,
       | even assuming we know where that is. More important, debugging
       | statements stay with the program; debugging sessions are
       | transient.
       | 
       | I found this lines up with my personal experience. I used to lean
       | on interactive debuggers a lot, and still enjoy using them.
       | They're fun and make for good exploring. But the act of figuring
       | out where you want to print really makes you think in ways that
       | interactive debugging cannot. I find the two forms really
       | complement each other.
       | 
       | [0] https://logging.apache.org/log4j/2.x/manual/index.html
        
       | varispeed wrote:
       | The best way of finding faults for me is writing a test that
       | fails the problematic condition and then use prints in all parts
       | that I think are being executed and may have key information to
       | help solving the mystery.
       | 
       | I tried using debuggers, but it was always too much hassle.
        
       | adam_arthur wrote:
       | I've never understood print debugging, at least in a web
       | dev/nodejs context.
       | 
       | I don't begrudge people having their own approach to things, but
       | almost universally when I see people use print debugging they
       | seem to take quite a bit longer than just break pointing at the
       | problem area.
       | 
       | If your code is in an unexpected state, it's much easier to hit a
       | breakpoint, examine local values, and then backstep through the
       | call stack to see what went wrong. I dare to say that in a single
       | threaded context, it's almost objectively more effective.
       | 
       | Versus the alternative of using printlines, you basically need to
       | map/model the state flow out in your head which is prone to error
       | (limited capacity of human working memory).
       | 
       | Is it not easier to directly see the problem rather than doing
       | mental math to make assumptions about the problem? I can't see a
       | case for that being more effective.
       | 
       | Most of the time I see people print debugging it seems to be
       | because they haven't used the debugger much... either they aren't
       | comfortable with it, or didn't bother to set it up, or see the
       | mental mapping approach as more "mathematical/logical"... or
       | something. Takes you back to the school days of solving
       | algorithms on paper :)
       | 
       | That being said for simple problems, I've used print debugging
       | myself (again, usually because I'm too lazy to setup the full
       | debugger). Or for multithreaded contexts etc, where thinking it
       | through can actually be more effective than looking directly at
       | the problem (multiple contexts)
        
       | Jeff_Brown wrote:
       | For print debugging in Python I recently discovered a nice little
       | time-saver: the icecream package. Rather than having to type
       | "print( "x: ", x )", you can instead type type "ic(x)".
       | 
       | [1] https://github.com/gruns/icecream
        
         | [deleted]
        
         | kstrauser wrote:
         | Also, "print(f'{x=}')" without an external dependency.
        
           | Jeff_Brown wrote:
           | Cool! Where can I read about what's going on in that?
        
             | kstrauser wrote:
             | Go to https://docs.python.org/3/reference/lexical_analysis.
             | html#f-... and search for " New in version 3.8: The equal
             | sign '='."
        
       | pbiggar wrote:
       | Both suck. With a debugger, you need to set up a debugger and
       | step through (and often, they don't work quite as well as you
       | hope). With print debugging, you need to add the print
       | statements.
       | 
       | In both, you can't retroactively debug already executed code.
       | 
       | This is one of the areas where I'm really proud of what we did in
       | Dark. In Dark (https://darklang.com), all execution is traced and
       | you can see the value of any expression on any trace by putting
       | your cursor in the expression. Advantages:
       | 
       | - no struggle to reproduce the error
       | 
       | - no need to set up a debugger
       | 
       | - no need to add print statements
       | 
       | When I write Dark, I can debug in seconds. When I work on the
       | Dark implementation (F# or ReScript), I spend at least minutes on
       | each bug because I need to do a bunch of setup to find enough
       | information to diagnose the error.
        
       | zmmmmm wrote:
       | Most under appreciated aspect of proper debuggers is not about
       | the code line of interest but the context they give you about the
       | whole application, ie: the stack frames and their state. When
       | handed a new codebase I often fire up the debugger and attach and
       | set various breakpoints in interesting places and then execute
       | the application to see where / when they get hit. It's a great
       | way to learn a codebase - things that are hard to discover ("when
       | is the database driver created and how does it know its
       | password") just pop out where you might have to spend ages
       | working it out if you were just examining the source tree.
        
         | amelius wrote:
         | The problem with async programming nowadays is that stack
         | traces become meaningless.
        
           | saagarjha wrote:
           | That depends on your tooling! Lots of async programming has
           | debuggers that tracks what you might consider to be synthetic
           | but more useful backtrace.
        
       | ArtWomb wrote:
       | Have never found writing to logs to be "effective". More a
       | necessary evil ;)
       | 
       | What is really effective is "visual debugging". Say for example
       | you are testing for bias in an RNG. Rendering a large format
       | image of random rgb values will immediately show any cycles, even
       | to the untrained eye.
       | 
       | Consider GPGPU workloads, for ML or ray tracing for example.
       | There are myriad levels of variables to track: resources,
       | allocations, command buffer state, synchronization, compute
       | kernel per vector, and so on. All primitives that very much lend
       | themselves to graphical representations!
       | 
       | Right now editing live code in a profiler usually involves
       | textual editing of the graphical shaders. But it's easy to see
       | how this evolves to a purely visual shader editor, not unlike
       | those found in Unreal or Godot.
        
       | sagichmal wrote:
       | I've not figured out a way to effectively debug a distributed
       | system except via printf. Debuggers are basically a nonstarter,
       | because stopping one component to inspect it almost always
       | triggers knock-on effects in other components that change the
       | overall state of the system.
        
       | misiti3780 wrote:
       | I have been developing large-scale django apps on ec2 for a while
       | and the solution that has been working best for me is a lot of
       | logger.** statements sent to papertrail.
        
       | mikeech wrote:
       | Don't let debugger heavy users tell you off
        
       | billytetrud wrote:
       | I definitely think we should create debuggers that can step
       | backwards. Would be incredibly helpful
        
       | sudoit wrote:
       | I'm working on Swift interpreter and the codebase is fairly
       | difficult to debug. There's a lot of reused bits. So if you put a
       | debug point somewhere trying to capture one behavior, odds are
       | that that line will run 10 times for other work before the
       | relevant part uses it.
       | 
       | So I tend to write a LOT of print statements that flush of debug
       | variables right before I where I want to debug. Then I set a
       | conditional breakpoint so that I can have the logs "stop" right
       | where I want the program to.
       | 
       | Example:
       | 
       | // debug print
       | 
       | let someValueICareAbout = variable...
       | 
       | print(someValueICareAbout)
       | 
       | print("") <- conditional debug point here "if someValueICareAbout
       | == 3"
       | 
       | I think it's technically still "print debugging", because I'm
       | only using the debugger to stop the program so I get a chance to
       | read my output.
        
         | saagarjha wrote:
         | Why not just add an action to the conditional breakpoint that
         | prints the value?
        
       | tester756 wrote:
       | I'd say that except some heavily multithreaded cases, then print
       | approach may be due to lack of mature tooling
       | 
       | I can't understand why would anyone prefer to write some print,
       | when you can have Visual Studio's
       | 
       | * break point
       | 
       | * conditional break point
       | 
       | * ability to place another break points when you're already on
       | the other
       | 
       | * expression evaluation at fly!!
       | 
       | * decent possibility to modify code at fly
       | 
       | I still remember case where I modified function with line with
       | bad SQL (breakpoint after executing this SQL), added call to the
       | same function with the same parameters after this breakpoint, let
       | it execute again, caught the breakpoint once again and removed
       | that call to itself
       | 
       | and all of that without recompiling program! it felt like magic
        
         | username90 wrote:
         | Print statements lets you see many things at once. Breakpoint
         | only breaks at one thing. They are good for different things.
        
           | tester756 wrote:
           | > Breakpoint only breaks at one thing.
           | 
           | One breakpoint breaks at one thing, that's why you can have
           | many of them
        
             | username90 wrote:
             | But it only stops at one thing at once. With print
             | debugging I can print 100 things in different places and
             | look at all of them at once giving me a temporal overview,
             | I can't do that in a debugger.
        
       | arendtio wrote:
       | Another aspect, where printf debugging can be better than
       | debuggers are use-cases where timing is relevant. Some bugs don't
       | occur when break points stop the program at certain points in
       | time. For completeness is should be added, that there are also
       | cases where the printf can change the performance and make it
       | impossible to find a bug.
       | 
       | I think the two methods are complementary and should be use in
       | combination.
       | 
       | However, the big issue is that basic printf debugging is very
       | simple to use and debuggers have a steeper learning curve in the
       | beginning. Therefore, people start using printf debugging and
       | don't invest into learning how to use debuggers. And when
       | developers don't invest into learning how to use debuggers
       | properly, they are missing the skills to utilize them and still
       | use printf debugging in cases when debuggers are clearly
       | superior.
        
         | maccard wrote:
         | If you have a timing related issue fixed by a debugger it's
         | probably going to be fixed by printing/logging too.
        
           | majewsky wrote:
           | Not at all. Stepping through a function with a debugger
           | usually takes on the order of seconds and minutes. Printing
           | some stuff in the function usually takes on the order of
           | microseconds or milliseconds. That's a difference of at least
           | three, possibly eight or nine orders of magnitude. It's very
           | easy to imagine a timing-related issue that's affected by a
           | delay of X seconds, but not a delay of X microseconds (RPC
           | calls are typically on the order of milliseconds, for
           | instance).
        
         | SAI_Peregrinus wrote:
         | Debuggers don't _have_ to halt execution on hitting a
         | breakpoint. They can do other things, like print the contents
         | of memory, letting the host system handle the formatting. They
         | 're actually usually _better_ for timing-sensitive prints than
         | printf debugging.
         | 
         | That said, most people don't know this is possible (the
         | learning curve issue you mentioned), even though it's an
         | important part of how to use debuggers!
        
           | ShroudedNight wrote:
           | In my experience, GDB running commands on a breakpoint is
           | generally much, much slower and more prone to materially
           | changing the timing of things than printf.
        
         | spaetzleesser wrote:
         | " I think the two methods are complementary and should be use
         | in combination"
         | 
         | This should be repeated many times. I am getting very tired of
         | the constant need of people who want to have a strict ideology
         | and find the one true way of doing things.
        
       | Someone1234 wrote:
       | This is why products like OzCode for Visual Studio[0] are
       | interesting. With their ability to put in a breakpoint and see
       | multiple variable's values instantly and "time travel" (i.e.
       | limit step back through logic), it kind of gives you the print
       | debugging benefits in regular debugging.
       | 
       | I've not seen anyone else try anything like this. There's a
       | YouTube demo here:
       | 
       | https://youtu.be/82jq5cvl67E?t=1561
       | 
       | [0] https://oz-code.com/ozcode-production-debugger
        
       | enriquto wrote:
       | Why "unreasonable"? There's nothing unreasonable nor wrong about
       | print debugging. Moreover, it's a great first step towards
       | logging and testing.
        
         | xnx wrote:
         | "Unreasonable" here means that it works way better than it
         | should for something so simple. It's a somewhat common
         | phrasing. Example: "The Unreasonable Effectiveness of Data"
         | https://static.googleusercontent.com/media/research.google.c...
        
         | falcolas wrote:
         | It's "unreasonably effective", meaning that a cost/benefit
         | analysis is very clearly tilted towards benefit.
        
         | elseweather wrote:
         | It's a meme, like "_____ Considered Harmful". That one started
         | with "GOTO Considered Harmful". This one started with:
         | https://en.wikipedia.org/wiki/The_Unreasonable_Effectiveness...
        
       | roenxi wrote:
       | Probably the most interesting thing about development as a
       | discipline is the near radio silence on how to debug.
       | 
       | There is a decided lack of academic success in engaging with
       | debugging as an object that can be studied. There are channels to
       | learn about debugging as a stand-alone topic. Programmers don't
       | often talk about debugging techniques in my experience.
       | 
       | For something that takes up the overwhelming bulk of a
       | developer's time the silence is in many ways deafening. It may be
       | that nobody has a method superior to print debugging.
        
         | imagica wrote:
         | It's one of those things that is acquired with experience and
         | from more and more peers one has had. I think I've learned a
         | bit from all my peers, almost everyone had something
         | interesting or an interesting way to tackle a problem. Once a
         | lot of time is spent in the industry one starts seeing patterns
         | as a new cycle starts.
         | 
         | As far as teaching debugging, it is one thing to show some
         | examples and another one is to run into a bug yourself and get
         | from having no idea how to debug to actually fixing it. That
         | whole experience is hard to replicate in unnatural ways.. When
         | I was in school they told me not to worry too much about
         | debugging and that I'd run into issues in the real world and
         | figure out ways to debug depending on the system and that
         | turned out to be quite correct.
        
         | geocar wrote:
         | > For something that takes up the overwhelming bulk of a
         | developer's time...
         | 
         | It isn't the bulk of my time.
         | 
         | Most of my time is spent figuring out what to do.
         | 
         | Once I have decided that, telling the computer is usually
         | straightforward.
         | 
         | > Programmers don't often talk about debugging techniques in my
         | experience.
         | 
         | No they don't, but look at it this way: Bugs are mistakes, and
         | nobody wants to be told they're making too many mistakes.
         | Anyone who discovers some amazing debugging technique will
         | struggle to share it with anyone else for a lot of reasons, and
         | this is one.
         | 
         | > It may be that nobody has a method superior to print
         | debugging.
         | 
         | Print debugging always works. Getting "a debugger" to work
         | isn't always easy, and if you aren't already comfortable using
         | the debugger to track down the kind of bug you're facing, you
         | will find it very difficult to find the bug and cure it faster
         | than with print debugging. And since people _don 't_ tend to
         | make the same mistakes over and over again, debuggers tend to
         | have a _very_ limited utility in those few mistakes made
         | frequently.
         | 
         | My experience is that mistakes like that are the fault of some
         | kind of fundamental misunderstanding, and rather than spend
         | time to learn all of the different fundamental
         | misunderstandings that the debugger was designed to work
         | around, time is better spent simply correcting your
         | misunderstandings.
        
         | thenoblesunfish wrote:
         | It's a very interesting point. I suspect it's hard to study
         | because it's a very high level capability of our brains. If you
         | understand how we debug, you understand a lot about how
         | reasoning itself works. I did read a book on debugging as a
         | general practice once, but it wasn't helpful, as it was mostly
         | anecdotes and generalities.
        
         | damagednoob wrote:
         | I mean there are other types of debuggers (step-through, time
         | travel[1]) but I agree with you that I have never seen any
         | research on which is better/faster. It seems an obvious topic
         | so it makes me suspect that it comes down to individual style.
         | 
         | [1] https://docs.microsoft.com/en-us/windows-
         | hardware/drivers/de...
        
           | spaetzleesser wrote:
           | " which is better/faster"
           | 
           | Because the answer is "it depends". As you mentioned it's a
           | lot about individual style and preference. I have seen a lot
           | of good coders that got things done but worked in totally
           | different ways.
        
         | Swizec wrote:
         | Debugging is impossibly difficult to teach. It's much closer to
         | "how to solve an escape room" than it is to "how to build X".
         | 
         | Debugging requires deep understanding what _you_ are doing and
         | _your_ system. It 's different every time. And while there's a
         | general algorithm you can follow:
         | 
         | 1. Guess what's wrong
         | 
         | 2. Ask "How would I prove that's wrong?"
         | 
         | 3. Try it
         | 
         | 4. If bug found, fix, if not go back to 1
         | 
         | How would you teach that other than asking people to go solve a
         | bunch of real world problems in real world systems for a few
         | years?
        
           | anaerobicover wrote:
           | This doesn't seem to be a different problem in kind than
           | teaching people to _write_ programs. How do we do that other
           | than teaching them some mechanics (syntax, how to run the
           | compiler) and then setting them a lot of exercises to gain
           | experience?
           | 
           | The same seems to apply to debugging. A student needs to be
           | introduced to the basic concepts and commands, and then
           | practice. Just same as with a writing exercise, the
           | instructor can have specific problems to practice specific
           | techniques.
        
           | slibhb wrote:
           | > 1. Guess what's wrong 2. Ask "How would I prove that's
           | wrong?" 3. Try it 4. If bug found, fix, if not go back to 1
           | 
           | I think this is exactly right. Teaching 1 is impossible I
           | guess but the general method (it's basically the scientific
           | method in an ideal environment) seems teachable.
           | 
           | Come up with a hypothesis of what's wrong, try to prove or
           | disprove the hypothesis.
        
           | travisjungroth wrote:
           | I think this is the standard algorithm and it's absolutely
           | terrible. People poke at things, which ends up giving a
           | linear search across a possibly huge system. Even if the
           | "guess" is intelligent, it's not like you can trust it. If
           | you actually fully understood the system, you would know
           | what's wrong and you wouldn't be debugging.
           | 
           | Do a bisect instead. The complexity is O(log n). It's
           | probably slower than if you guess right on the very first
           | time, but that's less important. Debugging time is dominated
           | by the _worst_ cases.
           | 
           | 1. Do something you're 90% sure will work that's on the path
           | towards your actual goal.
           | 
           | 2. If it works, move forward in complexity towards your
           | actual goal. Else, move halfway back to the last working
           | thing.
           | 
           | 3. When you've trapped the bug between working and non-
           | working to the point that you understand it, stop.
           | 
           | "The weather data isn't getting logged to the text files. Can
           | I ping the weather servers? Yes. Can I do a get on the report
           | endpoint? Yes. Can I append to a text file? Yes. Can I append
           | a line to the weather log file? No. Ok, that narrows it a
           | lot."
           | 
           | The real point of this is that you should spend most of your
           | time with _working_ code, not non-working code. You
           | methodically increment the difficulty of tasks. This is a
           | much more pleasant experience than fucking around with code
           | that just won 't work and you don't know why. Most
           | importantly, it completely avoids all those times you wasted
           | hours chasing a bug because of a tiny assumption. It's sorta
           | like TDD but without the massive test writing overhead.
           | 
           | A modification for the disciplined: give yourself one (1)
           | free pass at just taking a stab at the answer. This saves
           | time on easy fixes. "Oh, it must have been that the country
           | setting in the config file is off." Give it a single check.
           | And if it's not that, go back to the slow and steady mode.
           | Cause you don't understand the system as well as you thought.
        
             | majewsky wrote:
             | You're basically describing the scientific method.
             | Particularly the practical application of Occam's Razor:
             | Starting from simple theories, and working your way up
             | towards more complex ones until the theory is just complex
             | enough to describe the system behavior you're trying to
             | understand.
        
             | Swizec wrote:
             | Your algorithm is for creating programs or adding new
             | features. Not reslly for debugging already broken stuff.
             | 
             | I would agree that hoing from less to more complexity is a
             | great heuristic for making those guesses on what to check.
        
           | Fronzie wrote:
           | The one beginners often miss:
           | 
           | What output do you expect?
           | 
           | Ask this yourself before starting the debugger. Without this,
           | it is very easy to glance over the point where things go
           | funny.
        
           | 8note wrote:
           | There's also:
           | 
           | 1. Pick a spot in the code
           | 
           | 2. Figure out what you expect the state to be there
           | 
           | 3. Check and see that the actual state matches
           | 
           | You can kinda binary search your way to the location of a bug
           | by looking in different places
        
           | lainga wrote:
           | I might suggest a few of the adventures of Sherlock Holmes.
        
           | colonwqbang wrote:
           | For a system of moderate complexity, there are myriad answers
           | to question (1). A skilled programmer has the intuition to
           | guess the most likely causes. This ranges from the mundane
           | (e.g. recompile everything from scratch) to the occasional
           | almost magical lucky guess which immediately leads to a
           | solution.
        
           | ianmcgowan wrote:
           | It feels like there are basic heuristics that too often
           | people either don't know or forget to apply.
           | 
           | I recommend http://debuggingrules.com/ - it's a good book
           | that lays out some rules that have always helped me. When
           | people come to me for help debugging something, invariably
           | they've skipped some of these concepts, and applying them
           | usually gets to the bottom of things faster than randomly
           | changing things (which seems to be a common, but ineffective,
           | way to debug a problem).                   UNDERSTAND THE
           | SYSTEM         MAKE IT FAIL         QUIT THINKING AND LOOK
           | DIVIDE AND CONQUER         CHANGE ONE THING AT A TIME
           | KEEP AN AUDIT TRAIL         CHECK THE PLUG         GET A
           | FRESH VIEW         IF YOU DIDN'T FIX IT, IT AIN'T FIXED
        
       | jauco wrote:
       | set -o xtrace ftw!
       | 
       | More languages should have that.
        
       | Agingcoder wrote:
       | (I have already replied to another comment with the same
       | suggestion).
       | 
       | Pernosco offers the best of both worlds ( debugger, print), along
       | with a few magical features.
       | 
       | https://www.pernos.co
       | 
       | With it you can print anything present in your recording and
       | step, and do anything you'd do in a regular debugging.
        
         | mjw1007 wrote:
         | It's good to see that they hope to provide << the best printf
         | debugging experience you've ever had >>, but I'm disappointed
         | at the UI they show on the "Condition and print expressions"
         | page.
         | 
         | The video shows the user using their mouse and typing the
         | expression to be printed into a tiny text input.
         | 
         | Part of the attraction of print-style debugging is the
         | convenience of being able to use your main editor UI, along
         | with all the conveniences that provides, to write that
         | expression.
         | 
         | (That might be fancy completion or vi-style editing commands or
         | keyboard macros; it will be different for different
         | programmers.)
        
           | Agingcoder wrote:
           | I suggest you tell them! They'll probably be happy to get
           | some feedback.
           | 
           | If I'm honest, in spite of it not being perfect, it's much
           | better than regular printf. The other very nice feature is
           | dataflow (click on a variable value, and it tells you where
           | it comes from, and it handles copies seamlessly), which makes
           | a large number of debugging tasks trivial.
        
       | yetihehe wrote:
       | Besides "behaviour in time", print debugging is effective because
       | it's typically an extract of the most interesting for programmer
       | things. I have a debugger window open this very moment and I can
       | see about a hundred lines with various information about one
       | structure, but I'm interested only in two (and I have to rerun
       | this several times, because state got corrupted somewhere
       | earlier).
        
       | Dzugaru wrote:
       | I stopped doing step debugging at all many years ago. For me it
       | looks the same as visual vs. text programming. Text and text
       | search tools are just miles ahead of clicking buttons.
        
         | lights0123 wrote:
         | There's always gdb/lldb from the command line.
        
         | hobs wrote:
         | So (for instance) in PowerShell my code breaks right as it is
         | about to fail, with the state intact (ErrorActionPreference
         | Break) which allows me to effectively fix whatever problem is
         | about to occur and immediately have the state at the time of
         | failure.
         | 
         | I dont understand how printing text could EVER approach this
         | given I can test my assumptions right away and generally only
         | need 1 error to happen to understand the totality of the
         | circumstances.
        
       | danbmil99 wrote:
       | Debuggers are next to useless when dealing with today's
       | distributed systems, all operating asynchronously in parallel.
       | For the kind of bugs (race conditions, corner cases) that aren't
       | easily caught by compilers, linters, unit tests or code review
       | (in other words, the "Heisenbugs" that can stop a release in its
       | tracks), aggressive logging is the only tool I've ever seen that
       | is useful in-the-wild.
       | 
       | I would put forward that proficiency with this style of debugging
       | (closely related to useful performance profiling) is a major
       | factor separating mediocre programmers from the quasi-mythical
       | 10X rockstars.
        
       | zestyping wrote:
       | In one word, search. You can search the output over time.
        
       | SPBS wrote:
       | I feel like the author gets close to the point but fails to drive
       | it home: step-through debugging is _unbelievably_ cumbersome.
       | During a typical step-through debugging session, 90% of the time
       | is spent on lines you are completely not interested in. Oh, did
       | you accidentally skip the important point because of how tedious
       | it was to keep spamming step-over /step-in? Better start over
       | again. With print debugging, you set up your print statements
       | strategically and -zing-, you get your results back. Feedback
       | loop shorter. 100% of the lines are the ones you are interested
       | in, because you put the print statements there.
       | 
       | I'm still waiting for the feature where you can conditionally
       | stop at some breakpoint -only- if some other
       | breakpoint/watchpoint was crossed over. It's not a conditional
       | breakpoint, because conditional breakpoints can only watch
       | variables, not other breakpoints. You could of course set some
       | variable depending on whether some section was entered and then
       | conditionally break based on that variable. But then you're back
       | to print debugging land, having to manually insert code in order
       | debug the program.
       | 
       | Debuggers are superior when it comes to interrogating the exact
       | state of some variables, as well as the decision paths the
       | program takes. For anything simpler, print debugging simply
       | offers the better developer experience.
        
         | Stratoscope wrote:
         | > _I 'm still waiting for the feature where you can
         | conditionally stop at some breakpoint -only- if some other
         | breakpoint/watchpoint was crossed over._
         | 
         | PyCharm 2021.1 has this, so I would guess that other members of
         | the IntelliJ family probably have it too.
         | 
         | Set a breakpoint and then right-click the red dot, and click
         | More to open the full Breakpoints dialog. Open the drop-down
         | under "Disable until hitting the following breakpoint:" and
         | select the other breakpoint that should enable this one.
         | 
         | And thank you for mentioning this! I didn't know PyCharm had
         | this feature until I took a look after seeing your comment.
         | This will be super useful.
        
         | kmfpl wrote:
         | With lldb you can do that, basically you have the option of
         | running commands when a given breakpoint is hit, so you can
         | just make it place another breakpoint, and it will be placed
         | only if the first breakpoint is hit. I assume you can do
         | something like this on gdb as well.
        
       | hnnameblah365 wrote:
       | I think there's a conflation of processes and tools which leads
       | to the false comparison. Print debugging is a process, which uses
       | a tool called print statements. Stepping through code is a
       | process, which uses a tool called the debugger.
       | 
       | Print debugging excels at triaging the problem. And every
       | language has print statements. Ubiquitous first tier support.
       | They help you narrow down where your assumptions about the
       | program behavior may be wrong.
       | 
       | Once you know what area to focus on, you pull out the debugger
       | and step thru the code.
        
       | GuB-42 wrote:
       | printf debugging always have a place, but for some reason, I
       | found the debugging experience to be worse than 20 years ago.
       | Tools like Visual Studio still have great debuggers, but I didn't
       | notice significant improvement since the early days, and newer
       | toolchains are worse.
       | 
       | A couple of years ago, I had to maintain a bit of Java code using
       | Eclipse. That is, the old IDE everyone loves to hate. And while
       | some of that hate is well deserved, for debugging, it was the
       | most pleasant experience I had in a long time. Nice object
       | inspector, edit-and-continue, conditional breakpoints, and step-
       | by-step that works. Much better than fumbling around with GDB or
       | one of its less-than-perfect UIs.
       | 
       | Also note that printf debugging and the step-by-step and
       | breakpoint kind are not mutually exclusive. With an edit-and-
       | continue feature, you can get the best of both worlds, but that's
       | not something common these days, unfortunately.
        
         | vvanders wrote:
         | Maybe it was because I was exposed to it early in my career but
         | I have yet to find anything that rivals Visual Studio
         | debugging, either from a "just works" perspective or ability to
         | deep-dive into gnarly memory corruption(memory windows, robust
         | watch windows and data breakpoints).
        
       | da39a3ee wrote:
       | This should be a non-debate.
       | 
       | A debugger is for when you want to inspect local state in detail.
       | That can indeed often be very useful, and they are sophisticated
       | technology.
       | 
       | However, the people who think that a debugger is the only way to
       | debug just aren't good programmers: often you want a picture of
       | the overall behavior of your program. As has been said by someone
       | other than me, a debugger allows you to fix a bug; print
       | statements allow you to think about the right fix for a bug.
        
         | saagarjha wrote:
         | Perhaps the people using a debugger have it set so it can give
         | them a picture of the overall behavior of your program.
        
       | asimjalis wrote:
       | The reason I like print debugging is that it is repeatable. The
       | debugger requires too much interaction for it to be automatable.
        
       | midjji wrote:
       | it works, its convenient, its easier to learn, easier to setup,
       | it has less side effects in multithreaded programs meaning you
       | can debug those too. You can even log to a file and then get
       | these logs from your end users... The article does make a good
       | point, errors that only cause failure a few hundred calls after
       | the originating problem are easier to find this way too. Every
       | few years I make an effort to learn to use whatever the current
       | most popular debuggers are, but at the end of the day, its really
       | just very specific kinds of errors that the debugging tools are
       | better for finding and I generally go back to debug outputs soon
       | enough.
        
       | Rapzid wrote:
       | A lot of debuggers will also print/log and can even inject those
       | statements into a running app where hot reloading manual print
       | statements would otherwise not work.
       | 
       | From there there are situations where a debugger will save a LOT
       | of time. I'm thinking of trying to figure out what's causing a
       | behavior in a large dependency injected application with plugins
       | when you have little to no familiarity with all the code
       | involved. And then of course all the other things a debugger can
       | do for you.
       | 
       | > Clearly Real Debuggers offer a superior experience to print
       | debugging in so many ways. But print debugging is just easier to
       | get started with, and it reliably works anywhere, so that's why
       | we use print debugging so much.
       | 
       | I think the tone of the first sentence and the word "superior"
       | unnecessarily creates a strawman.
        
       | angst_ridden wrote:
       | The beauty of printf debugging for a novice C programmer is that
       | the recompiling with printfs changes the memory layout so your
       | buffer overflow no longer segfaults you.
       | 
       | ALternatively, your printf can use the wrong formatter string,
       | and cause unrelated crashes. Such joy!
       | 
       | Makes me nostalgic for the good old days.
        
         | majjgepolja wrote:
         | > ALternatively, your printf can use the wrong formatter
         | string, and cause unrelated crashes. Such joy!
         | 
         | What compiler are you using? Aztec C? Prehistoric C?
        
       | anarazel wrote:
       | For me this isn't an either or.
       | 
       | I constantly use both together. For problems that a quickly and
       | reliably reproducible I'll often just use the debugger (if rr is
       | suitable, even better).
       | 
       | But there's plenty problems that take a while to reproduce,
       | involve many threads / processes, etc. Where the initial set of
       | potential issues is too wide to easily target with a debugger.
       | There sprinkling printfs around can provide data at a lower
       | overhead than doable with a debugger.
       | 
       | Just yesterday I was debugging something where rr didn't finish
       | replaying a workload that originally takes 10s within an hour
       | (loads of io). Switching to print debugging I pinpointed the
       | issue in < 10min.
        
       | oweiler wrote:
       | Modern debuggers allow you to execute log statements on
       | breakpoints. Much better than modifying your program to output
       | something.
        
         | p4l4g4 wrote:
         | I used this a lot! Combined with scripting support, you can
         | make the experience even more interactive.
         | 
         | Used gdb scripts in the past to make debug sessions repeatable.
         | Stuck beyond the point your interested in? No problem, just
         | restart the session with your gdb script and your right back on
         | track! You can also add custom functions to output your state
         | in a more meaningful way or to mock some state. In longer
         | debugging sessions, a good debugger can be a life safer!
         | 
         | Still, for shorter sessions, reading logs and adding occasional
         | prints are hard to beat.
        
       | jollybean wrote:
       | Qt Creator debugger fails on me constantly, it's 2021 and the
       | leading C++ plaf. is completely unreliable in that many more
       | cases.
       | 
       | That's why 'I must' use print debugging, because the 'powers that
       | be' still provide a broken, half-baked solution 30 years in.
       | 
       | Print debugging is however so powerful, I think there almost
       | should be a mechanism built into languages and tooling around it
       | so that it becomes part of the process instead of a 'kind of
       | workaround'. It's something we all do, constantly, and yet you'll
       | never hear about it when people are arguing about Rust or Go.
        
         | ddingus wrote:
         | This kind of thing actually got added to a Microcontroller and
         | its native SPIN language.
         | 
         | There is "SEND" which can be used as an ad hoc comms channel,
         | aimed at a program method.
         | 
         | And a debug system that can both stream data, text and graphics
         | to a client, as well as capture and report on the state of the
         | 8 CPU cores possibly running.
         | 
         | https://www.parallax.com/propeller-2-graphical-debug-tools-i...
         | 
         | The debug output is something like using an xterm with
         | Tektronix emulation turned on, and with all the lower level
         | bits packaged away. The use can do a lot, from a "print" type
         | operation to sophisticated graphics, static or animated.
         | 
         | On the capture side, a sort of supervisor region of RAM is
         | reserved to for an ISR to capture processor state, or anything
         | in memory really. Can be time, or event driven.
        
         | winrid wrote:
         | Have you tried Clion?
        
       | hpoe wrote:
       | So I'd be curious. I usually work in scripted languages Bash,
       | Ruby, JS (bleh) a bit of python.
       | 
       | Sometimes I do some Java work though and I usually end up going
       | to print debugging because trying to figure out all the Java
       | logging framework, or not ending up like 40 layers deep in some
       | magic framework dependency that is interecepting my code which is
       | what always happens when I use a debugger.
       | 
       | That being said do those who work in compiled languages make more
       | heavy use of debuggers?
        
         | seneca wrote:
         | > do those who work in compiled languages make more heavy use
         | of debuggers?
         | 
         | I work in both quite a bit. I actually think I end up using a
         | debugger more in e.g. Python because I'm more often asking
         | questions like "what is the type of the thing being passed
         | here", which is not a thing I need to seek out in something
         | like Go.
         | 
         | That said, I think it's more a style difference than anything.
         | I use debuggers in both compiled and noncompiled languages when
         | I need a deeper look, and I'd guess people who don't use
         | debuggers in scripting languages wouldn't use them in compiled
         | languages. Probably also has to do with the ecosystem and how
         | easy/effective debuggers are.
        
         | UglyToad wrote:
         | I wonder if C# is a bit of an outlier here. I work mainly in C#
         | but also sometimes do Type/JavaScript. While I've got the VS
         | Code debugger running for JavaScript projects I'll rarely use
         | it and generally use print debugging.
         | 
         | In C# I'd almost never use print debugging and the whole thing
         | seems ridiculously antiquated (it's partly why I hate JS work).
         | [Assuming you're working in Visual Studio...] You literally hit
         | 1 key, F5 and then you can step through, time travel, edit and
         | continue. I wonder if people just haven't experienced the ease
         | of debugging in .NET with VS. I'd say I write probably 50% of
         | my code in a debugging session, edit and continue is a game
         | changer.
         | 
         | I did a little Java work in Intellij and it was similar but I
         | think partly due to a lack of familiarity with the UI didn't
         | feel quite as powerful.
        
       | domano wrote:
       | With the Jetbrains products breakpoint debugging is so easy that
       | i use it for development all the time. Evaluating expressions
       | inside a breakpoint while developing provides many answers in a
       | mich tighter feedback loop, even with go or something equally
       | fast. If i don't have the jetbrains tools i default to print
       | debugging because everything else is too much of a hassle.
        
         | nyanpasu64 wrote:
         | I wish that evaluating expressions in a C++ debugger worked
         | more often. It fails half the time (due to "optimized out") in
         | Visual Studio C++, and 80+% of the time (for various reasons)
         | in Qt Creator, even in debug builds.
         | 
         | Maybe it works better in non-C++ languages.
        
       | thenoblesunfish wrote:
       | Good points. Makes me think that if print debugging is primitive,
       | the more sophisticated alternative isn't a step debugger, but a
       | logging system.
        
       | goalieca wrote:
       | Print debugging is the only way in a distributed system the way
       | we are building micro services these days. We just call it
       | logging.
       | 
       | Edit: ..and do it in production
        
         | yaantc wrote:
         | Yes. The same apply to a lot of embedded systems. When you
         | can't stop the system you better learn how to debug from logs.
         | And put the right logging support in place ahead of time: it
         | may be impossible to replace the software in place by a new
         | debug version, and then it's only based on preexisting logs and
         | just adapting the logs configuration.
        
         | marco_craveiro wrote:
         | Completely agree.
        
         | kstrauser wrote:
         | Amen. "What do you use for debugging prod services?"
         | "CloudWatch."
        
       | razorfen wrote:
       | ITT: a non-controversial opinion shared by most programmers.
       | 
       | Print debugging is fast in many cases and requires little mental
       | overhead to get going.
       | 
       | But for some/many systems, there's a huge startup and cooldown
       | time for their applications - and compiling in a print, deploying
       | the service, and then running through the steps necessary to
       | recreate a bug is a non-trivial exercise. Think remote debugging
       | of a deployed system with a bug that requires select network and
       | data states that are hard or impossible to replicate in
       | local/dev.
       | 
       | For things like this, being able to isolate the exact point of
       | breakage by stepping through deployed code, and doing immediate
       | evaluation at various points to interrogate state can't be beat.
       | 
       | This post strikes me as either (a) a younger programmer who still
       | thinks that tool choice is a war rather than different tools for
       | different jobs (b) someone making a limp effort at stoking
       | controversy for attention.
        
         | diminish wrote:
         | In languages where you build a deeply nested call stack,
         | advanced debugging looks more promissing. But in simpler setups
         | like ASP/PHP/JSP etc, simply printing works fine.
        
         | jollybean wrote:
         | Or c) someone just making comments from observed experience,
         | and there's not much about that 'senior developers' have when
         | it comes to 'having had to compile something that takes a
         | while' - that's the purview of everyone, or at least, those who
         | have worked on those larger projects. And though remotely
         | debugging code definitely happens, it's in relative terms, very
         | rare. This is just someone making a comment on their blog,
         | that's it.
        
         | DangitBobby wrote:
         | > I should emphatically mention: I'm not saying that print
         | debugging is the best end state for debugging tools, far from
         | it. I'm just saying that we should reflect deeply on why print
         | debugging is so popular, beyond mere convenience, and
         | incorporate those lessons into new tools.
         | 
         | I'm not sure what about the article makes you think either a or
         | b. They are trying to critically examine why some people reach
         | for print debugging first, and I think it's spot on.
        
         | CJefferson wrote:
         | On the other hand, when you are working in an example like you
         | are discussing (a service, or multiple services, which must all
         | be deployed), it can be hard to figure out how to get the
         | debugger attached.
         | 
         | It possible depends on the kind of programming you do -- I find
         | myself doing little bits of work on projects in many languages,
         | so learning how to get the debugger going often takes longer
         | than finding + fixing the bug.
        
         | tyingq wrote:
         | Probably explains why java has such a rich set of logging and
         | debugging tools. Startup time, plus the idea that printing to
         | stderr/stdout doesn't help you figure out where that goes in
         | many java environments :)
        
       | pmichaud wrote:
       | I think the point about seeing the state over time is a great
       | one.
       | 
       | But also I want to nitpick because the title is one of my
       | "favorite" pet peeves: "The Unreasonable Effectiveness of ..."
       | thing is now used (as in this article) by people who are trying
       | to say that something is remarkably or surprisingly effective,
       | but that's not what the original essay was about at all!
       | 
       | "The unreasonable effectiveness of the mathematics in the natural
       | sciences" was a philosophy of science piece whose thesis was that
       | there is no reasonable (rational, provable) basis for the degree
       | to which our math abstractions and syllogisms happen to
       | correspond to the physical universe.
       | 
       | It is self evident that they do in fact correspond super well,
       | but the original piece was about how weird and spooky that
       | actually is, if you think about it at all. Math is super
       | effective, and there is no reasonable basis that we yet know that
       | it should be so effective. It's unreasonably effective.
       | 
       | It's such a perfect title for that piece, and it feels dirty or
       | diluting when it's just used to mean "remarkably effective."
        
       | tonymet wrote:
       | Print debugging is a tool in the toolkit . It's good enough for
       | many scenarios , and much easier to deploy most of the time . I
       | still recommend setting up and familiarizing yourself with a step
       | through debugger , but use both
        
       | [deleted]
        
       | corysama wrote:
       | In my experience, people who downplay debuggers don't have the
       | option to use effective debuggers. Debugging C++ and especially
       | C# in Visual Studio is wonderful. Debugging Java in Eclipse can
       | be great. Meanwhile GDB and most other language debuggers are
       | painful and every IDE integration I've seen of them has been
       | horribly unreliable.
       | 
       | I've heard there's a culture in parts of Google where kids go
       | through uni using GDB because "Woo Linux!" then go straight into
       | Google where everyone is "Woo Linux!" (I do like Linux, btw) so
       | they are either still using GDB, or more likely have given up on
       | it and reverted to printf. So, everything takes _forever_ to
       | figure out and that's just "normal". This was coming from a
       | console gamedev who was shocked by the transition after moving to
       | Google.
       | 
       | Meanwhile, I've spent a good part of the past couple decades
       | debugging large volumes of code that I will literally only see
       | once ever. With a good debugger, that can be done effectively
       | because watching and even modifying the code's behavior can be
       | done at a glance rather than a re-compile.
       | 
       | I've also worked on a very big project that used extensive
       | logging because they had a very bad debugger setup and
       | productivity was in the toilet compared to every other job I've
       | had. The only way I could keep productive was to take the time to
       | break out systems into small independent programs in my own
       | environment so that I could use a debugger on that rather the run
       | the code where it is.
        
         | damagednoob wrote:
         | I dunno. I was a C# dev for 7 years and exclusively used Visual
         | Studio's debugger. Then went to a JRuby project which had
         | abysmal debugger support at the time. Learned to used printf
         | style and it's now been my goto for the last 8 years. This
         | despite coding in Nodejs for last 4 which has pretty good
         | support. I only reach for the step through debugger when the
         | problem is tricky, mainly because of having to do the setup.
        
         | thrower123 wrote:
         | The Visual Studio debugger is great, but there are some
         | limitations. Anything very serious is going to be
         | multithreaded, and if you block a thread poking in the
         | debugger, other things are going to start timing out and the
         | real flow of the program is interrupted and impossible to
         | reproduce.
         | 
         | Log heavily, and log systematically - imagine you're going to
         | need to grep through days of logfiles to find the needle in the
         | haystack - you will eventually. Build in runtime switches to
         | dial log verbosity up and down. Err on the side of providing
         | more context than less. If something throws exceptions, catch
         | them, log exactly where it was, what it was supposed to be
         | doing, and any relevant parameters or state.
         | 
         | If you can get them, process dump files are unreasonably
         | effective, too.
        
         | saagarjha wrote:
         | I actually find GDB to be a fairly good debugger, but you need
         | a bit of work in how to translate what your IDE is doing into
         | something you can do in GDB.
        
       | majewsky wrote:
       | Interesting hypothesis.
       | 
       | I think a big part of the issue is that printf debugging has
       | always been "good enough" for me. I have used gdb in the past,
       | but I've never felt the incentive to become good at it, so my
       | knowledge of it atrophies and it has become a less interesting
       | option over time. On the other hand, my knowledge of how to
       | printf messages and extract them from the running process never
       | atrophy because I do exactly that every day.
       | 
       | So maybe the situation changes if ever I come across a bug that's
       | so mindbogglingly convoluted that printf debugging is not viable.
       | Then I'll be forced to learn to use a step debugger well, and
       | that could change my choice of tools going forward.
        
       | hprotagonist wrote:
       | For python: i specifically recommend
       | https://github.com/zestyping/q a lot, which is like print
       | debugging on steroids:                 All output goes to /tmp/q
       | (or on Windows, to $HOME/tmp/q). You can watch the output with
       | this shell command while your program is running:            tail
       | -f /tmp/q
        
       | mekoka wrote:
       | IDE vs Text editor. OOP vs Functional. Logger vs debugger. The
       | holy wars that shouldn't be. Why can't we all be friends and
       | accept that Vim is better than emacs.
        
         | lr4444lr wrote:
         | How's file exploring and method/class definition lookup these
         | days in Vim?
        
           | pjio wrote:
           | The quality of the language servers vary, but you could get a
           | decent IDE-like experience.
        
           | AlexCoventry wrote:
           | LSP is a great leveler, for that. From what I hear, vim has
           | great LSP support, these days.
        
         | fao_ wrote:
         | I used to think like you, friend! For over a decade, then I
         | discovered doom emacs :)
        
           | edwinyzh wrote:
           | Wow, by looking at this screenshot
           | (https://raw.githubusercontent.com/hlissner/doom-
           | emacs/screen...), is doom emacs a terminal/console program or
           | a GUI program?!
        
             | fao_ wrote:
             | It's a number of extremely, extremely well crafted layers
             | on top of Emacs.
             | 
             | I switched last July and after 8+ years of using variations
             | of Vim, Vi, Ex-Vi, Ed(1) (yes), NeoVim, et all, it is by
             | _far_ the smoothest experience I 've ever had.
             | 
             | Unlike my experience with Spacemacs, I haven't had _any_
             | problems adapting from Vim -- there are no points where the
             | Vim interaction layer breaks down, and it genuinely feels
             | like an editor that I 'll be using for the next 20+ years.
             | Like something that can grow around me.
        
             | sa1 wrote:
             | It's configuration boilerplate for emacs. Emacs itself can
             | run in both terminal and GUI mode, and doom should broadly
             | look similar in both settings.
        
           | AlexCoventry wrote:
           | Spacemacs is the one true way, heretic scum!
        
           | mcbuilder wrote:
           | For those wondering, Doom Emacs is a better vim (from evil-
           | mode) than vim and so much more (easy out of the box
           | community configs for most languages and tools, and way more
           | cool stuff) inside the Emacs OS.
        
             | j4yav wrote:
             | I tried using it but got stuck on having to learn Lisp to
             | understand my config file.
        
               | revscat wrote:
               | Apparently all the cool kids are using neovim + Lua these
               | days. Lisp turned me off of emacs years ago as well.
               | Recently I started digging into Neovim and have found Lua
               | much easier to parse/internalize than Lisp, and kind of a
               | joy to work with.
        
               | j4yav wrote:
               | Great, I am at least halfway on the right track since I
               | am using neovim. I know Lua a bit, I actually didn't
               | realize it was integrated.
        
             | alpaca128 wrote:
             | What always prevented me to actually switch to Emacs was
             | how it's so huge it seems impossible to get an overview of
             | how to do what. Every programming language-specific mode
             | comes with its own unique features that surprise me when I
             | just want to write code, meanwhile just entering a single
             | tab without it getting deleted again is an odysee of
             | reading documentation. At the same time it's slow and
             | despite it having the best Vim emulation it cannot hide
             | that Emacs just doesn't work like that. As soon as you
             | leave the file's buffer you discover how Evil mode's
             | illusion falls apart on all sides and you always land in
             | situations where you have to use a mix of Vim and Emacs
             | keybindings.
             | 
             | I love the concept behind Emacs, I just think at least 80%
             | of its code should actually be in plugins, and the program
             | itself and a lot of large expansions are really bogged down
             | by the sheer size and lack of simplicity.
             | 
             | Oh, and Emacs-Lisp...it's much better than Vimscript, but
             | it's a disappointment nonetheless. Loops instead of
             | recursion in Lisp, really? And last time I tried it the
             | parser could not handle unmatched brackets in comments.
        
               | ByteJockey wrote:
               | > Loops instead of recursion in Lisp, really?
               | 
               | That's pretty common in common lisp as well. Specifically
               | do loops (and lest we not forget the loop macro).
               | 
               | I think you might be thinking of the scheme branch of
               | lisps, but not all of them work that way.
        
         | Tade0 wrote:
         | Let us not forget the war to end all wars:
         | 
         | Tabs vs spaces
        
         | lamontcg wrote:
         | I've been a vim print debuggerer for like 30 years, and last
         | year picked up writing C# in an IDE (Rider) and its been quite
         | nice really.
        
         | catillac wrote:
         | I heard the latter sentiment earlier today, but I don't think
         | anyone is actually passionate about what editor others use.
         | Opinionated sometimes.
        
           | tyingq wrote:
           | Most of the time, I suppose. Watching someone try to write
           | java in vim (or generally, without an IDE) gives me anxiety
           | though, even with a language server :)
        
             | themadsens wrote:
             | That's perfectly doable. I routinely navigate / extend /
             | debug / refactor a 600 KLOC Java codebase with nvim + ctags
             | + ripgrep and will have the job done well before the
             | language server has even completed digging through those
             | 600 KLOC.
        
             | mdpye wrote:
             | Meh, it's fine. In general, I find that vim in more
             | productive most of the time (now I have a language server,
             | before, wouldn't ever consider it!)
             | 
             | The fluid and consistent (java is only a portion of what I
             | write at work) editing experience is mostly more valuable
             | to me than the slightly better autocompletion.
             | 
             | I keep intellij installed, but it only open it if I want to
             | do a fancy mechanical refactor, like extract an interface
             | from an existing class. Smaller niceties like creating a
             | local variable from an expression are only a handful of
             | keystrokes just feel like naturally describing what I want
             | (lexically, rather than semantically, I'll admit) in vim
             | anyway.
        
           | h2odragon wrote:
           | Passion about the tools others use can be called for if you
           | can see they're obviously struggling to meet their goals with
           | the tools they've chosen.
           | 
           | The hard part is, unlike a screwdriver where you can
           | demonstrate, editors and "IT" in general are mental tools
           | where the mindset is an invisible, nontransferable "handle"
           | to the visible portion that everyone can see and use.
        
             | kstrauser wrote:
             | A previous manager was snarky about me using Emacs to write
             | Python instead of "a proper tool". Every time he'd pass my
             | desk, "a real IDE could to that for you". We finally had a
             | conversation along the lines of "can it save me more time
             | than you waste pestering me about meaningless stuff? Also,
             | STFU until I miss a deadline for the first time since I've
             | been here."
             | 
             | I would not hire a carpenter who doesn't believe in using
             | hammers. Neither would I constantly bug a hired carpenter
             | to use the hammer I think they should be using instead of
             | the one they like.
        
         | [deleted]
        
       | mjw1007 wrote:
       | There are two separate questions: whether you want to see some
       | kind of trace of the program or you want to step around in its
       | state, and whether to use a "real" debugger or not.
       | 
       | In most cases I prefer to do something trace-based, and in the
       | IDEs I've used the debuggers have much weaker support for that
       | than they do for stepping around.
       | 
       | In particular, setting up tracepoints tends to involve fiddly
       | dialog boxes which are much less convenient than using the main
       | text-editor interface to say what you want.
       | 
       | I think there's plenty of scope for debuggers to provide a better
       | interface for trace-style debugging. For example I'd like to be
       | able to toggle a tracepoint after capturing the run, and have the
       | lines it created appear or disappear, or add a filter expression
       | or additional information to display without having to rerun the
       | program.
        
       | boatsie wrote:
       | A few more reasons why print debugging is used. If you are
       | debugging multiple things at once, you'll have breakpoints set
       | that aren't necessarily needed at the moment, meaning you have to
       | continue a bunch of times to get to the right spot. Or your
       | breakpoint needs to be in a loop that is called multiple times
       | and conditional breakpoints are a pain and subject to code errors
       | in the condition itself. Many debuggers are not great at
       | examining state of objects, for instance a deeply nested object
       | for which you want array index 42 within a dictionary of an
       | object. Or you need to see a value that is calculated rather than
       | just present in the current state.
        
         | 1337shadow wrote:
         | > you'll have breakpoints set that aren't necessarily needed at
         | the moment, meaning you have to continue a bunch of times to
         | get to the right spot.
         | 
         | Python: if something: breakpoint()
         | 
         | Js: if (something) debugger;
         | 
         | Much easier than breakpoint conditions in visual debuggers
         | imho.
        
       | bboreham wrote:
       | "With enough print statements, all bugs are shallow"
        
       | jhgb wrote:
       | I had a crazy idea the other day that perhaps there could be
       | something like "CSS for program execution traces". If you think
       | of function identifiers as XML/HTML tags and arguments for
       | individual function activations as element attributes, then
       | perhaps something similar to CSS selectors but acting on the tree
       | representation of a program's execution could trigger at certain
       | clearly defined points during the execution and format some
       | human-readable output of what the program was actually doing, or
       | a "cross-section" of it at least.
        
         | eddieh wrote:
         | Sounds a lot like syntactic sugar or a DSL for symbolic
         | breakpoints combined with conditionals. That's certainly
         | doable.
         | 
         | Something like: func1(4) > func2(null) debug;
         | 
         | Semantically: upon func1 called with arg 4 and some descending
         | path that calls func2 with arg null, enter the debugger
         | 
         | Neat idea!
        
           | jhgb wrote:
           | I got the idea when I was thinking about the applicability of
           | computer algebra systems to math education. Some way of
           | visualizing the decisions and steps of a logically
           | complicated program seemed necessary for that. Getting a
           | readable trace of the computation in a similar way to the one
           | that some logical programs or expert systems can justify
           | their reasoning with seemed like a usable form of such a
           | visualization, and some time later then the analogy with
           | CSS/XSLT struck me. I was thinking of collecting all the
           | steps into an output, but setting breakpoints in a similar
           | fashion with individual "selectors" could be useful for
           | debugging, too.
        
       | jameshart wrote:
       | The idea that print debugging is about being able to understand
       | the time dimension of your code resonates, definitely. It
       | reminded me of how the redux dev tools browser plug-in is an
       | interesting pointer to a better kind of debugging. And
       | essentially all that is is a rich UI around printing out the
       | entire redux state after each operation. But because the redux
       | state advances in discrete steps it's very easy to express
       | exactly what happened, and explore precisely what state change
       | happened in response to each action. I do find myself wondering
       | whether there's a much richer debugging capability along those
       | lines that could be applied more generally.
        
       | wodny wrote:
       | Print debugging is not that different from setting logging level
       | to DEBUG and those logging calls should already be there in code
       | and give meaningful insight so I don't get printing being often
       | ridiculed.
       | 
       | For over ten years of commercial work I used a debugger only a
       | couple of times and in most cases it was against someone else's
       | code, usually when things were completely broken and I needed to
       | get backtraces from multiple deadlocked threads or lacked
       | debugging symbols and things like radare were also required.
       | There were also times when I manually called a syscall using gdb.
       | 
       | My opinion is that if you can't reason about the code helping
       | yourself with just a couple of additional messages the code is
       | probably broken/too complicated to begin with and requires
       | serious refactoring. I've never understood people stepping
       | through a program hoping to find some mysterious creature
       | somewhere along a huge stack of calls. In my career I have often
       | seen people always debugging an application as a whole instead of
       | separated modules. Dividing a problem is the key. The same key
       | that allows me to still program using vim without autocompletion,
       | keep APIs sane and coherent, and avoid dead code.
       | 
       | One really useful exception is when dealing with electronics. My
       | friends programming hardware use debuggers all the time and in
       | this case it actually makes perfect sense because there is no way
       | to print anything and things like hardware interrupts come into
       | play.
        
         | lanstin wrote:
         | When I start to use a new server framework, I like to step thru
         | the main loop, just to see how it works with system
         | calls/listens/accepts/reads and how it dispatches up the stack.
         | But for debugging, I like to a) make it reproducible, b) read
         | the code, c) add logging to help with any deductions that b
         | yields. (Sometimes will just go to b if it's a simple bug).
        
         | blauditore wrote:
         | > I used a debugger only a couple of times and in most cases it
         | was against someone else's code
         | 
         | The vast majority of code I investigate is "someone else's"
         | code. Most of the cases, it's a historical accumulation by
         | multiple authors. If you generally only work in your own code,
         | that's quite a different experience, and debugging is generally
         | easier (because you were there when it was written).
        
         | saagarjha wrote:
         | > My opinion is that if you can't reason about the code helping
         | yourself with just a couple of additional messages the code is
         | probably broken/too complicated to begin with and requires
         | serious refactoring. I've never understood people stepping
         | through a program hoping to find some mysterious creature
         | somewhere along a huge stack of calls. In my career I have
         | often seen people always debugging an application as a whole
         | instead of separated modules. Dividing a problem is the key.
         | The same key that allows me to still program using vim without
         | autocompletion, keep APIs sane and coherent, and avoid dead
         | code.
         | 
         | The big thing here is that you seem to only work with your own
         | code, where you can arbitrary refactor it and keep the entire
         | thing in your head, as well as quickly find which module does
         | what. But when working with a large foreign project, none of
         | this works. You _have_ to start working at the scope of the
         | entire program, because you have no idea of the internal
         | structure yet. Of course, people who use debuggers divide the
         | code up as they go, but the point here is that they place a few
         | choice breakpoints at central points in the application logic,
         | inspect the stacktraces when one gets hit, and use them to
         | further dig in to the part of the code they need to look at.
        
         | xzel wrote:
         | I pretty much all of these. One thing I wanted to add is
         | decorators. There is code you might have easy access to edit to
         | add print statements. I don't love the spring boot docs and
         | reading the code isn't as useful as stepping through your
         | specific autowired code tree. There's definitely use cases but
         | 95% of the time prints will get you there. Imo you should learn
         | it because it will save you a bunch of time and headache when
         | you need it.
        
         | bsder wrote:
         | Actually, using the UART interface to send text breadcrumbs out
         | the port is a standard technique in embedded, too ...
         | 
         | The article hits the point of print debugging, you get to see
         | the _backward in time_.
         | 
         | By the time you hit "the problem", the pointer is NULL, the
         | memory is trashed, the system is deadlocked, etc. You need to
         | reason about how you got there.
         | 
         | There is a reason why the next step up from basic debugging
         | embedded is "streaming trace"--effectively print on steroids.
        
         | steelframe wrote:
         | > I don't get printing being often ridiculed
         | 
         | I just told one of my co-workers last week that I was going to
         | print-debug an issue. He paused for a moment before saying,
         | "Uh, I can just debug this for you if you like."
         | 
         | So yeah, there's definitely some kind of stigma against print-
         | debugging.
        
         | humbleMouse wrote:
         | You've only used a debugger a couple of times in 10 years?
         | Yikes.
        
       | 0xbadcafebee wrote:
       | Stupid question: why don't more programming languages and/or
       | compilers natively support the alternative to print debugging,
       | which is (afaik) tracing? I guess some languages have it, but
       | some don't, or they are onerous add-ons?
        
       | pestatije wrote:
       | For production, the only way is logs (print debugging).
        
       | haolez wrote:
       | I don't usually resort to a debugger to hunt for bugs, but I use
       | them a lot to explore APIs in "real time". I find them much more
       | convenient than the likes of Postman.
        
       | crnkofe wrote:
       | I find that the greater majority of the time there are better
       | tools to solve a problem than using print statements even when
       | considering the fact, that a project needs to be refactored to be
       | debuggable.
       | 
       | If I have a bug I can reproduce I can write a unit or integration
       | test, try narrowing down the issue and use a debugger on the test
       | itself for further help. Intellij has great support here, VS as
       | well and there's plenty others.
       | 
       | If the bug exists in production only using a debugger I can
       | connect to it remotely and dump the state (thread dumps in Java
       | or core dumps with Delve for Go). If there's an option of using a
       | profiler it makes the experience even better especially for
       | diagnosing performance issues.
       | 
       | For distributed systems monitoring libraries, log aggregators are
       | much more useful than raw logs. Proper metrics allow fast
       | pinpointing of issues and log aggregators give me an option to
       | either look for rare/common errors easily.
       | 
       | The only case I'd resort to prints nowadays is as a last resort
       | if there are no better options.
        
       | Androider wrote:
       | Speed of iteration beats quality of iteration.
       | 
       | You can step through the program, reason about what's going on,
       | tracking values as they change. But if you missed the moment, you
       | have start again from the beginning (time traveling debuggers
       | being rare). Or maybe you're looking at the wrong part entirely
       | at this stage, and just wasting time.
       | 
       | With print debugging you write a bit of code to test a
       | hypothesis. Then you run it, and you keep running it, and
       | especially if it's an UI program you play with the UI and see how
       | the values change during that run. Ideally the loop to change the
       | code -> see the result should be a few seconds.
       | 
       | You can then git commit or stash your prints, switch branches and
       | compare behavior with the same changes applied. And at the end of
       | the day if you walk away, your prints will still be there the
       | next morning. The debugger doesn't produce any comparable
       | tangible artifacts.
       | 
       | Once you do know where the problem is, and if it's not apparent
       | what the problem is (most problems are pretty trivial once
       | located), that's IMO the time to break out the debugger and
       | slowly step through it. But the vast majority of problems are
       | faster to solve through rapid iterative exploration with prints
       | in my experience (C, C++ for over a decade, Python, now JS/TS).
        
         | damagednoob wrote:
         | > Speed of iteration beats quality of iteration.
         | 
         | That's especially true if you're doing some form of TDD/unit
         | testing. With IntelliJ, I can easily set it to watch for
         | changes and cycle one unit test while I make changes. If
         | something weird happens I can just drop a printf in there,
         | understand and rectify the issue, then take it out. Much faster
         | than step through debugging.
        
         | forrestthewoods wrote:
         | > Speed of iteration beats quality of iteration.
         | 
         | Right. That's why printf debugging sucks.
         | 
         | If you're in a compiled language with a 2-minute iteration it
         | can take an hour to do a binary search to track down an issue
         | that would take 5 minutes with a proper step debugger.
         | 
         | Print debugging is great because it works and is the ultimate
         | fallback. But it sucks and I hate when I am forced to use it.
        
         | matsemann wrote:
         | I often use prints to find the suspect, and then debugger to
         | weed it out. Conditional breakpoints make it easy to stop at
         | the correct place.
         | 
         | About your debugging from the beginning: with Intellij on the
         | jvm one can "drop frame", which is basically to discard the
         | current function and start over with the stack as it was. Since
         | I mostly write kotlin my objects are immutable, so rerunning
         | most stuff actually works fine. And hot-swapping the function
         | while the debugger is paused I can even try multiple
         | implementations without having to rerun everything, just drop
         | frame, hot swap, step into the new and updated function.
         | 
         | I'd say knowing the debugger well and using it is a faster way
         | to iterate than not.
        
         | Blumfid wrote:
         | Java debugger can easily drop frames which helps tremendously
         | in going over a function multiple times.
         | 
         | Hot code replacement, which I have already and still use since
         | 2005 works very well as well.
         | 
         | In php, debugger are half as good but code replacement works
         | immediately.
         | 
         | I would rarely use print debugging and in Java never.
        
         | kapep wrote:
         | > Speed of iteration beats quality of iteration.
         | 
         | I totally agree but for me that means using a debugger and make
         | full use of its features.
         | 
         | > But if you missed the moment, you have start again from the
         | beginning
         | 
         | As already mentioned in another comment, "drop frame" is a
         | standard Java debugger feature. You can easily go back to the
         | start of any method and go though everything again (side
         | effects of already executed code can give some trouble though).
         | 
         | > Or maybe you're looking at the wrong part entirely at this
         | stage, and just wasting time.
         | 
         | You have the same issue when printing in the wrong parts. Of
         | course you can plaster the code with lots of print statements
         | to see which gets executed. But you can do the same with
         | breakpoints and see where the debugger stops.
         | 
         | > With print debugging you write a bit of code to test a
         | hypothesis. Then you run it, and you keep running it, and
         | especially if it's an UI program you play with the UI and see
         | how the values change during that run.
         | 
         | I really like conditional breakpoints for this. You write a
         | condition for a state that interests you. Then play around in
         | the UI until it stops for that condition and you can easily
         | inspect the complete state at that moment. This is quite useful
         | for debugging methods that are executed very often. Trigger
         | breakpoint (which disable all other breakpoints until they are
         | triggered) are also useful in those situations without
         | requiring any code.
         | 
         | > Once you do know where the problem is, and if it's not
         | apparent what the problem is (most problems are pretty trivial
         | once located), that's IMO the time to break out the debugger
         | and slowly step through it. But the vast majority of problems
         | are faster to solve through rapid iterative exploration with
         | prints in my experience [...]
         | 
         | I can just say that I usually locate issued way faster with a
         | debugger. "rapid iterative exploration" could also kind of
         | describe my workflow using breakpoints. Maybe it actually less
         | about the tool and more about your approach for locating issues
         | in the code.
        
       | cheeri0 wrote:
       | Yeah it works great until you install 30 frameworks and they all
       | tell you so much useless crap that you can't see your own
       | messages. Why do they log these useless messages? Because,
       | they're bad programmers who are 1000 AU from being able to
       | realize it.
        
       | beiller wrote:
       | Here's a hack I do when I'm running a tight loop. In something
       | like a video game at 60 fps, print is useless cause it spams so
       | much in the terminal it's unreadable. So I use my hack: If
       | math.random() > 0.99 print(debug_msg)
        
       | slaymaker1907 wrote:
       | I agree about being able to see the whole program execution. This
       | is particularly useful for multithreaded code since it provides a
       | linear view into how the program actually executed. How are you
       | supposed to figure out that A happened before B in a
       | multithreaded program using only a debugger? With adequate
       | logging, even if you don't log the precise times for A and B, you
       | can often infer the ordering of these events based on other
       | logged data.
       | 
       | For a lot of glue type code, I don't actually care about stepping
       | through something line by line. I really want to see how
       | components interact, not each step of execution. Though I do wish
       | languages had better support for doing something like printing
       | out all local variables in the current function along with the
       | stack trace, sort of like a very shallow, low-cost dump.
       | 
       | Another big advantage is that logging is usually much easier to
       | turn on (or even keep on by default) for production scenarios.
       | Good luck getting some bank to let you run a debugger or even get
       | a dump for anything.
        
         | skneko wrote:
         | > How are you supposed to figure out that A happened before B
         | in a multithreaded program using only a debugger? Setting
         | printpoints, letting them be hit and continuing... this whole
         | thread seems to arise from the fact people have not learned to
         | use debuggers.
        
         | saagarjha wrote:
         | > How are you supposed to figure out that A happened before B
         | in a multithreaded program using only a debugger?
         | 
         | Breakpoint at A, breakpoint at B, both automatically continue
         | when hit.
        
       ___________________________________________________________________
       (page generated 2021-04-24 23:00 UTC)