Earlier quoted context omitted.
It's good to strive to avoid making mistakes, but however hard you try, there will be bugs. That's basically what the quote is implying - you should not be throwing things together and hoping it will work after debugging, but carefully designing to avoid bugs, so there won't be much if any debugging required. An analogy to this can be found in the aviation industry: it's known that pilots do make errors and planes do…
All too often, the "carefully designing" becomes some sort of masochistic ritual where all errors are attempted to be piped through a single tool in the dev chain. Static typing is popular nowdays. As are high level functional strategies. It is great when these work. Or when you have a high level team that doesn't abuse the system at all and gets things done using these strategies. I have seen too many times where th…
Why debugging is all about understanding
71–80 of 80 posts
Re: Why debugging is all about understanding
#72Earlier quoted context omitted.
If you have a race condition in a multi threaded program, a simple printf is enough to screw the timings and make the bug disappear, it's not at all better than breakpoints and stepping in a debugger. In my experience, the only way to produce safe multi threaded code is to isolate the threading parts and synchronization and stress test them early on. At this point I use a combination of prints, random delays and simp…
> If you have a race condition in a multi threaded program, a simple printf is enough to screw the timings and make the bug disappear, it's not at all better than breakpoints and stepping in a debugger. If you have a race condition in a multi threaded program, a simple printf may be enough to change the timings and make the bug disappear. But a breakpoint and stepping in a debugger is guaranteed to completely change…
Re: Why debugging is all about understanding
#73Over the years I've become more and more convinced that debugging has done a lot to develop my problem solving skills and analytical thinking in general. It's like being a full-time modern times Sherlock Holmes with the crime scene and tools neatly at your disposal. Usually breakpoints and stepping through code solves things pretty easily but some bugs can be real stumpers. Here's some of the tools I tend to use: 1.…
1. Can you consistently replicate the bug? 2. Are you sure you can you consistently replicate the bug?
Re: Why debugging is all about understanding
#74Earlier quoted context omitted.
All too often, the "carefully designing" becomes some sort of masochistic ritual where all errors are attempted to be piped through a single tool in the dev chain. Static typing is popular nowdays. As are high level functional strategies. It is great when these work. Or when you have a high level team that doesn't abuse the system at all and gets things done using these strategies. I have seen too many times where th…
Just because it can be done badly is not a reason for abandoning it. To continue the aviation analogy, the solution there was to ensure that the people designing airplanes have had fairly rigorous training and that they have an adequate understanding of the relevant theory.
Re: Why debugging is all about understanding
#75Earlier quoted context omitted.
Because it seems you're making an assumption about the problem being reproducible and identifiable by running half the code. I've never found this to be the case. Ever. Its a strange idea. Where does this come from? This isn't a hypothesis based on data, it is an assumption. And a bizarre one.
The following program segfaults: main() { a(); b(); } You don't have a debugger. You don't have the source for a or b. Strategy? Sure printf works, but so does //.
Re: Why debugging is all about understanding
#76Earlier quoted context omitted.
The following program segfaults: main() { a(); b(); } You don't have a debugger. You don't have the source for a or b. Strategy? Sure printf works, but so does //.
I get the feeling you don't actually program. Or your writing is disconnected from the programmer part of you.
Re: Why debugging is all about understanding
#77Earlier quoted context omitted.
I get the feeling you don't actually program. Or your writing is disconnected from the programmer part of you.
That's interesting, could you elaborate?
You seem to be arguing that your example demonstrates the fact that you can localize a bug in the code with binary search; specifically that the bug must exist in either a() or b(), and that running them independently is both possible and will determine the single location of the bug.
This is not true. It is only true in the case that one assumes bugs must have single locations, and that those locations can be found with binary search over what amount to incomplete programs. In other words, you're assuming the prior, begging the question, etc.
It's tempting to say "real code isn't like this contrived example" but in fact this contrived example is the best possible demonstration of why blind binary search is a poor strategy. Let us say the 'bug' exists in a(). You seem to be assuming this is the necessary consequence:
main () { a(); b(); } -- segfaults main () { a(); /* b(); / } -- segfaults main () { / a(); / b(); } -- doesn't segfault
But this isn't the only possibility. With the bug existing in a(), you could also see this result:
main () { a(); b(); } -- segfaults main () { a(); / b(); / } -- segfaults main () { / a(); / b(); } -- segfaults
You would expect this in situations where b() uses data structures created by a().
We may also see this result, still assuming the bug exists in a():
main () { a(); b(); } -- segfaults main () { a(); / b(); / } -- doesn't segfault main () { / a(); / b(); } -- segfaults
If above we learned nothing, here we've actually got a falsehood - our binary search has localized the bug to b(), but it actually exists in a()!
So, in practice, binary search fails to localize a bug in a(). All of these situations can be created by having a() write a global which is relied upon by b() - a() may write to a protected area, b() may have a default value, a() may write nonsense, or pass an integer where b() expects an address - none of this is particularly exotic, they're all the sort of things you get every day when debugging segfaults.
We might now delve into a competing series of contrived examples of a() and b() and argue about their relative prevalence in the world (which none of us are capable of knowing), because if some case is particularly rare, it may make binary search very slightly better than flipping a coin in this case.
Instead, I will point out that this is once again* assuming the prior, and that we have these simple (if shockingly annoying) facts:
1) side effects exist 2) in the presence of side-effects, binary search cannot predict the location of a bug.
And it follows that in the sense that a "scientific" hypothesis has predictive power, then binary search over the codebase is basically the homeopathy of debugging.
Re: Why debugging is all about understanding
#78Earlier quoted context omitted.
That's interesting, could you elaborate?
I can. It's long and tedious, because a lot of it is very simple things you learn very early on writing and maintaining software. You seem to be arguing that your example demonstrates the fact that you can localize a bug in the code with binary search; specifically that the bug must exist in either a() or b(), and that running them independently is both possible and will determine the single location of the bug. This…
Further, there's a misunderstanding about the method. You do a binary search on the "percentage" of code viewed as an instruction stream that is allowed to execute, starting from the beginning. I understand that a can have a different length from b. Given more code, you can also search based on timestamps. You never comment out a and allow b to execute without it, this is nonsense. If that's what you thought I meant, I can understand comments about not actually being able to program. I did not explain this clearly, but only because I had forgotten that it was necessary to explain this clearly, because some people actually don't know how to program, even on HN.
Re: Why debugging is all about understanding
#79Earlier quoted context omitted.
I'd even dare to say that it is better to shove Vi/Emacs experience into a real IDE rather than the other way around. I really like Vim, I use it for almost everything, however when I am working on a large C++ codebase I tend to use an IDE that has full support for visual debugging, code navigation and so on. I am always amazed when some more experienced programmers than me spend valuable time grepping files and usin…
> I am always amazed when some more experienced programmers than me spend valuable time grepping files and using GDB on the command line. I don't know about Vim, but Emacs works very well as a visual debugger, for quite a couple of languages. It looks like this for C, for example: http://www.inet.net.nz/~nickrob/gdb-ui.png (it's Emacs debugging itself in this screenshot). In general both Vim and Emacs can become IDEs…
Regarding your GDB screenshot, that is certainly good, I would argue though that using pure text (with some images included) is limiting oneself.
This being said, I really hope that NeoVim will go far enough and bring good enough integration of Node.js and javascript in general (my current work uses these technologies). So far I have been quite disappointed by stuff like tern[1]
[1]: http://ternjs.net
Re: Why debugging is all about understanding
#80Earlier quoted context omitted.
I can. It's long and tedious, because a lot of it is very simple things you learn very early on writing and maintaining software. You seem to be arguing that your example demonstrates the fact that you can localize a bug in the code with binary search; specifically that the bug must exist in either a() or b(), and that running them independently is both possible and will determine the single location of the bug. This…
If you comment out b , and it segfaults, the segfault is caused by some code in a . Otherwise, the segfault is caused by some code in b . The root cause of the segfault in b may be found in a , but even looking at the stack trace from a debugger will still point you at b . This is nevertheless helpful information. Further, there's a misunderstanding about the method. You do a binary search on the "percentage" of code…
no source,
no debugger,
two function calls
And the assertion that // works as a strategy. There's only two things you could possibly comment out, so really the example is not so much "explained poorly" as "conceived poorly". Don't shoot the messenger - it's your example.As for the further explanation here, allowing a debugger makes the search irrelevant - there's only one piece of information the binary search can tell you: which function causes the segfault, but as you observe, that information's available from the debugger already. And no, it doesn't matter if you reframe things as "a percentage of an instruction stream".
The objection to binary search is not "binary search in the codebase can never tell you anything," it's that it's a method that can't -- not "doesn't" but "can't" -- produce a non-trivial testable hypothesis. Does this mean you can't ever use it? You may have no choice. But it's a terrible place to start, and most of the information it offers is available through other means, often with more precision.