I’m a coder, which means I spend a lot of time debugging programs. My dirty little secret is that quite a bit of this involves “grepping” for text strings in the source that appeared in log messages, so I can correlate an occurrence in the log with a spot in the code. This simple act illustrates that debugging is reasoning about code, typically to answer questions like “how on earth could this variable have had that value at that point.”
It is fun work, but usually there is a lot of pressure to resolve the problem in a hurry. Things that make the job easier are appreciated, and one of the most helpful is when the author took pains to restrict the scope of variables and functions as much as possible.
The worst case would be a public, global variable. Where in the code could it have been changed? Anywhere! Good luck with that.
Private instance variables in C++ and Java, file-scope variables in C are better. You can still get bitten by references to these values, but the work of analyzing where these values are updated is much more tractable then with variables of wider scope.
When I write code, I take this to the point that I do not declare local variables until they are needed. That is, instead of
int foo = 0; int bar = 0; /* lots of stuff */ bar = get_value(); foo = deal_with_it(bar);
/* lots of stuff */ int bar = get_value(); int foo = deal_with_it();
Many coders like the tidiness of declaring all their variables at the top of a routine. Some languages required this (e.g., COBOL, and the original release of C). But I no longer write COBOL, and C has had “declare anywhere” since the release of C-99. Although there is much value in having a regular layout for your code, I think clarity of intent trumps the convention of not mixing declarations and operations.
When I first learned C++, it struck me that the real strength of the language was not the ability to model problem domain objects with classes, but instead to isolate and insulate implementation from function. Limiting the interactions between various modules and components makes your code more robust, easier to maintain, and more likely to work.
Taking reduced scope a step further, it is a gift to your readers if you declare your constants to be constant. Any time you can, declare members const in C++, final in Java. The fewer moving parts, the easier it is to understand what is happening.
There is an analogous benefit to limiting the scope of functions. Often your question regarding a misbehaving function will be “who passed in this garbage”. The more limited the visibility of the function, the fewer suspects to investigate.
All things being equal: the more limited the scope of variables and functions, the easier it is to reason about a program’s behavior, and the easier it will be to debug problems. The easier you make it to debug your programs, the less people who have to do so will hate you.
In a world so rich and wonderful, who would want to be hated for writing cruddy code?