Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

The Single Responsibility Principle is based on the high cohesion principle. The difference between the two is that a highly cohesive classes features a set of responsibilities that are strongly related, while classes adhering to SRP have just one responsibility.

But how do we determine whether a particular class features a set of responsibilities and is thus just highly cohesive, or whether it has only one responsibility and thus adheres to SRP? In other words, isn't it more or less subjective, since some may consider a class very granular (and as such will believe the class adheres to SRP), while others may consider it not granular enough?

share|improve this question

migrated from Jun 28 '12 at 18:22

This question came from our site for professional and enthusiast programmers.

related: What is the real responsibility of a class? – gnat Jun 24 '15 at 15:32
up vote 11 down vote accepted

Why yes it is very subjective, and it is the subject of many heated, red-faced debates programmers get into.

There's not really any one answer, and the answer may change as your software becomes more complex. What was once a single well-defined task may eventually become multiple poorly-defined tasks. That's always the rub too. How do you choose the proper way to divide a program up into tasks?

About the only advice I can give is this: use your (and your coworkers') best judgement. And remember that mistakes can (usually) be corrected if you catch them soon enough.

share|improve this answer

Bob Martin (Uncle Bob), who originated the SOLID principles of which SRP is the first, says about this (I am paraphrasing, can't recall the actual words):

A class should only have one reason to change

If it has more than one reason, it does not adhere to SRP.

share|improve this answer
That's just repeating the definition really, but actually adhering to srp is still pretty subjective. – Andy Mar 12 '14 at 21:37

I can give you several rules of thumb.

  • How easy is it to name the class? If a class is difficult to name, it is probably doing too much.
  • How many public methods does the class have? 7+/-2 is a good rule of thumb. If the class has more than that, you should think about splitting it into several classes.
  • Are there cohesive groups of public methods used in separate contexts?
  • How many private methods or data members are there? If the class has a complex internal structure, you probably should refactor it so that the internals are packaged into separate smaller classes.
  • And the easiest rule of thumb: how big is the class? If you have a C++ header file containing a single class that is more than a couple of hundred lines long, you should probably split it up.
share|improve this answer
Regarding your second point, see… – Cameron Martin Mar 19 '14 at 12:59
Disagree strongly about 7+/-2 - the single responsibility principle is about semantic cohesion, not about arbitrary numbers. – JacquesB Jun 30 '15 at 10:23

OO says that classes are a grouping of data a functionality. This definition leaves plenty of room for subjective interpretation.

We do know that classes should be clearly and easily defined. But, in order to define such a class, we have to have a clear notion of how a class fits into the overall design. Without waterfall type requirements which, paradoxically, are considered an anti-pattern...this is difficult to achieve.

We can implement a class design with an architecture that works in most cases, like MVC. In MVC applications we only assume to have data, a user interface and a requirement for the two to communicate.

With a basic architecture, it's easier to identify cases where single responsibility rules are being broken. E.G. Passing an instance of a User Control to a Modal.

share|improve this answer

Single Responsibility Principles says that each software module should have only one reason to change. On a recent article Uncle Bob explained "reason to change",

However, as you think about this principle, remember that the reasons for change are people. It is people who request changes. And you don't want to confuse those people, or yourself, by mixing together the code that many different people care about for different reasons.

He further explained the concept with an example HERE.

share|improve this answer

Just for the sake of discussion, I will bring up a class from JUCE called AudioSampleBuffer. Now this class exists to hold a snippet (or perhaps a rather long snippet) of audio. It knows the number of channels, the number of samples (per channel), seems to be committed to 32-bit IEEE float rather than having a variable numeric representation or wordsize (but that is not a problem with me). There are member functions that allow you to get the numChannels or numSamples and pointers to any particular channel. You can make an AudioSampleBuffer longer or shorter. I presume the former zero-pads the buffer while the latter truncates.

There are a few private members of this class that are used for allocating space in the special heap that JUCE uses.

But this is what AudioSampleBuffer is missing (and I have had several discussions with Jules about it): a member called SampleRate. How could it be missing that?

The single responsibility that an AudioSampleBuffer needs to fulfill is to adequately represent the physical audio that one hears that its samples represent. When you input an AudioSampleBuffer from something that reads a soundfile or from a stream, there is an additional parameter that you must get and pass it along with the AudioSampleBuffer to processing methods (say it's a filter) that needs to know the sample rate or, eventually, to a method that plays the buffer out to be heard (or streams it to someplace else). Whatever.

But what you have to do is continue to pass this SampleRate, which is inherent to the specific audio living in the AudioSampleBuffer, around to everywhere. I have seen code where a constant 44100.0f was passed to a function, because the programmer didn't seem to know what else to do.

This is an example of failing to meet its single responsibility.

share|improve this answer

A concrete way can be done, based on what you said - that high cohesion leads single responsibility you can measure cohesion. A maximal cohesive class has all the fields used in all the methods. While a maximal cohesive class is not always possible nor desirable to have it's still best to reach to this. Having this class design goal it's pretty easy to deduce that your class cannot have many methods or fields (some say at most 7).

Another way is from the pure basics of OOP - model after real objects. Its much more easier to see the responsibility of the real objects. However, if the real object is too complex break it into multiple containg objects each of has its own responsibility.

share|improve this answer

protected by gnat Jun 29 '15 at 20:48

Thank you for your interest in this question. Because it has attracted low-quality or spam answers that had to be removed, posting an answer now requires 10 reputation on this site (the association bonus does not count).

Would you like to answer one of these unanswered questions instead?

Not the answer you're looking for? Browse other questions tagged or ask your own question.