On the other hand, too much modularity and factored-out code can also obscure the behavior of a program, even if each module has a well-defined role and satisfies its interface. (E.g., big Java programs can have hundreds of classes with small method bodies and lots of calls to other classes and interfaces. If you see an interface call, but the object came from somewhere several classes away, then good luck figuring out which implementation gets called.)
I'd say that the ultimate moral is "Keep the flow of logic and data relatively linear (or at least, no more complex than it needs to be to solve the problem). Avoid dicing it up between a dozen different spots, or performing crazy stunts with it, so that only an expert can understand what's going on. And just because some logical constructs (like dynamic dispatch) are unwritten doesn't mean they don't create mental load."