Does the Single Responsibility Principle work in OOP?
Asked Answered
F

8

10

I am struggling to understand how the Single Responsibility Principle can me made to work with OOP.

If we are to follow the principle to a tee, then are we not left with many classes, many of which may just have one method each?

If we don't follow the principle exactly, then what is the point in the principle?

Fronton answered 3/10, 2017 at 9:19 Comment(3)
Here is someone who wrote about struggling w/ SRP sklivvz.com/posts/…Echelon
the point at the fundamental level is encouraging writing objects w/ high cohesion (the "parts" that are included are highly related and belong together)Echelon
See the tag wiki.Nephron
A
14

I like to state the single responsibility principle this way: "Every thing you write -- every module, class, interface, or method, should have one job. It should do the whole job and only that job.

Notice that some of these things you write are big (modules), some are small (methods), some are in between (classes), and some of the big things are made of smaller things.

That is not a problem, because jobs or responsibilities also come in various sizes and can be decomposed hierarchically. The job of the police force, for example, is to "protect and serve" -- one job, that decomposes into "patrol the streets", "solve crimes", etc., which can each be handled by a different unit. That creates the need for coordination (a different job), and the job of each unit breaks down into jobs for individual officers, etc.

For every big job, there are many ways to break it down into smaller jobs, and every one of those can be modeled by a software design that adheres to SRP and the other SOLID principles. Deciding how to break a problem down is a big part of the art of software design.

Autobiography answered 4/10, 2017 at 3:7 Comment(7)
This is exactly what I was confused with - varying sizes of responsibilities across jobs. Is there a specific point where you should stop decomposing responsibilities, or just go with what feels right?Fronton
There is a trade-off: Breaking a job into smaller jobs makes the big job easier to understand, but increases the number of jobs, which can make the system as a whole more complex. There's a sweet spot where the solution for each job fits comfortably into your head and breaking it up more would make it more difficult to work with, because the changes you need to make would mess with more things. Stop there. It's a slightly different place for everybody.Autobiography
Absolutely. I believe ideally dividing big task into smaller ones that would restrict each function to do only one job. Each job is atomic meaning logically isolated and complete. This would be an ideal scenario but in practice we try to get as close as possible to this.Crannog
One of the best thought exercises I do to help with this is to try to predict what changes may occur in the system. Then I try to understand how to separate responsibilities so if something does change, I don't need to refactor existing code, but I can remove existing jobs, and replace them with new ones, keeping the interfaces between them as intact as possible. This reminds me of a talk Justin Searls gave at RailsConf this year, youtube.com/watch?v=V4fnzHxHXMI. Not all of it is relevant directly, but it may help your decision makingGardy
@Gardy Returning to say that the video is great! Though I stumbled onto some of the practices mentioned through trial and error, it is a really good resource for TDD and development in general.Fronton
This answer conflates the SRP with "do one thing" but they are two separate principles. See: What is the scope of the Single Responsibility Principle?Nephron
@Nephron That's a valid point, but I like to use the word "Job", because a single job implies a single boss. I don't think there's a need to consider these principles as separate when designing software, but now that you mention it, the rationale for adhering to those two principles is distinct.Autobiography
O
6

A class shall handle one topic, that's its single responsibility. A class Car could contain methods like startEngine() or attributes like weight:

class Car
{
    int weight;
    void startEngine();
    void stopEngine();
}

Of course you can break up this class more. For example by defining a class for the engine:

class Engine
{
    start();
    stop();
}

class Car
{
    Engine engine;
    int weight;
}

But you shall not define seperate classes for starting and stopping the engine like:

class EngineStop
{
    stop();
}

class EngineStart
{
    start();
}

class Car
{
    EngineStart engineStart;
    EngineStop engineStop;
    int weight;
}

The principle says to break up classes as reasonable as possible to achieve abstractness. Abstracting too deep violates this principle.

Otherdirected answered 3/10, 2017 at 9:33 Comment(1)
I understand the SRP, but where does the “ you shall not define seperate classes for starting and stopping the engine” come from?Fronton
S
3

This is one of the common misunderstanding of Single Responsibility Principle that a class should have only one function. A class is responsible for only one thing doesn't mean a class should have only one function. Single Responsibility Principle means logically separate your functionality into different classes instead of mixing up things.

