From RefactoringMercilesslyHidesTheForest: Breaking the system down into a lot of very simplistic pieces (as RefactorMercilessly will do) adds far too many trees and makes the system harder for someone new to understand what's going on.
StanSilver: I believe this is a matter of taste. Some people think little tiny methods are easier to understand, and some people think they are harder to understand. I think they are harder to understand.
Q: Am I misunderstanding you correctly? That the tiny methods themselves are easy to understand, but that the number of them makes the overall structure harder to understand. In other words, this is a seven plus or minus two problem.
A: I don't know. All I know is that little tiny methods are a pain in the butt, but I use them anyway because it makes my coding go faster. But let me think a little. Writing the little methods is not hard. Dealing with them as I write them is not hard. It is the thought of going back six months later and trying to figure out what the code does that makes me wince. And please don't tell me it doesn't make me wince :).
So maybe it is not so much working with more than 7 things, but reverse engineering more than 7 things that is the problem for me? (At my age, I have to reverse engineer my own code after a week of working on other things).
Q: You are saying that reverse engineering the little methods is hard, or that reverse engineering the thing that calls the little methods is hard?
A: If your style of coding includes refactoring mercilessly, as the title of this page suggests, you end up with a lot of tiny methods. It is code written in this style, in its entirety (not one or three small methods), that is hard to reverse engineer.
An analogy might be writing a letter by hand. Longhand is faster to write and harder to read; printing is slower to write and easier to read. The style I use to write the letter determines both how fast I write, and how easy it is to read. My mom would rather get more letters she has to struggle with than less letters she can read better.
Q: Ug, that answer didn't help me to understand at all, and the analogy suggests that I don't even have the context of the problem. Does a tangled thread analogy fit? Consider a tangled ball of thread - reverse engineering it is two separate tasks: first finding an end, second following the end. If this metaphor is relevant, which task is made more difficult by a lot of tiny methods?
A: Are you asking "what is hard for me" or "why is it hard for me" or both? Reverse engineering well written code is hard for me. I don't fully know why.
I like your analogy. I think it is fifty-fifty - it is difficult [for me] to find the starting point, and difficult to trace the flow of execution, in well-factored code. Well-factored code that is then made more understandable helps but does not eliminate my difficulty.
I stumbled over the same problem some years ago in a different context. My solution is to seek a consistent language of words to build the interfaces (think of 5000 function names built from 200 simple words). I started to describe this system in LanguageOrientedProgramming and ThelopLanguage but was unable to bridge the 10.000-mile+culture gap between your world and mine. So I decided to first read and learn from this wiki and to continue when I understand your way of thinking. -- HelmutLeitner
Lots of small methods are easier to understand if they belong to cohesive, coherent, classes, and those classes belong to cohesive, coherent packages, and those packages are organized in clear layers, and they all have intension-revealing names.
Very important to avoid mixing levels of abstraction within a method or class.
In the DomainLayer?, which models the core problem space, use UbiquitousLanguage in naming the classes and methods - a language shared by the domain experts / Customer / Users as well as the programmers.
-- KeithRay
KeithRay has alluded to the underlying problem here. Poor readability can rear its ugly head at any of several levels of abstraction. A method might be too long for easy comprehension, a class might have too many methods for maintaining a mental inventory, just like a package might contain too many classes without constantly consulting the documentation. Truly, this is a fractal exercise in project management: Project complexity should be similar at every level.
For extremely large projects, I'd generalize the ExtremeProgramming PairProgramming paradigm fractally... Divide your IT staff into application development groups according to the root of your IT staff size. For a large application development group, divide it into programming teams according to the root of the application development group size. Repeat these root subdivisions until you have PairProgramming at the bottom.
That way, each subdivision has as many peers as it has members. This balanced organizational style mimics my idea for structuring code itself.
Breaking the system down ... makes the system harder for someone new to understand what's going on.
My insight into this came when I realized that I do not need to understand the system. Furthermore, as systems become more complex, it is not possible for an individual to understand the system. What I do need to do is:
One should not try to fool himself into believe that he can "understand" the system. One should be content to know that the system operates correctly. When a change is required (either a new capability or a modification or correction of an existing capability), be willing to trace through the system at that time to determine where the change should be applied. In return, one should be able to make the change with minimal risk of side effects.
Something deserving of mention here is the increasing difficulty of debugging when a project has many small methods. When I step through code in a medium sized method, I can see the state of a small amount of variables and stay on the same screen. With tons of small methods, a new window pops up nearly every step, variables are often passed and renamed in the new methods, several states are 'lost' (can't be examined in the debugger) and it's hard to flip back to the interesting method (you must remember which tab).
This gets increasingly harder when you have empty base classes, empty constructors, etc. This is partially a limitation of the IDE and screen real-estate. But using context switches in code unfortunately requires developers to make a mental context switch as well.