I'm currently developing an application following the Clean Architecture principles (at least I'm trying really hard to follow these).
All my Dependency Injections are done manually, without any Framework.
One of my Use Case consists of the user being able to answer to a question he was asked.
If he/she is wrong, nothing happens, he can try again
If he/she is right, a list of things happens :
I get back his/her current session, and modify the state of that session. (Update session step - DB read)
I get back a contact record from the database (Get Contact step - DB read)
I send a mail into an in-app mailbox with this contact information (basically it's a database insert of a message) (Send Mail step - DB write)
I save the updated session (Save session step - DB write)
I push an event into a custom Message Queue (Programm event step - Queue write)
All of the work described above are the steps I need to go through if the user answer to this question; it's kind of an Application Logic. For that reason, I created a specific
AnswerQuestionUseCase which do all of this.
Because of all these databases interactions, I now have 5 dependencies injected into my Use Case, and I'm starting to think this is a code smell of bad design. The unit test of this class is ugly, not quite readable with all these mocks.
I searched a bit how to deal with this issue, and I found that Function Composition might be a good way to avoid so many dependencies, but I've found that if a go that way, all of the Application Logic would go outside of my Use Case, deported into the presenter maybe.
I could also break my Use Case into smaller Use Cases, but that just hide the issue, pushing the dependencies elsewhere.
I thought the Use Case was a block of Application Logic which you couldn't break apart for a specific use case of your app.
Is my understanding of what should be a Use Case any good ? How would you deal with that many dependencies ? How would you use Composition over DI to avoid so many mocks inside the unit test of this case ?
UseCaseis totally agnostic to concepts like
Sending an Email if...or
Program event. These things happen in different layers due to different reasons. Are not you, maybe, missing a service layer where to orchestrate whatever happens after the use case? Or a system of callbacks, error handling, etc.
Use Casemanipulate these concepts via interfaces. What would the service you're talking about look like in this case ? I'm afraid about just moving some work at another level (service), then having nothing to do inside the UC but calling the newly created service.