What does it take to grok code? I'm beginning to believe the answer is Study The Source Witha Debugger because Well Factored Programs Cannot Be Understood Statically.
Perhaps Tips For Reading Code would help?
I think there are at least two dimensions to understanding code. One dimension is understanding the point of the code and why it is as it is. Even with Very Long Descriptive Names That Programming Pairs Think Provide Good Descriptions, it?s hard to know why a piece of code exists in the first place. Is it an artifact of refactoring (such as a Visitor, a State, or a callback for Double Dispatch)? Or, is it a piece of the domain? It is a partial pattern because the full one was too much?
Do all these "why" questions really matter ? To put that more precisely - if the code says "what" it is doing - its role in the computation - will knowing its origins yield any useful insights ?
The second dimension is about importance. Not every piece of code is as important as the other for the purposes of understanding what's going on (of course, every piece of executed code is equally important for the correct (or incorrect) functioning of a program). When I read code for the first time, or even code I wrote that has grown stale, I find that I unconsciously treat every piece of code with the same level of importance. This brings on the Seven Plus Or Minus Two problem because I don?t know what to flush from my cache.
Do all these "why" questions really matter ? To put that more precisely - if the code says "what" it is doing - its role in the computation - will knowing its origins yield any useful insights ?
Yes, I think so. Not because it necessarily aids my understanding of what the code does, but it does help me accept the code as it is. I may be particularly hard headed, but when I see code that I don't immediately grok, I find myself challenging it. I ask questions like Why is that there? or How come they didn't use XXXX?
Oftentimes, this challenge is a useful part of my process of understanding the code. Of course, other times, it's just a waste of my time and energy, but I cannot seem to get to a point of understanding without going through this 'challenge' step.
A minor case to illustrate the point (The example isn't the greatest, but it's one that I came across recently):
public void removeItem(String itemKey) { try { Item item = keyGenerator.getItemFromKey(itemKey); itemCollection.removeItem(item); } catch (NotFoundException e) { } }
Why ignore the Not Found Exception? Where does this code exist in the overall architecture of the system? If it's deep in the bowels of the system, I think it's probably a bad thing to swallow the exception, if it's at the UI level and I'm looking at some part of the command pattern, it's probably not a big deal.
Of course, I don't need to know the answers to any of those questions before I understand what the code does, but will feel much more comfortable with my understanding if I knew the answers and thus its larger context.
public void removeItem(String itemKey) { try { Item item = keyGenerator.getItemFromKey(itemKey); itemCollection.removeItem(item); } catch (NotFoundException e) { } }
I would think that this needed some refactoring. There are two possibilities (as I see it) in this case. The first is that the removeItem method throws a Not Found Exception and since it is in a third-party library, whomever wrote the code had to deal with it. In this case, they should have propagated the exception further up by declaring it in the throws clause of the enclosing method. The other possibility is that it is not from a third-party library in which case it is modifiable. Either way, I can't really see a reason why code should go into production looking like this. At the very least (and this is not in my view an option in production) there should be a comment in that empty catch to explain why there is no processing being done.
I would guess that this would be commented with...
// We consider removal of a missing item to be OK. // (After the call, it's not there, is it? ;-)
Your comments exactly illustrate my point: You cannot grok the above code without something else. If I Study The Source Witha Debugger, I can grok it because because I see how it relates to other pieces of code. In fact, it is only used as part of a command pattern in the UI. Comments don't help, because I Dont Trust Comments. Refactoring is only valuable AFTER I grok the code.
I disagree. I think a debugger can only help you understand the behavior, not the reason that behavior exists. The above snippet seems very clear to me: if the item isn't there, then an exception will be thrown, which is then squelched. I don't see how using a debugger would add anything to my understanding.
What's uncertain is WHY the exception is squelched. My guess was the same as a previous poster's: it's okay to remove an item that's not there. That's a guess, but a plausible one, and I don't see how a debugger would help me understand the 'why' any more clearly. --Jim Little
How about renaming things a little to make the intention clearer:
public void removeItemSilently(String itemKey) { try { Item item = keyGenerator.getItemFromKey(itemKey); itemCollection.removeItem(item); } catch (NotFoundException irrelevant) { } }
It seems to me that callers would be mainly concerned with removing an item, and that the silence is incidental most of the time. What removeItemSilently has in precision it lacks in intuitiveness, and I think one might get frustrated very quickly with having to specify an unimportant level of stealth throughout one's code. I would think comments would be better.
Here's how the debugger can help you:
Add a nonsense line of code in the catch clause, like "int x=0;" and set a breakpoint on it. Run the system. When you hit the breakpoint, you've found a case where the system is trying to remove an item that doesn't exist. Now you have a leg up on figuring out why the system does that.
In the absence of a complete set of unit tests that check every piece of functionality that the system possesses, the "why" question becomes very important: Otherwise, one might just remove seemingly useless code, and find that it breaks the system.
Do all these "why" questions really matter ?
Of course. In fact, that's the only good reason for commenting code. The code tells you the what, the comment the why. Thus you communicate to the human and the compiler the full extent of what is happening.
Do all these "why" questions really matter ?
If you want ot know why, ask the users. Don't expect the code to replace them. The source code only needs to document how it is doing things.
See original on c2.com