I\'ve recently stumbled upon Clean Architecture, by Uncle Bob, and I\'m curious to know whether Interactors can execute other Interactors.
For example, these are my Inte
I am very new to Uncle Bob's work and I am also going through these exact same questions and problems.
My answer to maintaining the SRP and not repeating yourself (DRY) with use cases was to separate the use cases from the interactor. It's possible that this is overkill but it really worked out well for me.
I have my use cases in their own files, separated from the interactors so that all separate interactors can use whichever use cases they want and share. All the while, the interactor just "uses" (imports, depends on, etc) any use case it wants.
Doing it this way has made my interactors very simple and is really only a container for the dependency injection(s) required, and some class level member vars.
So in summary, getAllAlbums, getEmptyAlbums and getOtherAlbums use cases become their own files and follow SRP and you have an Interactor class that aggregates at will and/or stitches together use cases in sequence.
Lately I have also been making my use cases only do actual business logic and not include things from dependency injection gateways like database or network calls. I then put the code for these dependency gateway actions in the methods operating the use cases...
Now if you only have "black-boxed" business logic concepts in use cases, you can test without including the dependencies being tightly coupled. So if you we're making the game "Tic Tac Toe" for example, your use cases when (looked at in quick glance) would be talking only the language of "Tic Tac Toe" and not "save", "commit" or "fetch[X]". You can save testing those things in the interactors test or in the gateway itself.
I have been pondering the same thing and after finding very little on the subject, I have come to the conclusion "Yes" it is probably the best option.
my reasoning as follows:
To preserve single responsibility, I would consider limiting aggregating use-cases to do only that, i.e. executing those use cases and doing any final transformations.
Given the age of this question, I'd be interested to know which way you went with this and issues you encountered.
My answer would be no. Let me explain the reasons:
One of the most important concepts of Clean Architecture, is boundaries. Each use case defines a boundary, a vertical layer of a system. Therefore there's no reason to let a use case know about the existence of another use case. This vertical layers, allows to get independent develop-ability and deployability of the use cases. Imagine we are working as a team, you develop GetEmptyAlbums use case, and I work on the GetAllAlbums use case. If I call your use case in my own, we are not developing independently. Neither we're achieving independent deployability. The vertical boundaries breaks. See page 152 of Clean Architecture book and chapter 16 in general, for more details on that.
Suppose GetEmptyAlbums business rules changes for any reason. You will be in need to refactor that use case. And now maybe you need to accept some input. If GetAllAlbums invokes GetEmptyAlbums, this use case must be refactored too. In other words, by coupling use cases you are adding more responsibilities. Therefore SRP breaks.
There are 2 kinds of duplication: true duplication and accidental duplication. By defining 2 or more use cases that are very similar with each other, you're getting accidental duplication. It is accidental, because in the future the will become different probably and (this is what's matters) for different reasons. See page 154 for this concepts.
Very related to SRP. If you change something on use case A, and C calls A, not only A tests will break, but C tests too.
In conclusion, the answer is no, you cannot call a use case interactor from another one. But this rule applies if you want to achieve a pure Clean Architecture approach, which not always might be the right decision.
Another thing to point out, is that use cases must declare an input and output data structures. I'm not sure if your Album class is an Entity, but if so, there's a problem there. As Uncle Bob says: "we don't want to cheat and pass Entity objects" between boundaries (page 207).