From the article:
public void authenticateUser() {
findAuthenticationMethod();
if (isNetworkConnection()) authenticateHost();
String password = getPasswordFromUser();
if (invalidPassword(password)) soundAlarm();
}
I actually find that breaking things up in this manner doesn't necessarily lead to a better code smell, compared to something like:
public void authenticateUser() {
// find authentication method
{
...
}
// authenticate host if necessary
{
...
}
// get password from the user
{
...
}
// sound alarms as needed
{
...
}
}
The problem is that the first time you write some code to do something, you are probably not going to delineate the boundaries in the right way for extensibility, reuse etc. So, pretending that things are well-architected for reuse the first time through is often just that -- a pretense. Well-designed method names (i.e., turning the scoping blocks and comments in my example into method names in Mike's) only serve to codify the comment in the method name. It might read like it's better architecture, but it probably won't hold up to the test of time any better.
For example, odds are that the bit where Mike does "if (isNetworkConnection()) authenticateHost();" will eventually evolve into "authenticateTransport()", or maybe something like:
AuthenticationMechanism authMechanism = findAuthenticationMechanism();
authMechanism.authenticateTransport();
Typically, we don't know exactly which bits of code will need to be refactored in which ways. (If we did, we wouldn't really be *refactoring*; we'd just be renaming things here and there.)
Now, it would be absolutely bad to just copy-and-paste that block, or part of that block, somewhere else. But IMO, separating things out into appropriate blocks of reuse is a refactoring that is often best left for when that functionality needs to be reused.
Additionally, prematurely moving the actual implementation logic out of the picture often just makes an algorithm harder for a maintainer to grok. This is not to say that everything should be unrolled all the time, but putting something in a separate method just for the sake of getting it out of view has the side effect of adding a level of obfuscation. This can go horribly wrong if someone adds some bit of behavior to a method without changing the name of the method -- all of a sudden, a cursory read of the high-level does not provide a full picture of what's going on. This is one of the reasons I like using scoping blocks in code. In addition to enforcing isolation between logically separate bits of a method, blocks can be easily folded and unfolded by IDEs, so it is trivial to collapse a blocked-out section of code to get a high-level picture of what's going on.
This is all a balancing act, of course -- methods that are "too long" are certainly suspect. But methods that just call a handful of other methods can be similarly difficult to maintain.
More often than not, I find that the eventual finished code *does* end up with cohesive functionality broken up into separate methods, classes etc., but typically not in ways that I necessarily expected when I first started writing the code.
-Patrick
--
Patrick Linskey
http://solarmetric.com