One very simple example is, say if you are creating a Calculator you can add all functionalities purely for the calculator in the same class (add, subtract, multiply, divide etc.). You don't need to create a separate class for each of the functionality of calculator. But if you want to print calculated result to a printer then don't write the logic of printing to printer inside calculator class because printing to the printer is not the responsibility of calculator class. Create a separate class for the printer and write printing related logic in that class. If you are writing printing functionalities inside Calculator class then you are violating Single Responsibility Principle.

Spencer answered 3/10, 2017 at 10:40 Comment(0)
S
1

Single Responsibility term was introduced by Rober C. Martin. Main motto of this principle is a reason to change. A class or module should have one, and only one, reason to be changed.The major benefit of this principle is that is makes the class more robust. Changes in one class or module doesn't break the other part.

It prevents an object from becoming a God Object that is an example of Anti-Pattern. It also prevents from Ravioli code (A source code with lots of tiny, tightly-coupled objects).

Hence, Single responsibility principle is an important part of good source code design in OOP.

Synthesis answered 11/10, 2017 at 8:18 Comment(0)
O
0

I tend to think of the Single Responsibility Principle (and really a lot of the rules of thumb, patterns, and models) as a general way of thinking about problems. It's meant to guide you toward improvements to your code, but not necessarily prescribe exactly what a solution looks like. Because ultimately software design is a wicked and subjective problem.

I don't think that SRP should always lead to a bunch of single function classes. Though these may sometimes occur if you have some complex logic that you want to abstract away. In general, though, you should trend toward classes with highly cohesive functionality where methods:

  1. Are all related to the same abstraction(s)

    • Don't have a mish-mash of functionality that isn't related to each other in the same class.
    • Keep things like business logic separate from UI separate from I/O
  2. Share common dependencies

    • Related functionality usually has related dependencies.
    • I usually consider breaking up a class when I start getting more than around 7 dependencies. Often there's a class I can extract to move a few of the dependencies into a more cohesive unit.
  3. All operate at the same level of abstraction

    • Your abstractions should be hierarchical; some classes should orchestrate other classes to accomplish a workflow. Other classes will handle the specific implementation-level details.
    • Avoid having orchestration-style classes getting into the nitty-gritty. You don't want detailed operations to live side by side (in the same function or even the same class) with abstractions of more complex operations.

You actually want to try to group as much functionality as you can, while maintaining the above conditions and keeping in mind how understandable your abstraction is. Ultimately the goal of the Single Responsibility Principle is to help manage complexity and make the code more understandable.

Oaken answered 5/10, 2017 at 22:58 Comment(0)
W
0

Before you go into decomposing responsibilities, you should have an idea on what the class is supposed to do. It's supposed to do that thing and only that thing as Matt mentioned in his answer. Implement that idea in the simplest way possible just to make it work. That's when you go about decomposing the code you wrote into responsibilities.

The important thing to consider when you break down your code is to make sure that it is readable after breaking it down.

Weakminded answered 9/10, 2017 at 4:0 Comment(0)
H
0

Single Responsibility Principle should be renamed to:

Single Point of View (POV)

Meaning: you can not mix different points of view into single class/object.

Your class should be someone's point of view - a representation which is codified.

Every Representation consist of Subject and Object. Who is the knowing Subject is crucial.

This is the whole meaning of vastly misunderstood principle https://www.sicpers.info/2023/10/ive-vastly-misunderstood-the-single-responsibility-principle/

When you write a software module, you want to make sure that when changes are requested, those changes can only originate from a single person, or rather, a single tightly coupled group of people representing a single narrowly defined business function.

This is nothing more then knowing Subject(POV), which is more abstract term because it subsumes single person, group of man that exist or will exist in the future. Because if you are in early stage or startup those people or single man do not yet exist. But you need to be smart and recognize that POV in advance. In the end it is all about problem/task that needs to be solved and every problem has a unique POV because it requires multiple complex objects for solution. Or it may not be people in business but tech people - tech point of view (like aspects, loggers etc). You start with the problem. Problem creates your POV because it becomes more complex the more you focus on. Logging wants to solve some problem and from its POV creates different complex objects and it should not be mixed with business objects from domain like Product, Ticket etc.

Hibben answered 25/7 at 21:30 Comment(0)
A
-1

I quote Robert C. Martin from his book Clean Code:

The Single Responsibility Principle (SRP) states that a class or module should have one, and only one, reason to change. This principle gives us both a definition of responsibility, and a guidelines for class size. Classes should have one responsibility—one reason to change.

Automotive answered 11/10, 2017 at 7:2 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.