At what level of abstraction does Single Responsibility Principle (SRP) no longer make sense?

857 views Asked by At

I'm getting push back on a design from a colleague, and am wondering if there's consensus as to who is correct on application of SRP in this case.

I see SRP as relating mostly to the lower-level details of design, such as class responsibility. As you move up in levels of abstraction I believe SRP is still relevant but that the definition of what a single responsibility necessarily also moves toward a higher level of abstraction.

In my specific case, a service that "processes foos, stores their results, and provides access to those results" in my mind has the single responsibility of a "foo handling subsystem", however a colleague disagrees and sees this as 2-3 separate responsibilities. My case is that if you always break down single responsibilities to minute detail then having a "bank" is a violation of SRP since it "holds money, maintains accounts, sells mortgages, ...".

4

There are 4 answers

0
Ned Batchelder On

Like many principles of software design, this seems to me to be enormously subjective, but often argued about as if it were not. "Single Responsibility" is poorly defined, and depends on what you consider a responsibility. There are times when a single piece of code clearly is doing too much, and it's helpful to have a hook on which to hang that concern, but to pretend that it's always a cut-and-dried assessment is silly.

2
MattMcKnight On

I think you are probably right, but can't use this principle to solve your dispute. Robert Martin defines responsibility as "reason to change". If the structure of foo changes (e.g., a field is added) you would want the changes to be reflected in this class. In your colleague's approach, all of the classes would have to change. This is where the principle must be applied within the context of an application layer, because it would change display code as well, which obviously shouldn't be in the same class. If the storage mechanism changes (e.g., using a different database driver) I would expect this to be handled externally, via persistence configuration, so just keep other reasons to change out of your class, and everyone can be happy.

0
Henk van Dijken On

I disagree with your colleague.

The granularity of the single responsibility should match the level in which you are modeling. As you move up in levels of abstraction the granularity of responsibilities also should move toward a higher level of abstraction.

As for the bank example, its single responsibility would be delivering financial service.

This concept works like a work breakdown structure. As you descend and "see" a collection of departments, they will have their own single responsibility. Thus, the responsibility can also break down. Important thing is that the breakdown is aligned.

0
Tom Dalling On

I would agree with your colleague in this case. Storage and processing should be separated because both have different "reasons to change."

As for the bank example you gave, I would argue that a bank doesn't sell mortgages. The loans department (or whatever) sells mortgages, and the bank has a loans department. Treating "the bank" as a single object is the equivalent of one person running an entire bank.