Architecture – Clean architecture – How to deal with use case reuse

Architectureclean codeuse-case

Trying to apply Uncle Bob's clean architecture to an application I'm maintaining and I'm having difficulties with use cases and duplication/reuse. It's my understanding that usecases should be self contained and that duplication is to be expected but this does not seem to make sense with what I'm dealing with.
I feel there are multiple use cases that should end up using other use cases.

Here is a very simplified example of 4 use cases that exist separately but that are also dependent on each other in the following way.

BulkSendUsersToUnit               
    SendUserToUnit   
        AddUserToMandatoryGroups  
            AddUserToGroup 

Each of them have validation, repository calls and conditions that always apply.
Basically if I was doing this with services they would simply be methods that I would call from where I need them.

Can I/should I inject use cases in other use cases using DI?

What am I missing here?

Best Answer

A use case is not a method.
A use case is not an object.
A use case is not a layer.

A use case is a story about a user, using the software, in a particular case.

So it should come as no surprise that different use cases can reuse the same code.

But maybe you watched one of the video'spaywalled where Bob makes out like a use case is part of your architecture.

enter image description here

Well don't worry. It's just a name for the boxes in one of his layers. He's used other names for it:

enter image description here

Does this mean Uncle Bob is wrong? No. The Interactor / Use Case / Application Business Rule / Oh-pick-a-name-and-stick-with-it layer is where you ignore all of the needs of your application (details) and focus on the needs of the user going through a particular use case. But this location in your code is not THE use case. The use case is the whole story from when the user clicks a button to when they see the result.

So should interactors (or whatever you want to call them) use other interactors? Well this is the rub of following DRY to the extreme. You're not allowed to put the code from AddUserToGroup anywhere else right?

Baloney. If AddUserToMandatoryGroups means something different, has a different reason to want to change than AddUserToGroup does then it's ok to give AddUserToMandatoryGroups its own add-user code. Even if right now it's a character for character copy of the code in AddUserToGroup. If you have good reason to think these need to be able to change independent of each other it doesn't matter if right now they look identical. Apply DRY to repeating ideas. Not code.

As for Dependency Injection, that still works fine whenever you want to decouple what from when.

Bulk shitlist = new Bulk(annoyingUsers, bannedForLifeUnit);

Register.OnIveHadAllICanTake( ()-> shitlist.send() );