You might be wondering why I tackled single responsibility last rather than, as is more conventional, first. Partly it’s because I simply found it very hard to write about, but I think it goes deeper than that: it’s actually very hard to understand, partly because of the perspective issues it raises. There’s no one right answer to how to observe SRP.
The official statement of the principle is “A class should have one, and only one, reason to change.” It’s not clear to me that “one reason to change” is any better defined than “single responsibility”. As I’ve said before, it’s fundamentally a naming problem. Academic studies on functional cohesion focus on coming up with better metrics. Given that no-one’s developed a decent metric for evaluating a method yet, I don’t think this is going to be fruitful.
However, I think it’s worth looking at the single responsibility principle and seeing how it interacts with the other SOLID principles. From the perspective of the interface segregation principle, it basically looks like a generalization. Not only should your interactions be small and well defined, so should your implementations. Like the ISP, it makes observing Liskov easier. The fewer things a class does, the less likely you’re going to need to break Liskov to get a subclass to do what you need. Equally, it’s less likely to need to change, so it makes it easier to observe the open closed principle.
The story gets even more interesting when you look at dependency inversion. The smaller your objects, the more you’re going to have to throw around. Again, you probably need facades on top of these single responsibility objects to simplify interactions. Providing a facade is a responsibility in its own right.* However, just as Liskov makes inheritance work, Single Responsibility makes pluggability work. The smaller classes need to be changed less often, and are easier to swap out for alternative implementations.
So, where do we go next? Well, the Open Closed Principle lead us to refinements, where we came up with techniques to ensure it such as constructor injection and Liskov. Equally, since we have an issue of naming here, it can help to standardize naming in some way. Luckily, we have a fairly large catalog of standard names to begin with in the shape of design patterns. e.g. Abstract Factory, Repository, Presenter
*Or to put it another way: eventually you’re going to need a car object.