12 ms·
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 con
by CJefferson 6y ago
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.
- le-mark 6y agoI’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.
- axaxs 6y agoOK. 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.
- pjmlp 6y agoThey weren't ninjas, otherwise they would have used breakpoint actions for doing those print statements without modifying the source code.
- majjgepolja 6y agoWhat's breakpoint action? Is it like inserting printf before breakpoint?
- edoceo 6y agomaybe 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
- formerly_proven 6y agoBreaking 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.
- nomel 6y agoReading through the majority of this comment section, I get the impression that those who like print statements find value because they aren’t proficient with modern debuggers, rather than they find print statement valuable even though they’re proficient with debuggers.
- pjmlp 6y agoI once saw an interview with Visual Studio members that one reason why they started doing talks about how to use the debugger was the continuous set of requests for features that Visual Studio does almost since it exists. Same applies to other debuggers. It is not only the debuggers, but also OS and language runtime tracing facilities like DTrace, eBPF, ETW, JFR, .... Many devs aren't 10x because of QI, rather because they learn and make use of the tools available to increase knowledge about the platform.
- frou_dh 6y agoReminds me of this diagram http://i.imgur.com/ZOuf9hg.png http://i.imgur.com/ZOuf9hg.png (which I don't necessarily agree with)
- mmazing 6y agoTools 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 6y ago> 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 6y agoBut 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.
- dragonwriter 6y ago> 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 6y agoNo, 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.
- zeta0134 6y agoI'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.
- deleted 6y ago[deleted]
- CJefferson 6y agoI 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 6y agoYou 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 6y agoYou 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 6y agoWatched 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 6y agoPerhaps, but that lends credence to the theory that people using print debugging may just not have learned how to effectively use a debugger yet.
- xondono 6y agoI’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.
- deleted 6y ago[deleted]
- pugworthy 6y agoI 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.
- 1337shadow 6y agoWhat 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.
- CJefferson 6y agoHonestly, 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 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 6y agoI just tried python -m pdb and it works for me https://dpaste.org/9EQo#L26 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 6y agoI 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 6y agoI 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.
- bakatubas 6y agoAs 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.
- throwaway894345 6y agoI 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 6y agoAlso, 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 6y agoPrint 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.
- 6y ago
- wmichelin 6y agoPython 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.
- gmfawcett 6y agoIn recent Python, it's even easier -- just put `breakpoint()` in your code.
- anarazel 6y agoFwiw, 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).
- twobitshifter 6y agoPry with Ruby allows you to drop in to a repl anywhere with binding.pry You can edit the state and keep running after altering the program. But usually I just end up printing a few things from the repl and figuring out what is fouled up.
- rufus_foreman 6y ago>> 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 6y ago[deleted]
- fighterpilot 6y agoPart 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.
- christophilus 6y agoAgreed. Also certain classes of bugs (such as bugs in parallelism) are easier to debug via print than using a debugger.
- zamfi 6y agoPrint 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 6y agoIf 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.
- mschuster91 6y agoWorst 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.
- tgsovlerkhgsel 6y agoEspecially 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.
- m463 6y ago> Personally, I think my biggest reason for using print debugging is.. it works. I agree. A similar statement is that using a debugger often does not work. the sort of ratholes I've run into are: - debug build - proper symbols - interrupts and debugger - kernel and debugger - unfamiliarity with debugger - limitations of debugger Without a proper debug build, you can't run the debugger effectively. You have to set up a whole debug environment. Sometimes you need to do broad work to get proper symbols and stack trace information. By broad, I mean a debug build for everything. I've also found many debug builds, apart from altering some behavior, they also turn on a lot of printfs. If you're using interrupts/timers or debugging a kernel module, many times debuggers don't work or may alter, move or supress the problem. and then there's the... I haven't used a debugger in 6 months, how do I do (very simple thing). And sometimes the debugger is just not the right tool or a tedious tool to use. "If I just load this one macro and somehow get the right address maybe I can decode this one kernel data structure..." Personally, many times an ephereral printf isn't crude and meaningless, it's a precise scalpel getting to the core of the problem.
- bc4m 6y agoThis is the only argument for print debugging I can understand. Given the debugger experience I've had at every job in the last 10 years (IDE-driven, set breakpoints in editor, inspect state visually) it's mind-boggling that anyone thinks print statements are superior, but getting that experience can be frustrating depending on your tools and environment. FWIW my experience debugging Python in VS Code required no setup and I've encountered zero issues.