13

The SRP states that a class (module) should have only one reason to change. The "duties" of an Interactor in Bob Martin's clean architecture are, per use case: receive requests/inputs from a controller; orchestrate domain entities to fulfil the requests; and prepare the output data.

Does this imply three reasons to change? (ie whenever inputs change or domain functionality is expanded or extra output fields are added.) If necessary, what would be a good strategy to resolve this? (eg, CQRS?)

My current approach is to make a use-case Interactor module with three classes, one per each concern, and a fourth Facade/ Mediator class for orchestration and clients interfacing. However, doesn't this push SRP violation up onto the module level?


As pointed by @Robert Harvey, the term "duties" was used rather sloppily. The actual design issue has been the large changes to the interactor needed both when the domain changed, and the OutputData fields/formats changed (less so with input). Aren't these two distinct reasons for change?

As I realised from @Filip Milovanović and @guillaume31, SRP is not violated, esp. with three separate classes in the interactor module. Also, at the module level, the "Common Closure Principle" is perhaps more appropriate than the SRP. The CCP ("Gather into components ... classes that change for the same reasons and at the same times.") might suggest to separate the interactor classes. (But then the classes corresponding to the same use case would be spread out between locations.) Thanks to the answers and comments, these trade-offs have become much clearer to me.

5
  • Depends on how much logic or behavior there is in the receiving input and preparing output. I would agrue those should be just dumb "data mappers".
    – Euphoric
    Commented Jan 26, 2018 at 14:24
  • There's some logic in preparing output. The main issue is that both the domain evolves (which is fine), but also formats/fields of the output data change often. The latter has caused a lot of rework in interactors. Commented Jan 26, 2018 at 14:54
  • Perhaps an Interactor is essentially a three-side adaptor: Input to Domain and Domain to Output? Then it's natural for the Interactor to change once any of the three changes. With little input/output logic in the interactor (as commented by @Euphoric) SRP shouldn't matter much. With considerable (non-reducible) logic, it might be necessary to separate the responsibilities? Commented Jan 26, 2018 at 15:26
  • 1
    I'd say its OK to separate responsibilities if you find that there's a need. But if you find that you always have to make changes in several classes that constitute the same Interactor, then perhaps the concerns should be separated in a different way (depending on what kind of change patterns show up, and what parts of code you wan't to isolate from change). P.S. "However, doesn't this push SRP violation up onto the module level?" - I'd say no, because the specific responsibilities still remain in the subcomponents. Commented Jan 26, 2018 at 15:43
  • Otherwise, when you take that to the extreme, you could argue that the whole program violates SRP because it "does everything" - but that's not the point of SRP. Commented Jan 26, 2018 at 15:43

4 Answers 4

30

The "duties" of an Interactor in Bob Martin's clean architecture are, per use case: receive requests/inputs from a controller; orchestrate domain entities to fulfil the requests; and prepare the output data.

Does this imply three reasons to change?

You're confusing duties with responsibilities. More specifically, you're confusing "should have only one responsibility" with "should do only one thing."

The responsibility of an interactor is to "interact."

The responsibility of a data access class is to access data. It doesn't have four responsibilities because it creates, reads, updates and deletes; it has four duties.

If you're a short-order cook, your responsibility is to make meals. You don't split your duties into separate employees. You don't have one employee that cracks the egg, another employee that turns it over, and a third that puts it on the plate. You perform all three.

1
  • The chef in the kitchen has one responsibility: To cook good food. Doesn’t mean he can’t cook steaks, sausages, mashed potatoes vegetables and so on and so on.
    – gnasher729
    Commented Oct 1, 2023 at 19:04
4

For a method, receiving input parameters and returning an output are not responsibilities per se.

Mapping/formatting the data to make it ready for transfer to another layer might be considered one, but it can be externalized to a Mapper object.

And no matter if you orchestrate calls to one, 2 or ten collaborators, it's still a single responsibility, so no problem here.

0

One reason to change is not as clear as Robert Martin corrected himself in his videos. IMHO, the better explanation is One role to change (c), which means that only one role should change a module. For example, some of the possible roles are DBA, a product owner, a business analytic, a designer, a lawyer with the new calculation rules etc. That means, that css changes should not affect the business logic, and the DB sharding shouldn't change use case logic. That's all. And this rule is for modules only, someone could apply it to classes or methods, but the reason this rule was created for is to split code by roles who can change the code.

-1

The Clean Architecture book clarifies SRP (p.62):

Historically, the SRP has been described this way:

A module should have one, and only one, reason to change.

Software systems are changed to satisfy users and stakeholders; those users and stakeholders are the "reason to change" that the principle is talking about. Indeed, we can rephrase the principle to say this:

A module should be responsible to one, and only one, user or stakeholder

Unfortunately, the words "user" and "stakeholder" aren't really the right words to use here. There will likely be more than one user or stakeholder who wants the system changed in the same way. Instead, we're really referring to a group-- one or more people who require that change. We'll refer to that group as an actor.

Thus the final version of the SRP is:

A module should be responsible to one, and only one, actor.

1
  • Are you sure this is correct? I've done some editing, some of them were spelling corrections, and I can't imagine an official documentation making such kind of easy mistakes.
    – Dominique
    Commented Sep 28, 2023 at 9:01

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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