2

I've generally understood the SRP to roughly mean:

Each class should do one thing

Exactly what "one thing" is is up for debate.

However, I've recently seen claims that the entire SRP has been misunderstood and misquoted so severely that its meaning has changed. In fact, its original meaning was:

Each class should be the responsibility of a single team/person

Meaning that there is only a single team that would have any reason to change a class. Incidentally, that probably would lead you to a similar place as the more common definition.

Personally, I actually prefer the latter definition because it gives you most of the benefits of the first without also leading you towards unneccessary hyper-classification.

I'm just wondering if there's any truth behind these claims and what people's thoughts are on the competing definitions.

Also note, you can replace class with module or whatever unit of code your language uses.

9
  • 1
    Those two definitions do not lead to the same practices at all, and the former definition is far more well-known. Where do the claims you mention come from? Jan 24 at 12:22
  • @KilianFoth - galiarmero.dev/blog/… and that links through to a blog post by Uncle Bob Jan 24 at 13:38
  • 6
    No two ways about it: that blog post is just objectively wrong.
    – Duroth
    Jan 24 at 13:51
  • 1
    I think that your choice of wording ("team/person") is causing some confusion for the readers/answerers, as they seem to be interpreting "team" as "developer team" - but the blog doesn't actually phrase it like that, nor is it talking about dev teams, but rather about various stakeholders that represent different drivers of change. Jan 24 at 15:51
  • Being that Martin Fowler coined the term, see his definition: blog.cleancoder.com/uncle-bob/2014/05/08/… Jan 24 at 15:54

5 Answers 5

6

The Single Responsibility Principle is confusingly named and vaguely defined. Robert Martin who first named the principle has revised and clarified its meaning multiple times, but it still causes plenty of confusion. That said, neither of the two definitions you give are even close.

Initially, the principle was defined as "A class should have only one reason to change", where change refers to changes in the source code.

A responsibility is an "axis of change", i.e. it represents a business requirement that may change over time, making it necessary for developers to change the code.

Of course this just raises the question of how to identify such an "axis of change". In later elaborations, Robert Martin has focused on the different actors or stakeholders that may cause requirement changes - e.g. different departments in an organization.

For example, if you have a module that calculates tax and draws the company logo, you have a violation of the principle, since the tax code likely will change independently of the logo design, since these are decided by different organizations or departments.

Of course, the principle should not be taken too literally. It is common in software development to have a single "product owner" who decides what goes into the product. But you have to consider the deeper causes behind the changes. This means a developer cannot just blindly implement a list of requirements received from above. The developers also need to understand the reasons for the requirements and what might cause them to change.

A more practical approach is to observe what parts of a system change over time, and separate the things that change often from things that remain stable.

The principle does not say that a class should only do "one thing", which is a nonsensical principle anyway - what does "one thing" even mean?

2
  • 3
    "A more practical approach is to observe what parts of a system change over time, and separate the things that change often from things that remain stable." - this! ...
    – Doc Brown
    Jan 25 at 14:10
  • Great point - sometimes you aren't sure what parts will change over time until you start using the code.
    – user949300
    Jan 25 at 21:42
2
  1. Read the blog post kindly linked by @Greg Burghardt
  2. Ignore, for now, most everything Uncle Bob writes.
  3. Focus on the 1972 text by David Parnas, especially the parts that Uncle Bob highlights.

We propose instead that one begins with a list of difficult design decisions or design decisions which are likely to change. Each module is then designed to hide such a decision from the others.

Then go back and read Bob's text. The principle is about decisions. Decisions are made by people. And it will be clearer. I think he emphasizes company management too much - many technical decisions are made by tech leads. But the principle remains. If something was a difficult decision, such as REST vs GraphQL, or likely to change, such as starting with SQLite and realizing that if the product does great you will need a different DB, then that decision should be isolated, so that changing that decision only affects a few classes, not the entire code base.

1
  • 2
    I think item 2 is an universal answer to many questions on this site
    – Basilevs
    Jan 25 at 13:19
1

I would steer you away from the "reposisiblity to a team" interpretation.

Clearly, if you have a small company with a single dev team, you wouldn't want to put everything in a single class. Similarly, if you publish a library class "File Reader" which is used by many teams across the world you need to make sure it works for them all, not just you.

The normal interpretation of "Does one thing", Reads Files, talks to database, calculates square roots etc might be slightly vague on where you draw the line; but it does produce useful results. In that when you change the way you write to files, there is only one class to change instead of 100.

Also, often I see "single responsibility principle" brought up when developers aren't making enough classes. Questions like: "should I have two classes one that write and one that reads?" don't cause problems. It's "I need to change to Fat64 and have to find all the places we write to disk and change them", or "OMG you only have one class how do i write unit tests?" or "I changed one class and broke something unrelated" which cause the issues and make people invoke the principle.

1
  • 2
    I don't think following the alternative advice implies that you have a mono-class for everything else. You'd still want to split stuff down where it makes sense, you just don't get the interpretation that it should be taken to the extreme where each class has like 2 lines of useful code Jan 24 at 14:42
0

Note that the blog post speaks about modules, not classes. It is a bit more abstract and higher level. Note also that the reference to people is mostly to clarify what it means that a piece of software (module or - depending on your design - class) should have one concern/job. The post doesn't say only one person should edit the code or the like. It just says that change to one class should originate from one source and if you go high enough in a company theoretically you can trace that to one person. However, this all just serves to make "one job" more clear - as on an organizational level it is easier to understand that say the department for public relations should make no decision that directly requires a change in the method that calculates money each employee gets each month. They might use the output of said method when trying to hire people but should not change it. If you go out into the real world of company organisation that sometimes makes it clearer what domain an operation belongs to and how to split functionality up as company hierarchy often reflects that pretty clearly.

0

Each class should be the responsibility of a single team/person

There's certainly some truth in this, because what we are saying is that the source code should be structured in a way that it is fully covered by a single supervising agent - either an individual, or a team organised collectively for the purpose.

There should be no classes that are not under the sole supervision of either an individual or a team.

However I think this may be a different and unrelated principle, than the standard SRP.

I'm not really a fan of the SRP as conventionally expressed, because it's never clear exactly what a "responsibility" is, or why a single application should be automatically decomposable into a series of purely separate responsibilities.

Personally I think a "responsibility" is a potentially ephemeral idea in the mind of the programmer, and any part of code which performs a "responsibility" may well perform more than one such responsibility, including different, multiple, and overlapping responsibilities as conceived from time to time by different (or even the same) programmer. It therefore becomes impossible to ensure that elements of source code always have exactly one responsibility.

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