The bottom line:
Modularity. Details. Pick one.
I routinely work with programmers who feel uncomfortable with tiny methods and tiny classes, in spite of all the benefits of tiny methods and tiny classes:
- easier to test
- easier to read
- easier to understand
- easier to build correctly
- easier to compose into working systems
The programmers who don't like them cite these problems most often:
- "I can't find stuff!"
- "I have to click too much to see what's happening!"
This article by Kevin Rutherford reminded me of this issue. While Kevin extols the virtues of tiny methods, he doesn't address this phenomenon, although he admits to running into it himself. I wanted to share what I do with him, but it doesn't fit well into a comment. When I hear programmers complain about these things, I offer the following two responses to them.
You appear to be navigating. Would you like help with that?
I have paired, albeit mostly briefly, with hundreds of programmers by now. Most of them, to my surprise, navigate their code bases to find things. By this, I mean that they open up folders in a navigator view in their IDE, or navigate the file system, in order to locate a file containing the code that they want to read or change. Not wanting to make pair programming suck, I hold my tongue until I've built up more trust with the person. If I think they trust me, then I stop them and suggest:
Don't navigate when you can search.
I just don't care where to find things any more. Just knowing that "they're somewhere in this room"1 suffices. Only when searching fails do I resort to navigating.
The classic book The Pragmatic Programmer teaches us to learn one editor well, which I try to do. As part of classroom training and mentoring hundreds of programmers, I find myself working in unfamiliar environments quite often. When I work in a new one, I spend some time learning how to search for things. In Eclipse, I use "Open Type" and "Open Resource" extensively. Before I knew anything useful about
vim, I knew to press
/ to find text in a file. Before I knew anything useful about Unix, I could clumsily use
grep, and more recently I've learned about
ack and even
ag. I don't use Emacs any more, but I love its incremental search feature. I see this as an extension of the maxim that humans ought to delegate mechanical tasks to the computer, such as searching text for a pattern.
I still see programmers scan web pages with their eyes to find text, rather than use the "search" feature of their browser. I just don't understand why they do this. I prefer to work in environments where I don't even know that it stores my code in files!2
This brings me to my other response.
Modularity. Details. Pick One.
If you ask programmers whether they want modularity, they usually claim that they do. It sounds like something they ought to want, books on design tell them to want it, and so I imagine that some programmers claim to want it in order to look good among their peers. Unfortunately, many such programmers don't appear to understand that modularity comes from abstraction, and that abstraction literally means hiding details, and that doesn't mesh with their clinging to details. To them, I suggest repeating a little mantra all day today:
I don't care. I don't need to know. I don't want to know.
Giving up details won't lead you directly to writing modular code, but clinging to details will keep you from it. The more your code knows about its neighbors, the less you can change or replace those neighbors. Changes ripple out to the rest of the system. When you do this, you're writing more legacy code.
Modularity needs abstraction. Abstraction means hiding details. If you cling to details, then you won't create abstractions, and you won't achieve modularity. Modularity begins with your refusal to let others burden you with unnecessary detail.
I noticed that my designs improved once I began stubbornly refusing to know any more than I needed to achieve my current goal. Try starting there. "I don't care. I don't need to know. I don't want to know."
Look at the SOLID principles and how they relate to not wanting to know details.
- Single Responsibility: I don't want to know about any other behavior in this system right now.
- Open/Closed: I don't want to know how things work in order to extend them.
- Liskov Substitution: I don't want to know which implementation of each interface this code uses.
- Interface Segregation: I don't want to know anything more than the minimum I need to do my job.
- Dependency Inversion: I don't want to know how the rest of the system uses me.
I don't think I can make it any plainer than that.
Of course, I've assumed in this article that we want modular systems. You might not. I don't want to argue the merits of modularity here. Instead, I want to make one thing clear:
Modularity and obsession with details exclude one another. If you want one, then you can't have the other, so pick one.