views:

155

answers:

4

In the SRP, a 'responsibility' is usually described as 'a reason to change', so that each class (or object?) should have only one reason someone should have to go in there and change it.

But if you take this to the extreme fine-grain you could say that an object adding two numbers together is a responsibility and a possible reason to change. Therefore the object should contain no other logic, because it would produce another reason for change.

I'm curious if there is anyone out there that has any strategies for 'scoping', the single-responsibility principle that's slightly less objective?

+1  A: 

I tend to think in term of "velocity of change" of the business requirements rather than "reason to change" .

The question is indeed how likely stuffs will change together, not whether they could change or not.

The difference is subtle, but helps me. Let's consider the example on wikipedia about the reporting engine:

  • if the likelihood that the content and the template of the report change at the same time is high, it can be one component because they are apparently related. (It can also be two)

  • but if the likelihood that the content change without the template is important, then it must be two components, because they are not related. (Would be dangerous to have one)

But I know that's a personal interpretation of the SRP.

Also, a second technique that I like is: "Describe your class in one sentence". It usually helps me to identify if there is a clear responsibility or not.

ewernli
+1, interesting answer, that's kind of how I interpreted it originialy, but the wording of the principal seems a little vague. The principal seems to constantly require replacing of the word 'responsibility' with various phrases.
Mark Rogers
I've added a second trick that I like. I still completely agree that it's vague. But isn't it the case with any design *principle*? It's not a formula nor a recipe.
ewernli
+2  A: 

I don't see performing a task like adding two numbers together as a responsibility. Responsibilities come in different shapes and sizes but they certainly should be seen as something larger than performing a single function.

To understand this better, it is probably helpful to clearly differentiate between what a class is responsible for and what a method does. A method should "do only one thing" (e.g. add two numbers, though for most purposes '+' is a method that does that already) while a class should presents a single clear "responsibility" to it's consumers. It's responsibility is at a much higher level than a method.

A class like Repository has a clear and singular responsibility. It has multiple methods like Save and Load, but a clear responsibility to provide persistence support for Person entities. A class may also co-ordinate and/or abstract the responsibilities of dependent classes, again presenting this as a single responsibility to other consuming classes.

The bottom line is if the application of SRP is leading to single-method classes who's whole purpose seems to be just to wrap the functionality of that method in a class then SRP is not being applied correctly.

Chris Nicola
But it doesn't really provide an answer to the question "How can I identify the responsibility of a class?" (my answer neither, btw)
ewernli
Well I guess that is the nature of software design, it does require some level of intuition and (not so) common sense. If we could just apply some arbitrary rule to achieve SRP then it wouldn't really be design and there would probably be a ReSharper SRP short-cut ;P.
Chris Nicola
Also, I think it is important to note that SOLID is specifically about 'principles' and not 'rules'.
Chris Nicola
+1 Good points, but it seems like your saying that it's the duty of a principal is to be vague, and not like a rule. A principal could be extremely rule-like and still be too difficult to be conceptualize into an automated refactoring system. Though obviously SRP could never be a completely automated refactoring tool.
Mark Rogers
True, I definitely don't mean a principle is meant to be vague, but it is typically more comprehensive than a basic rule is. It is meant to provide guidance, but not necessarily to express in exact terms how something must be done.
Chris Nicola
I wonder if misapplication of SOLID principles can in fact just be another new kind of "code smell".
Warren P
+1  A: 

A simple rule of thumb I use is that: the level or grainularity of responsibility should match the level or grainularity of the "entity" in question. Obviously the purpose of a method will always be more precise than that of a class, or service, or component.

A good strategiy for evaluating the level of responsibility can be to use an appropriate metaphor. If you can relate what you are doing to something that exists in the real world it can help give you another view of the problem you're trying to solve - including being able to identify appropriate levels of abstraction and responsibility.

Adrian K
+3  A: 

it comes down to the context of what you are modeling. I've done some extensive writing and presenting on the SOLID principles and I specifically address your question in my discussions of Single Responsibility.

The following first appeared in the Jan/Feb 2010 issue of Code Magazine, and is available online at http://www.code-magazine.com/article.aspx?quickid=1001061&page=4


The Single Responsibility Principle says that a class should have one, and only one, reason to change.

This may seem counter-intuitive at first. Wouldn’t it be easier to say that a class should only have one reason to exist? Actually, no-one reason to exist could very easily be taken to an extreme that would cause more harm than good. If you take it to that extreme and build classes that have one reason to exist, you may end up with only one method per class. This would cause a large sprawl of classes for even the most simple of processes, causing the system to be difficult to understand and difficult to change.

The reason that a class should have one reason to change, instead of one reason to exist, is the business context in which you are building the system. Even if two concepts are logically different, the business context in which they are needed may necessitate them becoming one and the same. The key point of deciding when a class should change is not based on a purely logical separation of concepts, but rather the business’s perception of the concept. When the business perception and context has changed, then you have a reason to change the class. To understand what responsibilities a single class should have, you need to first understand what concept should be encapsulated by that class and where you expect the implementation details of that concept to change.

Consider an engine in a car, for example. Do you care about the inner working of the engine? Do you care that you have a specific size of piston, camshaft, fuel injector, etc? Or, do you only care that the engine operates as expected when you get in the car? The answer, of course, depends entirely on the context in which you need to use the engine.

If you are a mechanic working in an auto shop, you probably care about the inner workings of the engine. You need to know the specific model, the various part sizes, and other specifications of the engine. If you don’t have this information available, you likely cannot service the engine appropriately. However, if you are an average everyday person that only needs transportation from point A to point B, you will likely not need that level of information. The notion of the individual pistons, spark plugs, pulleys, belts, etc., is almost meaningless to you. You only care that the car you are driving has an engine and that it performs correctly.

The engine example drives straight to the heart of the Single Responsibility Principle. The contexts of driving the car vs. servicing the engine provide two different notions of what should and should not be a single concept-a reason for change. In the context of servicing the engine, every individual part needs to be separate. You need to code them as single classes and ensure they are all up to their individual specifications. In the context of driving a car, though, the engine is a single concept that does not need to be broken down any further. You would likely have a single class called Engine, in this case. In either case, the context has determined what the appropriate separation of responsibilities is.

Derick Bailey
Very well explained. As in all things in software design the context is key.
Chris Nicola