I disagree with Uncle Bob's use of the term "use case" but I understand what he's getting at. I don't really want to quibble over the semantics of the term in any case.
For the sake of this question, use cases
are application specific business rules.
Your question is really "when are separate layers needed for both enterprise business rules and application specific business rules?" And the quick answer is you need them when your application grows large enough to justify it.
If there are a small number of rules from either set, then it's just as easy to keep the implementation of those rules within a single application layer. If there are lots of rules for both sets, then you'll want to break them out to specific layers.
Uncle Bob lays out a rule that the inner circles shouldn't know of the outer circles in his architectural diagram. And that's ultimately the answer to your question. As the rules evolve and have clear delineation from the others then you'll need to isolate them out to separate layers.
In my opinion, that's absolutely not how it's meant. And it's a violation of DRY.
The idea is that the entity / domain object in the middle is modeled to represent the domain as good and as convenient as possible. It is in the center of everything and everything can depend on it since the domain itself doesn't change most of the time.
If your database on the outside can store those objects directly, then mapping them to another format for the sake of separating layers is not just pointless but creating duplicates of the model and that is not the intention.
To begin with, the clean architecture was made with a different typical environment / scenario in mind. Business server applications with behemoth outer layers that need their own types of special objects. For example databases that produce SQLRow
objects and need SQLTransactions
in return to update items. If you were to use those in the center, you were to violate the dependency direction because your core would depend on the database.
With lightweight ORMs that load and store entity objects thats not the case. They do the mapping between their internal SQLRow
and your domain. Even if you need put an @Entitiy
annotation of the ORM into your domain object, I'd argue that this does not establish a "mention" of the outer layer. Because annotations are just metadata, no code that isn't specifically looking for them will see them. And more importantly, nothing needs to change if you remove them or replace them with a different database's annotation.
In contrast, if you do change your domain and you made all those mappers, you have to change a lot.
Amendment: Above is a little oversimplified and could even be wrong. Because there is a part in clean architecture that wants you to create a representation per layer. But that has to be seen in context of the application.
Namely the following here https://blog.8thlight.com/uncle-bob/2012/08/13/the-clean-architecture.html
The important thing is that isolated, simple, data structures are passed across the boundaries. We don’t want to cheat and pass Entities or Database rows. We don’t want the data structures to have any kind of dependency that violates The Dependency Rule.
Passing entities from the center towards the outer layers does not violate the dependency rule, yet they are mentioned. But this has a reason in the context of the envisioned application. Passing entities around would move the application logic towards the outside. Outer layers would need to know how to interpret the inner objects, they would effectively have to do what inner layers like the "use case" layer is supposed to do.
Besides that, it also decouples layers so that changes to the core don't necessarily require changes in outer layers (see SteveCallender's comment). In that context, it's easy to see how objects should represent specifically the purpose they are used for. Also that layers should talk to each other in terms of objects that are made specifically for the purpose of this communication. This can even mean that there are 3 representations, 1 in each layer, 1 for transport between layers.
And there is https://blog.8thlight.com/uncle-bob/2011/11/22/Clean-Architecture.html which addresses above:
Other folks have worried that the net result of my advice would be lots of duplicated code, and lots of rote copying of data from one data structure to another across the layers of the system. Certainly I don’t want this either; and nothing I have suggested would inevitably lead to repetition of data structures and an inordinate of field copying.
That IMO implies that plain 1:1 copying of objects is a smell in the architecture because you're not actually using the proper layers and /or abstractions.
He later explains how he imagines all the "copying"
You separate the UI from the business rules by passing simple data structures between the two. You don’t let your controllers know anything about the business rules. Instead, the controllers unpack the HttpRequest object into a simple vanilla data structure, and then pass that data structure to an interactor object that implements the use case by invoking business objects. The interactor then gathers the response data into another vanilla data structure and passes it back to the UI. The views do not know about the business objects. They just look in that data structure and present the response.
In this application, there is a big difference between the representations. The data that flows isn't just the entities. And this warrants and demands different classes.
However, applied to a simple Android application like a photo viewer where the Photo
entity has about 0 business rules and the "use case" that deals with them is nearly non-existing and is actually more concerned about caching & downloading (that process should IMO be represented more explicitly), the point to make separate representations of a photo starts to vanish. I even get the feeling that the photo itself is the data transfer object while the real business-logic-core-layer is missing.
There is a difference between "separate the UI from the business rules by passing simple data structures between the two" and "when you want to display a photo rename it 3 times on the way".
Besides that, the point where I see those demo applications fail at representing the clean architecture is that they add huge emphasis on separating layers for the sake of separating layers but effectively hide what the application does. That is in contrast to what is said in https://blog.8thlight.com/uncle-bob/2011/09/30/Screaming-Architecture.html - namely that
the architecture of a software application scream about the use cases of the application
I don't see that emphasis on separating layers in the clean architecture. It's about dependency direction and focusing on representing the core of the application - entities and use cases - in ideally plain java without dependencies towards the outside. It's not so much about dependencies towards that core.
So if your application actually has a core that represents business rules and use cases, and / or different people work on different layers, please separate them in the intended way. If you're on the other hand just writing a simple app all by yourself don't overdo it. 2 layers with fluent bounds may be more than enough. And layers can be added later on as well.
Best Answer
OK, I think I see what's going on: you've got a context impedance mismatch.
The basic idea to recognize is this: the "View", so to speak, changes with every HTTP request that arrives (more precisely, it has a scope coupled to the lifetime of the HTTP Connection, but that's not important here).
That means that we need to compose a new
Controller->Use-Case-Interactor->Presenter
pipeline for each request.The good news: Spring is already doing that for you under the covers.
The bad news: Spring is using a single Input-Output boundary, rather than separating them.
I say "bad news" because you are trying to make this round peg fit into the square hole described by Martin. I think what Spring is doing here is "fine", it's just inconvenient for the interfaces you want.
So let's pretend: you have a use-case-interactor that expects to be wired to an input boundary and an output boundary, and you have this signature on your controller. Now what?
If you were a bit luckier with the API for your UseCaseInteractor, it might instead look like:
You might find this more familiar if we were to structure it as a callback
The core idea, though, is that you have two functions; in the module with your use case interactor, you have a function that looks like
and in your web layer, you have a function that looks like
the input and output boundaries are just a way to compose those two functions without introducing a dependency that points the wrong way.