Hacker News new | ask | show | jobs
by mikekchar 2600 days ago
I don't think what you are doing is vastly different than what is described. "Thinking hard" is about trying to isolate the problem. RMS famously said that you should try to only debug the code that is broken rather than trying to debug the code that isn't broken (this is especially true in big systems). Where is the error happening? How are these things connected? Etc, etc. When you write very tight unit tests around the sections of the code, you have to do exactly the same thing (and I would argue that writing those tests is a good tool for "getting into" the code).

Next: running a debugger. I use print statements, but seriously, what's the difference? You use watch points in the debugger. Same thing. Once I have tests I find it easier to run them and look at the output of my prints as opposed to stepping through the code. Stepping through the code requires you to remember what you have done before and what the output was (granted debuggers that allow you to go backwards are helpful). If you can do that, then it's all good, but I find that it's easier for me to essentially create a log and read through it. It's just a bit more structured, but in the end it's exactly the same thing.

I think the biggest mistake that less experienced programmers do is that they don't try to reason about the code before they start. It's that isolation that's key, not how you are displaying the state of the program. Single stepping is fine when you've got 100 lines of code, but when you have thousands or millions of lines of code, it's not going to work. You need to be able to work your way backward from the error, reasoning using the source code as a map. You then use debugging tools (or printfs) to narrow down your options.

2 comments

> I use print statements, but seriously, what's the difference? You use watch points in the debugger. Same thing. Once I have tests I find it easier to run them and look at the output of my prints as opposed to stepping through the code.

Maybe I have been spoiled by Visual Studio but as you said there are plenty of options in the debugger for winding back execution, changing execution, inspecting Objects, inspecting the state of the stack at the time, I can debug other people's assemblies, I can debug machines remotely.

Writing out to the console / log is my last resort.

> Stepping through the code requires you to remember what you have done before and what the output was (granted debuggers that allow you to go backwards are helpful).

No it doesn't require you to remember what you have done before. Even relatively basic debuggers such as the JavaScript debuggers in most browsers have a stack trace with what has been called where.

>If you can do that, then it's all good, but I find that it's easier for me to essentially create a log and read through it. It's just a bit more structured, but in the end it's exactly the same thing.

I don't understand why you would claim an inferior tool is better when a far superior one is available. It would like saying that a Impact Wrench / Spanner and a Spanner are the same thing, technically they both undo bolts, however one makes it far easier than the other.

> "Thinking hard" is about trying to isolate the problem. RMS famously said that you should try to only debug the code that is broken rather than trying to debug the code that isn't broken (this is especially true in big systems). Where is the error happening? How are these things connected? Etc, etc. When you write very tight unit tests around the sections of the code, you have to do exactly the same thing (and I would argue that writing those tests is a good tool for "getting into" the code).

Except it doesn't help you find the code. With a debugger I can stick in some breakpoints where I think the code is going to get hit and then walk myself back from there on what is called and in what order. I work with some terrible systems where it isn't obvious how the code is even executed because "senior" developers have abused IoC / DI, Reflection and Delegates in such a way to obscure what it is actually doing.

As for writing Unit-tests around sections of code. In quite a few areas I have been barred from doing it (for political reasons) and other times you realistically can't because your test setup would be just too complicated.

> Single stepping is fine when you've got 100 lines of code, but when you have thousands or millions of lines of code, it's not going to work

Yes it does work. I did it on Friday. I stick a break point on the entry point (in this case an ASP.NET MVC controller) and F10 and F11 my way down through the stack. I learned more doing this for 30 minutes then I did the previous 2 hours of looking at how the project was structured.

This "think harder" is akin to telling a man to dig harder with a shovel when they have a JCB excavator sitting round the corner.