2

From Wikipedia on Single responsibility principle SoC

... class should have responsibility over a single part of the functionality provided by the software, and that responsibility should be entirely encapsulated by the class. All its services should be narrowly aligned with that responsibility

class or module should have one, and only one, responsibility . As an example, consider a module that compiles and prints a report. Imagine such a module can be changed for two reasons. First, the content of the report could change. Second, the format of the report could change. These two things change for very different causes; one substantive, and one cosmetic. The single responsibility principle says that these two aspects of the problem are really two separate responsibilities, and should therefore be in separate classes or modules. It would be a bad design to couple two things that change for different reasons at different times.

The reason it is important to keep a class focused on a single concern is that it makes the class more robust. Continuing with the foregoing example, if there is a change to the report compilation process, there is greater danger that the printing code will break if it is part of the same class.

Is there a rule or general guideline on how to define responsibility of methods in class?

When we talk about objects inanimate objects its easy to see compile report and print report is two different responsibilities. However when it comes to animate objects like dog it becomes not so evident what methods are different in nature.

Say you have:

class dog {
   public $breed;
   public $age;
   public $color;

   function bark($loudness) (
      ...
   ) 

   function pee($amount) (
      ...
   ) 

   function run($speed, $distance, $direction) (
      ...
   ) 

   function growl() (
      ...
   ) 

   function drink() (
      ...
   ) 
} 

how can you tell what responsibility should be in a separate class?

Roman Toasov
  • 191
  • 6
  • Your example methods all fit the dog nicely. Feed would not belong here, while Eat would (unless it is the dog itself that is eating and not being eaten). Choosing class names carefully is really important, it only gets hard and error prone if the name is ambiguous or does not map well to the world you want to model. The criterion is to look for dependencies. Is the bark operation external to the dog? No, the dog can do that all by itself. What about the feeding? It needs someone to feed it so feeding is not a dog operation. – Martin Maat Nov 03 '16 at 13:12

3 Answers3

11

The responsibility here is dog. Dog is as dog does.

Many people read the Single Responsibility Principle as "Must do only one thing." That's not what it means. Bob Martin, author of the principle (and prolific source of mass confusion for inexperienced programmers everywhere) says it like this:

Every class should have only one reason to change.

I view a class as embodying a "purpose" or "area of responsibility." If you write a class that contains Create, Read, Update and Delete methods, those aren't four responsibilities; they are just one: Data Access.

Robert Harvey
  • 198,589
  • 55
  • 464
  • 673
  • Change what? Code or State? Can't be state. Must be code. What's a reason? Must be a stakeholder, then. Whether the stakeholder is the Accounting department or me wearing my refactoring hat in service of "developers". If people don't understand what you mean, but it's really important, they better hire you to come train them in exactly what you do mean. – Aaron Hall Nov 02 '16 at 22:02
  • @AaronHall: Don't ask me. I'm not the one who coined the phrase. – Robert Harvey Nov 02 '16 at 22:04
  • 1
    More specifically, Dog should have only one reason to change: because it is doing Dog things: eating, sleeping, pooping, etc. Trying to shoehorn Cat things into Dog doesn't work. Dogs don't fit on sunny windowsills. But Dog can still do multiple things. –  Nov 02 '16 at 23:00
  • 4
    +1 for _prolific source of mass confusion for inexperienced programmers everywhere_ – jleach Nov 02 '16 at 23:40
  • I've read this answer a few times and concluded that - like -jdl134679 - the take-away line is "... Bob Martin, author of the principle (and prolific source of mass confusion for inexperienced programmers everywhere) ...". So +1, despite a nagging doubt that you didn't really answer the question... :) – David Arno Nov 03 '16 at 00:36
  • 1
    @DavidArno: The answer is "No, there is no rule." If you dig into DDD or something similar, you might find organizational guidance that maps your classes to responsibilities in a sensible way that respects SRP. But SRP is littered with legitimate exceptions: `IEquatable`, `ToString()`, Reflection. It's hard to see how any of these could in any logical or common-sense way be viewed as part of a single responsibility. The best you can hope for is to get an intuitive sense from experience of "these two things do not naturally belong together." – Robert Harvey Nov 03 '16 at 02:23
3

General

Single Responsibility has something to say about semantic redundancy and false semantic cohesion of code fragments (modules, classes, methods functions). The problem is (with all SOLID principles) it's not about applying them, it's about identifying a violation them. Once you think it violates SRP you can make a thought experiment (coordinated with your business people) your code has to pass to verify your assumption.

Semantic redundancy

If a functional requirement occurs and you have to change two code fragments for the same reason you violate the SRP.

This often happens if a developer does not know that some logic already exists that will solve a probem for him and he develops it once again.

False semantic cohesion

If a functional requirement occurs and you produce an unintentional side effect in another code fragment you violate the SRP.

This happens if technically savvy developers try to reduce code duplication without consider semantics.

E.g. a local part check for an email address was implemented at different locations of your code base. A developer extracts the code into one central method because it looks technically equal. Another time another developer has to change the local part check for one case and he does not check if all other usages will be correct under the new implementation.

Conclusion

Duplicate code may be a reason to think of SRP violation. But you have to be careful if you put code together that seems to be equal. You cannot escape from semantics. You have to identify what the code really means in the context to decide if there is a violation of SRP.

You can break it down to: You have to put things together that belong together and you have to isolate thing that do not belong together. But this is an identification process.

In your example you have a Dog class with several methods that represent actions of a dog. If you are paranoid you can see your first redundancies: All methods can be "executed". So "Execution" is what they all have in common. But we have a hard time to extract this part as the programming language itself takes care of the execution. So there are lower boundaries to SRP that are related to the used programming language.

Ok. Your dog barks, pees, drinks, growls and runs. I only can say, that I currently see no violation of SRP. But that doesn't mean there isn't. Once you find an indicator that may be semantically redundant or false in the context of semantic cohesion you can ignite.

After all I want to say that sometimes some SRP violation can be tolerated as the code is expected to be stable in changes. But this is only about to be pragmatic and never a rule.

Robert Harvey
  • 198,589
  • 55
  • 464
  • 673
oopexpert
  • 769
  • 4
  • 7
1

I this conference in Yale, Uncle Bob gives this funny example:

enter image description here

He says that Employee has three reasons to change, three sources of change requirements, and gives this humorous, tongue-in-cheek, but illustrative nonetheless, explanation:

  • If the CalcPay() method has an error and costs the company millions of US$, the CFO will fire you.

  • If the ReportHours() method has an error and costs the company millions of US$, the COO will fire you.

  • If the WriteEmmployee() method has an error that causes the erasure of a lot of data and costs the company millions of US$, the CTO will fire you.

So having three different C level execs potentially firing you for costly errors in the the same class means the class has too many responsabilities.

He gives this solution that solves the violation of SRP but has yet to apply the DIP (Dependency Inversion Principle) which he explains but is not shown in the video because there's no camera shot to the slide while he does it.

enter image description here

Robert Harvey
  • 198,589
  • 55
  • 464
  • 673
Tulains Córdova
  • 39,201
  • 12
  • 97
  • 154